Search in sources :

Example 1 with OAuth20ResponseTypes

use of org.apereo.cas.support.oauth.OAuth20ResponseTypes in project cas by apereo.

the class OAuth20AccessTokenEndpointController method handleRequestInternal.

/**
     * Handle request internal model and view.
     *
     * @param request  the request
     * @param response the response
     * @return the model and view
     * @throws Exception the exception
     */
@PostMapping(path = OAuthConstants.BASE_OAUTH20_URL + '/' + OAuthConstants.ACCESS_TOKEN_URL)
public ModelAndView handleRequestInternal(final HttpServletRequest request, final HttpServletResponse response) throws Exception {
    try {
        response.setContentType(MediaType.TEXT_PLAIN_VALUE);
        if (!verifyAccessTokenRequest(request, response)) {
            LOGGER.error("Access token request verification fails");
            return OAuthUtils.writeTextError(response, OAuthConstants.INVALID_REQUEST);
        }
        final String grantType = request.getParameter(OAuthConstants.GRANT_TYPE);
        final Service service;
        final Authentication authentication;
        final boolean generateRefreshToken;
        final OAuthRegisteredService registeredService;
        final J2EContext context = WebUtils.getPac4jJ2EContext(request, response);
        final ProfileManager manager = WebUtils.getPac4jProfileManager(request, response);
        if (isGrantType(grantType, OAuth20GrantTypes.AUTHORIZATION_CODE) || isGrantType(grantType, OAuth20GrantTypes.REFRESH_TOKEN)) {
            final Optional<UserProfile> profile = manager.get(true);
            final String clientId = profile.get().getId();
            registeredService = OAuthUtils.getRegisteredOAuthService(getServicesManager(), clientId);
            // we generate a refresh token if requested by the service but not from a refresh token
            generateRefreshToken = registeredService != null && registeredService.isGenerateRefreshToken() && isGrantType(grantType, OAuth20GrantTypes.AUTHORIZATION_CODE);
            final String parameterName;
            if (isGrantType(grantType, OAuth20GrantTypes.AUTHORIZATION_CODE)) {
                parameterName = OAuthConstants.CODE;
            } else {
                parameterName = OAuthConstants.REFRESH_TOKEN;
            }
            final OAuthToken token = getToken(request, parameterName);
            if (token == null) {
                LOGGER.error("No token found for authorization_code or refresh_token grant types");
                return OAuthUtils.writeTextError(response, OAuthConstants.INVALID_GRANT);
            }
            service = token.getService();
            authentication = token.getAuthentication();
        } else {
            final String clientId = request.getParameter(OAuthConstants.CLIENT_ID);
            registeredService = OAuthUtils.getRegisteredOAuthService(getServicesManager(), clientId);
            generateRefreshToken = registeredService != null && registeredService.isGenerateRefreshToken();
            try {
                // resource owner password grant type
                final Optional<OAuthUserProfile> profile = manager.get(true);
                if (!profile.isPresent()) {
                    throw new UnauthorizedServiceException("OAuth user profile cannot be determined");
                }
                service = createService(registeredService, context);
                authentication = createAuthentication(profile.get(), registeredService, context, service);
                RegisteredServiceAccessStrategyUtils.ensurePrincipalAccessIsAllowedForService(service, registeredService, authentication);
            } catch (final Exception e) {
                LOGGER.error(e.getMessage(), e);
                return OAuthUtils.writeTextError(response, OAuthConstants.INVALID_GRANT);
            }
        }
        final AccessToken accessToken = generateAccessToken(service, authentication, context);
        RefreshToken refreshToken = null;
        if (generateRefreshToken) {
            refreshToken = this.refreshTokenFactory.create(service, authentication);
            getTicketRegistry().addTicket(refreshToken);
        }
        LOGGER.debug("access token: [{}] / timeout: [{}] / refresh token: [{}]", accessToken, casProperties.getTicket().getTgt().getTimeToKillInSeconds(), refreshToken);
        final String responseType = context.getRequestParameter(OAuthConstants.RESPONSE_TYPE);
        final OAuth20ResponseTypes type = Arrays.stream(OAuth20ResponseTypes.values()).filter(t -> t.getType().equalsIgnoreCase(responseType)).findFirst().orElse(OAuth20ResponseTypes.CODE);
        this.accessTokenResponseGenerator.generate(request, response, registeredService, service, accessToken, refreshToken, casProperties.getTicket().getTgt().getTimeToKillInSeconds(), type);
        getTicketRegistry().addTicket(accessToken);
        response.setStatus(HttpServletResponse.SC_OK);
        return null;
    } catch (final Exception e) {
        LOGGER.error(e.getMessage(), e);
        throw Throwables.propagate(e);
    }
}
Also used : ProfileManager(org.pac4j.core.profile.ProfileManager) OAuth20ResponseTypes(org.apereo.cas.support.oauth.OAuth20ResponseTypes) OAuthUserProfile(org.apereo.cas.support.oauth.profile.OAuthUserProfile) UserProfile(org.pac4j.core.profile.UserProfile) OAuthRegisteredService(org.apereo.cas.support.oauth.services.OAuthRegisteredService) WebApplicationService(org.apereo.cas.authentication.principal.WebApplicationService) OAuthRegisteredService(org.apereo.cas.support.oauth.services.OAuthRegisteredService) Service(org.apereo.cas.authentication.principal.Service) UnauthorizedServiceException(org.apereo.cas.services.UnauthorizedServiceException) J2EContext(org.pac4j.core.context.J2EContext) UnauthorizedServiceException(org.apereo.cas.services.UnauthorizedServiceException) OAuthToken(org.apereo.cas.ticket.OAuthToken) RefreshToken(org.apereo.cas.ticket.refreshtoken.RefreshToken) Authentication(org.apereo.cas.authentication.Authentication) AccessToken(org.apereo.cas.ticket.accesstoken.AccessToken) OAuthUserProfile(org.apereo.cas.support.oauth.profile.OAuthUserProfile) PostMapping(org.springframework.web.bind.annotation.PostMapping)

