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", 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", 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("client_credentials", true, true, ParameterRequirement.OPTIONAL, Collections.<String>emptySet()); 063 064 065 /** 066 * JWT bearer, as specified in RFC 7523. 067 */ 068 public static final GrantType JWT_BEARER = new GrantType("urn:ietf:params:oauth:grant-type:jwt-bearer", false, false, ParameterRequirement.OPTIONAL, Collections.singleton("assertion")); 069 070 071 /** 072 * SAML 2.0 bearer, as specified in RFC 7522. 073 */ 074 public static final GrantType SAML2_BEARER = new GrantType("urn:ietf:params:oauth:grant-type:saml2-bearer", false, false, ParameterRequirement.OPTIONAL, Collections.singleton("assertion")); 075 076 077 /** 078 * Device authorisation grant, as specified in RFC 8628. 079 */ 080 public static final GrantType DEVICE_CODE = new GrantType("urn:ietf:params:oauth:grant-type:device_code", false, true, ParameterRequirement.NOT_ALLOWED, Collections.singleton("device_code")); 081 082 083 /** 084 * Client Initiated Back-channel Authentication (CIBA), as specified in 085 * OpenID Connect Client Initiated Backchannel Authentication Flow - 086 * Core 1.0. 087 */ 088 public static final GrantType CIBA = new GrantType("urn:openid:params:grant-type:ciba", true, true, ParameterRequirement.NOT_ALLOWED, Collections.singleton("auth_req_id")); 089 090 091 /** 092 * Token exchange, as specified in RFC 8693. 093 */ 094 public static final GrantType TOKEN_EXCHANGE = new GrantType("urn:ietf:params:oauth:grant-type:token-exchange", 095 false, false, ParameterRequirement.OPTIONAL, 096 new HashSet<>(Arrays.asList( 097 "audience", "requested_token_type", "subject_token", "subject_token_type", "actor_token", "actor_token_type" 098 ))); 099 100 101 private static final long serialVersionUID = -5367937758427680765L; 102 103 104 /** 105 * The client authentication requirement. 106 */ 107 private final boolean requiresClientAuth; 108 109 110 /** 111 * The client identifier requirement. 112 */ 113 private final boolean requiresClientID; 114 115 116 /** 117 * The scope parameter requirement in token requests. 118 */ 119 private final ParameterRequirement scopeRequirementInTokenRequest; 120 121 122 /** 123 * The names of the token request parameters specific to this grant 124 * type. 125 */ 126 private final Set<String> requestParamNames; 127 128 129 /** 130 * Creates a new OAuth 2.0 authorisation grant type with the specified 131 * value. The client authentication and identifier requirements are set 132 * to {@code false}. The scope parameter in token requests is not 133 * allowed. 134 * 135 * @param value The authorisation grant type value. Must not be 136 * {@code null} or empty string. 137 */ 138 public GrantType(final String value) { 139 140 this(value, false, false, ParameterRequirement.NOT_ALLOWED, Collections.<String>emptySet()); 141 } 142 143 144 /** 145 * Creates a new OAuth 2.0 authorisation grant type with the specified 146 * value. 147 * 148 * @param value The authorisation grant type 149 * value. Must not be 150 * {@code null} or empty string. 151 * @param requiresClientAuth The client authentication 152 * requirement. 153 * @param requiresClientID The client identifier 154 * requirement. 155 * @param scopeRequirementInTokenRequest The scope parameter 156 * requirement in token requests. 157 * Must not be {@code null}. 158 * @param requestParamNames The names of the token request 159 * parameters specific to this 160 * grant type, empty set or 161 * {@code null} if none. 162 */ 163 private GrantType(final String value, 164 final boolean requiresClientAuth, 165 final boolean requiresClientID, 166 final ParameterRequirement scopeRequirementInTokenRequest, 167 final Set<String> requestParamNames) { 168 169 super(value); 170 171 this.requiresClientAuth = requiresClientAuth; 172 173 this.requiresClientID = requiresClientID; 174 175 Objects.requireNonNull(scopeRequirementInTokenRequest); 176 this.scopeRequirementInTokenRequest = scopeRequirementInTokenRequest; 177 178 this.requestParamNames = requestParamNames == null ? Collections.<String>emptySet() : Collections.unmodifiableSet(requestParamNames); 179 } 180 181 182 /** 183 * Gets the client authentication requirement. 184 * 185 * @return {@code true} if explicit client authentication is always 186 * required for this grant type, else {@code false}. 187 */ 188 public boolean requiresClientAuthentication() { 189 190 return requiresClientAuth; 191 } 192 193 194 /** 195 * Gets the client identifier requirement. 196 * 197 * @return {@code true} if a client identifier must always be 198 * communicated for this grant type (either as part of the 199 * client authentication, or as a parameter in the token 200 * request), else {@code false}. 201 */ 202 public boolean requiresClientID() { 203 204 return requiresClientID; 205 } 206 207 /** 208 * Gets the scope parameter requirement in token requests. 209 * 210 * @return The scope parameter requirement. 211 */ 212 public ParameterRequirement getScopeRequirementInTokenRequest() { 213 214 return scopeRequirementInTokenRequest; 215 } 216 217 218 /** 219 * Gets the names of the token request parameters specific to this 220 * grant type. 221 * 222 * @return The parameter names, empty set if none. 223 */ 224 public Set<String> getRequestParameterNames() { 225 226 return requestParamNames; 227 } 228 229 230 @Override 231 public boolean equals(final Object object) { 232 233 return object instanceof GrantType && this.toString().equals(object.toString()); 234 } 235 236 237 /** 238 * Parses a grant type from the specified string. 239 * 240 * @param value The string to parse. 241 * 242 * @return The grant type. 243 * 244 * @throws ParseException If string is {@code null}, blank or empty. 245 */ 246 public static GrantType parse(final String value) 247 throws ParseException { 248 249 GrantType grantType; 250 251 try { 252 grantType = new GrantType(value); 253 254 } catch (IllegalArgumentException e) { 255 256 throw new ParseException(e.getMessage()); 257 } 258 259 if (grantType.equals(GrantType.AUTHORIZATION_CODE)) { 260 261 return GrantType.AUTHORIZATION_CODE; 262 263 } else if (grantType.equals(GrantType.IMPLICIT)) { 264 265 return GrantType.IMPLICIT; 266 267 } else if (grantType.equals(GrantType.REFRESH_TOKEN)) { 268 269 return GrantType.REFRESH_TOKEN; 270 271 } else if (grantType.equals(GrantType.PASSWORD)) { 272 273 return GrantType.PASSWORD; 274 275 } else if (grantType.equals(GrantType.CLIENT_CREDENTIALS)) { 276 277 return GrantType.CLIENT_CREDENTIALS; 278 279 } else if (grantType.equals(GrantType.JWT_BEARER)) { 280 281 return GrantType.JWT_BEARER; 282 283 } else if (grantType.equals(GrantType.SAML2_BEARER)) { 284 285 return GrantType.SAML2_BEARER; 286 287 } else if (grantType.equals(GrantType.DEVICE_CODE)) { 288 289 return GrantType.DEVICE_CODE; 290 291 } else if (grantType.equals(GrantType.CIBA)) { 292 293 return GrantType.CIBA; 294 295 } else if (grantType.equals(GrantType.TOKEN_EXCHANGE)) { 296 297 return GrantType.TOKEN_EXCHANGE; 298 299 } else { 300 301 return grantType; 302 } 303 } 304 305 306 /** 307 * Ensures the specified grant type is set in a list of parameters. 308 * 309 * @param grantType The grant type. Must not be {@code null}. 310 * @param params The parameters. Must not be {@code null}. 311 * 312 * @throws ParseException If the grant type is not set. 313 */ 314 public static void ensure(final GrantType grantType, final Map<String, List<String>> params) 315 throws ParseException { 316 317 // Parse grant type 318 String grantTypeString = MultivaluedMapUtils.getFirstValue(params, "grant_type"); 319 320 if (grantTypeString == null) { 321 String msg = "Missing grant_type parameter"; 322 throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg)); 323 } 324 325 if (! GrantType.parse(grantTypeString).equals(grantType)) { 326 String msg = "The grant_type must be " + grantType + ""; 327 throw new ParseException(msg, OAuth2Error.UNSUPPORTED_GRANT_TYPE.appendDescription(": " + msg)); 328 } 329 } 330}