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}