Test Failed
Push — master ( 253ac2...f7fd53 )
by Misagh
15:49
created

handlePostRequest(HttpServletRequest,HttpServletResponse)   B

Complexity

Conditions 5

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 5
c 1
b 1
f 0
dl 0
loc 28
rs 8.0894
1
package org.apereo.cas.oidc.web.controllers;
2
3
import org.apache.commons.lang3.StringUtils;
4
import org.apereo.cas.CentralAuthenticationService;
5
import org.apereo.cas.authentication.Authentication;
6
import org.apereo.cas.authentication.AuthenticationManager;
7
import org.apereo.cas.authentication.principal.PrincipalFactory;
8
import org.apereo.cas.authentication.principal.ServiceFactory;
9
import org.apereo.cas.authentication.principal.WebApplicationService;
10
import org.apereo.cas.configuration.CasConfigurationProperties;
11
import org.apereo.cas.oidc.OidcConstants;
12
import org.apereo.cas.oidc.introspection.OidcIntrospectionAccessTokenResponse;
13
import org.apereo.cas.services.ServicesManager;
14
import org.apereo.cas.support.oauth.OAuth20Constants;
15
import org.apereo.cas.support.oauth.profile.OAuth20ProfileScopeToAttributesFilter;
16
import org.apereo.cas.support.oauth.services.OAuthRegisteredService;
17
import org.apereo.cas.support.oauth.util.OAuth20Utils;
18
import org.apereo.cas.support.oauth.validator.OAuth20Validator;
19
import org.apereo.cas.support.oauth.web.endpoints.BaseOAuth20Controller;
20
import org.apereo.cas.ticket.accesstoken.AccessToken;
21
import org.apereo.cas.ticket.accesstoken.AccessTokenFactory;
22
import org.apereo.cas.ticket.registry.TicketRegistry;
23
import org.apereo.cas.util.CollectionUtils;
24
import org.apereo.cas.util.Pac4jUtils;
25
import org.apereo.cas.web.support.CookieRetrievingCookieGenerator;
26
import org.pac4j.core.credentials.UsernamePasswordCredentials;
27
import org.pac4j.core.credentials.extractor.BasicAuthExtractor;
28
import org.pac4j.core.credentials.extractor.CredentialsExtractor;
29
import org.slf4j.Logger;
30
import org.slf4j.LoggerFactory;
31
import org.springframework.http.HttpStatus;
32
import org.springframework.http.MediaType;
33
import org.springframework.http.ResponseEntity;
34
import org.springframework.web.bind.annotation.GetMapping;
35
import org.springframework.web.bind.annotation.PostMapping;
36
37
import javax.servlet.http.HttpServletRequest;
38
import javax.servlet.http.HttpServletResponse;
39
import java.util.stream.Collectors;
40
41
/**
42
 * This is {@link OidcIntrospectionEndpointController}.
43
 *
44
 * @author Misagh Moayyed
45
 * @since 5.2.0
46
 */
47
public class OidcIntrospectionEndpointController extends BaseOAuth20Controller {
48
    private static final Logger LOGGER = LoggerFactory.getLogger(OidcIntrospectionEndpointController.class);
49
50
    private final CentralAuthenticationService centralAuthenticationService;
51
52
    public OidcIntrospectionEndpointController(final ServicesManager servicesManager,
53
                                               final TicketRegistry ticketRegistry,
54
                                               final OAuth20Validator validator,
55
                                               final AccessTokenFactory accessTokenFactory,
56
                                               final PrincipalFactory principalFactory,
57
                                               final ServiceFactory<WebApplicationService> webApplicationServiceServiceFactory,
58
                                               final OAuth20ProfileScopeToAttributesFilter scopeToAttributesFilter,
59
                                               final CasConfigurationProperties casProperties,
60
                                               final CookieRetrievingCookieGenerator cookieGenerator,
61
                                               final CentralAuthenticationService centralAuthenticationService) {
62
        super(servicesManager, ticketRegistry, validator, accessTokenFactory, principalFactory,
63
                webApplicationServiceServiceFactory,
64
                scopeToAttributesFilter, casProperties, cookieGenerator);
65
        this.centralAuthenticationService = centralAuthenticationService;
66
    }
67
68
    /**
69
     * Handle request.
70
     *
71
     * @param request  the request
72
     * @param response the response
73
     * @return the response entity
74
     * @throws Exception the exception
75
     */
76
    @GetMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
77
            produces = MediaType.APPLICATION_JSON_VALUE,
78
            value = {'/' + OidcConstants.BASE_OIDC_URL + '/' + OidcConstants.INTROSPECTION_URL})
