Search in sources :

Example 1 with ID_TOKEN_HINT

use of org.wso2.carbon.identity.openidconnect.model.Constants.ID_TOKEN_HINT in project identity-inbound-auth-oauth by wso2-extensions.

the class CibaAuthRequestValidator method validateUserHint.

/**
 * Validation for login_hint_token,id_token_hint.
 * Anyone and exactly one is mandatory.
 *
 * @param authRequest CIBA Authentication request.
 * @throws CibaAuthFailureException CIBA Authentication Failed Exception.
 */
public void validateUserHint(String authRequest) throws CibaAuthFailureException {
    try {
        SignedJWT signedJWT = SignedJWT.parse(authRequest);
        JWTClaimsSet claimsSet = signedJWT.getJWTClaimsSet();
        // Validation to  check if any hints present.
        if ((claimsSet.getClaim(CibaConstants.LOGIN_HINT_TOKEN) == null) && (claimsSet.getClaim(Constants.LOGIN_HINT) == null) && (claimsSet.getClaim(Constants.ID_TOKEN_HINT) == null)) {
            // All hints are null.
            if (log.isDebugEnabled()) {
                log.debug("Invalid request. Missing mandatory parameter, 'hints' from the request : " + authRequest);
            }
            throw new CibaAuthFailureException(ErrorCodes.UNAUTHORIZED_USER, "Missing user hints.");
        }
        // Validation when login_hint_token exists.
        if (!(claimsSet.getClaim(CibaConstants.LOGIN_HINT_TOKEN) == null)) {
            if (log.isDebugEnabled()) {
                log.debug("No Login_hint_token support for current version of IS.Invalid CIBA Authentication " + "request : " + authRequest);
            }
            throw new CibaAuthFailureException(OAuth2ErrorCodes.INVALID_REQUEST, "Invalid parameter (login_hint_token)");
        }
        // Validation when login_hint exists.
        if (!(claimsSet.getClaim(Constants.LOGIN_HINT) == null)) {
            // id_token_hint is also present
            if (!(claimsSet.getClaim(Constants.ID_TOKEN_HINT) == null)) {
                throw new CibaAuthFailureException(OAuth2ErrorCodes.INVALID_REQUEST, "Both ID token hint and " + "login hint present in the request");
            }
            // Claim exists for login_hint.
            if (StringUtils.isBlank(claimsSet.getClaim(Constants.LOGIN_HINT).toString())) {
                // Login_hint is blank.
                throw new CibaAuthFailureException(ErrorCodes.UNAUTHORIZED_USER, "login_hint is blank.");
            }
            if (log.isDebugEnabled()) {
                log.debug("CIBA Authentication Request made by Client with clientID," + claimsSet.getIssuer() + " is having a proper user hint  : " + claimsSet.getClaim(Constants.LOGIN_HINT) + ".");
            }
            return;
        }
        if (!(claimsSet.getClaim(Constants.ID_TOKEN_HINT) == null)) {
            // Value exists for id_token_hint
            if (StringUtils.isBlank(claimsSet.getClaim(Constants.ID_TOKEN_HINT).toString())) {
                // Existing values for id_token_hint are blank.
                if (log.isDebugEnabled()) {
                    log.debug("Unknown user identity from the request " + authRequest);
                }
                throw new CibaAuthFailureException(ErrorCodes.UNAUTHORIZED_USER, "Invalid (sub) value for the provided id_token_hint");
            }
            if (!OAuth2Util.validateIdToken(String.valueOf(claimsSet.getClaim(Constants.ID_TOKEN_HINT)))) {
                // Provided id_token_hint is not valid.
                if (log.isDebugEnabled()) {
                    log.debug("Invalid id_token_hint from the request " + authRequest);
                }
                throw new CibaAuthFailureException(ErrorCodes.UNAUTHORIZED_USER, "invalid id_token_hint.");
            }
            if (log.isDebugEnabled()) {
                log.debug("CIBA Authentication Request made by Client with clientID," + claimsSet.getAudience() + " is having a proper id_token_hint: " + claimsSet.getClaim(Constants.ID_TOKEN_HINT) + ".");
            }
        }
    } catch (ParseException e) {
        throw new CibaAuthFailureException(OAuth2ErrorCodes.SERVER_ERROR, "Error occurred in validating user hints.", e);
    }
}
Also used : CibaAuthFailureException(org.wso2.carbon.identity.oauth.endpoint.exception.CibaAuthFailureException) JWTClaimsSet(com.nimbusds.jwt.JWTClaimsSet) SignedJWT(com.nimbusds.jwt.SignedJWT) ParseException(java.text.ParseException)

Example 2 with ID_TOKEN_HINT

use of org.wso2.carbon.identity.openidconnect.model.Constants.ID_TOKEN_HINT 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 3 with ID_TOKEN_HINT

use of org.wso2.carbon.identity.openidconnect.model.Constants.ID_TOKEN_HINT in project identity-inbound-auth-oauth by wso2-extensions.

the class OIDCLogoutServletTest method testDoGet.

