001package com.nimbusds.openid.connect.provider.spi.tokens.introspection; 002 003 004import java.sql.Date; 005 006import com.nimbusds.oauth2.sdk.TokenIntrospectionSuccessResponse; 007import com.nimbusds.oauth2.sdk.token.AccessTokenType; 008import com.nimbusds.openid.connect.provider.spi.tokens.AccessTokenAuthorization; 009import net.jcip.annotations.ThreadSafe; 010 011 012/** 013 * Base implementation of the SPI for composing token introspection (RFC 7662) 014 * responses. 015 * 016 * <p>Outputs only those introspection details which are defined in section 2.2 017 * of the standard OAuth 2.0 Token Introspection (RFC 7662) specification as 018 * well as in section 3.2 of OAuth 2.0 Mutual TLS Client Authentication and 019 * Certificate Bound Access Tokens(draft-ietf-oauth-mtls-07): 020 * 021 * <ul> 022 * <li>"active" 023 * <li>"scope" 024 * <li>"client_id" 025 * <li>"token_type" 026 * <li>"exp" 027 * <li>"iat" 028 * <li>"sub" 029 * <li>"aud" 030 * <li>"iss" 031 * <li>"jti" 032 * <li>"cnf.x5t#S256" 033 * </ul> 034 * 035 * <p>The following non-standard access token parameters are not output by this 036 * base implementation: 037 * 038 * <ul> 039 * <li>{@link AccessTokenAuthorization#getClaimNames() consented OpenID claim names} 040 * <li>{@link AccessTokenAuthorization#getClaimsLocales() preferred claims locales} 041 * <li>{@link AccessTokenAuthorization#getPresetClaims() preset OpenID claims} 042 * <li>{@link AccessTokenAuthorization#getActor() actor, in impersonation and delegation scenarios} 043 * <li>{@link AccessTokenAuthorization#getData() additional data} 044 * </ul> 045 * 046 * <p>The extending class may implement output of the above non-standard 047 * parameters. It may also choose not to output parameters if they are not 048 * required by the client (resource server), e.g. for privacy and data 049 * minimisation purposes. 050 */ 051@ThreadSafe 052public abstract class BaseTokenIntrospectionResponseComposer implements TokenIntrospectionResponseComposer { 053 054 055 @Override 056 public TokenIntrospectionSuccessResponse compose(final AccessTokenAuthorization tokenAuthz, 057 final TokenIntrospectionContext context) { 058 059 if (tokenAuthz == null) { 060 // Access token was found invalid or expired 061 return new TokenIntrospectionSuccessResponse.Builder(false) 062 .build(); 063 } 064 065 return new TokenIntrospectionSuccessResponse.Builder(true) 066 .tokenType(AccessTokenType.BEARER) 067 .subject(tokenAuthz.getSubject()) 068 .clientID(tokenAuthz.getClientID()) 069 .scope(tokenAuthz.getScope()) 070 .expirationTime(tokenAuthz.getExpirationTime() != null ? Date.from(tokenAuthz.getExpirationTime()) : null) 071 .issueTime(tokenAuthz.getIssueTime() != null ? Date.from(tokenAuthz.getIssueTime()) : null) 072 .issuer(tokenAuthz.getIssuer()) 073 .audience(tokenAuthz.getAudienceList()) 074 .jwtID(tokenAuthz.getJWTID()) 075 .x509CertificateConfirmation(tokenAuthz.getClientCertificateConfirmation()) 076 .build(); 077 } 078}