001package com.nimbusds.openid.connect.provider.spi.grants;
002
003
004import java.util.List;
005
006import com.nimbusds.oauth2.sdk.ParseException;
007import com.nimbusds.oauth2.sdk.id.Audience;
008import com.nimbusds.oauth2.sdk.id.Subject;
009import com.nimbusds.oauth2.sdk.token.TokenEncoding;
010import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
011import net.jcip.annotations.Immutable;
012import net.minidev.json.JSONObject;
013
014
015/**
016 * Access token specification..
017 */
018@Immutable
019public class AccessTokenSpec extends TokenSpec {
020
021
022        /**
023         * Default access token specification. No explicit token lifetime is
024         * specified (to let the Connect2id server apply the default configured
025         * lifetime for access tokens). No explicit token audience is
026         * specified. No subject in impersonation and delegation cases is
027         * specified. The token is self-contained (JWT-encoded) and not
028         * encrypted.
029         */
030        public static final AccessTokenSpec DEFAULT = new AccessTokenSpec();
031
032
033        /**
034         * The access token encoding.
035         */
036        private final TokenEncoding encoding;
037
038
039        /**
040         * If {@code true} flags the access token for encryption. Applies to
041         * self-contained access tokens only.
042         */
043        private final boolean encrypt;
044
045
046        /**
047         * Creates a new default access token specification. No explicit
048         * token lifetime is specified (to let the Connect2id server apply the
049         * default configured lifetime for access tokens). No explicit token
050         * audience is specified. No subject in impersonation and delegation
051         * cases is specified. The token is self-contained (JWT-encoded) and
052         * not encrypted.
053         */
054        public AccessTokenSpec() {
055
056                this(0L, null, TokenEncoding.SELF_CONTAINED, null, false);
057        }
058
059
060        /**
061         * Creates a new access token specification.
062         *
063         * @param lifetime            The access token lifetime, in seconds,
064         *                            zero if not specified (to let the
065         *                            Connect2id server apply the default
066         *                            configured lifetime for access tokens).
067         * @param audList             Explicit list of audiences for the access
068         *                            token, {@code null} if not specified.
069         * @param encoding            The access token encoding. Must not be
070         *                            {@code null}.
071         * @param impersonatedSubject The subject in impersonation and
072         *                            delegation cases, {@code null} if not
073         *                            applicable.
074         * @param encrypt             If {@code true} flags the access token
075         *                            for encryption. Applies to self-contained
076         *                            (JWT) access tokens only.
077         */
078        public AccessTokenSpec(final long lifetime,
079                               final List<Audience> audList,
080                               final TokenEncoding encoding,
081                               final Subject impersonatedSubject,
082                               final boolean encrypt) {
083
084                super(lifetime, audList, impersonatedSubject);
085
086                if (encoding == null) {
087                        throw new IllegalArgumentException("The access token encoding must not be null");
088                }
089
090                this.encoding = encoding;
091
092                // Only JWT tokens may be encrypted
093                this.encrypt = encoding.equals(TokenEncoding.SELF_CONTAINED) && encrypt;
094        }
095
096
097        /**
098         * Creates a new access token specification. No subject in
099         * impersonation and delegation cases is specified.
100         *
101         * @param lifetime The access token lifetime, in seconds, zero if not
102         *                 specified (to let the Connect2id server apply the
103         *                 default configured lifetime for access tokens).
104         * @param audList  Explicit list of audiences for the access token,
105         *                 {@code null} if not specified.
106         * @param encoding The access token encoding. Must not be {@code null}.
107         * @param encrypt  If {@code true} flags the access token for
108         *                 encryption. Applies to self-contained (JWT) access
109         *                 tokens only.
110         */
111        public AccessTokenSpec(final long lifetime,
112                               final List<Audience> audList,
113                               final TokenEncoding encoding,
114                               final boolean encrypt) {
115
116                this(lifetime, audList, encoding, null, encrypt);
117        }
118
119
120        /**
121         * Creates a new access token specification. No explicit token audience
122         * is specified. No subject in impersonation and delegation cases is
123         * specified.
124         *
125         * @param lifetime The access token lifetime, in seconds, zero if not
126         *                 specified (to let the Connect2id server apply the
127         *                 default configured lifetime for access tokens).
128         * @param encoding The access token encoding. Must not be {@code null}.
129         * @param encrypt  If {@code true} flags the access token for
130         *                 encryption. Applies to self-contained (JWT) access
131         *                 tokens only.
132         */
133        public AccessTokenSpec(final long lifetime,
134                               final TokenEncoding encoding,
135                               final boolean encrypt) {
136
137                this(lifetime, null, encoding, null, encrypt);
138        }
139
140
141        /**
142         * Returns the access token encoding.
143         *
144         * @return The access token encoding.
145         */
146        public TokenEncoding getEncoding() {
147
148                return encoding;
149        }
150
151
152        /**
153         * Returns the access token encryption flag.
154         *
155         * @return If {@code true} the access token is flagged for encryption.
156         *         Applies to self-contained access tokens only.
157         */
158        public boolean encrypt() {
159
160                return encrypt;
161        }
162
163
164        @Override
165        public JSONObject toJSONObject() {
166
167                JSONObject o = super.toJSONObject();
168                
169                if (getLifetime() <= 0) {
170                        // Implies not specified - remove
171                        o.remove("lifetime");
172                }
173
174                o.put("encoding", encoding.toString());
175
176                if (encoding.equals(TokenEncoding.SELF_CONTAINED)) {
177                        o.put("encrypt", encrypt);
178                }
179
180                return o;
181        }
182
183
184        /**
185         * Parses an access token specification from the specified JSON object.
186         *
187         * @param jsonObject The JSON object. Must not be {@code null}.
188         *
189         * @return The access token specification.
190         *
191         * @throws ParseException If parsing failed.
192         */
193        public static AccessTokenSpec parse(final JSONObject jsonObject)
194                throws ParseException {
195
196                TokenSpec tokenSpec = TokenSpec.parse(jsonObject);
197                
198                // Adjust lifetime value for not specified (0)
199                long lifetime = tokenSpec.getLifetime() > 0 ? tokenSpec.getLifetime() : 0;
200
201                TokenEncoding encoding = TokenEncoding.SELF_CONTAINED;
202                boolean encrypt = false;
203
204                if (jsonObject.containsKey("encoding")) {
205
206                        String c = JSONObjectUtils.getString(jsonObject, "encoding");
207
208                        try {
209                                encoding = TokenEncoding.valueOf(c.toUpperCase());
210
211                        } catch (IllegalArgumentException e) {
212
213                                throw new ParseException("Invalid access token encoding");
214                        }
215                }
216
217                if (encoding.equals(TokenEncoding.SELF_CONTAINED)) {
218                        if (jsonObject.containsKey("encrypt")) {
219
220                                encrypt = JSONObjectUtils.getBoolean(jsonObject, "encrypt");
221                        }
222                }
223
224                return new AccessTokenSpec(lifetime, tokenSpec.getAudience(), encoding, tokenSpec.getImpersonatedSubject(), encrypt);
225        }
226}