Search in sources :

Example 1 with OIDCSessionDataCacheEntry

use of org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheEntry in project identity-inbound-auth-oauth by wso2-extensions.

the class OIDCLogoutServlet method generatePostLogoutRedirectUrl.

/**
 * If postLogoutRedirectUri is send in Logout request parameter then set it as redirect URL.
 *
 * @param redirectURL               Redirect URL.
 * @param opBrowserStateCookieValue OP browser state cookie value.
 * @param request                   HttpServletRequest.
 * @return If postLogoutRedirectUri is sent in Logout request parameter then return it as redirect URL.
 * @throws UnsupportedEncodingException
 */
private String generatePostLogoutRedirectUrl(String redirectURL, String opBrowserStateCookieValue, HttpServletRequest request) throws UnsupportedEncodingException {
    // Set postLogoutRedirectUri as redirectURL.
    boolean postLogoutRedirectUriRedirectIsEnabled = Boolean.parseBoolean(IdentityUtil.getProperty(OIDC_LOGOUT_CONSENT_DENIAL_REDIRECT_URL));
    if (postLogoutRedirectUriRedirectIsEnabled) {
        OIDCSessionDataCacheEntry cacheEntry = getSessionDataFromCache(opBrowserStateCookieValue);
        if (cacheEntry != null && cacheEntry.getPostLogoutRedirectUri() != null) {
            Map<String, String> params = new HashMap<>();
            params.put(OAuthConstants.OAUTH_ERROR, OAuth2ErrorCodes.ACCESS_DENIED);
            params.put(OAuthConstants.OAUTH_ERROR_DESCRIPTION, "End User denied the logout request");
            if (cacheEntry.getState() != null) {
                params.put(OAuthConstants.OAuth20Params.STATE, cacheEntry.getState());
            }
            redirectURL = FrameworkUtils.buildURLWithQueryParams(cacheEntry.getPostLogoutRedirectUri(), params);
        }
    }
    return buildRedirectURLAfterLogout(redirectURL, request);
}
Also used : ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) OIDCSessionDataCacheEntry(org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheEntry)

Example 2 with OIDCSessionDataCacheEntry

use of org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheEntry in project identity-inbound-auth-oauth by wso2-extensions.

the class OIDCLogoutServlet method handleLogoutResponseFromFramework.

private void handleLogoutResponseFromFramework(HttpServletRequest request, HttpServletResponse response) throws IOException {
    String sessionDataKey = request.getParameter(FrameworkConstants.SESSION_DATA_KEY);
    OIDCSessionDataCacheEntry cacheEntry = getSessionDataFromCache(sessionDataKey);
    String obpsCookieValue = getOPBrowserState(request);
    String tenantDomain = OAuth2Util.resolveTenantDomain(request);
    if (cacheEntry != null) {
        if (log.isDebugEnabled()) {
            String clientId = cacheEntry.getParamMap().get(OIDCSessionConstants.OIDC_CACHE_CLIENT_ID_PARAM);
            String sidClaim;
            log.debug("Logout request received from client: " + clientId);
            if (StringUtils.isNotBlank(obpsCookieValue)) {
                OIDCSessionState sessionState = OIDCSessionManagementUtil.getSessionManager().getOIDCSessionState(obpsCookieValue, tenantDomain);
                if (sessionState != null) {
                    sidClaim = sessionState.getSidClaim();
                    log.debug("Logout request received for sessionId: " + sidClaim);
                }
            }
        }
        // BackChannel logout request.
        doBackChannelLogout(obpsCookieValue, tenantDomain);
        String redirectURL = cacheEntry.getPostLogoutRedirectUri();
        if (redirectURL == null) {
            redirectURL = OIDCSessionManagementUtil.getOIDCLogoutURL();
        }
        try {
            triggerLogoutHandlersForPostLogout(request, response);
        } catch (OIDCSessionManagementException e) {
            log.error("Error executing logout handlers on post logout.");
            if (log.isDebugEnabled()) {
                log.debug("Error executing logout handlers on post logout.", e);
            }
            response.sendRedirect(getRedirectURL(getErrorPageURL(OAuth2ErrorCodes.SERVER_ERROR, "User logout failed."), request));
        }
        redirectURL = appendStateQueryParam(redirectURL, cacheEntry.getState());
        removeSessionDataFromCache(sessionDataKey);
        OIDCSessionManagementUtil.getSessionManager().removeOIDCSessionState(obpsCookieValue, tenantDomain);
        // Clear binding elements from the response.
        clearTokenBindingElements(cacheEntry.getParamMap().get(OIDCSessionConstants.OIDC_CACHE_CLIENT_ID_PARAM), request, response);
        response.sendRedirect(buildRedirectURLAfterLogout(redirectURL, request));
    } else {
        response.sendRedirect(getRedirectURL(getErrorPageURL(OAuth2ErrorCodes.SERVER_ERROR, "User logout failed"), request));
    }
}
Also used : OIDCSessionState(org.wso2.carbon.identity.oidc.session.OIDCSessionState) OIDCSessionDataCacheEntry(org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheEntry) OIDCSessionManagementException(org.wso2.carbon.identity.oidc.session.OIDCSessionManagementException)

