001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2023, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.oauth2.sdk; 019 020 021import com.nimbusds.oauth2.sdk.id.Identifier; 022import com.nimbusds.oauth2.sdk.util.MultivaluedMapUtils; 023import net.jcip.annotations.Immutable; 024 025import java.util.*; 026 027 028/** 029 * Authorisation grant type. 030 */ 031@Immutable 032public final class GrantType extends Identifier { 033 034 035 /** 036 * Authorisation code, as specified in RFC 6749. 037 */ 038 public static final GrantType AUTHORIZATION_CODE = new GrantType("authorization_code", "code", false, true, ParameterRequirement.NOT_ALLOWED, new HashSet<>(Arrays.asList("code", "redirect_uri", "code_verifier"))); 039 040 041 /** 042 * Implicit, as specified in RFC 6749. 043 */ 044 public static final GrantType IMPLICIT = new GrantType("implicit", false, true, ParameterRequirement.NOT_ALLOWED, Collections.<String>emptySet()); 045 046 047 /** 048 * Refresh token, as specified in RFC 6749. 049 */ 050 public static final GrantType REFRESH_TOKEN = new GrantType("refresh_token", "refresh token", false, false, ParameterRequirement.OPTIONAL, Collections.singleton("refresh_token")); 051 052 053 /** 054 * Password, as specified in RFC 6749. 055 */ 056 public static final GrantType PASSWORD = new GrantType("password", false, false, ParameterRequirement.OPTIONAL, new HashSet<>(Arrays.asList("username", "password"))); 057 058 059 /** 060 * Client credentials, as specified in RFC 6749. 061 */ 062 public static final GrantType CLIENT_CREDENTIALS = new GrantType( 063 "client_credentials", 064 "client credentials", true, true, ParameterRequirement.OPTIONAL, 065 Collections.<String>emptySet()); 066 067 068 /** 069 * JWT bearer, as specified in RFC 7523. 070 */ 071 public static final GrantType JWT_BEARER = new GrantType( 072 "urn:ietf:params:oauth:grant-type:jwt-bearer", 073 "JWT bearer", false, false, ParameterRequirement.OPTIONAL, 074 Collections.singleton("assertion")); 075 076 077 /** 078 * SAML 2.0 bearer, as specified in RFC 7522. 079 */ 080 public static final GrantType SAML2_BEARER = new GrantType( 081 "urn:ietf:params:oauth:grant-type:saml2-bearer", 082 "SAML 2.0 bearer", false, false, ParameterRequirement.OPTIONAL, 083 Collections.singleton("assertion")); 084 085 086 /** 087 * Device authorisation grant, as specified in RFC 8628. 088 */ 089 public static final GrantType DEVICE_CODE = new GrantType( 090 "urn:ietf:params:oauth:grant-type:device_code", 091 "device code", false, true, ParameterRequirement.NOT_ALLOWED, 092 Collections.singleton("device_code")); 093 094 095 /** 096 * Client Initiated Back-channel Authentication (CIBA), as specified in 097 * OpenID Connect Client Initiated Backchannel Authentication Flow - 098 * Core 1.0. 099 */ 100 public static final GrantType CIBA = new GrantType( 101 "urn:openid:params:grant-type:ciba", 102 "CIBA", true, true, ParameterRequirement.NOT_ALLOWED, 103 Collections.singleton("auth_req_id")); 104 105 106 /** 107 * Token exchange, as specified in RFC 8693. 108 */ 109 public static final GrantType TOKEN_EXCHANGE = new GrantType( 110 "urn:ietf:params:oauth:grant-type:token-exchange", 111 "token exchange", false, false, ParameterRequirement.OPTIONAL, 112 new HashSet<>(Arrays.asList( 113 "audience", "requested_token_type", "subject_token", "subject_token_type", "actor_token", "actor_token_type" 114 ))); 115 116 117 private static final long serialVersionUID = -5367937758427680765L; 118 119 120 /** 121 * Short name for the grant. 122 */ 123 private final String shortName; 124 125 126 /** 127 * The client authentication requirement. 128 */ 129 private final boolean requiresClientAuth; 130 131 132 /** 133 * The client identifier requirement. 134 */ 135 private final boolean requiresClientID; 136 137 138 /** 139 * The scope parameter requirement in token requests. 140 */ 141 private final ParameterRequirement scopeRequirementInTokenRequest; 142 143 144 /** 145 * The names of the token request parameters specific to this grant 146 * type. 147 */ 148 private final Set<String> requestParamNames; 149 150 151 /** 152 * Creates a new OAuth 2.0 authorisation grant type with the specified 153 * value. The client authentication and identifier requirements are set 154 * to {@code false}. The scope parameter in token requests is not 155 * allowed. 156 * 157 * @param value The authorisation grant type value. Must not be 158 * {@code null} or empty string. 159 */ 160 public GrantType(final String value) { 161 162 this(value, false, false, ParameterRequirement.NOT_ALLOWED, Collections.<String>emptySet()); 163 } 164 165 166 /** 167 * Creates a new OAuth 2.0 authorisation grant type with the specified 168 * value. 169 * 170 * @param value The authorisation grant type 171 * value. Must not be 172 * {@code null} or empty string. 173 * @param requiresClientAuth The client authentication 174 * requirement. 175 * @param requiresClientID The client identifier 176 * requirement. 177 * @param scopeRequirementInTokenRequest The scope parameter 178 * requirement in token requests. 179 * Must not be {@code null}. 180 * @param requestParamNames The names of the token request 181 * parameters specific to this 182 * grant type, empty set or 183 * {@code null} if none. 184 */ 185 private GrantType(final String value, 186 final boolean requiresClientAuth, 187 final boolean requiresClientID, 188 final ParameterRequirement scopeRequirementInTokenRequest, 189 final Set<String> requestParamNames) { 190 191 this(value, value, requiresClientAuth, requiresClientID, scopeRequirementInTokenRequest, requestParamNames); 192 } 193 194 195 /** 196 * Creates a new OAuth 2.0 authorisation grant type with the specified 197 * value. 198 * 199 * @param value The authorisation grant type 200 * value. Must not be 201 * {@code null} or empty string. 202 * @param shortName Short (display) name for the 203 * grant. Must not be 204 * {@code null}. 205 * @param requiresClientAuth The client authentication 206 * requirement. 207 * @param requiresClientID The client identifier 208 * requirement. 209 * @param scopeRequirementInTokenRequest The scope parameter 210 * requirement in token requests. 211 * Must not be {@code null}. 212 * @param requestParamNames The names of the token request 213 * parameters specific to this 214 * grant type, empty set or 215 * {@code null} if none. 216 */ 217 private GrantType(final String value, 218 final String shortName, 219 final boolean requiresClientAuth, 220 final boolean requiresClientID, 221 final ParameterRequirement scopeRequirementInTokenRequest, 222 final Set<String> requestParamNames) { 223 224 super(value); 225 226 this.shortName = Objects.requireNonNull(shortName); 227 228 this.requiresClientAuth = requiresClientAuth; 229 230 this.requiresClientID = requiresClientID; 231 232 Objects.requireNonNull(scopeRequirementInTokenRequest); 233 this.scopeRequirementInTokenRequest = scopeRequirementInTokenRequest; 234 235 this.requestParamNames = requestParamNames == null ? Collections.<String>emptySet() : Collections.unmodifiableSet(requestParamNames); 236 } 237 238 239 /** 240 * Returns a short (display) name for the grant. 241 * 242 * @return The short name. 243 */ 244 public String getShortName() { 245 246 return shortName; 247 } 248 249 250 /** 251 * Gets the client authentication requirement. 252 * 253 * @return {@code true} if explicit client authentication is always 254 * required for this grant type, else {@code false}. 255 */ 256 public boolean requiresClientAuthentication() { 257 258 return requiresClientAuth; 259 } 260 261 262 /** 263 * Gets the client identifier requirement. 264 * 265 * @return {@code true} if a client identifier must always be 266 * communicated for this grant type (either as part of the 267 * client authentication, or as a parameter in the token 268 * request), else {@code false}. 269 */ 270 public boolean requiresClientID() { 271 272 return requiresClientID; 273 } 274 275 /** 276 * Gets the scope parameter requirement in token requests. 277 * 278 * @return The scope parameter requirement. 279 */ 280 public ParameterRequirement getScopeRequirementInTokenRequest() { 281 282 return scopeRequirementInTokenRequest; 283 } 284 285 286 /** 287 * Gets the names of the token request parameters specific to this 288 * grant type. 289 * 290 * @return The parameter names, empty set if none. 291 */ 292 public Set<String> getRequestParameterNames() { 293 294 return requestParamNames; 295 } 296 297 298 @Override 299 public boolean equals(final Object object) { 300 301 return object instanceof GrantType && this.toString().equals(object.toString()); 302 } 303 304 305 /** 306 * Parses a grant type from the specified string. 307 * 308 * @param value The string to parse. 309 * 310 * @return The grant type. 311 * 312 * @throws ParseException If string is {@code null}, blank or empty. 313 */ 314 public static GrantType parse(final String value) 315 throws ParseException { 316 317 GrantType grantType; 318 319 try { 320 grantType = new GrantType(value); 321 322 } catch (IllegalArgumentException e) { 323 324 throw new ParseException(e.getMessage()); 325 } 326 327 if (grantType.equals(GrantType.AUTHORIZATION_CODE)) { 328 329 return GrantType.AUTHORIZATION_CODE; 330 331 } else if (grantType.equals(GrantType.IMPLICIT)) { 332 333 return GrantType.IMPLICIT; 334 335 } else if (grantType.equals(GrantType.REFRESH_TOKEN)) { 336 337 return GrantType.REFRESH_TOKEN; 338 339 } else if (grantType.equals(GrantType.PASSWORD)) { 340 341 return GrantType.PASSWORD; 342 343 } else if (grantType.equals(GrantType.CLIENT_CREDENTIALS)) { 344 345 return GrantType.CLIENT_CREDENTIALS; 346 347 } else if (grantType.equals(GrantType.JWT_BEARER)) { 348 349 return GrantType.JWT_BEARER; 350 351 } else if (grantType.equals(GrantType.SAML2_BEARER)) { 352 353 return GrantType.SAML2_BEARER; 354 355 } else if (grantType.equals(GrantType.DEVICE_CODE)) { 356 357 return GrantType.DEVICE_CODE; 358 359 } else if (grantType.equals(GrantType.CIBA)) { 360 361 return GrantType.CIBA; 362 363 } else if (grantType.equals(GrantType.TOKEN_EXCHANGE)) { 364 365 return GrantType.TOKEN_EXCHANGE; 366 367 } else { 368 369 return grantType; 370 } 371 } 372 373 374 /** 375 * Ensures the specified grant type is set in a list of parameters. 376 * 377 * @param grantType The grant type. Must not be {@code null}. 378 * @param params The parameters. Must not be {@code null}. 379 * 380 * @throws ParseException If the grant type is not set. 381 */ 382 public static void ensure(final GrantType grantType, final Map<String, List<String>> params) 383 throws ParseException { 384 385 // Parse grant type 386 String grantTypeString = MultivaluedMapUtils.getFirstValue(params, "grant_type"); 387 388 if (grantTypeString == null) { 389 String msg = "Missing grant_type parameter"; 390 throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg)); 391 } 392 393 if (! GrantType.parse(grantTypeString).equals(grantType)) { 394 String msg = "The grant_type must be " + grantType + ""; 395 throw new ParseException(msg, OAuth2Error.UNSUPPORTED_GRANT_TYPE.appendDescription(": " + msg)); 396 } 397 } 398}