001package com.nimbusds.openid.connect.provider.spi.grants;
002
003
004import com.nimbusds.oauth2.sdk.ParseException;
005import com.nimbusds.oauth2.sdk.Scope;
006import com.nimbusds.oauth2.sdk.id.Audience;
007import com.nimbusds.oauth2.sdk.id.Subject;
008import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
009import com.nimbusds.openid.connect.sdk.claims.ACR;
010import com.nimbusds.openid.connect.sdk.claims.AMR;
011import net.jcip.annotations.Immutable;
012import net.minidev.json.JSONObject;
013import org.checkerframework.checker.nullness.qual.Nullable;
014
015import java.util.Date;
016import java.util.List;
017import java.util.Objects;
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                this.longLived = longLived;
233                this.refreshTokenSpec = Objects.requireNonNull(refreshTokenSpec);
234        }
235
236
237        /**
238         * Returns the authorisation lifetime.
239         *
240         * @return {@code true} for a long-lived authorisation (implies
241         *         persistence), {@code false} for a short-lived (transient).
242         */
243        public boolean isLongLived() {
244
245                return longLived;
246        }
247
248
249        /**
250         * Returns the refresh token specification.
251         *
252         * @return The refresh token specification.
253         */
254        public RefreshTokenSpec getRefreshTokenSpec() {
255
256                return refreshTokenSpec;
257        }
258
259
260        @Override
261        public JSONObject toJSONObject() {
262
263                JSONObject o = super.toJSONObject();
264
265                o.put("long_lived", longLived);
266
267                if (refreshTokenSpec.issue()) {
268                        o.put("refresh_token", refreshTokenSpec.toJSONObject());
269                }
270
271                return o;
272        }
273
274
275        /**
276         * Parses a password grant authorisation from the specified JSON
277         * object.
278         *
279         * @param jsonObject The JSON object to parse. Must not be
280         *                   {@code null}.
281         *
282         * @return The password grant authorisation.
283         *
284         * @throws ParseException If parsing failed.
285         */
286        public static PasswordGrantAuthorization parse(final JSONObject jsonObject)
287                throws ParseException {
288
289                SubjectAuthorization authz = SubjectAuthorization.parse(jsonObject);
290
291                boolean longLived = JSONObjectUtils.getBoolean(jsonObject, "long_lived", false);
292
293                RefreshTokenSpec rtSpec;
294                if (jsonObject.containsKey("refresh_token")) {
295                        rtSpec = RefreshTokenSpec.parse(JSONObjectUtils.getJSONObject(jsonObject, "refresh_token"));
296                } else {
297                        rtSpec = RefreshTokenSpec.DEFAULT;
298                }
299
300                return new PasswordGrantAuthorization(
301                        authz.getSubject(),
302                        authz.getScope(),
303                        longLived,
304                        authz.getAccessTokenSpec(),
305                        rtSpec,
306                        authz.getIDTokenSpec(),
307                        authz.getClaimsSpec(),
308                        authz.getData());
309        }
310
311
312        /**
313         * Parses a password grant authorisation from the specified JSON
314         * object string.
315         *
316         * @param json The JSON object string to parse. Must not be
317         *             {@code null}.
318         *
319         * @return The password grant authorisation.
320         *
321         * @throws ParseException If parsing failed.
322         */
323        public static PasswordGrantAuthorization parse(final String json)
324                throws ParseException {
325
326                return parse(JSONObjectUtils.parse(json));
327        }
328}