Example 3 with OIDCSessionDataCacheEntry

use of org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheEntry in project identity-inbound-auth-oauth by wso2-extensions.

the class OIDCLogoutServlet method doGet.

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    /**
     * Recommended Parameter : id_token_hint
     * As per the specification https://openid.net/specs/openid-connect-session-1_0.html#RFC6454, it's recommended
     * to expect id_token_hint parameter to determine which RP initiated the logout request.
     * Otherwise, it could lead to DoS attacks. Thus, at least explicit user confirmation is needed to act upon
     * such logout requests.
     *
     * Optional Parameter : post_logout_redirect_uri
     * This denotes the RP URL to be redirected after logout has been performed. This value must be previously
     * registered at IdP via post_logout_redirect_uris registration parameter or by some other configuration. And
     * the received URL should be validated to be one of registered.
     */
    /**
     * todo: At the moment we do not persist id_token issued for clients, thus we could not retrieve the RP that
     * todo: a specific id_token has been issued.
     * todo: Since we use a browser cookie to track the session, for the moment, we
     * todo: will validate if the logout request is being initiated by an active session via the cookie
     * todo: This need to be fixed such that we do not rely on the cookie and the request is validated against
     * todo: the id_token_hint received
     *
     * todo: Should provide a way to register post_logout_redirect_uris at IdP and should validate the received
     * todo: parameter against the set of registered values. This depends on retrieving client for the received
     * todo: id_token_hint value
     */
    String redirectURL;
    String opBrowserState = getOPBrowserState(request);
    if (StringUtils.isBlank(opBrowserState)) {
        String msg = OIDCSessionConstants.OPBS_COOKIE_ID + " cookie not received. Missing session state.";
        if (log.isDebugEnabled()) {
            log.debug(msg);
        }
        if (OIDCSessionManagementUtil.handleAlreadyLoggedOutSessionsGracefully()) {
            handleMissingSessionStateGracefully(request, response);
            return;
        } else {
            if (log.isDebugEnabled()) {
                msg = "HandleAlreadyLoggedOutSessionsGracefully configuration disabled. Missing session state is " + "handled by redirecting to error page instead of default logout page.";
                log.debug(msg);
            }
            redirectURL = getErrorPageURL(OAuth2ErrorCodes.ACCESS_DENIED, msg);
            response.sendRedirect(getRedirectURL(redirectURL, request));
            return;
        }
    }
    if (!OIDCSessionManagementUtil.getSessionManager().sessionExists(opBrowserState, OAuth2Util.resolveTenantDomain(request))) {
        String msg = "No valid session found for the received session state.";
        if (log.isDebugEnabled()) {
            log.debug(msg);
        }
        OIDCSessionManagementUtil.removeOPBrowserStateCookie(request, response);
        if (OIDCSessionManagementUtil.handleAlreadyLoggedOutSessionsGracefully()) {
            handleMissingSessionStateGracefully(request, response);
        } else {
            if (log.isDebugEnabled()) {
                msg = "HandleAlreadyLoggedOutSessionsGracefully configuration enabled. No valid session found is " + "handled by redirecting to error page instead of default logout page.";
                log.debug(msg);
            }
            redirectURL = getErrorPageURL(OAuth2ErrorCodes.ACCESS_DENIED, msg);
            response.sendRedirect(getRedirectURL(redirectURL, request));
        }
        return;
    }
    String consent = request.getParameter(OIDCSessionConstants.OIDC_LOGOUT_CONSENT_PARAM);
    if (StringUtils.isNotBlank(consent)) {
        // User consent received for logout
        if (consent.equals(OAuthConstants.Consent.APPROVE)) {
            // User approved logout. Logout from authentication framework
            sendToFrameworkForLogout(request, response);
            return;
        } else {
            // User denied logout.
            redirectURL = getErrorPageURL(OAuth2ErrorCodes.ACCESS_DENIED, "End User denied the logout request");
            // If postlogoutUri is available then set it as redirectUrl
            redirectURL = generatePostLogoutRedirectUrl(redirectURL, opBrowserState, request);
            response.sendRedirect(redirectURL);
            return;
        }
    } else {
        // OIDC Logout response
        String sessionDataKey = request.getParameter(OIDCSessionConstants.OIDC_SESSION_DATA_KEY_PARAM);
        if (sessionDataKey != null) {
            handleLogoutResponseFromFramework(request, response);
            return;
        }
        String idTokenHint = request.getParameter(OIDCSessionConstants.OIDC_ID_TOKEN_HINT_PARAM);
        boolean skipConsent;
        // Get user consent to logout
        try {
            skipConsent = getOpenIDConnectSkipUserConsent(request);
        } catch (ParseException e) {
            if (log.isDebugEnabled()) {
                log.debug("Error while getting clientId from the IdTokenHint.", e);
            }
            redirectURL = getErrorPageURL(OAuth2ErrorCodes.ACCESS_DENIED, "ID token signature validation failed.");
            response.sendRedirect(getRedirectURL(redirectURL, request));
            return;
        } catch (IdentityOAuth2ClientException e) {
            if (log.isDebugEnabled()) {
                log.debug("Error while getting service provider from the clientId.", e);
            }
            redirectURL = getErrorPageURL(OAuth2ErrorCodes.ACCESS_DENIED, "ID token signature validation failed.");
            response.sendRedirect(getRedirectURL(redirectURL, request));
            return;
        } catch (IdentityOAuth2Exception e) {
            log.error("Error occurred while getting oauth application information.", e);
            return;
        }
        if (skipConsent) {
            if (StringUtils.isNotBlank(idTokenHint)) {
                redirectURL = processLogoutRequest(request, response);
                if (StringUtils.isNotBlank(redirectURL)) {
                    response.sendRedirect(getRedirectURL(redirectURL, request));
                    return;
                }
            } else {
                // Add OIDC Cache entry without properties since OIDC Logout should work without id_token_hint
                OIDCSessionDataCacheEntry cacheEntry = new OIDCSessionDataCacheEntry();
                /*
                     Logout request without id_token_hint will redirected to an IDP's page once logged out, rather a
                     RP's callback endpoint. The state parameter is set here in the cache, so that it will be
                     available in the redirected IDP's page to support any custom requirement.
                     */
                setStateParameterInCache(request, cacheEntry);
                addSessionDataToCache(opBrowserState, cacheEntry);
            }
            sendToFrameworkForLogout(request, response);
            return;
        } else {
            sendToConsentUri(request, response);
            return;
        }
    }
}
Also used : IdentityOAuth2Exception(org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception) OIDCSessionDataCacheEntry(org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheEntry) ParseException(java.text.ParseException) IdentityOAuth2ClientException(org.wso2.carbon.identity.oauth2.IdentityOAuth2ClientException)

