001package com.nimbusds.oauth2.sdk.token;
002
003
004import java.util.HashSet;
005import java.util.Set;
006
007import net.minidev.json.JSONObject;
008
009import com.nimbusds.oauth2.sdk.ParseException;
010import com.nimbusds.oauth2.sdk.Scope;
011
012
013/**
014 * The base abstract class for access tokens. Concrete extending classes should
015 * be immutable.
016 *
017 * <p>Related specifications:
018 *
019 * <ul>
020 *     <li>OAuth 2.0 (RFC 6749), sections 1.4 and 5.1.
021 * </ul>
022 */
023public abstract class AccessToken extends Token {
024
025        
026        /**
027         * The access token type.
028         */
029        private final AccessTokenType type;
030        
031        
032        /**
033         * Optional lifetime, in seconds.
034         */
035        private final long lifetime;
036        
037        
038        /**
039         * Optional scope.
040         */
041        private final Scope scope;
042
043
044        /**
045         * Creates a new minimal access token with a randomly generated 256-bit 
046         * (32-byte) value, Base64URL-encoded. The optional lifetime and scope 
047         * are left undefined.
048         *
049         * @param type The access token type. Must not be {@code null}.
050         */
051        public AccessToken(final AccessTokenType type) {
052        
053                this(type, 32);
054        }
055
056
057        /**
058         * Creates a new minimal access token with a randomly generated value 
059         * of the specified byte length, Base64URL-encoded. The optional 
060         * lifetime and scope are left undefined.
061         *
062         * @param type       The access token type. Must not be {@code null}.
063         * @param byteLength The byte length of the value to generate. Must be
064         *                   greater than one.
065         */
066        public AccessToken(final AccessTokenType type, final int byteLength) {
067        
068                this(type, byteLength, 0l, null);
069        }
070
071
072        /**
073         * Creates a new access token with a randomly generated 256-bit 
074         * (32-byte) value, Base64URL-encoded.
075         *
076         * @param type     The access token type. Must not be {@code null}.
077         * @param lifetime The lifetime in seconds, 0 if not specified.
078         * @param scope    The scope, {@code null} if not specified.
079         */
080        public AccessToken(final AccessTokenType type,
081                           final long lifetime, 
082                           final Scope scope) {
083        
084                this(type, 32, lifetime, scope);
085        }
086
087
088        /**
089         * Creates a new access token with a randomly generated value 
090         * of the specified byte length, Base64URL-encoded, and optional 
091         * lifetime and scope.
092         *
093         * @param type       The access token type. Must not be {@code null}.
094         * @param byteLength The byte length of the value to generate. Must be
095         *                   greater than one.
096         * @param lifetime   The lifetime in seconds, 0 if not specified.
097         * @param scope      The scope, {@code null} if not specified.
098         */
099        public AccessToken(final AccessTokenType type, 
100                           final int byteLength, 
101                           final long lifetime, 
102                           final Scope scope) {
103        
104                super(byteLength);
105
106                if (type == null)
107                        throw new IllegalArgumentException("The access token type must not be null");
108
109                this.type = type;
110
111                this.lifetime = lifetime;
112                this.scope = scope;
113        }
114        
115        
116        /**
117         * Creates a new minimal access token with the specified value. The 
118         * optional lifetime and scope are left undefined.
119         *
120         * @param type  The access token type. Must not be {@code null}.
121         * @param value The access token value. Must not be {@code null} or
122         *              empty string.
123         */
124        public AccessToken(final AccessTokenType type, final String value) {
125        
126                this(type, value, 0l, null);
127        }
128        
129        
130        /**
131         * Creates a new access token with the specified value and optional 
132         * lifetime and scope.
133         *
134         * @param type     The access token type. Must not be {@code null}.
135         * @param value    The access token value. Must not be {@code null} or
136         *                 empty string.
137         * @param lifetime The lifetime in seconds, 0 if not specified.
138         * @param scope    The scope, {@code null} if not specified.
139         */
140        public AccessToken(final AccessTokenType type, 
141                           final String value, 
142                           final long lifetime, 
143                           final Scope scope) {
144        
145                super(value);
146
147                if (type == null)
148                        throw new IllegalArgumentException("The access token type must not be null");
149
150                this.type = type;
151
152                this.lifetime = lifetime;
153                this.scope = scope;
154        }
155
156
157        /**
158         * Returns the access token type.
159         *
160         * @return The access token type.
161         */
162        public AccessTokenType getType() {
163
164                return type;
165        }
166
167        
168        /**
169         * Returns the lifetime of this access token.
170         *
171         * @return The lifetime in seconds, 0 if not specified.
172         */
173        public long getLifetime() {
174        
175                return lifetime;
176        }
177        
178        
179        /**
180         * Returns the scope of this access token.
181         *
182         * @return The scope, {@code null} if not specified.
183         */
184        public Scope getScope() {
185        
186                return scope;
187        }
188
189
190        @Override
191        public Set<String> getParameterNames() {
192
193                Set<String> paramNames = new HashSet<>();
194                paramNames.add("access_token");
195                paramNames.add("token_type");
196
197                if (getLifetime() > 0)
198                        paramNames.add("expires_in");
199
200                if (getScope() != null)
201                        paramNames.add("scope");
202
203                return paramNames;
204        }
205
206
207        @Override
208        public JSONObject toJSONObject() {
209
210                JSONObject o = new JSONObject();
211
212                o.put("access_token", getValue());
213                o.put("token_type", type.toString());
214                
215                if (getLifetime() > 0)
216                        o.put("expires_in", lifetime);
217
218                if (getScope() != null)
219                        o.put("scope", scope.toString());
220                
221                return o;
222        }
223
224
225        @Override
226        public String toJSONString() {
227
228                return toJSONObject().toString();
229        }
230        
231        
232        /**
233         * Returns the {@code Authorization} HTTP request header value for this
234         * access token.
235         *
236         * @return The {@code Authorization} header value.
237         */
238        public abstract String toAuthorizationHeader();
239
240
241        /**
242         * Parses an access token from a JSON object access token response.
243         * Only bearer access tokens are supported.
244         *
245         * @param jsonObject The JSON object to parse. Must not be 
246         *                   {@code null}.
247         *
248         * @return The access token.
249         *
250         * @throws ParseException If the JSON object couldn't be parsed to an
251         *                        access token.
252         */
253        public static AccessToken parse(final JSONObject jsonObject)
254                throws ParseException {
255
256                return BearerAccessToken.parse(jsonObject);
257        }
258        
259        
260        /**
261         * Parses an {@code Authorization} HTTP request header value for an 
262         * access token. Only bearer access token are supported.
263         *
264         * @param header The {@code Authorization} header value to parse. Must 
265         *               not be {@code null}.
266         *
267         * @return The access token.
268         *
269         * @throws ParseException If the {@code Authorization} header value 
270         *                        couldn't be parsed to an access token.
271         */
272        public static AccessToken parse(final String header)
273                throws ParseException {
274        
275                return BearerAccessToken.parse(header);
276        }
277}