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        private static final long serialVersionUID = -5367937758427680765L;
101        
102        
103        /**
104         * The client authentication requirement for this grant type.
105         */
106        private final boolean requiresClientAuth;
107
108
109        /**
110         * The client identifier requirement for this grant type.
111         */
112        private final boolean requiresClientID;
113
114
115        /**
116         * The names of the token request parameters specific to this grant
117         * type.
118         */
119        private final Set<String> requestParamNames;
120
121
122        /**
123         * Creates a new OAuth 2.0 authorisation grant type with the specified
124         * value. The client authentication requirement is set to
125         * {@code false}. So is the client identifier requirement.
126         *
127         * @param value The authorisation grant type value. Must not be
128         *              {@code null} or empty string.
129         */
130        public GrantType(final String value) {
131
132                this(value, false, false, Collections.<String>emptySet());
133        }
134
135
136        /**
137         * Creates a new OAuth 2.0 authorisation grant type with the specified
138         * value.
139         *
140         * @param value              The authorisation grant type value. Must
141         *                           not be {@code null} or empty string.
142         * @param requiresClientAuth The client authentication requirement.
143         * @param requiresClientID   The client identifier requirement.
144         * @param requestParamNames  The names of the token request parameters
145         *                           specific to this grant type, empty set or
146         *                           {@code null} if none.
147         */
148        private GrantType(final String value,
149                          final boolean requiresClientAuth,
150                          final boolean requiresClientID,
151                          final Set<String> requestParamNames) {
152
153                super(value);
154                this.requiresClientAuth = requiresClientAuth;
155                this.requiresClientID = requiresClientID;
156                this.requestParamNames = requestParamNames == null ? Collections.<String>emptySet() : Collections.unmodifiableSet(requestParamNames);
157        }
158
159
160        /**
161         * Gets the client authentication requirement.
162         *
163         * @return {@code true} if explicit client authentication is always
164         *         required for this grant type, else {@code false}.
165         */
166        public boolean requiresClientAuthentication() {
167
168                return requiresClientAuth;
169        }
170
171
172        /**
173         * Gets the client identifier requirement.
174         *
175         * @return {@code true} if a client identifier must always be
176         *         communicated for this grant type (either as part of the
177         *         client authentication, or as a parameter in the token
178         *         request body), else {@code false}.
179         */
180        public boolean requiresClientID() {
181
182                return requiresClientID;
183        }
184
185
186        /**
187         * Gets the names of the token request parameters specific to this
188         * grant type.
189         *
190         * @return The parameter names, empty set if none.
191         */
192        public Set<String> getRequestParameterNames() {
193
194                return requestParamNames;
195        }
196
197
198        @Override
199        public boolean equals(final Object object) {
200        
201                return object instanceof GrantType && this.toString().equals(object.toString());
202        }
203
204
205        /**
206         * Parses a grant type from the specified string.
207         *
208         * @param value The string to parse.
209         *
210         * @return The grant type.
211         *
212         * @throws ParseException If string is {@code null}, blank or empty.
213         */
214        public static GrantType parse(final String value)
215                throws ParseException {
216
217                GrantType grantType;
218
219                try {
220                        grantType = new GrantType(value);
221
222                } catch (IllegalArgumentException e) {
223
224                        throw new ParseException(e.getMessage());
225                }
226
227                if (grantType.equals(GrantType.AUTHORIZATION_CODE)) {
228
229                        return GrantType.AUTHORIZATION_CODE;
230
231                } else if (grantType.equals(GrantType.IMPLICIT)) {
232
233                        return GrantType.IMPLICIT;
234
235                } else if (grantType.equals(GrantType.REFRESH_TOKEN)) {
236
237                        return GrantType.REFRESH_TOKEN;
238
239                } else if (grantType.equals(GrantType.PASSWORD)) {
240
241                        return GrantType.PASSWORD;
242
243                } else if (grantType.equals(GrantType.CLIENT_CREDENTIALS)) {
244
245                        return GrantType.CLIENT_CREDENTIALS;
246
247                } else if (grantType.equals(GrantType.JWT_BEARER)) {
248
249                        return GrantType.JWT_BEARER;
250
251                } else if (grantType.equals(GrantType.SAML2_BEARER)) {
252
253                        return GrantType.SAML2_BEARER;
254
255                } else if (grantType.equals(GrantType.DEVICE_CODE)) {
256
257                        return GrantType.DEVICE_CODE;
258
259                } else if (grantType.equals(GrantType.CIBA)) {
260
261                        return GrantType.CIBA;
262
263                } else {
264
265                        return grantType;
266                }
267        }
268        
269        
270        /**
271         * Ensures the specified grant type is set in a list of parameters.
272         *
273         * @param grantType The grant type. Must not be {@code null}.
274         * @param params    The parameters. Must not be {@code null}.
275         *
276         * @throws ParseException If the grant type is not set.
277         */
278        public static void ensure(final GrantType grantType, final Map<String, List<String>> params)
279                throws ParseException {
280                
281                // Parse grant type
282                String grantTypeString = MultivaluedMapUtils.getFirstValue(params, "grant_type");
283                
284                if (grantTypeString == null) {
285                        String msg = "Missing grant_type parameter";
286                        throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg));
287                }
288                
289                if (! GrantType.parse(grantTypeString).equals(grantType)) {
290                        String msg = "The grant_type must be " + grantType + "";
291                        throw new ParseException(msg, OAuth2Error.UNSUPPORTED_GRANT_TYPE.appendDescription(": " + msg));
292                }
293        }
294}