@Test(dataProvider = "provideDataForTestDoGet")
public void testDoGet(Object cookie, boolean sessionExists, String redirectUrl, String expected, String consent, String sessionDataKey, boolean skipUserConsent, String idTokenHint, boolean isJWTSignedWithSPKey, String postLogoutUrl, Object flowStatus) throws Exception {
    TestUtil.startTenantFlow(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
    mockStatic(OIDCSessionManagementUtil.class);
    when(OIDCSessionManagementUtil.handleAlreadyLoggedOutSessionsGracefully()).thenReturn(false);
    when(OIDCSessionManagementUtil.getOPBrowserStateCookie(request)).thenReturn((Cookie) cookie);
    when(OIDCSessionManagementUtil.getErrorPageURL(anyString(), anyString())).thenReturn(redirectUrl);
    mockStatic(OIDCSessionManager.class);
    when(OIDCSessionManagementUtil.getSessionManager()).thenReturn(oidcSessionManager);
    when(oidcSessionManager.sessionExists(OPBROWSER_STATE, MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)).thenReturn(sessionExists);
    when(request.getParameter("consent")).thenReturn(consent);
    when(request.getHeaderNames()).thenReturn(Collections.enumeration(Arrays.asList(new String[] { "cookie" })));
    when(request.getHeader("COOKIE")).thenReturn("opbs");
    when(request.getAttribute(FrameworkConstants.RequestParams.FLOW_STATUS)).thenReturn(flowStatus);
    doThrow(new ServletException()).when(commonAuthenticationHandler).doPost(request, response);
    when(request.getSession()).thenReturn(httpSession);
    when(httpSession.getMaxInactiveInterval()).thenReturn(2);
    mockStatic(IdentityConfigParser.class);
    when(IdentityConfigParser.getInstance()).thenReturn(identityConfigParser);
    when(request.getParameter("sessionDataKey")).thenReturn(sessionDataKey);
    mockStatic(OAuthServerConfiguration.class);
    when(OAuthServerConfiguration.getInstance()).thenReturn(oAuthServerConfiguration);
    when(oAuthServerConfiguration.getOpenIDConnectSkipLogoutConsentConfig()).thenReturn(skipUserConsent);
    when(request.getParameter("id_token_hint")).thenReturn(idTokenHint);
    when(OIDCSessionManagementUtil.removeOPBrowserStateCookie(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn((Cookie) cookie);
    when(OIDCSessionManagementUtil.getOIDCLogoutConsentURL()).thenReturn(redirectUrl);
    when(OIDCSessionManagementUtil.getOIDCLogoutURL()).thenReturn(redirectUrl);
    mockStatic(IdentityTenantUtil.class);
    when(IdentityTenantUtil.getTenantId(anyString())).thenReturn(TENANT_ID);
    when(IdentityTenantUtil.getTenantDomain(TENANT_ID)).thenReturn(SUPER_TENANT_DOMAIN_NAME);
    mockStatic(OAuthServerConfiguration.class);
    when(OAuthServerConfiguration.getInstance()).thenReturn(oAuthServerConfiguration);
    when(oAuthServerConfiguration.isJWTSignedWithSPKey()).thenReturn(isJWTSignedWithSPKey);
    mockStatic(KeyStoreManager.class);
    when(KeyStoreManager.getInstance(TENANT_ID)).thenReturn(keyStoreManager);
    when(keyStoreManager.getDefaultPublicKey()).thenReturn(TestUtil.getPublicKey(TestUtil.loadKeyStoreFromFileSystem(TestUtil.getFilePath("wso2carbon.jks"), "wso2carbon", "JKS"), "wso2carbon"));
    mockStatic(OIDCSessionManagementComponentServiceHolder.class);
    when(OIDCSessionManagementComponentServiceHolder.getApplicationMgtService()).thenReturn(mockedApplicationManagementService);
    when(mockedApplicationManagementService.getServiceProviderNameByClientId(anyString(), anyString(), anyString())).thenReturn("SP1");
    mockStatic(OAuthServerConfiguration.class);
    when(OAuthServerConfiguration.getInstance()).thenReturn(oAuthServerConfiguration);
    when(oAuthServerConfiguration.getPersistenceProcessor()).thenReturn(tokenPersistenceProcessor);
    when(tokenPersistenceProcessor.getProcessedClientId(anyString())).thenAnswer(invocation -> invocation.getArguments()[0]);
    when(request.getParameter("post_logout_redirect_uri")).thenReturn(postLogoutUrl);
    mockStatic(IdentityDatabaseUtil.class);
    when(IdentityDatabaseUtil.getDBConnection()).thenAnswer(invocationOnMock -> dataSource.getConnection());
    mockStatic(OAuth2Util.class);
    when(OAuth2Util.getAppInformationByClientId(anyString())).thenCallRealMethod();
    when(OAuth2Util.getTenantDomainOfOauthApp(anyString())).thenReturn("wso2.com");
    when(OAuth2Util.getTenantDomainOfOauthApp(any(oAuthAppDO.getClass()))).thenReturn("wso2.com");
    when(keyStoreManager.getKeyStore(anyString())).thenReturn(TestUtil.loadKeyStoreFromFileSystem(TestUtil.getFilePath("wso2carbon.jks"), "wso2carbon", "JKS"));
    mockServiceURLBuilder(OIDCSessionConstants.OIDCEndpoints.OIDC_LOGOUT_ENDPOINT);
    ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
    mockStatic(OIDCSessionDataCache.class);
    when(OIDCSessionDataCache.getInstance()).thenReturn(oidcSessionDataCache);
    OIDCSessionDataCacheKey opbsKey = mock(OIDCSessionDataCacheKey.class);
    OIDCSessionDataCacheKey sessionIdKey = mock(OIDCSessionDataCacheKey.class);
    when(opbsKey.getSessionDataId()).thenReturn(OPBROWSER_STATE);
    when(sessionIdKey.getSessionDataId()).thenReturn(sessionDataKey);
    when(OIDCSessionDataCache.getInstance().getValueFromCache(opbsKey)).thenReturn(opbsCacheEntry);
    when(OIDCSessionDataCache.getInstance().getValueFromCache(sessionIdKey)).thenReturn(sessionIdCacheEntry);
    ConcurrentMap<String, String> paramMap = new ConcurrentHashMap<>();
    paramMap.put(OIDCSessionConstants.OIDC_CACHE_CLIENT_ID_PARAM, CLIENT_ID_VALUE);
    paramMap.put(OIDCSessionConstants.OIDC_CACHE_TENANT_DOMAIN_PARAM, SUPER_TENANT_DOMAIN_NAME);
    when(opbsCacheEntry.getParamMap()).thenReturn(paramMap);
    when(sessionIdCacheEntry.getParamMap()).thenReturn(paramMap);
    logoutServlet.doGet(request, response);
    verify(response).sendRedirect(captor.capture());
    assertTrue(captor.getValue().contains(expected));
}
Also used : ServletException(javax.servlet.ServletException) HttpServletRequest(javax.servlet.http.HttpServletRequest) OIDCSessionDataCacheKey(org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheKey) HttpServletResponse(javax.servlet.http.HttpServletResponse) Matchers.anyString(org.mockito.Matchers.anyString) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Test(org.testng.annotations.Test) AfterTest(org.testng.annotations.AfterTest) BeforeTest(org.testng.annotations.BeforeTest) PrepareForTest(org.powermock.core.classloader.annotations.PrepareForTest)

Example 4 with ID_TOKEN_HINT

use of org.wso2.carbon.identity.openidconnect.model.Constants.ID_TOKEN_HINT 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)

Example 5 with ID_TOKEN_HINT

use of org.wso2.carbon.identity.openidconnect.model.Constants.ID_TOKEN_HINT in project identity-inbound-auth-oauth by wso2-extensions.

the class CibaAuthRequestValidator method getUserfromIDToken.

/**
 * Obtain sub from given id token.
 *
 * @param idTokenHint it carries user identity
 * @return String- the user identity
 * @throws CibaAuthFailureException CIBA Authentication Failed Exception.
 */
private String getUserfromIDToken(String idTokenHint) throws CibaAuthFailureException {
    // Obtain (sub) from id_token_hint
    try {
        if (log.isDebugEnabled()) {
            log.debug("Extracting 'sub' from this id_token_hint " + idTokenHint);
        }
        SignedJWT signedJWT = SignedJWT.parse(idTokenHint);
        JWTClaimsSet claimsSet = signedJWT.getJWTClaimsSet();
        return claimsSet.getSubject();
    } catch (ParseException e) {
        throw new CibaAuthFailureException(OAuth2ErrorCodes.SERVER_ERROR, "Error in obtaining (sub) from id_token.", e);
    }
}
Also used : CibaAuthFailureException(org.wso2.carbon.identity.oauth.endpoint.exception.CibaAuthFailureException) JWTClaimsSet(com.nimbusds.jwt.JWTClaimsSet) SignedJWT(com.nimbusds.jwt.SignedJWT) ParseException(java.text.ParseException)

Aggregations

ParseException (java.text.ParseException)3 JWTClaimsSet (com.nimbusds.jwt.JWTClaimsSet)2 SignedJWT (com.nimbusds.jwt.SignedJWT)2 CibaAuthFailureException (org.wso2.carbon.identity.oauth.endpoint.exception.CibaAuthFailureException)2 OIDCSessionDataCacheEntry (org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheEntry)2 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 ServletException (javax.servlet.ServletException)1 Cookie (javax.servlet.http.Cookie)1 HttpServletRequest (javax.servlet.http.HttpServletRequest)1 HttpServletResponse (javax.servlet.http.HttpServletResponse)1 Matchers.anyString (org.mockito.Matchers.anyString)1 PrepareForTest (org.powermock.core.classloader.annotations.PrepareForTest)1 AfterTest (org.testng.annotations.AfterTest)1 BeforeTest (org.testng.annotations.BeforeTest)1 Test (org.testng.annotations.Test)1 IdentityOAuth2ClientException (org.wso2.carbon.identity.oauth2.IdentityOAuth2ClientException)1 IdentityOAuth2Exception (org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception)1 OIDCSessionDataCacheKey (org.wso2.carbon.identity.oidc.session.cache.OIDCSessionDataCacheKey)1