Example 2 with OAuth20ResponseTypes

use of org.apereo.cas.support.oauth.OAuth20ResponseTypes in project cas by apereo.

the class OAuth20AccessTokenEndpointController method generateAccessTokenResponse.

private void generateAccessTokenResponse(final HttpServletRequest request, final HttpServletResponse response, final AccessTokenRequestDataHolder requestHolder, final J2EContext context, final AccessToken accessToken, final RefreshToken refreshToken) {
    LOGGER.debug("Generating access token response for [{}]", accessToken);
    final OAuth20ResponseTypes type = OAuth20Utils.getResponseType(context);
    LOGGER.debug("Located response type as [{}]", type);
    this.accessTokenResponseGenerator.generate(request, response, requestHolder.getRegisteredService(), requestHolder.getService(), accessToken, refreshToken, accessTokenExpirationPolicy.getTimeToLive(), type);
}
Also used : OAuth20ResponseTypes(org.apereo.cas.support.oauth.OAuth20ResponseTypes)

Example 3 with OAuth20ResponseTypes

use of org.apereo.cas.support.oauth.OAuth20ResponseTypes in project cas by apereo.

the class OidcIdTokenGeneratorService method produceIdTokenClaims.

/**
 * Produce id token claims jwt claims.
 *
 * @param request       the request
 * @param accessTokenId the access token id
 * @param timeout       the timeout
 * @param service       the service
 * @param profile       the user profile
 * @param context       the context
 * @param responseType  the response type
 * @return the jwt claims
 */