Example 4 with OIDCSessionDataCacheEntry

use of org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheEntry in project identity-inbound-auth-oauth by wso2-extensions.

the class OIDCLogoutServlet method sendToFrameworkForLogout.

private void sendToFrameworkForLogout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        triggerLogoutHandlersForPreLogout(request, response);
    } catch (OIDCSessionManagementException e) {
        log.error("Error executing logout handlers on pre logout.");
        if (log.isDebugEnabled()) {
            log.debug("Error executing logout handlers on pre logout.", e);
        }
        response.sendRedirect(getRedirectURL(getErrorPageURL(OAuth2ErrorCodes.SERVER_ERROR, "User logout failed."), request));
    }
    // Generate a SessionDataKey. Authentication framework expects this parameter
    String sessionDataKey = UUID.randomUUID().toString();
    String opBrowserStateCookieValue = OIDCSessionManagementUtil.getOPBrowserStateCookie(request).getValue();
    // Add all parameters to authentication context before sending to authentication framework
    AuthenticationRequest authenticationRequest = new AuthenticationRequest();
    Map<String, String[]> map = new HashMap<>();
    map.put(OIDCSessionConstants.OIDC_SESSION_DATA_KEY_PARAM, new String[] { sessionDataKey });
    authenticationRequest.setRequestQueryParams(map);
    authenticationRequest.addRequestQueryParam(FrameworkConstants.RequestParams.LOGOUT, new String[] { "true" });
    try {
        authenticationRequest.setCommonAuthCallerPath(ServiceURLBuilder.create().addPath(OIDC_LOGOUT_ENDPOINT).build().getRelativeInternalURL());
    } catch (URLBuilderException e) {
        log.error("Error building commonauth caller path to send logout request to framework.", e);
        response.sendRedirect(getRedirectURL(getErrorPageURL(OAuth2ErrorCodes.SERVER_ERROR, "User logout failed."), request));
    }
    authenticationRequest.setPost(true);
    OIDCSessionDataCacheEntry cacheEntry = getSessionDataFromCache(opBrowserStateCookieValue);
    if (cacheEntry != null) {
        authenticationRequest.setRelyingParty(cacheEntry.getParamMap().get(OIDCSessionConstants.OIDC_CACHE_CLIENT_ID_PARAM));
        authenticationRequest.setTenantDomain(cacheEntry.getParamMap().get(OIDCSessionConstants.OIDC_CACHE_TENANT_DOMAIN_PARAM));
        addOPBSCookieValueToCacheEntry(opBrowserStateCookieValue, cacheEntry);
        addSessionDataToCache(sessionDataKey, cacheEntry);
    }
    // Add headers to AuthenticationRequestContext
    for (Enumeration e = request.getHeaderNames(); e.hasMoreElements(); ) {
        String headerName = e.nextElement().toString();
        authenticationRequest.addHeader(headerName, request.getHeader(headerName));
    }
    AuthenticationRequestCacheEntry authenticationRequestCacheEntry = new AuthenticationRequestCacheEntry(authenticationRequest);
    addAuthenticationRequestToRequest(request, authenticationRequestCacheEntry);
    OIDCSessionManagementUtil.removeOPBrowserStateCookie(request, response);
    sendRequestToFramework(request, response, sessionDataKey, FrameworkConstants.RequestType.CLAIM_TYPE_OIDC);
}
Also used : URLBuilderException(org.wso2.carbon.identity.core.URLBuilderException) Enumeration(java.util.Enumeration) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) OIDCSessionDataCacheEntry(org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheEntry) AuthenticationRequest(org.wso2.carbon.identity.application.authentication.framework.model.AuthenticationRequest) OIDCSessionManagementException(org.wso2.carbon.identity.oidc.session.OIDCSessionManagementException) AuthenticationRequestCacheEntry(org.wso2.carbon.identity.application.authentication.framework.cache.AuthenticationRequestCacheEntry)

