Java tutorial
/* * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.carbon.identity.oauth.endpoint.authz; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; import org.apache.axis2.transport.http.HTTPConstants; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest; import org.apache.oltu.oauth2.as.validator.CodeValidator; import org.apache.oltu.oauth2.as.validator.TokenValidator; import org.apache.oltu.oauth2.common.OAuth; import org.apache.oltu.oauth2.common.exception.OAuthProblemException; import org.apache.oltu.oauth2.common.message.OAuthResponse; import org.apache.oltu.oauth2.common.message.types.ResponseType; import org.apache.oltu.oauth2.common.validators.OAuthValidator; import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.powermock.core.classloader.annotations.PrepareForTest; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.wso2.carbon.base.CarbonBaseConstants; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.identity.application.authentication.framework.AuthenticatorFlowStatus; import org.wso2.carbon.identity.application.authentication.framework.cache.AuthenticationResultCacheEntry; import org.wso2.carbon.identity.application.authentication.framework.context.SessionContext; import org.wso2.carbon.identity.application.authentication.framework.handler.request.RequestCoordinator; import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.consent.ConsentClaimsData; import org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.consent.SSOConsentService; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticationResult; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants; import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; import org.wso2.carbon.identity.application.common.IdentityApplicationManagementException; import org.wso2.carbon.identity.application.common.model.ClaimMapping; import org.wso2.carbon.identity.application.common.model.ServiceProvider; import org.wso2.carbon.identity.application.common.model.ServiceProviderProperty; import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.core.util.IdentityUtil; import org.wso2.carbon.identity.oauth.cache.SessionDataCache; import org.wso2.carbon.identity.oauth.cache.SessionDataCacheEntry; import org.wso2.carbon.identity.oauth.cache.SessionDataCacheKey; import org.wso2.carbon.identity.oauth.common.OAuth2ErrorCodes; import org.wso2.carbon.identity.oauth.common.OAuthConstants; import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.endpoint.exception.InvalidRequestParentException; import org.wso2.carbon.identity.oauth.endpoint.expmapper.InvalidRequestExceptionMapper; import org.wso2.carbon.identity.oauth.endpoint.message.OAuthMessage; import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; import org.wso2.carbon.identity.oauth.endpoint.util.OpenIDConnectUserRPStore; import org.wso2.carbon.identity.oauth.endpoint.util.TestOAuthEndpointBase; import org.wso2.carbon.identity.oauth.tokenprocessor.TokenPersistenceProcessor; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.OAuth2Service; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeRespDTO; import org.wso2.carbon.identity.oauth2.dto.OAuth2ClientValidationResponseDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.CarbonOAuthAuthzRequest; import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.oidc.session.OIDCSessionManager; import org.wso2.carbon.identity.oidc.session.OIDCSessionState; import org.wso2.carbon.identity.oidc.session.util.OIDCSessionManagementUtil; import org.wso2.carbon.identity.openidconnect.RequestObjectService; import org.wso2.carbon.utils.CarbonUtils; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.nio.file.Paths; import java.sql.Connection; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.ws.rs.HttpMethod; import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyMap; import static org.mockito.Matchers.anySet; import static org.mockito.Matchers.anyString; import static org.mockito.MockitoAnnotations.initMocks; import static org.powermock.api.mockito.PowerMockito.doAnswer; import static org.powermock.api.mockito.PowerMockito.doNothing; import static org.powermock.api.mockito.PowerMockito.doReturn; import static org.powermock.api.mockito.PowerMockito.doThrow; import static org.powermock.api.mockito.PowerMockito.mock; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.spy; import static org.powermock.api.mockito.PowerMockito.when; import static org.powermock.api.mockito.PowerMockito.whenNew; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.FileAssert.fail; @PrepareForTest({ OAuth2Util.class, SessionDataCache.class, OAuthServerConfiguration.class, IdentityDatabaseUtil.class, EndpointUtil.class, FrameworkUtils.class, EndpointUtil.class, OpenIDConnectUserRPStore.class, CarbonOAuthAuthzRequest.class, IdentityTenantUtil.class, OAuthResponse.class, SignedJWT.class, OIDCSessionManagementUtil.class, CarbonUtils.class, SessionDataCache.class, IdentityUtil.class }) public class OAuth2AuthzEndpointTest extends TestOAuthEndpointBase { @Mock HttpServletRequest httpServletRequest; @Mock HttpServletResponse httpServletResponse; @Mock SessionDataCache sessionDataCache; @Mock SessionDataCacheEntry loginCacheEntry, consentCacheEntry; @Mock OAuthServerConfiguration oAuthServerConfiguration; @Mock TokenPersistenceProcessor tokenPersistenceProcessor; @Mock OAuth2Service oAuth2Service; @Mock RequestObjectService requestObjectService; @Mock HttpSession httpSession; @Mock RequestCoordinator requestCoordinator; @Mock OpenIDConnectUserRPStore openIDConnectUserRPStore; @Mock OAuth2ClientValidationResponseDTO oAuth2ClientValidationResponseDTO; @Mock CarbonOAuthAuthzRequest carbonOAuthAuthzRequest; @Mock OAuthAuthzRequest oAuthAuthzRequest; @Mock SignedJWT signedJWT; @Mock OIDCSessionManager oidcSessionManager; @Mock ApplicationManagementService applicationManagementService; @Mock OAuthMessage oAuthMessage; private static final String ERROR_PAGE_URL = "https://localhost:9443/authenticationendpoint/oauth2_error.do"; private static final String LOGIN_PAGE_URL = "https://localhost:9443/authenticationendpoint/login.do"; private static final String USER_CONSENT_URL = "https://localhost:9443/authenticationendpoint/oauth2_authz.do"; private static final String CLIENT_ID = "client_id"; private static final String REDIRECT_URI = "redirect_uri"; private static final String RESPONSE_MODE_FORM_POST = "form_post"; private static final String SESSION_DATA_KEY_CONSENT_VALUE = "savedSessionDataKeyForConsent"; private static final String SESSION_DATA_KEY_VALUE = "savedSessionDataKey"; private static final String CLIENT_ID_VALUE = "ca19a540f544777860e44e75f605d927"; private static final String APP_NAME = "myApp"; private static final String INACTIVE_CLIENT_ID_VALUE = "inactiveId"; private static final String SECRET = "87n9a540f544777860e44e75f605d435"; private static final String INACTIVE_APP_NAME = "inactiveApp"; private static final String USERNAME = "user1"; private static final String APP_REDIRECT_URL = "http://localhost:8080/redirect"; private static final String APP_REDIRECT_URL_JSON = "{\"url\":\"http://localhost:8080/redirect\"}"; private static final String SP_DISPLAY_NAME = "DisplayName"; private static final String SP_NAME = "Name"; private OAuth2AuthzEndpoint oAuth2AuthzEndpoint; private Object authzEndpointObject; @BeforeTest public void setUp() throws Exception { System.setProperty(CarbonBaseConstants.CARBON_HOME, Paths.get(System.getProperty("user.dir"), "src", "test", "resources").toString()); oAuth2AuthzEndpoint = new OAuth2AuthzEndpoint(); initiateInMemoryH2(); createOAuthApp(CLIENT_ID_VALUE, SECRET, USERNAME, APP_NAME, "ACTIVE"); createOAuthApp(INACTIVE_CLIENT_ID_VALUE, "dummySecret", USERNAME, INACTIVE_APP_NAME, "INACTIVE"); Class<?> clazz = OAuth2AuthzEndpoint.class; authzEndpointObject = clazz.newInstance(); } @AfterTest public void cleanData() throws Exception { super.cleanData(); } @DataProvider(name = "providePostParams") public Object[][] providePostParams() { MultivaluedMap<String, String> paramMap1 = new MultivaluedHashMap<String, String>(); List<String> list1 = new ArrayList<>(); list1.add("value1"); list1.add("value2"); paramMap1.put("paramName1", list1); Map<String, String[]> requestParams1 = new HashMap<>(); requestParams1.put("reqParam1", new String[] { "val1", "val2" }); MultivaluedMap<String, String> paramMap2 = new MultivaluedHashMap<String, String>(); List<String> list2 = new ArrayList<>(); list2.add("value1"); paramMap2.put("paramName1", list2); Map<String, String[]> requestParams2 = new HashMap<>(); requestParams2.put("reqParam1", new String[] { "val1" }); return new Object[][] { { paramMap2, requestParams2, HttpServletResponse.SC_FOUND }, { paramMap1, requestParams2, HttpServletResponse.SC_BAD_REQUEST }, }; } @Test(dataProvider = "providePostParams") public void testAuthorizePost(Object paramObject, Map<String, String[]> requestParams, int expected) throws Exception { MultivaluedMap<String, String> paramMap = (MultivaluedMap<String, String>) paramObject; when(httpServletRequest.getParameterMap()).thenReturn(requestParams); when(httpServletRequest.getParameterNames()).thenReturn(new Vector(requestParams.keySet()).elements()); mockStatic(OAuth2Util.OAuthURL.class); when(OAuth2Util.OAuthURL.getOAuth2ErrorPageUrl()).thenReturn(ERROR_PAGE_URL); Response response; try { response = oAuth2AuthzEndpoint.authorizePost(httpServletRequest, httpServletResponse, paramMap); } catch (InvalidRequestParentException ire) { InvalidRequestExceptionMapper invalidRequestExceptionMapper = new InvalidRequestExceptionMapper(); response = invalidRequestExceptionMapper.toResponse(ire); } assertEquals(response.getStatus(), expected, "Unexpected HTTP response status"); } @DataProvider(name = "provideParams") public Object[][] provideParams() { initMocks(this); return new Object[][] { { AuthenticatorFlowStatus.SUCCESS_COMPLETED, new String[] { "val1", "val2" }, SESSION_DATA_KEY_CONSENT_VALUE, "true", "scope1", SESSION_DATA_KEY_VALUE, null, HttpServletResponse.SC_BAD_REQUEST, OAuth2ErrorCodes.INVALID_REQUEST }, { AuthenticatorFlowStatus.SUCCESS_COMPLETED, new String[] { CLIENT_ID_VALUE }, SESSION_DATA_KEY_CONSENT_VALUE, "true", "scope1", SESSION_DATA_KEY_VALUE, null, HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.INVALID_REQUEST }, { AuthenticatorFlowStatus.SUCCESS_COMPLETED, null, null, "true", "scope1", null, null, HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.INVALID_REQUEST }, { AuthenticatorFlowStatus.SUCCESS_COMPLETED, new String[] { CLIENT_ID_VALUE }, SESSION_DATA_KEY_CONSENT_VALUE, "true", "scope1", "invalidSession", null, HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.ACCESS_DENIED }, { AuthenticatorFlowStatus.SUCCESS_COMPLETED, new String[] { CLIENT_ID_VALUE }, "invalidConsentCacheKey", "true", "scope1", null, null, HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.ACCESS_DENIED }, { AuthenticatorFlowStatus.SUCCESS_COMPLETED, new String[] { "invalidId" }, "invalidConsentCacheKey", "true", "scope1", SESSION_DATA_KEY_VALUE, null, HttpServletResponse.SC_UNAUTHORIZED, OAuth2ErrorCodes.INVALID_CLIENT }, { AuthenticatorFlowStatus.SUCCESS_COMPLETED, new String[] { INACTIVE_CLIENT_ID_VALUE }, "invalidConsentCacheKey", "true", "scope1", SESSION_DATA_KEY_VALUE, null, HttpServletResponse.SC_UNAUTHORIZED, OAuth2ErrorCodes.INVALID_CLIENT }, { AuthenticatorFlowStatus.SUCCESS_COMPLETED, new String[] { CLIENT_ID_VALUE }, "invalidConsentCacheKey", "true", "scope1", SESSION_DATA_KEY_VALUE, null, HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.INVALID_REQUEST }, { null, new String[] { CLIENT_ID_VALUE }, SESSION_DATA_KEY_CONSENT_VALUE, "true", "scope1", SESSION_DATA_KEY_VALUE, null, HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.INVALID_REQUEST }, { null, new String[] { CLIENT_ID_VALUE }, SESSION_DATA_KEY_CONSENT_VALUE, "true", "scope1", SESSION_DATA_KEY_VALUE, new IOException(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null }, { AuthenticatorFlowStatus.SUCCESS_COMPLETED, new String[] { CLIENT_ID_VALUE }, null, "true", "scope1", null, null, HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.INVALID_REQUEST }, { AuthenticatorFlowStatus.SUCCESS_COMPLETED, new String[] { CLIENT_ID_VALUE }, null, "true", "scope1", null, OAuthProblemException.error("error"), HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.INVALID_REQUEST }, { AuthenticatorFlowStatus.SUCCESS_COMPLETED, new String[] { CLIENT_ID_VALUE }, null, "true", "scope1", null, new IOException(), HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.INVALID_REQUEST }, { null, new String[] { CLIENT_ID_VALUE }, null, "false", null, null, null, HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.INVALID_REQUEST }, { AuthenticatorFlowStatus.INCOMPLETE, new String[] { CLIENT_ID_VALUE }, null, "false", OAuthConstants.Scope.OPENID, null, null, HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.INVALID_REQUEST }, { AuthenticatorFlowStatus.INCOMPLETE, null, null, "false", OAuthConstants.Scope.OPENID, null, null, HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.INVALID_REQUEST }, }; } @Test(dataProvider = "provideParams", groups = "testWithConnection") public void testAuthorize(Object flowStatusObject, String[] clientId, String sessionDataKayConsent, String toCommonAuth, String scope, String sessionDataKey, Exception e, int expectedStatus, String expectedError) throws Exception { AuthenticatorFlowStatus flowStatus = (AuthenticatorFlowStatus) flowStatusObject; Map<String, String[]> requestParams = new HashMap<>(); Map<String, Object> requestAttributes = new HashMap<>(); if (clientId != null) { requestParams.put(CLIENT_ID, clientId); } requestParams.put(OAuthConstants.SESSION_DATA_KEY_CONSENT, new String[] { sessionDataKayConsent }); requestParams.put(FrameworkConstants.RequestParams.TO_COMMONAUTH, new String[] { toCommonAuth }); requestParams.put(OAuthConstants.OAuth20Params.SCOPE, new String[] { scope }); requestAttributes.put(FrameworkConstants.RequestParams.FLOW_STATUS, flowStatus); requestAttributes.put(FrameworkConstants.SESSION_DATA_KEY, sessionDataKey); if (e instanceof OAuthProblemException) { mockStatic(CarbonOAuthAuthzRequest.class); whenNew(CarbonOAuthAuthzRequest.class).withAnyArguments().thenThrow(e); requestParams.put(REDIRECT_URI, new String[] { APP_REDIRECT_URL }); } mockHttpRequest(requestParams, requestAttributes, HttpMethod.POST); mockStatic(OAuth2Util.OAuthURL.class); when(OAuth2Util.OAuthURL.getOAuth2ErrorPageUrl()).thenReturn(ERROR_PAGE_URL); mockStatic(IdentityTenantUtil.class); when(IdentityTenantUtil.getTenantDomain(anyInt())) .thenReturn(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); mockStatic(SessionDataCache.class); when(SessionDataCache.getInstance()).thenReturn(sessionDataCache); SessionDataCacheKey loginDataCacheKey = new SessionDataCacheKey(SESSION_DATA_KEY_VALUE); SessionDataCacheKey consentDataCacheKey = new SessionDataCacheKey(SESSION_DATA_KEY_CONSENT_VALUE); when(sessionDataCache.getValueFromCache(loginDataCacheKey)).thenReturn(loginCacheEntry); when(sessionDataCache.getValueFromCache(consentDataCacheKey)).thenReturn(consentCacheEntry); when(loginCacheEntry.getoAuth2Parameters()).thenReturn(setOAuth2Parameters( new HashSet<>(Collections.singletonList(OAuthConstants.Scope.OPENID)), APP_NAME, null, null)); mockOAuthServerConfiguration(); mockStatic(IdentityDatabaseUtil.class); when(IdentityDatabaseUtil.getDBConnection()).thenReturn(connection); mockEndpointUtil(); when(oAuth2Service.validateClientInfo(anyString(), anyString())) .thenReturn(oAuth2ClientValidationResponseDTO); when(oAuth2Service.getOauthApplicationState(CLIENT_ID_VALUE)).thenReturn("ACTIVE"); when(oAuth2ClientValidationResponseDTO.isValidClient()).thenReturn(true); final String[] redirectUrl = new String[1]; if (e instanceof IOException) { doThrow(e).when(httpServletResponse).sendRedirect(anyString()); } else { doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) { String key = (String) invocation.getArguments()[0]; redirectUrl[0] = key; return null; } }).when(httpServletResponse).sendRedirect(anyString()); } Response response; try { response = oAuth2AuthzEndpoint.authorize(httpServletRequest, httpServletResponse); } catch (InvalidRequestParentException ire) { InvalidRequestExceptionMapper invalidRequestExceptionMapper = new InvalidRequestExceptionMapper(); response = invalidRequestExceptionMapper.toResponse(ire); } if (response != null) { assertEquals(response.getStatus(), expectedStatus, "Unexpected HTTP response status"); MultivaluedMap<String, Object> responseMetadata = response.getMetadata(); assertNotNull(responseMetadata, "HTTP response metadata is null"); if (expectedError != null) { List<Object> redirectPath = responseMetadata.get(HTTPConstants.HEADER_LOCATION); if (CollectionUtils.isNotEmpty(redirectPath)) { String location = (String) redirectPath.get(0); assertTrue(location.contains(expectedError), "Expected error code not found in URL"); } else { assertNotNull(response.getEntity(), "Response entity is null"); assertTrue(response.getEntity().toString().contains(expectedError), "Expected error code not found response entity"); } } } else { assertNotNull(redirectUrl[0]); } } @DataProvider(name = "provideAuthenticatedData") public Object[][] provideAuthenticatedData() { return new Object[][] { { true, true, new HashMap(), null, null, null, new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL, HttpServletResponse.SC_FOUND }, { false, true, null, null, null, null, new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL, HttpServletResponse.SC_FOUND }, { true, true, new HashMap(), null, null, null, new HashSet<>(Arrays.asList("scope1")), "not_form_post", APP_REDIRECT_URL, HttpServletResponse.SC_FOUND }, { true, true, new HashMap(), null, null, null, new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL_JSON, HttpServletResponse.SC_OK }, { true, true, new HashMap(), null, null, null, new HashSet<>(Arrays.asList("scope1")), RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL_JSON, HttpServletResponse.SC_OK }, { true, false, null, OAuth2ErrorCodes.INVALID_REQUEST, null, null, new HashSet<>(Arrays.asList("scope1")), RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL, HttpServletResponse.SC_OK }, { true, false, null, null, "Error!", null, new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL, HttpServletResponse.SC_OK }, { true, false, null, null, null, "http://localhost:8080/error", new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), RESPONSE_MODE_FORM_POST, APP_REDIRECT_URL, HttpServletResponse.SC_OK } }; } @Test(dataProvider = "provideAuthenticatedData", groups = "testWithConnection") public void testAuthorizeForAuthenticationResponse(boolean isResultInRequest, boolean isAuthenticated, Map<ClaimMapping, String> attributes, String errorCode, String errorMsg, String errorUri, Set<String> scopes, String responseMode, String redirectUri, int expected) throws Exception { mockStatic(SessionDataCache.class); when(SessionDataCache.getInstance()).thenReturn(sessionDataCache); SessionDataCacheKey loginDataCacheKey = new SessionDataCacheKey(SESSION_DATA_KEY_VALUE); when(sessionDataCache.getValueFromCache(loginDataCacheKey)).thenReturn(loginCacheEntry); AuthenticationResult result = setAuthenticationResult(isAuthenticated, attributes, errorCode, errorMsg, errorUri); AuthenticationResult resultInRequest = null; AuthenticationResultCacheEntry authResultCacheEntry = null; if (isResultInRequest) { resultInRequest = result; } else { authResultCacheEntry = new AuthenticationResultCacheEntry(); authResultCacheEntry.setResult(result); } Map<String, String[]> requestParams = new HashMap<>(); Map<String, Object> requestAttributes = new HashMap<>(); requestParams.put(CLIENT_ID, new String[] { CLIENT_ID_VALUE }); requestParams.put(FrameworkConstants.RequestParams.TO_COMMONAUTH, new String[] { "false" }); requestParams.put(OAuthConstants.OAuth20Params.SCOPE, new String[] { OAuthConstants.Scope.OPENID }); requestAttributes.put(FrameworkConstants.RequestParams.FLOW_STATUS, AuthenticatorFlowStatus.INCOMPLETE); requestAttributes.put(FrameworkConstants.SESSION_DATA_KEY, SESSION_DATA_KEY_VALUE); requestAttributes.put(FrameworkConstants.RequestAttribute.AUTH_RESULT, resultInRequest); mockHttpRequest(requestParams, requestAttributes, HttpMethod.POST); spy(FrameworkUtils.class); doReturn(requestCoordinator).when(FrameworkUtils.class, "getRequestCoordinator"); spy(IdentityUtil.class); doReturn("https://localhost:9443/carbon").when(IdentityUtil.class, "getServerURL", anyString(), anyBoolean(), anyBoolean()); OAuth2Parameters oAuth2Params = setOAuth2Parameters(scopes, APP_NAME, responseMode, redirectUri); oAuth2Params.setClientId(CLIENT_ID_VALUE); when(loginCacheEntry.getoAuth2Parameters()).thenReturn(oAuth2Params); when(loginCacheEntry.getLoggedInUser()).thenReturn(result.getSubject()); mockOAuthServerConfiguration(); mockStatic(IdentityTenantUtil.class); when(IdentityTenantUtil.getTenantDomain(anyInt())) .thenReturn(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); try (Connection connection = getConnection()) { mockStatic(IdentityDatabaseUtil.class); when(IdentityDatabaseUtil.getDBConnection()).thenReturn(connection); mockStatic(OpenIDConnectUserRPStore.class); when(OpenIDConnectUserRPStore.getInstance()).thenReturn(openIDConnectUserRPStore); when(openIDConnectUserRPStore.hasUserApproved(any(AuthenticatedUser.class), anyString(), anyString())) .thenReturn(true); mockEndpointUtil(); when(oAuth2Service.getOauthApplicationState(CLIENT_ID_VALUE)).thenReturn("ACTIVE"); mockApplicationManagementService(); Response response = oAuth2AuthzEndpoint.authorize(httpServletRequest, httpServletResponse); assertEquals(response.getStatus(), expected, "Unexpected HTTP response status"); } } @DataProvider(name = "provideConsentData") public Object[][] provideConsentData() { return new Object[][] { { null, APP_REDIRECT_URL, new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), HttpServletResponse.SC_FOUND, OAuth2ErrorCodes.INVALID_REQUEST }, { "deny", APP_REDIRECT_URL, new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), HttpServletResponse.SC_OK, OAuth2ErrorCodes.ACCESS_DENIED }, { "deny", APP_REDIRECT_URL, new HashSet<>(Arrays.asList("scope1")), HttpServletResponse.SC_OK, OAuth2ErrorCodes.ACCESS_DENIED }, { "approve", APP_REDIRECT_URL, new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), HttpServletResponse.SC_FOUND, null }, { "approve", APP_REDIRECT_URL, new HashSet<>(Arrays.asList("scope1")), HttpServletResponse.SC_FOUND, null }, { "approve", APP_REDIRECT_URL_JSON, new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), HttpServletResponse.SC_OK, null }, { "approve", APP_REDIRECT_URL_JSON, new HashSet<>(Arrays.asList("scope1")), HttpServletResponse.SC_OK, null }, }; } @Test(dataProvider = "provideConsentData", groups = "testWithConnection") public void testUserConsentResponse(String consent, String redirectUrl, Set<String> scopes, int expectedStatus, String expectedError) throws Exception { mockStatic(SessionDataCache.class); when(SessionDataCache.getInstance()).thenReturn(sessionDataCache); SessionDataCacheKey consentDataCacheKey = new SessionDataCacheKey(SESSION_DATA_KEY_CONSENT_VALUE); when(sessionDataCache.getValueFromCache(consentDataCacheKey)).thenReturn(consentCacheEntry); Map<String, String[]> requestParams = new HashMap<>(); Map<String, Object> requestAttributes = new HashMap<>(); requestParams.put(OAuthConstants.SESSION_DATA_KEY_CONSENT, new String[] { SESSION_DATA_KEY_CONSENT_VALUE }); requestParams.put(FrameworkConstants.RequestParams.TO_COMMONAUTH, new String[] { "false" }); requestParams.put(OAuthConstants.OAuth20Params.SCOPE, new String[] { OAuthConstants.Scope.OPENID }); requestParams.put(OAuthConstants.Prompt.CONSENT, new String[] { consent }); requestAttributes.put(FrameworkConstants.RequestParams.FLOW_STATUS, AuthenticatorFlowStatus.INCOMPLETE); mockHttpRequest(requestParams, requestAttributes, HttpMethod.POST); OAuth2Parameters oAuth2Params = setOAuth2Parameters(scopes, APP_NAME, RESPONSE_MODE_FORM_POST, redirectUrl); when(consentCacheEntry.getoAuth2Parameters()).thenReturn(oAuth2Params); when(consentCacheEntry.getLoggedInUser()).thenReturn(new AuthenticatedUser()); mockStatic(OpenIDConnectUserRPStore.class); when(OpenIDConnectUserRPStore.getInstance()).thenReturn(openIDConnectUserRPStore); doNothing().when(openIDConnectUserRPStore).putUserRPToStore(any(AuthenticatedUser.class), anyString(), anyBoolean(), anyString()); mockOAuthServerConfiguration(); mockStatic(OAuth2Util.OAuthURL.class); when(OAuth2Util.OAuthURL.getOAuth2ErrorPageUrl()).thenReturn(ERROR_PAGE_URL); mockStatic(OAuth2Util.class); when(OAuth2Util.getServiceProvider(CLIENT_ID_VALUE)).thenReturn(new ServiceProvider()); mockEndpointUtil(); when(oAuth2Service.getOauthApplicationState(CLIENT_ID_VALUE)).thenReturn("ACTIVE"); mockApplicationManagementService(); Response response; try { response = oAuth2AuthzEndpoint.authorize(httpServletRequest, httpServletResponse); } catch (InvalidRequestParentException ire) { InvalidRequestExceptionMapper invalidRequestExceptionMapper = new InvalidRequestExceptionMapper(); response = invalidRequestExceptionMapper.toResponse(ire); } if (response != null) { assertEquals(response.getStatus(), expectedStatus, "Unexpected HTTP response status"); MultivaluedMap<String, Object> responseMetadata = response.getMetadata(); assertNotNull(responseMetadata); if (expectedError != null) { if (response.getEntity() != null) { String htmlPost = response.getEntity().toString(); assertTrue(htmlPost.contains(expectedError)); } else { CollectionUtils.isNotEmpty(responseMetadata.get(HTTPConstants.HEADER_LOCATION)); assertTrue(CollectionUtils.isNotEmpty(responseMetadata.get(HTTPConstants.HEADER_LOCATION)), "Location header not found in the response"); String location = (String) responseMetadata.get(HTTPConstants.HEADER_LOCATION).get(0); assertTrue(location.contains(expectedError), "Expected error code not found in URL"); } } } } @DataProvider(name = "provideAuthzRequestData") public Object[][] provideAuthzRequestData() { String validPKCEChallenge = "abcdef1234A46gfdhhjhnmvmu764745463565nnnvbnn6"; return new Object[][] { // Authz request from Valid client, PKCE not enabled. request sent to framework for authentication { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, null, true, false, true, LOGIN_PAGE_URL }, // Blank client ID is received. Redirected to error page with invalid_request error { "", APP_REDIRECT_URL, null, null, null, true, false, true, ERROR_PAGE_URL }, // Valid client, ACR url null, PKCE not enabled. request sent to framework for authentication { CLIENT_ID_VALUE, null, null, null, null, true, false, true, LOGIN_PAGE_URL }, // Valid client, ACR value is "null". Correctly considers it as a null ACR. // PKCE not enabled. Request sent to framework for authentication { CLIENT_ID_VALUE, "null", null, null, null, true, false, true, LOGIN_PAGE_URL }, // Invalid client. Redirected to error page. { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, null, false, false, true, ERROR_PAGE_URL }, // Valid client, PKCE is enabled and mandatory, PKCE code is null. // Redirected to error page with invalid_request error { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, null, true, true, true, ERROR_PAGE_URL }, // Valid client, PKCE is enabled but not mandatory, PKCE code is null. // Request sent to framework for authentication { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, null, true, true, false, LOGIN_PAGE_URL }, // Valid client, PKCE is enabled and mandatory, valid PKCE code, plain PKCE challenge method, // plain PKCE is supported. Request sent to framework for authentication { CLIENT_ID_VALUE, APP_REDIRECT_URL, validPKCEChallenge, OAuthConstants.OAUTH_PKCE_PLAIN_CHALLENGE, null, true, true, true, LOGIN_PAGE_URL }, // Valid client, PKCE is enabled and mandatory, invalid PKCE code, plain PKCE challenge method, // plain PKCE is supported. Redirected to error page with invalid_request error { CLIENT_ID_VALUE, APP_REDIRECT_URL, "dummmyPkceChallenge", OAuthConstants.OAUTH_PKCE_PLAIN_CHALLENGE, null, true, true, true, ERROR_PAGE_URL }, // Valid client, PKCE is enabled but not mandatory, valid plain PKCE code, un supported PKCE challenge method, // plain PKCE is not supported. Redirected to error page with invalid_request error { CLIENT_ID_VALUE, APP_REDIRECT_URL, validPKCEChallenge, "invalidMethod", null, true, true, false, ERROR_PAGE_URL }, // Valid client, PKCE is enabled but not mandatory, valid plain PKCE code, plain PKCE challenge method, // plain PKCE is not supported. Redirected to error page with invalid_request error { CLIENT_ID_VALUE, APP_REDIRECT_URL, validPKCEChallenge, OAuthConstants.OAUTH_PKCE_PLAIN_CHALLENGE, null, true, true, false, ERROR_PAGE_URL }, // Valid client, PKCE is enabled but not mandatory, valid plain PKCE code, PKCE challenge method is null, // plain PKCE is not supported. Redirected to error page with invalid_request error { CLIENT_ID_VALUE, APP_REDIRECT_URL, validPKCEChallenge, null, null, true, true, false, ERROR_PAGE_URL }, // Valid client, PKCE is enabled but not mandatory, valid plain PKCE code, PKCE challenge method is s256, // plain PKCE is not supported. Redirected to error page with invalid_request error { CLIENT_ID_VALUE, APP_REDIRECT_URL, validPKCEChallenge, OAuthConstants.OAUTH_PKCE_S256_CHALLENGE, null, true, true, false, ERROR_PAGE_URL }, // Valid client, prompt is "none", PKCE not supported. Request sent to framework for authentication // since user is not authenticated { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, OAuthConstants.Prompt.NONE, true, false, true, LOGIN_PAGE_URL }, // Valid client, prompt is "consent" and "login", PKCE not supported. // Request sent to framework for authentication { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, OAuthConstants.Prompt.CONSENT + " " + OAuthConstants.Prompt.LOGIN, true, false, true, LOGIN_PAGE_URL }, // Valid client, prompt is "login", PKCE not supported. Request sent to framework for authentication { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, OAuthConstants.Prompt.SELECT_ACCOUNT + " " + OAuthConstants.Prompt.LOGIN, true, false, true, LOGIN_PAGE_URL }, // Valid client, prompt is "consent" and "select_account", PKCE not supported. // Request sent to framework for authentication { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, OAuthConstants.Prompt.SELECT_ACCOUNT + " " + OAuthConstants.Prompt.CONSENT, true, false, true, LOGIN_PAGE_URL }, // Valid client, prompt is "none" and "login", PKCE not supported. // Redirected to application with invalid_request error { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, OAuthConstants.Prompt.NONE + " " + OAuthConstants.Prompt.LOGIN, true, false, true, APP_REDIRECT_URL }, // Valid client, unsupported prompt, PKCE not supported. // Redirected to application with invalid_request error { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, "dummyPrompt", true, false, true, APP_REDIRECT_URL }, // Valid client, prompt is "login", PKCE not supported. Request sent to framework for authentication { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, OAuthConstants.Prompt.LOGIN, true, false, true, LOGIN_PAGE_URL }, // Valid client, prompt is "consent", PKCE not supported. Request sent to framework for authentication { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, OAuthConstants.Prompt.CONSENT, true, false, true, LOGIN_PAGE_URL }, // Valid client, prompt is "select_account", PKCE not supported. // Request sent to framework for authentication { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, OAuthConstants.Prompt.SELECT_ACCOUNT, true, false, true, LOGIN_PAGE_URL }, // Special data manipulation. For this combination of inputs, EndpointUtil.getLoginPageURL() is set to // throw a IdentityOAuth2Exception. // Redirected to error page with invalid_request error because of the exception { CLIENT_ID_VALUE, APP_REDIRECT_URL, null, null, OAuthConstants.Prompt.NONE, true, false, true, ERROR_PAGE_URL }, }; } /** * * Tests the scenario of authorization request from the client */ @Test(dataProvider = "provideAuthzRequestData", groups = "testWithConnection") public void testHandleOAuthAuthorizationRequest(String clientId, String redirectUri, String pkceChallengeCode, String pkceChallengeMethod, String prompt, boolean clientValid, boolean pkceEnabled, boolean supportPlainPkce, String expectedLocation) throws Exception { Map<String, String[]> requestParams = new HashMap(); Map<String, Object> requestAttributes = new HashMap(); requestParams.put(CLIENT_ID, new String[] { clientId }); // No consent data is saved in the cache yet and client doesn't send cache key requestParams.put(OAuthConstants.SESSION_DATA_KEY_CONSENT, new String[] { null }); requestParams.put(FrameworkConstants.RequestParams.TO_COMMONAUTH, new String[] { "false" }); requestParams.put(REDIRECT_URI, new String[] { APP_REDIRECT_URL }); requestParams.put(OAuthConstants.OAUTH_PKCE_CODE_CHALLENGE, new String[] { pkceChallengeCode }); requestParams.put(OAuthConstants.OAUTH_PKCE_CODE_CHALLENGE_METHOD, new String[] { pkceChallengeMethod }); requestParams.put(OAuth.OAUTH_RESPONSE_TYPE, new String[] { ResponseType.TOKEN.toString() }); if (redirectUri != null) { requestParams.put("acr_values", new String[] { redirectUri }); requestParams.put("claims", new String[] { "essentialClaims" }); requestParams.put(MultitenantConstants.TENANT_DOMAIN, new String[] { MultitenantConstants.SUPER_TENANT_DOMAIN_NAME }); } requestAttributes.put(FrameworkConstants.RequestParams.FLOW_STATUS, AuthenticatorFlowStatus.INCOMPLETE); // No authentication data is saved in the cache yet and client doesn't send cache key requestAttributes.put(FrameworkConstants.SESSION_DATA_KEY, null); if (prompt != null) { requestParams.put(OAuthConstants.OAuth20Params.PROMPT, new String[] { prompt }); } boolean checkErrorCode = ERROR_PAGE_URL.equals(expectedLocation); mockHttpRequest(requestParams, requestAttributes, HttpMethod.POST); mockOAuthServerConfiguration(); Map<String, Class<? extends OAuthValidator<HttpServletRequest>>> responseTypeValidators = new Hashtable<>(); responseTypeValidators.put(ResponseType.CODE.toString(), CodeValidator.class); responseTypeValidators.put(ResponseType.TOKEN.toString(), TokenValidator.class); when(oAuthServerConfiguration.getSupportedResponseTypeValidators()).thenReturn(responseTypeValidators); mockStatic(IdentityDatabaseUtil.class); when(IdentityDatabaseUtil.getDBConnection()).thenReturn(connection); mockEndpointUtil(); when(oAuth2Service.getOauthApplicationState(CLIENT_ID_VALUE)).thenReturn("ACTIVE"); when(oAuth2Service.isPKCESupportEnabled()).thenReturn(pkceEnabled); if (ERROR_PAGE_URL.equals(expectedLocation) && OAuthConstants.Prompt.NONE.equals(prompt)) { doThrow(new IdentityOAuth2Exception("error")).when(EndpointUtil.class, "getLoginPageURL", anyString(), anyString(), anyBoolean(), anyBoolean(), anySet(), anyMap()); checkErrorCode = false; } mockStatic(OAuth2Util.OAuthURL.class); when(OAuth2Util.OAuthURL.getOAuth2ErrorPageUrl()).thenReturn(ERROR_PAGE_URL); OAuth2ClientValidationResponseDTO validationResponseDTO = new OAuth2ClientValidationResponseDTO(); validationResponseDTO.setValidClient(clientValid); validationResponseDTO.setCallbackURL(APP_REDIRECT_URL); if (!clientValid) { validationResponseDTO.setErrorCode(OAuth2ErrorCodes.INVALID_REQUEST); validationResponseDTO.setErrorMsg("client is invalid"); } validationResponseDTO.setPkceMandatory(supportPlainPkce); validationResponseDTO.setPkceSupportPlain(supportPlainPkce); when(oAuth2Service.validateClientInfo(anyString(), anyString())).thenReturn(validationResponseDTO); final String[] redirectUrl = new String[1]; doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) { String key = (String) invocation.getArguments()[0]; redirectUrl[0] = key; return null; } }).when(httpServletResponse).sendRedirect(anyString()); Response response; try { response = oAuth2AuthzEndpoint.authorize(httpServletRequest, httpServletResponse); } catch (InvalidRequestParentException ire) { InvalidRequestExceptionMapper invalidRequestExceptionMapper = new InvalidRequestExceptionMapper(); response = invalidRequestExceptionMapper.toResponse(ire); } if (response != null) { assertEquals(response.getStatus(), HttpServletResponse.SC_FOUND, "Unexpected HTTP response status"); MultivaluedMap<String, Object> responseMetadata = response.getMetadata(); assertNotNull(responseMetadata, "Response metadata is null"); assertTrue(CollectionUtils.isNotEmpty(responseMetadata.get(HTTPConstants.HEADER_LOCATION)), "Location header not found in the response"); String location = (String) responseMetadata.get(HTTPConstants.HEADER_LOCATION).get(0); assertTrue(location.contains(expectedLocation), "Unexpected redirect url in the response"); if (checkErrorCode) { assertTrue(location.contains(OAuth2ErrorCodes.INVALID_REQUEST), "Expected error code not found in URL"); } } else { assertNotNull(redirectUrl[0], "Response not redirected to outside"); } } @DataProvider(name = "provideUserConsentData") public Object[][] provideUserConsentData() { String authzCode = "67428657950009705658674645643"; String accessToken = "56789876734982650746509776325"; String idToken = "eyJzdWIiOiJQUklNQVJZXC9zdXJlc2hhdHQiLCJlbWFpbCI6InN1cmVzaGdlbXVudUBteW1haWwuY29tIiwibmFtZSI" + "6IlN1cmVzaCBBdHRhbmF5YWtlIiwiZmFtaWx5X25hbWUiOiJBdHRhbmF5YWtlIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic3VyZXN" + "oZ2VtdW51IiwiZ2l2ZW5fbmFtZSI6IlN1cmVzaCJ9"; // These values are provided to cover all the branches in handleUserConsent private method. return new Object[][] { { true, OAuthConstants.Consent.APPROVE_ALWAYS, false, OAuth2ErrorCodes.SERVER_ERROR, null, null, null, null, null, null, null, HttpServletResponse.SC_FOUND, APP_REDIRECT_URL }, { false, OAuthConstants.Consent.APPROVE_ALWAYS, true, null, authzCode, null, null, null, null, "idp1", null, HttpServletResponse.SC_FOUND, APP_REDIRECT_URL }, { false, OAuthConstants.Consent.APPROVE_ALWAYS, false, null, null, accessToken, null, OAuthConstants.ACCESS_TOKEN, RESPONSE_MODE_FORM_POST, "idp1", "ACTIVE", HttpServletResponse.SC_OK, null }, { false, OAuthConstants.Consent.APPROVE_ALWAYS, false, null, null, accessToken, idToken, OAuthConstants.ID_TOKEN, RESPONSE_MODE_FORM_POST, null, "ACTIVE", HttpServletResponse.SC_OK, null }, { false, OAuthConstants.Consent.APPROVE, false, null, null, accessToken, idToken, OAuthConstants.NONE, RESPONSE_MODE_FORM_POST, "", "", HttpServletResponse.SC_OK, null }, { false, OAuthConstants.Consent.APPROVE, false, null, null, accessToken, idToken, OAuthConstants.ID_TOKEN, null, null, "ACTIVE", HttpServletResponse.SC_FOUND, APP_REDIRECT_URL }, { false, OAuthConstants.Consent.APPROVE, false, null, null, accessToken, null, OAuthConstants.ID_TOKEN, null, null, "ACTIVE", HttpServletResponse.SC_FOUND, APP_REDIRECT_URL }, { false, OAuthConstants.Consent.APPROVE_ALWAYS, false, OAuth2ErrorCodes.INVALID_CLIENT, null, null, null, null, null, null, null, HttpServletResponse.SC_FOUND, APP_REDIRECT_URL }, }; } @Test(dataProvider = "provideUserConsentData", groups = "testWithConnection") public void testHandleUserConsent(boolean isRespDTONull, String consent, boolean skipConsent, String errorCode, String authCode, String accessToken, String idToken, String responseType, String responseMode, String authenticatedIdps, String state, int expectedStatus, String expectedLocation) throws Exception { Map<String, String[]> requestParams = new HashMap<>(); Map<String, Object> requestAttributes = new HashMap<>(); requestParams.put(OAuthConstants.SESSION_DATA_KEY_CONSENT, new String[] { SESSION_DATA_KEY_CONSENT_VALUE }); requestParams.put(FrameworkConstants.RequestParams.TO_COMMONAUTH, new String[] { "false" }); requestParams.put(OAuthConstants.OAuth20Params.SCOPE, new String[] { OAuthConstants.Scope.OPENID }); requestParams.put(OAuthConstants.Prompt.CONSENT, new String[] { consent }); requestAttributes.put(FrameworkConstants.RequestParams.FLOW_STATUS, AuthenticatorFlowStatus.INCOMPLETE); mockHttpRequest(requestParams, requestAttributes, HttpMethod.POST); mockStatic(SessionDataCache.class); when(SessionDataCache.getInstance()).thenReturn(sessionDataCache); SessionDataCacheKey consentDataCacheKey = new SessionDataCacheKey(SESSION_DATA_KEY_CONSENT_VALUE); when(sessionDataCache.getValueFromCache(consentDataCacheKey)).thenReturn(consentCacheEntry); OAuth2Parameters oAuth2Params = setOAuth2Parameters(new HashSet<String>(), APP_NAME, responseMode, APP_REDIRECT_URL); oAuth2Params.setResponseType(responseType); oAuth2Params.setState(state); when(consentCacheEntry.getoAuth2Parameters()).thenReturn(oAuth2Params); when(consentCacheEntry.getLoggedInUser()).thenReturn(new AuthenticatedUser()); when(consentCacheEntry.getAuthenticatedIdPs()).thenReturn(authenticatedIdps); OAuth2AuthorizeRespDTO authzRespDTO = null; if (!isRespDTONull) { authzRespDTO = new OAuth2AuthorizeRespDTO(); authzRespDTO.setAuthorizationCode(authCode); authzRespDTO.setCallbackURI(APP_REDIRECT_URL); authzRespDTO.setAccessToken(accessToken); authzRespDTO.setIdToken(idToken); authzRespDTO.setErrorCode(errorCode); if (OAuthConstants.ID_TOKEN.equals(responseType) && idToken == null) { authzRespDTO.setCallbackURI(APP_REDIRECT_URL + "?"); } } mockEndpointUtil(); when(oAuth2Service.authorize(any(OAuth2AuthorizeReqDTO.class))).thenReturn(authzRespDTO); when(oAuth2Service.getOauthApplicationState(CLIENT_ID_VALUE)).thenReturn("ACTIVE"); mockStatic(OpenIDConnectUserRPStore.class); when(OpenIDConnectUserRPStore.getInstance()).thenReturn(openIDConnectUserRPStore); doNothing().when(openIDConnectUserRPStore).putUserRPToStore(any(AuthenticatedUser.class), anyString(), anyBoolean(), anyString()); when(oAuthServerConfiguration.getOpenIDConnectSkipeUserConsentConfig()).thenReturn(skipConsent); mockStatic(OAuthServerConfiguration.class); when(OAuthServerConfiguration.getInstance()).thenReturn(oAuthServerConfiguration); when(oAuthServerConfiguration.getAuthorizationCodeValidityPeriodInSeconds()).thenReturn(300L); mockStatic(OAuth2Util.class); when(OAuth2Util.getServiceProvider(CLIENT_ID_VALUE)).thenReturn(new ServiceProvider()); mockApplicationManagementService(); Response response; try { response = oAuth2AuthzEndpoint.authorize(httpServletRequest, httpServletResponse); } catch (InvalidRequestParentException ire) { InvalidRequestExceptionMapper invalidRequestExceptionMapper = new InvalidRequestExceptionMapper(); response = invalidRequestExceptionMapper.toResponse(ire); } assertNotNull(response, "Authorization response is null"); assertEquals(response.getStatus(), expectedStatus, "Unexpected HTTP response status"); if (expectedLocation != null) { MultivaluedMap<String, Object> responseMetadata = response.getMetadata(); assertNotNull(responseMetadata, "Response metadata is null"); assertTrue(CollectionUtils.isNotEmpty(responseMetadata.get(HTTPConstants.HEADER_LOCATION)), "Location header not found in the response"); String location = (String) responseMetadata.get(HTTPConstants.HEADER_LOCATION).get(0); assertTrue(location.contains(expectedLocation), "Unexpected redirect url in the response"); if (errorCode != null) { assertTrue(location.contains(errorCode), "Expected error code not found in URL"); } } } @DataProvider(name = "provideDataForUserAuthz") public Object[][] provideDataForUserAuthz() { String idTokenHint = "tokenHintString"; // This object provides data to cover all branches in doUserAuthz() private method return new Object[][] { { OAuthConstants.Prompt.CONSENT, null, true, false, false, USERNAME, USERNAME, null }, { OAuthConstants.Prompt.NONE, null, true, true, false, USERNAME, USERNAME, null }, { OAuthConstants.Prompt.NONE, null, false, false, false, USERNAME, USERNAME, OAuth2ErrorCodes.CONSENT_REQUIRED }, { OAuthConstants.Prompt.NONE, null, false, true, false, USERNAME, USERNAME, null }, { OAuthConstants.Prompt.NONE, idTokenHint, true, false, true, USERNAME, USERNAME, null }, { OAuthConstants.Prompt.NONE, idTokenHint, true, false, false, USERNAME, USERNAME, null }, { OAuthConstants.Prompt.NONE, idTokenHint, false, false, true, USERNAME, USERNAME, OAuth2ErrorCodes.CONSENT_REQUIRED }, { OAuthConstants.Prompt.NONE, "invalid", false, false, true, USERNAME, USERNAME, null }, { OAuthConstants.Prompt.NONE, idTokenHint, false, false, true, "", USERNAME, OAuth2ErrorCodes.LOGIN_REQUIRED }, { OAuthConstants.Prompt.NONE, idTokenHint, true, false, true, USERNAME, "user2", OAuth2ErrorCodes.LOGIN_REQUIRED }, { OAuthConstants.Prompt.LOGIN, null, true, false, false, USERNAME, USERNAME, null }, { OAuthConstants.Prompt.LOGIN, null, false, false, false, USERNAME, USERNAME, null }, { "", null, false, true, false, USERNAME, USERNAME, null }, { OAuthConstants.Prompt.SELECT_ACCOUNT, null, false, false, false, USERNAME, USERNAME, null }, }; } @Test(dataProvider = "provideDataForUserAuthz", groups = "testWithConnection") public void testDoUserAuthz(String prompt, String idTokenHint, boolean hasUserApproved, boolean skipConsent, boolean idTokenHintValid, String loggedInUser, String idTokenHintSubject, String errorCode) throws Exception { AuthenticationResult result = setAuthenticationResult(true, null, null, null, null); result.getSubject().setAuthenticatedSubjectIdentifier(loggedInUser); Map<String, String[]> requestParams = new HashMap<>(); Map<String, Object> requestAttributes = new HashMap<>(); requestParams.put(CLIENT_ID, new String[] { CLIENT_ID_VALUE }); requestParams.put(FrameworkConstants.RequestParams.TO_COMMONAUTH, new String[] { "false" }); requestParams.put(OAuthConstants.OAuth20Params.SCOPE, new String[] { OAuthConstants.Scope.OPENID }); requestAttributes.put(FrameworkConstants.RequestParams.FLOW_STATUS, AuthenticatorFlowStatus.INCOMPLETE); requestAttributes.put(FrameworkConstants.SESSION_DATA_KEY, SESSION_DATA_KEY_VALUE); requestAttributes.put(FrameworkConstants.RequestAttribute.AUTH_RESULT, result); mockHttpRequest(requestParams, requestAttributes, HttpMethod.POST); OAuth2Parameters oAuth2Params = setOAuth2Parameters(new HashSet<String>(), APP_NAME, null, APP_REDIRECT_URL); oAuth2Params.setClientId(CLIENT_ID_VALUE); oAuth2Params.setPrompt(prompt); oAuth2Params.setIDTokenHint(idTokenHint); mockStatic(SessionDataCache.class); when(SessionDataCache.getInstance()).thenReturn(sessionDataCache); SessionDataCacheKey loginDataCacheKey = new SessionDataCacheKey(SESSION_DATA_KEY_VALUE); when(sessionDataCache.getValueFromCache(loginDataCacheKey)).thenReturn(loginCacheEntry); when(loginCacheEntry.getLoggedInUser()).thenReturn(result.getSubject()); when(loginCacheEntry.getoAuth2Parameters()).thenReturn(oAuth2Params); mockEndpointUtil(); mockOAuthServerConfiguration(); mockStatic(IdentityDatabaseUtil.class); when(IdentityDatabaseUtil.getDBConnection()).thenReturn(connection); mockStatic(OpenIDConnectUserRPStore.class); when(OpenIDConnectUserRPStore.getInstance()).thenReturn(openIDConnectUserRPStore); when(openIDConnectUserRPStore.hasUserApproved(any(AuthenticatedUser.class), anyString(), anyString())) .thenReturn(hasUserApproved); spy(OAuth2Util.class); doReturn(idTokenHintValid).when(OAuth2Util.class, "validateIdToken", anyString()); mockStatic(SignedJWT.class); if ("invalid".equals(idTokenHint)) { when(SignedJWT.parse(anyString())).thenThrow(new ParseException("error", 1)); } else { when(SignedJWT.parse(anyString())).thenReturn(signedJWT); } JWTClaimsSet.Builder jwtClaimsSetBuilder = new JWTClaimsSet.Builder(); jwtClaimsSetBuilder.subject(idTokenHintSubject); JWTClaimsSet jwtClaimsSet = jwtClaimsSetBuilder.build(); when(signedJWT.getJWTClaimsSet()).thenReturn(jwtClaimsSet); when(oAuth2Service.getOauthApplicationState(CLIENT_ID_VALUE)).thenReturn("ACTIVE"); mockApplicationManagementService(); Response response; try { response = oAuth2AuthzEndpoint.authorize(httpServletRequest, httpServletResponse); } catch (InvalidRequestParentException ire) { InvalidRequestExceptionMapper invalidRequestExceptionMapper = new InvalidRequestExceptionMapper(); response = invalidRequestExceptionMapper.toResponse(ire); } assertNotNull(response, "Authorization response is null"); assertEquals(response.getStatus(), HttpServletResponse.SC_FOUND, "Unexpected HTTP response status"); if (errorCode != null) { MultivaluedMap<String, Object> responseMetadata = response.getMetadata(); assertNotNull(responseMetadata, "Response metadata is null"); assertTrue(CollectionUtils.isNotEmpty(responseMetadata.get(HTTPConstants.HEADER_LOCATION)), "Location header not found in the response"); String location = (String) responseMetadata.get(HTTPConstants.HEADER_LOCATION).get(0); assertTrue(location.contains(errorCode), "Expected error code not found in URL"); } } @DataProvider(name = "provideOidcSessionData") public Object[][] provideOidcSessionData() { Cookie opBrowserStateCookie = new Cookie("opbs", "2345678776gffdgdsfafa"); OIDCSessionState previousSessionState1 = new OIDCSessionState(); OIDCSessionState previousSessionState2 = new OIDCSessionState(); previousSessionState1.setSessionParticipants(new HashSet<>(Arrays.asList(CLIENT_ID_VALUE))); previousSessionState2.setSessionParticipants(new HashSet<String>()); String[] returnValues = new String[] { "http://localhost:8080/redirect?session_state=sessionStateValue", "<form method=\"post\" action=\"http://localhost:8080/redirect\">" }; // This object provides values to cover the branches in ManageOIDCSessionState() private method return new Object[][] { { opBrowserStateCookie, previousSessionState1, APP_REDIRECT_URL, null, HttpServletResponse.SC_FOUND, returnValues[0] }, { opBrowserStateCookie, previousSessionState2, APP_REDIRECT_URL, RESPONSE_MODE_FORM_POST, HttpServletResponse.SC_OK, returnValues[1] }, { null, previousSessionState1, APP_REDIRECT_URL, null, HttpServletResponse.SC_FOUND, returnValues[0] }, { null, previousSessionState1, APP_REDIRECT_URL, null, HttpServletResponse.SC_FOUND, returnValues[0] }, { opBrowserStateCookie, null, APP_REDIRECT_URL, null, HttpServletResponse.SC_FOUND, returnValues[0] }, }; } @Test(dataProvider = "provideOidcSessionData", groups = "testWithConnection") public void testManageOIDCSessionState(Object cookieObject, Object sessionStateObject, String callbackUrl, String responseMode, int expectedStatus, String expectedResult) throws Exception { Cookie opBrowserStateCookie = (Cookie) cookieObject; Cookie newOpBrowserStateCookie = new Cookie("opbs", "f6454r678776gffdgdsfafa"); OIDCSessionState previousSessionState = (OIDCSessionState) sessionStateObject; AuthenticationResult result = setAuthenticationResult(true, null, null, null, null); Map<String, String[]> requestParams = new HashMap<>(); Map<String, Object> requestAttributes = new HashMap<>(); requestParams.put(CLIENT_ID, new String[] { CLIENT_ID_VALUE }); requestParams.put(FrameworkConstants.RequestParams.TO_COMMONAUTH, new String[] { "false" }); requestParams.put(OAuthConstants.OAuth20Params.SCOPE, new String[] { OAuthConstants.Scope.OPENID }); requestParams.put(OAuthConstants.OAuth20Params.PROMPT, new String[] { OAuthConstants.Prompt.LOGIN }); requestAttributes.put(FrameworkConstants.RequestParams.FLOW_STATUS, AuthenticatorFlowStatus.INCOMPLETE); requestAttributes.put(FrameworkConstants.SESSION_DATA_KEY, SESSION_DATA_KEY_VALUE); requestAttributes.put(FrameworkConstants.RequestAttribute.AUTH_RESULT, result); mockHttpRequest(requestParams, requestAttributes, HttpMethod.POST); OAuth2Parameters oAuth2Params = setOAuth2Parameters( new HashSet<>(Arrays.asList(OAuthConstants.Scope.OPENID)), APP_NAME, responseMode, APP_REDIRECT_URL); oAuth2Params.setClientId(CLIENT_ID_VALUE); oAuth2Params.setPrompt(OAuthConstants.Prompt.LOGIN); mockOAuthServerConfiguration(); mockEndpointUtil(); when(oAuthServerConfiguration.getOpenIDConnectSkipeUserConsentConfig()).thenReturn(true); OAuth2AuthorizeRespDTO authzRespDTO = new OAuth2AuthorizeRespDTO(); authzRespDTO.setCallbackURI(callbackUrl); when(oAuth2Service.authorize(any(OAuth2AuthorizeReqDTO.class))).thenReturn(authzRespDTO); mockStatic(OAuth2Util.OAuthURL.class); when(OAuth2Util.OAuthURL.getOAuth2ErrorPageUrl()).thenReturn(ERROR_PAGE_URL); mockStatic(OIDCSessionManagementUtil.class); when(OIDCSessionManagementUtil.getOPBrowserStateCookie(any(HttpServletRequest.class))) .thenReturn(opBrowserStateCookie); when(OIDCSessionManagementUtil.addOPBrowserStateCookie(any(HttpServletResponse.class))) .thenReturn(newOpBrowserStateCookie); when(OIDCSessionManagementUtil.getSessionManager()).thenReturn(oidcSessionManager); when(oidcSessionManager.getOIDCSessionState(anyString())).thenReturn(previousSessionState); when(OIDCSessionManagementUtil.getSessionStateParam(anyString(), anyString(), anyString())) .thenReturn("sessionStateValue"); when(OIDCSessionManagementUtil.addSessionStateToURL(anyString(), anyString(), anyString())) .thenCallRealMethod(); mockStatic(SessionDataCache.class); when(SessionDataCache.getInstance()).thenReturn(sessionDataCache); SessionDataCacheKey loginDataCacheKey = new SessionDataCacheKey(SESSION_DATA_KEY_VALUE); when(sessionDataCache.getValueFromCache(loginDataCacheKey)).thenReturn(loginCacheEntry); when(loginCacheEntry.getoAuth2Parameters()).thenReturn(oAuth2Params); when(loginCacheEntry.getLoggedInUser()).thenReturn(result.getSubject()); mockStatic(IdentityDatabaseUtil.class); when(IdentityDatabaseUtil.getDBConnection()).thenReturn(connection); mockStatic(OpenIDConnectUserRPStore.class); when(OpenIDConnectUserRPStore.getInstance()).thenReturn(openIDConnectUserRPStore); when(openIDConnectUserRPStore.hasUserApproved(any(AuthenticatedUser.class), anyString(), anyString())) .thenReturn(true); when(oAuth2Service.getOauthApplicationState(CLIENT_ID_VALUE)).thenReturn("ACTIVE"); mockApplicationManagementService(); Response response; try { response = oAuth2AuthzEndpoint.authorize(httpServletRequest, httpServletResponse); } catch (InvalidRequestParentException ire) { InvalidRequestExceptionMapper invalidRequestExceptionMapper = new InvalidRequestExceptionMapper(); response = invalidRequestExceptionMapper.toResponse(ire); } assertNotNull(response, "Authorization response is null"); assertEquals(response.getStatus(), expectedStatus, "Unexpected HTTP response status"); MultivaluedMap<String, Object> responseMetadata = response.getMetadata(); assertNotNull(responseMetadata, "Response metadata is null"); if (response.getStatus() != HttpServletResponse.SC_OK) { assertTrue(CollectionUtils.isNotEmpty(responseMetadata.get(HTTPConstants.HEADER_LOCATION)), "Location header not found in the response"); String location = (String) responseMetadata.get(HTTPConstants.HEADER_LOCATION).get(0); assertTrue(location.contains(expectedResult), "Expected redirect URL is not returned"); } else { assertTrue(response.getEntity().toString().contains(expectedResult), "Expected redirect URL is not returned"); } } private void mockApplicationManagementService() throws IdentityApplicationManagementException { mockApplicationManagementService(new ServiceProvider()); } private void mockApplicationManagementService(ServiceProvider sp) throws IdentityApplicationManagementException { ApplicationManagementService appMgtService = mock(ApplicationManagementService.class); when(appMgtService.getServiceProviderByClientId(anyString(), anyString(), anyString())).thenReturn(sp); OAuth2ServiceComponentHolder.setApplicationMgtService(appMgtService); } @DataProvider(name = "providePathExistsData") public Object[][] providePathExistsData() { return new Object[][] { { System.getProperty(CarbonBaseConstants.CARBON_HOME), true }, { "carbon_home", false } }; } @Test(dataProvider = "providePathExistsData") public void testGetFormPostRedirectPage(String carbonHome, boolean fileExists) throws Exception { spy(CarbonUtils.class); doReturn(carbonHome).when(CarbonUtils.class, "getCarbonHome"); Method getFormPostRedirectPage = authzEndpointObject.getClass() .getDeclaredMethod("getFormPostRedirectPage"); getFormPostRedirectPage.setAccessible(true); String value = (String) getFormPostRedirectPage.invoke(authzEndpointObject); assertEquals((value != null), fileExists, "FormPostRedirectPage value is incorrect"); Field formPostRedirectPage = authzEndpointObject.getClass().getDeclaredField("formPostRedirectPage"); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(formPostRedirectPage, formPostRedirectPage.getModifiers() & ~Modifier.FINAL); formPostRedirectPage.setAccessible(true); formPostRedirectPage.set(authzEndpointObject, value); Method createFormPage = authzEndpointObject.getClass().getDeclaredMethod("createFormPage", String.class, String.class, String.class, String.class); createFormPage.setAccessible(true); value = (String) createFormPage.invoke(authzEndpointObject, APP_REDIRECT_URL_JSON, APP_REDIRECT_URL, StringUtils.EMPTY, "sessionDataValue"); assertNotNull(value, "Form post page is null"); } @DataProvider(name = "provideSendRequestToFrameworkData") public Object[][] provideSendRequestToFrameworkData() { return new Object[][] { { null }, { AuthenticatorFlowStatus.SUCCESS_COMPLETED }, { AuthenticatorFlowStatus.INCOMPLETE } }; } @Test(dataProvider = "provideSendRequestToFrameworkData") public void testSendRequestToFramework(Object flowStatusObject) throws Exception { AuthenticatorFlowStatus flowStatus = (AuthenticatorFlowStatus) flowStatusObject; Map<String, String[]> requestParams = new HashMap<>(); Map<String, Object> requestAttributes = new HashMap<>(); requestAttributes.put(FrameworkConstants.RequestParams.FLOW_STATUS, flowStatus); mockHttpRequest(requestParams, requestAttributes, HttpMethod.POST); final String[] redirectUrl = new String[1]; doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) { String key = (String) invocation.getArguments()[0]; redirectUrl[0] = key; return null; } }).when(httpServletResponse).sendRedirect(anyString()); spy(FrameworkUtils.class); doReturn(requestCoordinator).when(FrameworkUtils.class, "getRequestCoordinator"); doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) { return null; } }).when(requestCoordinator).handle(any(HttpServletRequest.class), any(HttpServletResponse.class)); mockOAuthServerConfiguration(); mockStatic(OAuth2Util.OAuthURL.class); when(OAuth2Util.OAuthURL.getOAuth2ErrorPageUrl()).thenReturn(ERROR_PAGE_URL); Method sendRequestToFramework = authzEndpointObject.getClass() .getDeclaredMethod("handleAuthFlowThroughFramework", OAuthMessage.class, String.class); sendRequestToFramework.setAccessible(true); when(oAuthMessage.getRequest()).thenReturn(httpServletRequest); when(oAuthMessage.getResponse()).thenReturn(httpServletResponse); Response response; try { response = (Response) sendRequestToFramework.invoke(authzEndpointObject, oAuthMessage, "type"); } catch (Exception ire) { InvalidRequestExceptionMapper invalidRequestExceptionMapper = new InvalidRequestExceptionMapper(); response = invalidRequestExceptionMapper.toResponse((InvalidRequestParentException) ire.getCause()); } assertNotNull(response, "Returned response is null"); requestAttributes.put(FrameworkConstants.RequestParams.FLOW_STATUS, flowStatus); mockHttpRequest(requestParams, requestAttributes, HttpMethod.POST); when(oAuthMessage.getRequest()).thenReturn(httpServletRequest); when(oAuthMessage.getResponse()).thenReturn(httpServletResponse); Method sendRequestToFramework2 = authzEndpointObject.getClass() .getDeclaredMethod("handleAuthFlowThroughFramework", OAuthMessage.class, String.class); sendRequestToFramework2.setAccessible(true); try { response = (Response) sendRequestToFramework.invoke(authzEndpointObject, oAuthMessage, "type"); } catch (Exception ire) { InvalidRequestExceptionMapper invalidRequestExceptionMapper = new InvalidRequestExceptionMapper(); response = invalidRequestExceptionMapper.toResponse((InvalidRequestParentException) ire.getCause()); } assertNotNull(response, "Returned response is null"); } @DataProvider(name = "provideAuthenticatedTimeFromCommonAuthData") public Object[][] provideAuthenticatedTimeFromCommonAuthData() { return new Object[][] { { new SessionContext(), 1479249799770L, 1479249798770L }, { new SessionContext(), null, 1479249798770L }, { null, null, 1479249798770L } }; } @Test(dataProvider = "provideAuthenticatedTimeFromCommonAuthData") public void testGetAuthenticatedTimeFromCommonAuthCookie(Object sessionContextObject, Object updatedTimestamp, Object createdTimeStamp) throws Exception { SessionContext sessionContext = (SessionContext) sessionContextObject; Cookie commonAuthCookie = new Cookie(FrameworkConstants.COMMONAUTH_COOKIE, "32414141346576"); if (sessionContext != null) { sessionContext.addProperty(FrameworkConstants.UPDATED_TIMESTAMP, updatedTimestamp); sessionContext.addProperty(FrameworkConstants.CREATED_TIMESTAMP, createdTimeStamp); } mockStatic(FrameworkUtils.class); when(FrameworkUtils.getSessionContextFromCache(anyString())).thenReturn(sessionContext); Method getAuthenticatedTimeFromCommonAuthCookie = authzEndpointObject.getClass() .getDeclaredMethod("getAuthenticatedTimeFromCommonAuthCookie", Cookie.class); getAuthenticatedTimeFromCommonAuthCookie.setAccessible(true); long timestamp = (long) getAuthenticatedTimeFromCommonAuthCookie.invoke(authzEndpointObject, commonAuthCookie); if (sessionContext == null) { assertEquals(timestamp, 0, "Authenticated time should be 0 when session context is null"); } else if (updatedTimestamp != null) { assertEquals(timestamp, Long.parseLong(updatedTimestamp.toString()), "session context updated time should be equal to the authenticated time"); } else { assertEquals(timestamp, Long.parseLong(createdTimeStamp.toString()), "session context created time should be equal to the authenticated time"); } } @DataProvider(name = "provideGetServiceProviderData") public Object[][] provideGetServiceProviderData() { return new Object[][] { { CLIENT_ID_VALUE, null }, { CLIENT_ID_VALUE, new IdentityOAuth2Exception("Error") }, { "invalidId", null }, }; } @Test(dataProvider = "provideGetServiceProviderData", groups = "testWithConnection") public void testGetServiceProvider(String clientId, Exception e) throws Exception { Method getServiceProvider = authzEndpointObject.getClass().getDeclaredMethod("getServiceProvider", String.class); getServiceProvider.setAccessible(true); ServiceProvider sp = new ServiceProvider(); sp.setApplicationName(APP_NAME); mockOAuthServerConfiguration(); mockEndpointUtil(); mockApplicationManagementService(sp); mockStatic(IdentityTenantUtil.class); when(IdentityTenantUtil.getTenantDomain(anyInt())) .thenReturn(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); try (Connection connection = getConnection()) { mockStatic(IdentityDatabaseUtil.class); when(IdentityDatabaseUtil.getDBConnection()).thenReturn(connection); if (e instanceof IdentityOAuth2Exception) { when(tokenPersistenceProcessor.getPreprocessedClientSecret(anyString())).thenThrow(e); } try { ServiceProvider result = (ServiceProvider) getServiceProvider.invoke(authzEndpointObject, clientId); assertEquals(result.getApplicationName(), APP_NAME); } catch (Exception e1) { if (e == null && CLIENT_ID_VALUE.equals(clientId)) { fail("Unexpected Exception"); } } } } @DataProvider(name = "provideHandleOAuthAuthorizationRequest1Data") public Object[][] provideHandleOAuthAuthorizationRequest1Data() { ServiceProvider sp1 = new ServiceProvider(); ServiceProvider sp2 = new ServiceProvider(); ServiceProvider sp3 = new ServiceProvider(); ServiceProviderProperty property1 = new ServiceProviderProperty(); property1.setName(SP_DISPLAY_NAME); property1.setValue("myApplication"); ServiceProviderProperty property2 = new ServiceProviderProperty(); property2.setName(SP_NAME); property2.setValue(APP_NAME); ServiceProviderProperty[] properties1 = new ServiceProviderProperty[] { property1, property2 }; sp1.setSpProperties(properties1); ServiceProviderProperty[] properties2 = new ServiceProviderProperty[] { property2 }; sp2.setSpProperties(properties2); return new Object[][] { { true, sp1, "myApplication" }, { true, sp2, null }, { true, sp3, null }, { false, sp1, null }, }; } @Test(dataProvider = "provideHandleOAuthAuthorizationRequest1Data", groups = "testWithConnection") public void testHandleOAuthAuthorizationRequest1(boolean showDisplayName, Object spObj, String savedDisplayName) throws Exception { ServiceProvider sp = (ServiceProvider) spObj; sp.setApplicationName(APP_NAME); mockApplicationManagementService(sp); mockOAuthServerConfiguration(); mockEndpointUtil(); mockStatic(IdentityTenantUtil.class); when(IdentityTenantUtil.getTenantDomain(anyInt())) .thenReturn(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); mockStatic(IdentityDatabaseUtil.class); when(IdentityDatabaseUtil.getDBConnection()).thenReturn(connection); Map<String, String[]> requestParams = new HashMap(); Map<String, Object> requestAttributes = new HashMap(); requestParams.put(CLIENT_ID, new String[] { CLIENT_ID_VALUE }); requestParams.put(REDIRECT_URI, new String[] { APP_REDIRECT_URL }); requestParams.put(OAuth.OAUTH_RESPONSE_TYPE, new String[] { ResponseType.TOKEN.toString() }); mockHttpRequest(requestParams, requestAttributes, HttpMethod.POST); OAuth2ClientValidationResponseDTO validationResponseDTO = new OAuth2ClientValidationResponseDTO(); validationResponseDTO.setValidClient(true); validationResponseDTO.setCallbackURL(APP_REDIRECT_URL); when(oAuth2Service.validateClientInfo(anyString(), anyString())).thenReturn(validationResponseDTO); Map<String, Class<? extends OAuthValidator<HttpServletRequest>>> responseTypeValidators = new Hashtable<>(); responseTypeValidators.put(ResponseType.CODE.toString(), CodeValidator.class); responseTypeValidators.put(ResponseType.TOKEN.toString(), TokenValidator.class); when(oAuthServerConfiguration.getSupportedResponseTypeValidators()).thenReturn(responseTypeValidators); when(oAuthServerConfiguration.isShowDisplayNameInConsentPage()).thenReturn(showDisplayName); Method handleOAuthAuthorizationRequest = authzEndpointObject.getClass() .getDeclaredMethod("handleOAuthAuthorizationRequest", OAuthMessage.class); handleOAuthAuthorizationRequest.setAccessible(true); SessionDataCache sessionDataCache = mock(SessionDataCache.class); mockStatic(SessionDataCache.class); when(SessionDataCache.getInstance()).thenReturn(sessionDataCache); final SessionDataCacheEntry[] cacheEntry = new SessionDataCacheEntry[1]; doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) { cacheEntry[0] = (SessionDataCacheEntry) invocation.getArguments()[1]; return null; } }).when(sessionDataCache).addToCache(any(SessionDataCacheKey.class), any(SessionDataCacheEntry.class)); when(oAuthMessage.getRequest()).thenReturn(httpServletRequest); when(oAuthMessage.getClientId()).thenReturn(CLIENT_ID_VALUE); handleOAuthAuthorizationRequest.invoke(authzEndpointObject, oAuthMessage); assertNotNull(cacheEntry[0], "Parameters not saved in cache"); assertEquals(cacheEntry[0].getoAuth2Parameters().getDisplayName(), savedDisplayName); } @Test(dependsOnGroups = "testWithConnection") public void testIdentityOAuthAdminException() throws Exception { //OAuthAdminException will not occur due to introduce a new Service to get the App State instead directly use // dao Map<String, String[]> requestParams = new HashMap<>(); Map<String, Object> requestAttributes = new HashMap<>(); requestParams.put(CLIENT_ID, new String[] { CLIENT_ID_VALUE }); requestParams.put(FrameworkConstants.RequestParams.TO_COMMONAUTH, new String[] { "false" }); requestAttributes.put(FrameworkConstants.RequestParams.FLOW_STATUS, AuthenticatorFlowStatus.SUCCESS_COMPLETED); mockHttpRequest(requestParams, requestAttributes, HttpMethod.POST); mockOAuthServerConfiguration(); mockStatic(IdentityDatabaseUtil.class); when(IdentityDatabaseUtil.getDBConnection()).thenReturn(connection); connection.close(); // Closing connection to create SQLException mockEndpointUtil(); mockStatic(OAuth2Util.OAuthURL.class); when(OAuth2Util.OAuthURL.getOAuth2ErrorPageUrl()).thenReturn(ERROR_PAGE_URL); when(oAuth2Service.getOauthApplicationState(CLIENT_ID_VALUE)).thenReturn("ACTIVE"); Response response; try { response = oAuth2AuthzEndpoint.authorize(httpServletRequest, httpServletResponse); } catch (InvalidRequestParentException ire) { InvalidRequestExceptionMapper invalidRequestExceptionMapper = new InvalidRequestExceptionMapper(); response = invalidRequestExceptionMapper.toResponse(ire); } assertEquals(response.getStatus(), HttpServletResponse.SC_FOUND); } private void mockHttpRequest(final Map<String, String[]> requestParams, final Map<String, Object> requestAttributes, String method) { doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) { String key = (String) invocation.getArguments()[0]; return requestParams.get(key) != null ? requestParams.get(key)[0] : null; } }).when(httpServletRequest).getParameter(anyString()); doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) { String key = (String) invocation.getArguments()[0]; return requestAttributes.get(key); } }).when(httpServletRequest).getAttribute(anyString()); doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) { String key = (String) invocation.getArguments()[0]; Object value = invocation.getArguments()[1]; requestAttributes.put(key, value); return null; } }).when(httpServletRequest).setAttribute(anyString(), Matchers.anyObject()); when(httpServletRequest.getParameterMap()).thenReturn(requestParams); when(httpServletRequest.getParameterNames()) .thenReturn(Collections.enumeration(requestAttributes.keySet())); when(httpServletRequest.getSession()).thenReturn(httpSession); when(httpServletRequest.getMethod()).thenReturn(method); when(httpServletRequest.getContentType()).thenReturn(OAuth.ContentType.URL_ENCODED); String authHeader = "Basic Y2ExOWE1NDBmNTQ0Nzc3ODYwZTQ0ZTc1ZjYwNWQ5Mjc6ODduOWE1NDBmNTQ0Nzc3ODYwZTQ0ZTc1ZjYwNWQ0MzU="; when(httpServletRequest.getHeader("Authorization")).thenReturn(authHeader); } private void mockEndpointUtil() throws Exception { spy(EndpointUtil.class); doReturn(oAuth2Service).when(EndpointUtil.class, "getOAuth2Service"); doReturn(oAuthServerConfiguration).when(EndpointUtil.class, "getOAuthServerConfiguration"); doReturn(USER_CONSENT_URL).when(EndpointUtil.class, "getUserConsentURL", any(OAuth2Parameters.class), anyString(), anyString(), anyBoolean()); doReturn(LOGIN_PAGE_URL).when(EndpointUtil.class, "getLoginPageURL", anyString(), anyString(), anyBoolean(), anyBoolean(), anySet(), anyMap()); doReturn(requestObjectService).when(EndpointUtil.class, "getRequestObjectService"); // TODO: Remove mocking consentUtil and test the consent flow as well // https://github.com/wso2/product-is/issues/2679 SSOConsentService ssoConsentService = mock(SSOConsentService.class); when(ssoConsentService.getConsentRequiredClaimsWithExistingConsents(any(ServiceProvider.class), any(AuthenticatedUser.class))).thenReturn(new ConsentClaimsData()); when(ssoConsentService.getConsentRequiredClaimsWithoutExistingConsents(any(ServiceProvider.class), any(AuthenticatedUser.class))).thenReturn(new ConsentClaimsData()); doReturn(ssoConsentService).when(EndpointUtil.class, "getSSOConsentService"); } private AuthenticationResult setAuthenticationResult(boolean isAuthenticated, Map<ClaimMapping, String> attributes, String errorCode, String errorMsg, String errorUri) { AuthenticationResult authResult = new AuthenticationResult(); authResult.setAuthenticated(isAuthenticated); if (!isAuthenticated) { authResult.addProperty(FrameworkConstants.AUTH_ERROR_CODE, errorCode); authResult.addProperty(FrameworkConstants.AUTH_ERROR_MSG, errorMsg); authResult.addProperty(FrameworkConstants.AUTH_ERROR_URI, errorUri); } AuthenticatedUser subject = new AuthenticatedUser(); subject.setAuthenticatedSubjectIdentifier(USERNAME); subject.setUserName(USERNAME); subject.setUserAttributes(attributes); authResult.setSubject(subject); return authResult; } private OAuth2Parameters setOAuth2Parameters(Set<String> scopes, String appName, String responseMode, String redirectUri) { OAuth2Parameters oAuth2Parameters = new OAuth2Parameters(); oAuth2Parameters.setScopes(scopes); oAuth2Parameters.setResponseMode(responseMode); oAuth2Parameters.setRedirectURI(redirectUri); oAuth2Parameters.setApplicationName(appName); return oAuth2Parameters; } private void mockOAuthServerConfiguration() throws Exception { mockStatic(OAuthServerConfiguration.class); when(OAuthServerConfiguration.getInstance()).thenReturn(oAuthServerConfiguration); when(oAuthServerConfiguration.getPersistenceProcessor()).thenReturn(tokenPersistenceProcessor); when(tokenPersistenceProcessor.getProcessedClientId(anyString())).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) { return invocation.getArguments()[0]; } }); } }