protected JwtClaims produceIdTokenClaims(final HttpServletRequest request, final AccessToken accessTokenId, final long timeout, final OidcRegisteredService service, final UserProfile profile, final J2EContext context, final OAuth20ResponseTypes responseType) {
    final Authentication authentication = accessTokenId.getAuthentication();
    final Principal principal = authentication.getPrincipal();
    final OidcProperties oidc = casProperties.getAuthn().getOidc();
    final JwtClaims claims = new JwtClaims();
    claims.setJwtId(getOAuthServiceTicket(accessTokenId.getTicketGrantingTicket()).getKey());
    claims.setIssuer(oidc.getIssuer());
    claims.setAudience(service.getClientId());
    final NumericDate expirationDate = NumericDate.now();
    expirationDate.addSeconds(timeout);
    claims.setExpirationTime(expirationDate);
    claims.setIssuedAtToNow();
    claims.setNotBeforeMinutesInThePast(oidc.getSkew());
    claims.setSubject(principal.getId());
    final MultifactorAuthenticationProperties mfa = casProperties.getAuthn().getMfa();
    final Map<String, Object> attributes = authentication.getAttributes();
    if (attributes.containsKey(mfa.getAuthenticationContextAttribute())) {
        final Collection<Object> val = CollectionUtils.toCollection(attributes.get(mfa.getAuthenticationContextAttribute()));
        claims.setStringClaim(OidcConstants.ACR, val.iterator().next().toString());
    }
    if (attributes.containsKey(AuthenticationHandler.SUCCESSFUL_AUTHENTICATION_HANDLERS)) {
        final Collection<Object> val = CollectionUtils.toCollection(attributes.get(AuthenticationHandler.SUCCESSFUL_AUTHENTICATION_HANDLERS));
        claims.setStringListClaim(OidcConstants.AMR, val.toArray(new String[] {}));
    }
    claims.setClaim(OAuth20Constants.STATE, attributes.get(OAuth20Constants.STATE));
    claims.setClaim(OAuth20Constants.NONCE, attributes.get(OAuth20Constants.NONCE));
    claims.setClaim(OidcConstants.CLAIM_AT_HASH, generateAccessTokenHash(accessTokenId, service));
    principal.getAttributes().entrySet().stream().filter(entry -> oidc.getClaims().contains(entry.getKey())).forEach(entry -> claims.setClaim(entry.getKey(), entry.getValue()));
    if (!claims.hasClaim(OidcConstants.CLAIM_PREFERRED_USERNAME)) {
        claims.setClaim(OidcConstants.CLAIM_PREFERRED_USERNAME, profile.getId());
    }
    return claims;
}
Also used : CasConfigurationProperties(org.apereo.cas.configuration.CasConfigurationProperties) Arrays(java.util.Arrays) AlgorithmIdentifiers(org.jose4j.jws.AlgorithmIdentifiers) DigestUtils(org.apereo.cas.util.DigestUtils) HttpServletRequest(javax.servlet.http.HttpServletRequest) AuthenticationHandler(org.apereo.cas.authentication.AuthenticationHandler) MultifactorAuthenticationProperties(org.apereo.cas.configuration.model.support.mfa.MultifactorAuthenticationProperties) Authentication(org.apereo.cas.authentication.Authentication) OidcProperties(org.apereo.cas.configuration.model.support.oidc.OidcProperties) Map(java.util.Map) CollectionUtils(org.apereo.cas.util.CollectionUtils) TicketGrantingTicket(org.apereo.cas.ticket.TicketGrantingTicket) AccessToken(org.apereo.cas.ticket.accesstoken.AccessToken) ServicesManager(org.apereo.cas.services.ServicesManager) OAuth20Constants(org.apereo.cas.support.oauth.OAuth20Constants) OAuth20ResponseTypes(org.apereo.cas.support.oauth.OAuth20ResponseTypes) OidcConstants(org.apereo.cas.oidc.OidcConstants) Collection(java.util.Collection) HttpServletResponse(javax.servlet.http.HttpServletResponse) OAuthRegisteredService(org.apereo.cas.support.oauth.services.OAuthRegisteredService) ProfileManager(org.pac4j.core.profile.ProfileManager) StandardCharsets(java.nio.charset.StandardCharsets) Pac4jUtils(org.apereo.cas.util.Pac4jUtils) Slf4j(lombok.extern.slf4j.Slf4j) MessageDigestAlgorithms(org.apache.commons.codec.digest.MessageDigestAlgorithms) NumericDate(org.jose4j.jwt.NumericDate) OidcRegisteredService(org.apereo.cas.services.OidcRegisteredService) Stream(java.util.stream.Stream) JwtClaims(org.jose4j.jwt.JwtClaims) Service(org.apereo.cas.authentication.principal.Service) Entry(java.util.Map.Entry) J2EContext(org.pac4j.core.context.J2EContext) Optional(java.util.Optional) Preconditions(com.google.common.base.Preconditions) Principal(org.apereo.cas.authentication.principal.Principal) EncodingUtils(org.apereo.cas.util.EncodingUtils) UserProfile(org.pac4j.core.profile.UserProfile) NumericDate(org.jose4j.jwt.NumericDate) JwtClaims(org.jose4j.jwt.JwtClaims) Authentication(org.apereo.cas.authentication.Authentication) OidcProperties(org.apereo.cas.configuration.model.support.oidc.OidcProperties) MultifactorAuthenticationProperties(org.apereo.cas.configuration.model.support.mfa.MultifactorAuthenticationProperties) Principal(org.apereo.cas.authentication.principal.Principal)

