001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2021, 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 java.util.*;
022
023import net.jcip.annotations.Immutable;
024
025import com.nimbusds.oauth2.sdk.id.Identifier;
026import com.nimbusds.oauth2.sdk.util.MultivaluedMapUtils;
027
028
029/**
030 * Authorisation grant type.
031 */
032@Immutable
033public final class GrantType extends Identifier {
034
035        
036        /**
037         * Authorisation code. Client authentication required only for
038         * confidential clients.
039         */
040        public static final GrantType AUTHORIZATION_CODE = new GrantType("authorization_code", false, true, new HashSet<>(Arrays.asList("code", "redirect_uri", "code_verifier")));
041
042
043        /**
044         * Implicit. Client authentication is not performed (except for signed
045         * OpenID Connect authentication requests).
046         */
047        public static final GrantType IMPLICIT = new GrantType("implicit", false, true, Collections.<String>emptySet());
048        
049        
050        /**
051         * Refresh token. Client authentication required only for confidential
052         * clients.
053         */
054        public static final GrantType REFRESH_TOKEN = new GrantType("refresh_token", false, false, Collections.singleton("refresh_token"));
055
056
057        /**
058         * Password. Client authentication required only for confidential
059         * clients.
060         */
061        public static final GrantType PASSWORD = new GrantType("password", false, false, new HashSet<>(Arrays.asList("username", "password")));
062
063
064        /**
065         * Client credentials. Client authentication is required.
066         */
067        public static final GrantType CLIENT_CREDENTIALS = new GrantType("client_credentials", true, true, Collections.<String>emptySet());
068
069
070        /**
071         * JWT bearer, as defined in RFC 7523. Explicit client authentication
072         * is optional.
073         */
074        public static final GrantType JWT_BEARER = new GrantType("urn:ietf:params:oauth:grant-type:jwt-bearer", false, false, Collections.singleton("assertion"));
075
076
077        /**
078         * SAML 2.0 bearer, as defined in RFC 7522. Explicit client
079         * authentication is optional.
080         */
081        public static final GrantType SAML2_BEARER = new GrantType("urn:ietf:params:oauth:grant-type:saml2-bearer", false, false, Collections.singleton("assertion"));
082
083
084        /**
085         * Device Code, as defined in OAuth 2.0 Device Flow for
086         * Browserless and Input Constrained Devices. Explicit client
087         * authentication is optional.
088         */
089        public static final GrantType DEVICE_CODE = new GrantType("urn:ietf:params:oauth:grant-type:device_code", false, true, Collections.singleton("device_code"));
090
091
092        /**
093         * Client Initiated Back-channel Authentication (CIBA), as defined in
094         * OpenID Connect Client Initiated Backchannel Authentication Flow -
095         * Core 1.0. Explicit client authentication is optional.
096         */
097        public static final GrantType CIBA = new GrantType("urn:openid:params:grant-type:ciba", true, true, Collections.singleton("auth_req_id"));
098
099        
100        /**
101         * Token Exchange, as defined in RFC 8693. Explicit client
102         * authentication is optional.
103         */
104        public static final GrantType TOKEN_EXCHANGE = new GrantType("urn:ietf:params:oauth:grant-type:token-exchange",
105                        false, false,
106                        new HashSet<>(Arrays.asList(
107                                        "audience", "requested_token_type", "subject_token", "subject_token_type", "actor_token", "actor_token_type"
108                        )));
109        
110        
111        private static final long serialVersionUID = -5367937758427680765L;
112        
113        
114        /**
115         * The client authentication requirement for this grant type.
116         */
117        private final boolean requiresClientAuth;
118
119
120        /**
121         * The client identifier requirement for this grant type.
122         */
123        private final boolean requiresClientID;
124
125
126        /**
127         * The names of the token request parameters specific to this grant
128         * type.
129         */
130        private final Set<String> requestParamNames;
131
132
133        /**
134         * Creates a new OAuth 2.0 authorisation grant type with the specified
135         * value. The client authentication requirement is set to
136         * {@code false}. So is the client identifier requirement.
137         *
138         * @param value The authorisation grant type value. Must not be
139         *              {@code null} or empty string.
140         */
141        public GrantType(final String value) {
142
143                this(value, false, false, Collections.<String>emptySet());
144        }
145
146
147        /**
148         * Creates a new OAuth 2.0 authorisation grant type with the specified
149         * value.
150         *
151         * @param value              The authorisation grant type value. Must
152         *                           not be {@code null} or empty string.
153         * @param requiresClientAuth The client authentication requirement.
154         * @param requiresClientID   The client identifier requirement.
155         * @param requestParamNames  The names of the token request parameters
156         *                           specific to this grant type, empty set or
157         *                           {@code null} if none.
158         */
159        private GrantType(final String value,
160                          final boolean requiresClientAuth,
161                          final boolean requiresClientID,
162                          final Set<String> requestParamNames) {
163
164                super(value);
165                this.requiresClientAuth = requiresClientAuth;
166                this.requiresClientID = requiresClientID;
167                this.requestParamNames = requestParamNames == null ? Collections.<String>emptySet() : Collections.unmodifiableSet(requestParamNames);
168        }
169
170
171        /**
172         * Gets the client authentication requirement.
173         *
174         * @return {@code true} if explicit client authentication is always
175         *         required for this grant type, else {@code false}.
176         */
177        public boolean requiresClientAuthentication() {
178
179                return requiresClientAuth;
180        }
181
182
183        /**
184         * Gets the client identifier requirement.
185         *
186         * @return {@code true} if a client identifier must always be
187         *         communicated for this grant type (either as part of the
188         *         client authentication, or as a parameter in the token
189         *         request body), else {@code false}.
190         */
191        public boolean requiresClientID() {
192
193                return requiresClientID;
194        }
195
196
197        /**
198         * Gets the names of the token request parameters specific to this
199         * grant type.
200         *
201         * @return The parameter names, empty set if none.
202         */
203        public Set<String> getRequestParameterNames() {
204
205                return requestParamNames;
206        }
207
208
209        @Override
210        public boolean equals(final Object object) {
211        
212                return object instanceof GrantType && this.toString().equals(object.toString());
213        }
214
215
216        /**
217         * Parses a grant type from the specified string.
218         *
219         * @param value The string to parse.
220         *
221         * @return The grant type.
222         *
223         * @throws ParseException If string is {@code null}, blank or empty.
224         */
225        public static GrantType parse(final String value)
226                throws ParseException {
227
228                GrantType grantType;
229
230                try {
231                        grantType = new GrantType(value);
232
233                } catch (IllegalArgumentException e) {
234
235                        throw new ParseException(e.getMessage());
236                }
237
238                if (grantType.equals(GrantType.AUTHORIZATION_CODE)) {
239
240                        return GrantType.AUTHORIZATION_CODE;
241
242                } else if (grantType.equals(GrantType.IMPLICIT)) {
243
244                        return GrantType.IMPLICIT;
245
246                } else if (grantType.equals(GrantType.REFRESH_TOKEN)) {
247
248                        return GrantType.REFRESH_TOKEN;
249
250                } else if (grantType.equals(GrantType.PASSWORD)) {
251
252                        return GrantType.PASSWORD;
253
254                } else if (grantType.equals(GrantType.CLIENT_CREDENTIALS)) {
255
256                        return GrantType.CLIENT_CREDENTIALS;
257
258                } else if (grantType.equals(GrantType.JWT_BEARER)) {
259
260                        return GrantType.JWT_BEARER;
261
262                } else if (grantType.equals(GrantType.SAML2_BEARER)) {
263
264                        return GrantType.SAML2_BEARER;
265
266                } else if (grantType.equals(GrantType.DEVICE_CODE)) {
267
268                        return GrantType.DEVICE_CODE;
269
270                } else if (grantType.equals(GrantType.CIBA)) {
271
272                        return GrantType.CIBA;
273
274                } else if (grantType.equals(GrantType.TOKEN_EXCHANGE)) {
275
276                        return GrantType.TOKEN_EXCHANGE;
277
278                } else {
279
280                        return grantType;
281                }
282        }
283        
284        
285        /**
286         * Ensures the specified grant type is set in a list of parameters.
287         *
288         * @param grantType The grant type. Must not be {@code null}.
289         * @param params    The parameters. Must not be {@code null}.
290         *
291         * @throws ParseException If the grant type is not set.
292         */
293        public static void ensure(final GrantType grantType, final Map<String, List<String>> params)
294                throws ParseException {
295                
296                // Parse grant type
297                String grantTypeString = MultivaluedMapUtils.getFirstValue(params, "grant_type");
298                
299                if (grantTypeString == null) {
300                        String msg = "Missing grant_type parameter";
301                        throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg));
302                }
303                
304                if (! GrantType.parse(grantTypeString).equals(grantType)) {
305                        String msg = "The grant_type must be " + grantType + "";
306                        throw new ParseException(msg, OAuth2Error.UNSUPPORTED_GRANT_TYPE.appendDescription(": " + msg));
307                }
308        }
309}