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