Example 4 with OAuth20ResponseTypes

use of org.apereo.cas.support.oauth.OAuth20ResponseTypes in project cas by apereo.

the class OAuth20Utils method getResponseType.

/**
 * Gets response type.
 *
 * @param context the context
 * @return the response type
 */
public static OAuth20ResponseTypes getResponseType(final J2EContext context) {
    final String responseType = context.getRequestParameter(OAuth20Constants.RESPONSE_TYPE);
    final OAuth20ResponseTypes type = Arrays.stream(OAuth20ResponseTypes.values()).filter(t -> t.getType().equalsIgnoreCase(responseType)).findFirst().orElse(OAuth20ResponseTypes.CODE);
    LOGGER.debug("OAuth response type is [{}]", type);
    return type;
}
Also used : OAuth20ResponseTypes(org.apereo.cas.support.oauth.OAuth20ResponseTypes)

Example 5 with OAuth20ResponseTypes

use of org.apereo.cas.support.oauth.OAuth20ResponseTypes in project cas by apereo.

the class OidcIdTokenGeneratorService method buildJwtClaims.

/**
 * Produce claims as jwt.
 * As per OpenID Connect Core section 5.4, 'The Claims requested by the profile,
 * email, address, and phone scope values are returned from the UserInfo Endpoint',
 * except for response_type=id_token, where they are returned in the id_token
 * (as there is no access token issued that could be used to access the userinfo endpoint).
 *
 * @param accessToken      the access token
 * @param timeoutInSeconds the timeoutInSeconds
 * @param service          the service
 * @param responseType     the response type
 * @param grantType        the grant type
 * @return the jwt claims
 */
