001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * docs/licenses/cddl.txt 011 * or http://www.opensource.org/licenses/cddl1.php. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * docs/licenses/cddl.txt. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2016-2021 Ping Identity Corporation 026 */ 027 028 029package com.unboundid.directory.sdk.common.types; 030 031import com.unboundid.util.NotExtensible; 032 033import java.util.Collections; 034import java.util.Map; 035import java.util.Objects; 036import java.util.Set; 037import java.util.concurrent.TimeUnit; 038 039/** 040 * Object returned from a request to an AccessTokenValidator to validate a 041 * token. The fields of this object are derived from the IETF OAuth 2.0 Token 042 * Introspection specification (RFC7662). 043 * <p> 044 * The decision as to whether an access token is accepted or not varies by 045 * product. For the Directory Server, Directory Proxy Server, 046 * Data Sync Server, or Data Metrics Server, different REST APIs 047 * may enforce different authorization rules, depending on their configuration; 048 * please refer to the relevant documentation. In general, a token's 049 * {@code active} property must be true. 050 * <p> 051 * For the PingAuthorize Server, authorization decisions are made by the policy 052 * engine. All properties of the TokenValidationResult may be accessed by 053 * policies; however, the default policy may only examine a subset of those 054 * properties (e.g. especially the {@code active} property). 055 */ 056@NotExtensible() 057public final class TokenValidationResult { 058 059 060 private final String accessToken; 061 062 private final Boolean active; 063 064 private final Set<String> scope; 065 066 private final String clientId; 067 068 private final String username; 069 070 private final String tokenType; 071 072 private final Long expirationTime; 073 074 private final Long issuedAt; 075 076 private final Long notUsedBefore; 077 078 private final String tokenSubject; 079 080 private final Set<String> audience; 081 082 private final String tokenIdentifier; 083 084 /** 085 * This field contains any extension values implemented by the 086 * Token Validator. 087 */ 088 private final Map<String,Object> additionalProperties; 089 090 /** 091 * Private constructor for builder. 092 * @param builder Builder source for properties. 093 */ 094 private TokenValidationResult(final Builder builder) 095 { 096 this.accessToken = builder.accessToken; 097 this.active = builder.active; 098 this.scope = builder.scope; 099 this.clientId = builder.clientId; 100 this.username = builder.username; 101 this.tokenType = builder.tokenType; 102 this.expirationTime = builder.expirationTime; 103 this.issuedAt = builder.issuedAt; 104 this.notUsedBefore = builder.notUsedBefore; 105 this.tokenSubject = builder.tokenSubject; 106 this.audience = builder.audience; 107 this.tokenIdentifier = builder.tokenIdentifier; 108 this.additionalProperties = (builder.additionalProperties == null) ? 109 Collections.emptyMap() : 110 builder.additionalProperties; 111 } 112 113 /** 114 * Get the actual access token as issued by the authorization server. 115 * @return the access token. May be null. 116 */ 117 public String getAccessToken() { 118 return accessToken; 119 } 120 121 /** 122 * Get whether the token is active. Per RFC 7662, a value of true for this 123 * property indicates that the given token was issued by the Token 124 * Validator's associated authorization server, has not been revoked by the 125 * resource owner, and is within its given time window of validity 126 * (e.g. after its issuance time and before its expiration time). 127 * @return the active state. 128 */ 129 public Boolean getActive() { 130 return active; 131 } 132 133 /** 134 * Get the scopes granted to this token. 135 * @return set of scope names. 136 */ 137 public Set<String> getScope() { 138 return scope; 139 } 140 141 /** 142 * Get the OAuth2 client Id of the client that requested the token. 143 * @return client Id string. 144 */ 145 public String getClientId() { 146 return clientId; 147 } 148 149 /** 150 * Get a human-readable user name for the resource owner that authorized 151 * the token. 152 * @return user name string. 153 */ 154 public String getUsername() { 155 return username; 156 } 157 158 /** 159 * Get the token type. The type of the token is defined in section 5.1 of 160 * OAuth 2.0 [RFC6749]. 161 * @return token type string. 162 */ 163 public String getTokenType() { 164 return tokenType; 165 } 166 167 /** 168 * Get the token expiration time in seconds since January 1 1970 UTC. 169 * @return expiration time in seconds. 170 */ 171 public Long getExpirationTime() { 172 return expirationTime; 173 } 174 175 /** 176 * Get the token issue time in seconds since January 1 1970 UTC. 177 * @return token issue time in seconds. 178 */ 179 public Long getIssuedAt() { 180 return issuedAt; 181 } 182 183 /** 184 * Get the not used before time in seconds since January 1 1070 UTC. 185 * @return not used before time in seconds. 186 */ 187 public Long getNotUsedBefore() { 188 return notUsedBefore; 189 } 190 191 /** 192 * Get the token subject as defined in JWT [RFC7519]. This value should 193 * contain the subject ID as known to the external authorization server rather 194 * than the local server. 195 * @return token subject string. 196 */ 197 public String getTokenSubject() { 198 return tokenSubject; 199 } 200 201 /** 202 * Get the token's intended audience(s). The audience is a Service-specific 203 * identifier representing the intended audience(s) for this token, as 204 * defined in JWT [RFC7519]. 205 * @return token audience. 206 */ 207 public Set<String> getAudience() { 208 return audience; 209 } 210 211 /** 212 * Get the unique identifier for this token. as defined in section 4.1.7 of 213 * JWT [RFC7519]. 214 * @return token unique identifier string. 215 */ 216 public String getTokenIdentifier() { 217 return tokenIdentifier; 218 } 219 220 /** 221 * Get any extension properties associated with the token. 222 * @return Map of property names to values. 223 */ 224 public Map<String, Object> getAdditionalProperties() { 225 return additionalProperties; 226 } 227 228 /** 229 * A Builder for TokenValidationResult. 230 */ 231 public static class Builder 232 { 233 private final String accessToken; 234 private Boolean active; 235 private Set<String> scope; 236 private String clientId; 237 private String username; 238 private String tokenType; 239 private Long expirationTime; 240 private Long issuedAt; 241 private Long notUsedBefore; 242 private String tokenSubject; 243 private Set<String> audience; 244 private String tokenIdentifier; 245 private Map<String,Object> additionalProperties; 246 247 248 /** 249 * Creates a new builder object. 250 * @param active true if the token is active, false if not. Per RFC 251 * 7662, a value of true for this property indicates 252 * that the given token was issued by the Token 253 * Validator's associated authorization server, has not 254 * been revoked by the resource owner, and is within its 255 * given time window of validity (e.g. after its issuance 256 * time and before its expiration time). 257 */ 258 public Builder(final boolean active) 259 { 260 this(null, active); 261 } 262 263 /** 264 * Creates a new builder object. 265 * @param accessToken the actual access token, as received from the 266 * authorization server. May be null. 267 * @param active true if the token is active, false if not. Per RFC 268 * 7662, a value of true for this property indicates 269 * that the given token was issued by the Token 270 * Validator's associated authorization server, has not 271 * been revoked by the resource owner, and is within its 272 * given time window of validity (e.g. after its issuance 273 * time and before its expiration time). 274 */ 275 public Builder(final String accessToken, final boolean active) 276 { 277 this.accessToken = accessToken; 278 this.active = active; 279 setScope(Collections.emptySet()); 280 } 281 282 /** 283 * Set the active field of the token validation result. 284 * 285 * @param active true if the token is active, false if not. Per RFC 7662, 286 * a value of true for this property indicates that the given 287 * token was issued by the Token Validator's associated 288 * authorization server, has not been revoked by the resource 289 * owner, and is within its given time window of validity 290 * (e.g. after its issuance time and before its expiration 291 * time). 292 * @return this. 293 */ 294 public Builder setActive(final boolean active) 295 { 296 this.active = active; 297 return this; 298 } 299 300 /** 301 * Set the optional scope field of the token validation result. 302 * 303 * @param scope A list of strings representing the scopes associated with 304 * this token. 305 * @return this. 306 */ 307 public Builder setScope(final Set<String> scope) 308 { 309 this.scope = (scope == null) ? Collections.emptySet() : scope; 310 return this; 311 } 312 313 /** 314 * Set the optional clientId field of the token validation result. 315 * 316 * @param clientId Client identifier for the OAuth 2.0 client that 317 * requested this token. 318 * @return this. 319 */ 320 public Builder setClientId(final String clientId) 321 { 322 this.clientId = clientId; 323 return this; 324 } 325 326 /** 327 * Set the optional username field of the token validation result. 328 * 329 * @param username Human-readable identifier for the resource owner who 330 * authorized this token. 331 * @return this. 332 */ 333 public Builder setUsername(final String username) 334 { 335 this.username = username; 336 return this; 337 } 338 339 /** 340 * Set the optional tokenType field of the token validation result. 341 * 342 * @param tokenType Type of the token as defined in section 5.1 of OAuth 343 * 2.0 [RFC6749]. 344 * @return this. 345 */ 346 public Builder setTokenType(final String tokenType) 347 { 348 this.tokenType = tokenType; 349 return this; 350 } 351 352 /** 353 * Set the optional expirationTime field of the token validation result. 354 * 355 * @param expirationTime Integer timestamp, measured in the number of 356 * time units since January 1 1970 UTC, indicating 357 * when this token will expire. 358 * @param timeUnit the time units of the specified expiration time. 359 * @return this. 360 */ 361 public Builder setExpirationTime( 362 final long expirationTime, 363 final TimeUnit timeUnit) 364 { 365 this.expirationTime = timeUnit.toSeconds(expirationTime); 366 return this; 367 } 368 369 /** 370 * Set the optional issuedAt field of the token validation result. 371 * 372 * @param issuedAt Integer timestamp, measured in the number of time 373 * units since January 1 1970 UTC, indicating when this 374 * token was originally issued. 375 * @param timeUnit the time units of the specified issuedAt time. 376 * @return this. 377 */ 378 public Builder setIssuedAt( 379 final long issuedAt, 380 final TimeUnit timeUnit) 381 { 382 this.issuedAt = timeUnit.toSeconds(issuedAt); 383 return this; 384 } 385 386 /** 387 * Set the optional notUsedBefore field of the token validation result. 388 * 389 * @param notUsedBefore Integer timestamp, measured in the number of 390 * time units since January 1 1970 UTC, indicating 391 * when this token is not to be used before. 392 * @param timeUnit the time units of the specified notUsedBefore time. 393 * @return this. 394 */ 395 public Builder setNotUsedBefore( 396 final long notUsedBefore, 397 final TimeUnit timeUnit) 398 { 399 this.notUsedBefore = timeUnit.toSeconds(notUsedBefore); 400 return this; 401 } 402 403 /** 404 * Set the optional subjectToken field of the token validation result. 405 * 406 * @param tokenSubject Subject of the token, as defined in JWT [RFC7519]. 407 * This value should contain the subject ID as known to 408 * the external authorization server rather than the 409 * local server. 410 * @return this. 411 */ 412 public Builder setTokenSubject(final String tokenSubject) 413 { 414 this.tokenSubject = tokenSubject; 415 return this; 416 } 417 418 /** 419 * Set the optional audience field of the token validation result. 420 * 421 * @param audience Service-specific identifiers representing the 422 * intended audience(s) for this token, as defined in 423 * JWT [RFC7519]. 424 * @return this. 425 */ 426 public Builder setAudience(final Set<String> audience) 427 { 428 this.audience = audience; 429 return this; 430 } 431 432 /** 433 * Set the optional tokenIdentifier field of the token validation result. 434 * 435 * @param tokenIdentifier Unique string identifier for the token, as 436 * defined in section 4.1.7 of JWT [RFC7519]. 437 * @return this. 438 */ 439 public Builder setTokenIdentifier(final String tokenIdentifier) 440 { 441 this.tokenIdentifier = tokenIdentifier; 442 return this; 443 } 444 445 /** 446 * Set the optional additionalProperties field of the token validation 447 * result. 448 * @param properties Map of property names to values, containing any 449 * extension values implemented by the 450 * AccessTokenValidator. 451 * @return this. 452 */ 453 public Builder setAdditionalProperties( 454 final Map<String,Object> properties) { 455 456 this.additionalProperties = properties; 457 return this; 458 } 459 460 /** 461 * Builds a new TokenValidationResult from the parameters 462 * previously supplied to the builder. 463 * 464 * @return a new TokenValidationResult. 465 */ 466 public TokenValidationResult build() 467 { 468 return new TokenValidationResult(this); 469 } 470 } 471 472 @Override 473 public boolean equals(final Object other) { 474 if (this == other) { 475 return true; 476 } 477 if (other == null || getClass() != other.getClass()) { 478 return false; 479 } 480 final TokenValidationResult that = (TokenValidationResult) other; 481 return Objects.equals(accessToken, that.accessToken) && 482 active.equals(that.active) && 483 Objects.equals(scope, that.scope) && 484 Objects.equals(clientId, that.clientId) && 485 Objects.equals(username, that.username) && 486 Objects.equals(tokenType, that.tokenType) && 487 Objects.equals(expirationTime, that.expirationTime) && 488 Objects.equals(issuedAt, that.issuedAt) && 489 Objects.equals(notUsedBefore, that.notUsedBefore) && 490 Objects.equals(tokenSubject, that.tokenSubject) && 491 Objects.equals(audience, that.audience) && 492 Objects.equals(tokenIdentifier, that.tokenIdentifier) && 493 Objects.equals(additionalProperties, that.additionalProperties); 494 } 495 496 @Override 497 public int hashCode() { 498 return Objects.hash(accessToken, active, scope, clientId, username, 499 tokenType, expirationTime, issuedAt, notUsedBefore, tokenSubject, 500 audience, tokenIdentifier, additionalProperties); 501 } 502}