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