protected JwtClaims buildJwtClaims(final OAuth20AccessToken accessToken, final long timeoutInSeconds, final OidcRegisteredService service, final OAuth20ResponseTypes responseType, final OAuth20GrantTypes grantType) {
    val authentication = accessToken.getAuthentication();
    val principal = getConfigurationContext().getProfileScopeToAttributesFilter().filter(accessToken.getService(), authentication.getPrincipal(), service, accessToken);
    LOGGER.debug("Principal to use to build th ID token is [{}]", principal);
    val oidc = getConfigurationContext().getCasProperties().getAuthn().getOidc();
    val claims = new JwtClaims();
    val tgt = accessToken.getTicketGrantingTicket();
    val jwtId = getJwtId(tgt);
    claims.setJwtId(jwtId);
    claims.setClaim(OidcConstants.CLAIM_SESSION_ID, DigestUtils.sha(jwtId));
    claims.setIssuer(getConfigurationContext().getIssuerService().determineIssuer(Optional.empty()));
    claims.setAudience(accessToken.getClientId());
    val expirationDate = NumericDate.now();
    expirationDate.addSeconds(timeoutInSeconds);
    claims.setExpirationTime(expirationDate);
    claims.setIssuedAtToNow();
    claims.setNotBeforeMinutesInThePast((float) Beans.newDuration(oidc.getCore().getSkew()).toMinutes());
    claims.setSubject(principal.getId());
    val mfa = getConfigurationContext().getCasProperties().getAuthn().getMfa();
    val attributes = authentication.getAttributes();
    if (attributes.containsKey(mfa.getCore().getAuthenticationContextAttribute())) {
        val acrValues = CollectionUtils.toCollection(attributes.get(mfa.getCore().getAuthenticationContextAttribute()));
        val authnContexts = oidc.getCore().getAuthenticationContextReferenceMappings();
        val mappings = CollectionUtils.convertDirectedListToMap(authnContexts);
        val acrMapped = acrValues.stream().map(acrValue -> mappings.entrySet().stream().filter(entry -> entry.getValue().equalsIgnoreCase(acrValue.toString())).map(Map.Entry::getKey).findFirst().orElseGet(acrValue::toString)).collect(Collectors.joining(" "));
        LOGGER.debug("ID token acr claim calculated as [{}]", acrMapped);
        claims.setStringClaim(OidcConstants.ACR, acrMapped);
    }
    if (attributes.containsKey(AuthenticationHandler.SUCCESSFUL_AUTHENTICATION_HANDLERS)) {
        val val = CollectionUtils.toCollection(attributes.get(AuthenticationHandler.SUCCESSFUL_AUTHENTICATION_HANDLERS));
        claims.setStringListClaim(OidcConstants.AMR, val.toArray(ArrayUtils.EMPTY_STRING_ARRAY));
    }
    claims.setStringClaim(OAuth20Constants.CLIENT_ID, service.getClientId());
    claims.setClaim(OidcConstants.CLAIM_AUTH_TIME, tgt.getAuthentication().getAuthenticationDate().toEpochSecond());
    if (attributes.containsKey(OAuth20Constants.STATE)) {
        setClaim(claims, OAuth20Constants.STATE, attributes.get(OAuth20Constants.STATE).get(0));
    }
    if (attributes.containsKey(OAuth20Constants.NONCE)) {
        setClaim(claims, OAuth20Constants.NONCE, attributes.get(OAuth20Constants.NONCE).get(0));
    }
    generateAccessTokenHash(accessToken, service, claims);
    val includeClaims = responseType != OAuth20ResponseTypes.CODE && grantType != OAuth20GrantTypes.AUTHORIZATION_CODE;
    if (includeClaims || oidc.getCore().isIncludeIdTokenClaims()) {
        FunctionUtils.doIf(oidc.getCore().isIncludeIdTokenClaims(), ignore -> LOGGER.warn("Individual claims requested by OpenID scopes are forced to be included in the ID token. " + "This is a violation of the OpenID Connect specification and a workaround via dedicated CAS configuration. " + "Claims should be requested from the userinfo/profile endpoints in exchange for an access token.")).accept(claims);
        collectIdTokenClaims(principal, claims);
    } else {
        LOGGER.debug("Per OpenID Connect specification, individual claims requested by OpenID scopes " + "such as profile, email, address, etc. are only put " + "into the OpenID Connect ID token when the response type is set to id_token.");
    }
    return claims;
}
Also used : lombok.val(lombok.val) OAuth20AccessTokenAtHashGenerator(org.apereo.cas.support.oauth.web.response.accesstoken.OAuth20AccessTokenAtHashGenerator) DigestUtils(org.apereo.cas.util.DigestUtils) ArrayUtils(org.apache.commons.lang3.ArrayUtils) BooleanUtils(org.apache.commons.lang3.BooleanUtils) Beans(org.apereo.cas.configuration.support.Beans) StringUtils(org.apache.commons.lang3.StringUtils) ArrayList(java.util.ArrayList) FunctionUtils(org.apereo.cas.util.function.FunctionUtils) ObjectProvider(org.springframework.beans.factory.ObjectProvider) AuthenticationHandler(org.apereo.cas.authentication.AuthenticationHandler) Map(java.util.Map) CollectionUtils(org.apereo.cas.util.CollectionUtils) TicketGrantingTicket(org.apereo.cas.ticket.TicketGrantingTicket) OAuth20JwtAccessTokenEncoder(org.apereo.cas.support.oauth.web.response.accesstoken.response.OAuth20JwtAccessTokenEncoder) OAuth20Constants(org.apereo.cas.support.oauth.OAuth20Constants) OAuth20ResponseTypes(org.apereo.cas.support.oauth.OAuth20ResponseTypes) BaseIdTokenGeneratorService(org.apereo.cas.ticket.BaseIdTokenGeneratorService) OAuth20GrantTypes(org.apereo.cas.support.oauth.OAuth20GrantTypes) OidcConstants(org.apereo.cas.oidc.OidcConstants) lombok.val(lombok.val) OAuthRegisteredService(org.apereo.cas.support.oauth.services.OAuthRegisteredService) Collectors(java.util.stream.Collectors) OAuth20AccessToken(org.apereo.cas.ticket.accesstoken.OAuth20AccessToken) OidcConfigurationContext(org.apereo.cas.oidc.OidcConfigurationContext) Objects(java.util.Objects) Slf4j(lombok.extern.slf4j.Slf4j) NumericDate(org.jose4j.jwt.NumericDate) OidcRegisteredService(org.apereo.cas.services.OidcRegisteredService) Stream(java.util.stream.Stream) JwtClaims(org.jose4j.jwt.JwtClaims) Optional(java.util.Optional) Principal(org.apereo.cas.authentication.principal.Principal) UserProfile(org.pac4j.core.profile.UserProfile) Assert(org.springframework.util.Assert) JwtClaims(org.jose4j.jwt.JwtClaims)

