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);
}
}
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;
}
}
}
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));
}
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));
}
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);
}
}
Aggregations