Example 5 with OIDCSessionDataCacheEntry

use of org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheEntry in project identity-inbound-auth-oauth by wso2-extensions.

the class OIDCLogoutServlet method sendToConsentUri.

/**
 * Send request to consent URI.
 *
 * @param request  Http servlet request
 * @param response Http servlet response
 * @throws IOException
 */
private void sendToConsentUri(HttpServletRequest request, HttpServletResponse response) throws IOException {
    String idTokenHint = request.getParameter(OIDCSessionConstants.OIDC_ID_TOKEN_HINT_PARAM);
    String redirectURL = OIDCSessionManagementUtil.getOIDCLogoutConsentURL();
    if (idTokenHint != null) {
        redirectURL = processLogoutRequest(request, response);
        if (StringUtils.isNotBlank(redirectURL)) {
            response.sendRedirect(getRedirectURL(redirectURL, request));
            return;
        } else {
            redirectURL = OIDCSessionManagementUtil.getOIDCLogoutConsentURL();
        }
    } else {
        // Add OIDC Cache entry without properties since OIDC Logout should work without id_token_hint
        OIDCSessionDataCacheEntry cacheEntry = new OIDCSessionDataCacheEntry();
        // Logout request without id_token_hint will redirected to an IDP's page once logged out, rather a RP's
        // callback endpoint. The state parameter is set here in the cache, so that it will be available in the
        // redirected IDP's page to support any custom requirement.
        setStateParameterInCache(request, cacheEntry);
        Cookie opBrowserStateCookie = OIDCSessionManagementUtil.getOPBrowserStateCookie(request);
        addSessionDataToCache(opBrowserStateCookie.getValue(), cacheEntry);
    }
    response.sendRedirect(getRedirectURL(redirectURL, request));
}
Also used : Cookie(javax.servlet.http.Cookie) OIDCSessionDataCacheEntry(org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheEntry)

Aggregations

OIDCSessionDataCacheEntry (org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheEntry)6 HashMap (java.util.HashMap)3 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)3 ParseException (java.text.ParseException)2 Cookie (javax.servlet.http.Cookie)2 IdentityOAuth2Exception (org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception)2 OIDCSessionManagementException (org.wso2.carbon.identity.oidc.session.OIDCSessionManagementException)2 JWT (com.nimbusds.jwt.JWT)1 SignedJWT (com.nimbusds.jwt.SignedJWT)1 Enumeration (java.util.Enumeration)1 AuthenticationRequestCacheEntry (org.wso2.carbon.identity.application.authentication.framework.cache.AuthenticationRequestCacheEntry)1 AuthenticationRequest (org.wso2.carbon.identity.application.authentication.framework.model.AuthenticationRequest)1 URLBuilderException (org.wso2.carbon.identity.core.URLBuilderException)1 InvalidOAuthClientException (org.wso2.carbon.identity.oauth.common.exception.InvalidOAuthClientException)1 OAuthAppDO (org.wso2.carbon.identity.oauth.dao.OAuthAppDO)1 IdentityOAuth2ClientException (org.wso2.carbon.identity.oauth2.IdentityOAuth2ClientException)1 OIDCSessionState (org.wso2.carbon.identity.oidc.session.OIDCSessionState)1 OIDCSessionDataCacheKey (org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheKey)1