Aggregations

OAuth20ResponseTypes (org.apereo.cas.support.oauth.OAuth20ResponseTypes)5 OAuthRegisteredService (org.apereo.cas.support.oauth.services.OAuthRegisteredService)3 UserProfile (org.pac4j.core.profile.UserProfile)3 Map (java.util.Map)2 Optional (java.util.Optional)2 Stream (java.util.stream.Stream)2 Slf4j (lombok.extern.slf4j.Slf4j)2 Authentication (org.apereo.cas.authentication.Authentication)2 AuthenticationHandler (org.apereo.cas.authentication.AuthenticationHandler)2 Principal (org.apereo.cas.authentication.principal.Principal)2 Service (org.apereo.cas.authentication.principal.Service)2 OidcConstants (org.apereo.cas.oidc.OidcConstants)2 OidcRegisteredService (org.apereo.cas.services.OidcRegisteredService)2 OAuth20Constants (org.apereo.cas.support.oauth.OAuth20Constants)2 TicketGrantingTicket (org.apereo.cas.ticket.TicketGrantingTicket)2 AccessToken (org.apereo.cas.ticket.accesstoken.AccessToken)2 CollectionUtils (org.apereo.cas.util.CollectionUtils)2 DigestUtils (org.apereo.cas.util.DigestUtils)2 J2EContext (org.pac4j.core.context.J2EContext)2 ProfileManager (org.pac4j.core.profile.ProfileManager)2