79
    public ResponseEntity<OidcIntrospectionAccessTokenResponse> handleRequest(final HttpServletRequest request,
80
                                                                              final HttpServletResponse response) throws Exception {
81
        return handlePostRequest(request, response);
82
    }
83
84
    /**
85
     * Handle post request.
86
     *
87
     * @param request  the request
88
     * @param response the response
89
     * @return the response entity
90
     */
91
    @PostMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
92
            produces = MediaType.APPLICATION_JSON_VALUE,
93
            value = {'/' + OidcConstants.BASE_OIDC_URL + '/' + OidcConstants.INTROSPECTION_URL})
94
    public ResponseEntity<OidcIntrospectionAccessTokenResponse> handlePostRequest(final HttpServletRequest request,
95
                                                                                  final HttpServletResponse response) {
96
        try {
97
            final CredentialsExtractor<UsernamePasswordCredentials> authExtractor = new BasicAuthExtractor(getClass().getSimpleName());
98
            final UsernamePasswordCredentials credentials = authExtractor.extract(Pac4jUtils.getPac4jJ2EContext(request, response));
99
            if (credentials == null) {
100
                throw new IllegalArgumentException("No credentials are provided to verify introspection on the access token");
101
            }
102
103
            final OAuthRegisteredService service = OAuth20Utils.getRegisteredOAuthService(this.servicesManager, credentials.getUsername());
104
            if (validateIntrospectionRequest(service, credentials, request)) {
105
                final String accessToken = StringUtils.defaultIfBlank(request.getParameter(OAuth20Constants.ACCESS_TOKEN),
106
                        request.getParameter(OAuth20Constants.TOKEN));
107
108
                LOGGER.debug("Located access token [{}] in the request", accessToken);
109
                final AccessToken ticket = this.centralAuthenticationService.getTicket(accessToken, AccessToken.class);
110
                if (ticket != null) {
111
                    return createIntrospectionResponse(service, ticket);
112
                }
113
            }
114
        } catch (final Exception e) {
115
            LOGGER.error(e.getMessage(), e);
116
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
117
        }
118
        return new ResponseEntity<>(HttpStatus.OK);
119
    }
120
121
    private boolean validateIntrospectionRequest(final OAuthRegisteredService service,
122
                                                 final UsernamePasswordCredentials credentials,
123
                                                 final HttpServletRequest request) {
124
        final boolean tokenExists = validator.checkParameterExist(request, OAuth20Constants.ACCESS_TOKEN)
125
                || validator.checkParameterExist(request, OAuth20Constants.TOKEN);
126
        return validator.checkServiceValid(service)
127
                && tokenExists
128
                && validator.checkClientSecret(service, credentials.getPassword());
129
    }
130
131
    private ResponseEntity<OidcIntrospectionAccessTokenResponse> createIntrospectionResponse(final OAuthRegisteredService service, final AccessToken ticket) {
132
        final OidcIntrospectionAccessTokenResponse introspect = new OidcIntrospectionAccessTokenResponse();
133
        introspect.setActive(true);
134
        introspect.setClientId(service.getClientId());
135
        final Authentication authentication = ticket.getAuthentication();
136
        final String subject = authentication.getPrincipal().getId();
137
        introspect.setSub(subject);
138
        introspect.setUniqueSecurityName(subject);
139
        introspect.setExp(ticket.getExpirationPolicy().getTimeToLive());
140
        introspect.setIat(ticket.getCreationTime().toInstant().toEpochMilli());
141
142
        final Object methods = authentication.getAttributes().get(AuthenticationManager.AUTHENTICATION_METHOD_ATTRIBUTE);
143
        final String realmNames = CollectionUtils.toCollection(methods)
144
                .stream()
145
                .map(Object::toString)
146
                .collect(Collectors.joining(","));
147
148
        introspect.setRealmName(realmNames);
149
        introspect.setTokenType(OAuth20Constants.TOKEN_TYPE_BEARER);
150
151
        final String grant = authentication.getAttributes()
152
                .getOrDefault(OAuth20Constants.GRANT_TYPE, StringUtils.EMPTY).toString().toLowerCase();
153
        introspect.setGrantType(grant);
154
        introspect.setScope(OidcConstants.StandardScopes.OPENID.getScope());
155
        introspect.setAud(service.getServiceId());
156
        introspect.setIss(casProperties.getAuthn().getOidc().getIssuer());
157
        return new ResponseEntity<>(introspect, HttpStatus.OK);
158
    }
159
}
160