001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2016, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.oauth2.sdk.token; 019 020 021import com.nimbusds.oauth2.sdk.ParseException; 022import com.nimbusds.oauth2.sdk.Scope; 023import com.nimbusds.oauth2.sdk.http.HTTPRequest; 024import com.nimbusds.oauth2.sdk.rar.AuthorizationDetail; 025import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 026import net.minidev.json.JSONObject; 027 028import java.util.HashSet; 029import java.util.List; 030import java.util.Map; 031import java.util.Set; 032 033 034/** 035 * The base abstract class for access tokens. Concrete extending classes should 036 * be immutable. 037 * 038 * <p>Related specifications: 039 * 040 * <ul> 041 * <li>OAuth 2.0 (RFC 6749), sections 1.4 and 5.1. 042 * <li>OAuth 2.0 Rich Authorization Requests (RFC 9396), section 7. 043 * <li>OAuth 2.0 Token Exchange (RFC 8693), section 3. 044 * </ul> 045 */ 046public abstract class AccessToken extends Token { 047 048 049 private static final long serialVersionUID = 2947643641344083799L; 050 051 052 /** 053 * The access token type. 054 */ 055 private final AccessTokenType type; 056 057 058 /** 059 * Optional lifetime, in seconds. 060 */ 061 private final long lifetime; 062 063 064 /** 065 * Optional scope. 066 */ 067 private final Scope scope; 068 069 070 /** 071 * Optional authorisation details. 072 */ 073 private final List<AuthorizationDetail> authorizationDetails; 074 075 076 /** 077 * Optional identifier URI for the token type, as defined in OAuth 2.0 078 * Token Exchange (RFC 8693). 079 */ 080 private final TokenTypeURI issuedTokenType; 081 082 083 /** 084 * Creates a new minimal access token with a randomly generated 256-bit 085 * (32-byte) value, Base64URL-encoded. The optional lifetime, scope and 086 * token type URI are left unspecified. 087 * 088 * @param type The access token type. Must not be {@code null}. 089 */ 090 public AccessToken(final AccessTokenType type) { 091 092 this(type, 32); 093 } 094 095 096 /** 097 * Creates a new minimal access token with a randomly generated value 098 * of the specified byte length, Base64URL-encoded. The optional 099 * lifetime, scope and token type URI are left unspecified. 100 * 101 * @param type The access token type. Must not be {@code null}. 102 * @param byteLength The byte length of the value to generate. Must be 103 * greater than one. 104 */ 105 public AccessToken(final AccessTokenType type, final int byteLength) { 106 107 this(type, byteLength, 0L, null); 108 } 109 110 111 /** 112 * Creates a new access token with a randomly generated 256-bit 113 * (32-byte) value, Base64URL-encoded. The optional token type URI is 114 * left unspecified. 115 * 116 * @param type The access token type. Must not be {@code null}. 117 * @param lifetime The lifetime in seconds, 0 if not specified. 118 * @param scope The scope, {@code null} if not specified. 119 */ 120 public AccessToken(final AccessTokenType type, 121 final long lifetime, 122 final Scope scope) { 123 124 this(type, 32, lifetime, scope); 125 } 126 127 128 /** 129 * Creates a new access token with a randomly generated value 130 * of the specified byte length, Base64URL-encoded. The optional token 131 * type URI is left unspecified. 132 * 133 * @param type The access token type. Must not be {@code null}. 134 * @param byteLength The byte length of the value to generate. Must be 135 * greater than one. 136 * @param lifetime The lifetime in seconds, 0 if not specified. 137 * @param scope The scope, {@code null} if not specified. 138 */ 139 public AccessToken(final AccessTokenType type, 140 final int byteLength, 141 final long lifetime, 142 final Scope scope) { 143 144 this(type, byteLength, lifetime, scope, null); 145 } 146 147 148 /** 149 * Creates a new access token with a randomly generated value 150 * of the specified byte length, Base64URL-encoded. 151 * 152 * @param type The access token type. Must not be 153 * {@code null}. 154 * @param byteLength The byte length of the value to generate. 155 * Must be greater than one. 156 * @param lifetime The lifetime in seconds, 0 if not specified. 157 * @param scope The scope, {@code null} if not specified. 158 * @param issuedTokenType The token type URI, {@code null} if not 159 * specified. 160 */ 161 public AccessToken(final AccessTokenType type, 162 final int byteLength, 163 final long lifetime, 164 final Scope scope, 165 final TokenTypeURI issuedTokenType) { 166 167 this(type, byteLength, lifetime, scope, null, issuedTokenType); 168 } 169 170 171 /** 172 * Creates a new access token with a randomly generated value 173 * of the specified byte length, Base64URL-encoded. 174 * 175 * @param type The access token type. Must not be 176 * {@code null}. 177 * @param byteLength The byte length of the value to 178 * generate. Must be greater than one. 179 * @param lifetime The lifetime in seconds, 0 if not 180 * specified. 181 * @param scope The scope, {@code null} if not 182 * specified. 183 * @param authorizationDetails The authorisation details, {@code null} 184 * if not specified. 185 * @param issuedTokenType The token type URI, {@code null} if not 186 * specified. 187 */ 188 public AccessToken(final AccessTokenType type, 189 final int byteLength, 190 final long lifetime, 191 final Scope scope, 192 final List<AuthorizationDetail> authorizationDetails, 193 final TokenTypeURI issuedTokenType) { 194 195 super(byteLength); 196 197 if (type == null) 198 throw new IllegalArgumentException("The access token type must not be null"); 199 200 this.type = type; 201 202 this.lifetime = lifetime; 203 this.scope = scope; 204 this.authorizationDetails = authorizationDetails; 205 this.issuedTokenType = issuedTokenType; 206 } 207 208 209 /** 210 * Creates a new minimal access token with the specified value. The 211 * optional lifetime, scope and token type URI are left unspecified. 212 * 213 * @param type The access token type. Must not be {@code null}. 214 * @param value The access token value. Must not be {@code null} or 215 * empty string. 216 */ 217 public AccessToken(final AccessTokenType type, final String value) { 218 219 this(type, value, 0L, null); 220 } 221 222 223 /** 224 * Creates a new access token with the specified value. The optional 225 * token type URI is left unspecified. 226 * 227 * @param type The access token type. Must not be {@code null}. 228 * @param value The access token value. Must not be {@code null} or 229 * empty string. 230 * @param lifetime The lifetime in seconds, 0 if not specified. 231 * @param scope The scope, {@code null} if not specified. 232 */ 233 public AccessToken(final AccessTokenType type, 234 final String value, 235 final long lifetime, 236 final Scope scope) { 237 this(type, value, lifetime, scope, null); 238 } 239 240 241 /** 242 * Creates a new access token with the specified value. 243 * 244 * @param type The access token type. Must not be 245 * {@code null}. 246 * @param value The access token value. Must not be 247 * {@code null} or empty string. 248 * @param lifetime The lifetime in seconds, 0 if not specified. 249 * @param scope The scope, {@code null} if not specified. 250 * @param issuedTokenType The token type URI, {@code null} if not 251 * specified. 252 */ 253 public AccessToken(final AccessTokenType type, 254 final String value, 255 final long lifetime, 256 final Scope scope, 257 final TokenTypeURI issuedTokenType) { 258 259 this(type, value, lifetime, scope, null, issuedTokenType); 260 } 261 262 263 /** 264 * Creates a new access token with the specified value. 265 * 266 * @param type The access token type. Must not be 267 * {@code null}. 268 * @param value The access token value. Must not be 269 * {@code null} or empty string. 270 * @param lifetime The lifetime in seconds, 0 if not specified. 271 * @param scope The scope, {@code null} if not specified. 272 * @param issuedTokenType The token type URI, {@code null} if not 273 * specified. 274 */ 275 public AccessToken(final AccessTokenType type, 276 final String value, 277 final long lifetime, 278 final Scope scope, 279 final List<AuthorizationDetail> authorizationDetails, 280 final TokenTypeURI issuedTokenType) { 281 282 super(value); 283 284 if (type == null) 285 throw new IllegalArgumentException("The access token type must not be null"); 286 287 this.type = type; 288 289 this.lifetime = lifetime; 290 this.scope = scope; 291 this.authorizationDetails = authorizationDetails; 292 this.issuedTokenType = issuedTokenType; 293 } 294 295 296 /** 297 * Returns the access token type. 298 * 299 * @return The access token type. 300 */ 301 public AccessTokenType getType() { 302 303 return type; 304 } 305 306 307 /** 308 * Returns the lifetime of this access token. 309 * 310 * @return The lifetime in seconds, 0 if not specified. 311 */ 312 public long getLifetime() { 313 314 return lifetime; 315 } 316 317 318 /** 319 * Returns the scope of this access token. 320 * 321 * @return The scope, {@code null} if not specified. 322 */ 323 public Scope getScope() { 324 325 return scope; 326 } 327 328 329 /** 330 * Returns the authorisation details for this access token. 331 * 332 * @return The authorisation details, {@code null} if not specified. 333 */ 334 public List<AuthorizationDetail> getAuthorizationDetails() { 335 336 return authorizationDetails; 337 } 338 339 340 /** 341 * Returns the identifier URI for the type of this access token. Used 342 * in OAuth 2.0 Token Exchange (RFC 8693). 343 * 344 * @return The token type URI, {@code null} if not specified. 345 */ 346 public TokenTypeURI getIssuedTokenType() { 347 348 return issuedTokenType; 349 } 350 351 352 @Override 353 public Set<String> getParameterNames() { 354 355 Set<String> paramNames = new HashSet<>(); 356 paramNames.add("access_token"); 357 paramNames.add("token_type"); 358 359 if (getLifetime() > 0) 360 paramNames.add("expires_in"); 361 362 if (getScope() != null) 363 paramNames.add("scope"); 364 365 if (getAuthorizationDetails() != null) 366 paramNames.add("authorization_details"); 367 368 if (getIssuedTokenType() != null) { 369 paramNames.add("issued_token_type"); 370 } 371 372 return paramNames; 373 } 374 375 376 @Override 377 public JSONObject toJSONObject() { 378 379 JSONObject o = new JSONObject(); 380 381 o.put("access_token", getValue()); 382 o.put("token_type", type.toString()); 383 384 if (getLifetime() > 0) 385 o.put("expires_in", lifetime); 386 387 if (getScope() != null) 388 o.put("scope", scope.toString()); 389 390 if (getAuthorizationDetails() != null) 391 o.put("authorization_details", AuthorizationDetail.toJSONString(getAuthorizationDetails())); 392 393 if (getIssuedTokenType() != null) { 394 o.put("issued_token_type", getIssuedTokenType().getURI().toString()); 395 } 396 397 return o; 398 } 399 400 401 @Override 402 public String toJSONString() { 403 404 return toJSONObject().toString(); 405 } 406 407 408 /** 409 * Returns the {@code Authorization} HTTP request header value for this 410 * access token. 411 * 412 * @return The {@code Authorization} header value. 413 */ 414 public abstract String toAuthorizationHeader(); 415 416 417 /** 418 * Parses an access token from a JSON object access token response. 419 * Only bearer and DPoP access tokens are supported. 420 * 421 * @param jsonObject The JSON object to parse. Must not be 422 * {@code null}. 423 * 424 * @return The access token. 425 * 426 * @throws ParseException If the JSON object couldn't be parsed to an 427 * access token. 428 */ 429 public static AccessToken parse(final JSONObject jsonObject) 430 throws ParseException { 431 432 AccessTokenType tokenType = new AccessTokenType(JSONObjectUtils.getString(jsonObject, "token_type")); 433 434 if (AccessTokenType.BEARER.equals(tokenType)) { 435 return BearerAccessToken.parse(jsonObject); 436 } else if (AccessTokenType.DPOP.equals(tokenType)) { 437 return DPoPAccessToken.parse(jsonObject); 438 } else if (AccessTokenType.N_A.equals(tokenType)) { 439 return NAAccessToken.parse(jsonObject); 440 } else { 441 throw new ParseException("Unsupported token_type: " + tokenType); 442 } 443 } 444 445 446 /** 447 * Parses an {@code Authorization} HTTP request header value for an 448 * access token. Only bearer access token are supported. 449 * 450 * @param header The {@code Authorization} header value to parse. Must 451 * not be {@code null}. 452 * 453 * @return The access token. 454 * 455 * @throws ParseException If the {@code Authorization} header value 456 * couldn't be parsed to an access token. 457 * 458 * @see #parse(String, AccessTokenType) 459 */ 460 @Deprecated 461 public static AccessToken parse(final String header) 462 throws ParseException { 463 464 return BearerAccessToken.parse(header); 465 } 466 467 468 /** 469 * Parses an {@code Authorization} HTTP request header value for an 470 * access token. Only bearer and DPoP access token are supported. 471 * 472 * @param header The {@code Authorization} header value to 473 * parse. Must not be {@code null}. 474 * @param preferredType The preferred (primary) access token type. 475 * Must be either {@link AccessTokenType#BEARER} 476 * or {@link AccessTokenType#DPOP} and not 477 * {@code null}. 478 * 479 * @return The access token. 480 * 481 * @throws ParseException If the {@code Authorization} header value 482 * couldn't be parsed to an access token. 483 */ 484 public static AccessToken parse(final String header, 485 final AccessTokenType preferredType) 486 throws ParseException { 487 488 if (! AccessTokenType.BEARER.equals(preferredType) && ! AccessTokenType.DPOP.equals(preferredType)) { 489 throw new IllegalArgumentException("Unsupported Authorization scheme: " + preferredType); 490 } 491 492 if (header != null && header.startsWith(AccessTokenType.BEARER.getValue()) || AccessTokenType.BEARER.equals(preferredType)) { 493 return BearerAccessToken.parse(header); 494 } else { 495 return DPoPAccessToken.parse(header); 496 } 497 } 498 499 500 /** 501 * Parses an HTTP request header value for an access token. 502 * 503 * @param request The HTTP request to parse. Must not be {@code null}. 504 * 505 * @return The access token. 506 * 507 * @throws ParseException If an access token wasn't found in the HTTP 508 * request. 509 */ 510 public static AccessToken parse(final HTTPRequest request) 511 throws ParseException { 512 513 if (request.getAuthorization() != null) { 514 515 AccessTokenType tokenType = AccessTokenUtils.determineAccessTokenTypeFromAuthorizationHeader(request.getAuthorization()); 516 517 if (AccessTokenType.BEARER.equals(tokenType)) { 518 return BearerAccessToken.parse(request.getAuthorization()); 519 } 520 521 if (AccessTokenType.DPOP.equals(tokenType)) { 522 return DPoPAccessToken.parse(request.getAuthorization()); 523 } 524 525 throw new ParseException("Couldn't determine access token type from Authorization header"); 526 } 527 528 // Try alternative token locations, form and query string are 529 // parameters are not differentiated here 530 Map<String, List<String>> params = request.getQueryParameters(); 531 return new TypelessAccessToken(AccessTokenUtils.parseValueFromQueryParameters(params)); 532 } 533}