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> getParamNames() {
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
204                return paramNames;
205        }
206
207
208        @Override
209        public JSONObject toJSONObject() {
210
211                JSONObject o = new JSONObject();
212
213                o.put("access_token", getValue());
214                o.put("token_type", type.toString());
215                
216                if (getLifetime() > 0)
217                        o.put("expires_in", lifetime);
218
219                if (getScope() != null)
220                        o.put("scope", scope.toString());
221                
222                return o;
223        }
224
225
226        @Override
227        public String toJSONString() {
228
229                return toJSONObject().toString();
230        }
231        
232        
233        /**
234         * Returns the {@code Authorization} HTTP request header value for this
235         * access token.
236         *
237         * @return The {@code Authorization} header value.
238         */
239        public abstract String toAuthorizationHeader();
240
241
242        /**
243         * Parses an access token from a JSON object access token response.
244         * Only bearer access tokens are supported.
245         *
246         * @param jsonObject The JSON object to parse. Must not be 
247         *                   {@code null}.
248         *
249         * @return The access token.
250         *
251         * @throws ParseException If the JSON object couldn't be parsed to an
252         *                        access token.
253         */
254        public static AccessToken parse(final JSONObject jsonObject)
255                throws ParseException {
256
257                return BearerAccessToken.parse(jsonObject);
258        }
259        
260        
261        /**
262         * Parses an {@code Authorization} HTTP request header value for an 
263         * access token. Only bearer access token are supported.
264         *
265         * @param header The {@code Authorization} header value to parse. Must 
266         *               not be {@code null}.
267         *
268         * @return The access token.
269         *
270         * @throws ParseException If the {@code Authorization} header value 
271         *                        couldn't be parsed to an access token.
272         */
273        public static AccessToken parse(final String header)
274                throws ParseException {
275        
276                return BearerAccessToken.parse(header);
277        }
278}