001package com.nimbusds.openid.connect.provider.spi.grants;
002
003
004import java.util.Date;
005import java.util.List;
006
007import net.jcip.annotations.Immutable;
008import net.minidev.json.JSONObject;
009import org.checkerframework.checker.nullness.qual.Nullable;
010
011import com.nimbusds.oauth2.sdk.ParseException;
012import com.nimbusds.oauth2.sdk.Scope;
013import com.nimbusds.oauth2.sdk.id.Audience;
014import com.nimbusds.oauth2.sdk.id.Subject;
015import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
016import com.nimbusds.openid.connect.sdk.claims.ACR;
017import com.nimbusds.openid.connect.sdk.claims.AMR;
018
019
020/**
021 * Authorisation produced by a {@link PasswordGrantHandler}. Specifies a
022 * subject (end-user) and permits ID and refresh token issue.
023 *
024 * <p>Required authorisation details:
025 *
026 * <ul>
027 *     <li>The authenticated subject (end-user).
028 *     <li>The authorised scope.
029 * </ul>
030 *
031 * <p>All other parameters are optional or have suitable defaults.
032 */
033@Immutable
034public class PasswordGrantAuthorization extends SubjectAuthorization {
035
036
037        /**
038         * Controls the authorisation lifetime, {@code true} for a long-lived
039         * (implies persistence), {@code false} for a short-lived (transient).
040         */
041        private final boolean longLived;
042
043
044        /**
045         * The refresh token specification.
046         */
047        private final RefreshTokenSpec refreshTokenSpec;
048
049
050        /**
051         * Creates a new OAuth 2.0 - only authorisation for a password grant.
052         *
053         * @param subject          The subject (end-user) identifier. Must not
054         *                         be {@code null}.
055         * @param scope            The authorised scope values. Must not be
056         *                         {@code null}.
057         */
058        public PasswordGrantAuthorization(final Subject subject,
059                                          final Scope scope) {
060
061                this (subject, null, null, null, scope, null, false, AccessTokenSpec.DEFAULT, RefreshTokenSpec.DEFAULT,
062                        IDTokenSpec.NONE, ClaimsSpec.NONE, null);
063        }
064
065
066        /**
067         * Creates a new OAuth 2.0 - only authorisation for a password grant.
068         *
069         * @param subject          The subject (end-user) identifier. Must not
070         *                         be {@code null}.
071         * @param scope            The authorised scope values. Must not be
072         *                         {@code null}.
073         * @param audList          Explicit list of audiences for the access
074         *                         token, {@code null} if not specified.
075         * @param longLived        Controls the authorisation lifetime,
076         *                         {@code true} for a long-lived (implies
077         *                         persistence), {@code false} for a
078         *                         short-lived (transient).
079         * @param accessTokenSpec  The access token specification. Must not
080         *                         be {@code null}.
081         * @param refreshTokenSpec The refresh token specification. Must not
082         *                         be {@code null}.
083         * @param data             Additional data as a JSON object,
084         *                         {@code null} if not specified.
085         */
086        @Deprecated
087        public PasswordGrantAuthorization(final Subject subject,
088                                          final Scope scope,
089                                          final @Nullable List<Audience> audList,
090                                          final boolean longLived,
091                                          final AccessTokenSpec accessTokenSpec,
092                                          final RefreshTokenSpec refreshTokenSpec,
093                                          final @Nullable JSONObject data) {
094
095                this (subject, null, null, null, scope, audList, longLived, accessTokenSpec, refreshTokenSpec,
096                        IDTokenSpec.NONE, ClaimsSpec.NONE, data);
097        }
098
099
100        /**
101         * Creates a new OAuth 2.0 - only authorisation for a password grant.
102         *
103         * @param subject          The subject (end-user) identifier. Must not
104         *                         be {@code null}.
105         * @param scope            The authorised scope values. Must not be
106         *                         {@code null}.
107         * @param longLived        Controls the authorisation lifetime,
108         *                         {@code true} for a long-lived (implies
109         *                         persistence), {@code false} for a
110         *                         short-lived (transient).
111         * @param accessTokenSpec  The access token specification. Must not
112         *                         be {@code null}.
113         * @param refreshTokenSpec The refresh token specification. Must not
114         *                         be {@code null}.
115         * @param data             Additional data as a JSON object,
116         *                         {@code null} if not specified.
117         */
118        public PasswordGrantAuthorization(final Subject subject,
119                                          final Scope scope,
120                                          final boolean longLived,
121                                          final AccessTokenSpec accessTokenSpec,
122                                          final RefreshTokenSpec refreshTokenSpec,
123                                          final @Nullable JSONObject data) {
124
125                this(subject, scope, longLived, accessTokenSpec, refreshTokenSpec, IDTokenSpec.NONE, ClaimsSpec.NONE, data);
126        }
127
128
129        /**
130         * Creates a new OpenID Connect / OAuth 2.0 authorisation for a
131         * password grant.
132         *
133         * @param subject          The subject (end-user) identifier. Must not
134         *                         be {@code null}.
135         * @param authTime         The time of the subject authentication. If
136         *                         {@code null} it will be set to now.
137         *                         Applies only if an ID token is issued.
138         * @param acr              The Authentication Context Class Reference
139         *                         (ACR), {@code null} if not specified.
140         *                         Applies only if an ID token is issued.
141         * @param amrList          The Authentication Methods Reference (AMR)
142         *                         list, {@code null} if not specified. Applies
143         *                         only if an ID token is issued.
144         * @param scope            The authorised scope values. Must not be
145         *                         {@code null}.
146         * @param audList          Explicit list of audiences for the access
147         *                         token, {@code null} if not specified.
148         * @param longLived        Controls the authorisation lifetime.
149         *                         {@code true} for a long-lived (implies
150         *                         persistence), {@code false} for a
151         *                         short-lived (transient).
152         * @param accessTokenSpec  The access token specification. Must not be
153         *                         {@code null}.
154         * @param refreshTokenSpec The refresh token specification. Must not be
155         *                         {@code null}.
156         * @param idTokenSpec      The ID token specification. Must not be
157         *                         {@code null}.
158         * @param claimsSpec       The OpenID claims specification.
159         * @param data             Additional data as a JSON object,
160         *                         {@code null} if not specified.
161         */
162        @Deprecated
163        public PasswordGrantAuthorization(final Subject subject,
164                                          final @Nullable Date authTime,
165                                          final @Nullable ACR acr,
166                                          final @Nullable List<AMR> amrList,
167                                          final Scope scope,
168                                          final @Nullable List<Audience> audList,
169                                          final boolean longLived,
170                                          final AccessTokenSpec accessTokenSpec,
171                                          final RefreshTokenSpec refreshTokenSpec,
172                                          final IDTokenSpec idTokenSpec,
173                                          final ClaimsSpec claimsSpec,
174                                          final @Nullable JSONObject data) {
175
176                this(
177                        subject,
178                        scope,
179                        longLived,
180                        new AccessTokenSpec(
181                                accessTokenSpec.getLifetime(),
182                                audList,
183                                accessTokenSpec.getEncoding(),
184                                accessTokenSpec.getImpersonatedSubject(),
185                                accessTokenSpec.getEncryptSelfContained(),
186                                accessTokenSpec.getSubjectType()),
187                        refreshTokenSpec,
188                        new IDTokenSpec(
189                                idTokenSpec.issue(),
190                                idTokenSpec.getLifetime(),
191                                authTime,
192                                acr,
193                                amrList,
194                                idTokenSpec.getImpersonatedSubject()),
195                        claimsSpec,
196                        data);
197        }
198
199
200        /**
201         * Creates a new OpenID Connect / OAuth 2.0 authorisation for a
202         * password grant.
203         *
204         * @param subject          The subject (end-user) identifier. Must not
205         *                         be {@code null}.
206         * @param scope            The authorised scope values. Must not be
207         *                         {@code null}.
208         * @param longLived        Controls the authorisation lifetime.
209         *                         {@code true} for a long-lived (implies
210         *                         persistence), {@code false} for a
211         *                         short-lived (transient).
212         * @param accessTokenSpec  The access token specification. Must not be
213         *                         {@code null}.
214         * @param refreshTokenSpec The refresh token specification. Must not be
215         *                         {@code null}.
216         * @param idTokenSpec      The ID token specification. Must not be
217         *                         {@code null}.
218         * @param claimsSpec       The OpenID claims specification.
219         * @param data             Additional data as a JSON object,
220         *                         {@code null} if not specified.
221         */
222        public PasswordGrantAuthorization(final Subject subject,
223                                          final Scope scope,
224                                          final boolean longLived,
225                                          final AccessTokenSpec accessTokenSpec,
226                                          final RefreshTokenSpec refreshTokenSpec,
227                                          final IDTokenSpec idTokenSpec,
228                                          final ClaimsSpec claimsSpec,
229                                          final @Nullable JSONObject data) {
230
231                super(subject, scope, accessTokenSpec, idTokenSpec, claimsSpec, data);
232
233                this.longLived = longLived;
234
235                if (refreshTokenSpec == null) {
236                        throw new IllegalArgumentException("The refresh token specification must not be null");
237                }
238                this.refreshTokenSpec = refreshTokenSpec;
239        }
240
241
242        /**
243         * Returns the authorisation lifetime.
244         *
245         * @return {@code true} for a long-lived authorisation (implies
246         *         persistence), {@code false} for a short-lived (transient).
247         */
248        public boolean isLongLived() {
249
250                return longLived;
251        }
252
253
254        /**
255         * Returns the refresh token specification.
256         *
257         * @return The refresh token specification.
258         */
259        public RefreshTokenSpec getRefreshTokenSpec() {
260
261                return refreshTokenSpec;
262        }
263
264
265        @Override
266        public JSONObject toJSONObject() {
267
268                JSONObject o = super.toJSONObject();
269
270                o.put("long_lived", longLived);
271
272                if (refreshTokenSpec.issue()) {
273                        o.put("refresh_token", refreshTokenSpec.toJSONObject());
274                }
275
276                return o;
277        }
278
279
280        /**
281         * Parses a password grant authorisation from the specified JSON
282         * object.
283         *
284         * @param jsonObject The JSON object to parse. Must not be
285         *                   {@code null}.
286         *
287         * @return The password grant authorisation.
288         *
289         * @throws ParseException If parsing failed.
290         */
291        public static PasswordGrantAuthorization parse(final JSONObject jsonObject)
292                throws ParseException {
293
294                SubjectAuthorization authz = SubjectAuthorization.parse(jsonObject);
295
296                boolean longLived = JSONObjectUtils.getBoolean(jsonObject, "long_lived", false);
297
298                RefreshTokenSpec rtSpec;
299                if (jsonObject.containsKey("refresh_token")) {
300                        rtSpec = RefreshTokenSpec.parse(JSONObjectUtils.getJSONObject(jsonObject, "refresh_token"));
301                } else {
302                        rtSpec = RefreshTokenSpec.DEFAULT;
303                }
304
305                return new PasswordGrantAuthorization(
306                        authz.getSubject(),
307                        authz.getScope(),
308                        longLived,
309                        authz.getAccessTokenSpec(),
310                        rtSpec,
311                        authz.getIDTokenSpec(),
312                        authz.getClaimsSpec(),
313                        authz.getData());
314        }
315
316
317        /**
318         * Parses a password grant authorisation from the specified JSON
319         * object string.
320         *
321         * @param json The JSON object string to parse. Must not be
322         *             {@code null}.
323         *
324         * @return The password grant authorisation.
325         *
326         * @throws ParseException If parsing failed.
327         */
328        public static PasswordGrantAuthorization parse(final String json)
329                throws ParseException {
330
331                return parse(JSONObjectUtils.parse(json));
332        }
333}