From 6494d89eb103f7e29e462f3d1fe0e0c6f9d00873 Mon Sep 17 00:00:00 2001 From: Hasanthi Dissanayake Date: Fri, 13 Oct 2023 12:13:34 +0530 Subject: [PATCH] Modify the OIDC Authenticator to support for the API Based Authentication --- .../oidc/OIDCAuthenticatorConstants.java | 6 ++ .../oidc/OpenIDConnectAuthenticator.java | 66 ++++++++++++++++++- .../oidc/OpenIDConnectAuthenticatorTest.java | 46 +++++++++++++ pom.xml | 2 +- 4 files changed, 118 insertions(+), 2 deletions(-) diff --git a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/OIDCAuthenticatorConstants.java b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/OIDCAuthenticatorConstants.java index 817aecbd..55ae0539 100644 --- a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/OIDCAuthenticatorConstants.java +++ b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/OIDCAuthenticatorConstants.java @@ -59,6 +59,12 @@ private OIDCAuthenticatorConstants() { public static final Pattern OIDC_BACKCHANNEL_LOGOUT_ENDPOINT_URL_PATTERN = Pattern.compile("(.*)/identity/oidc" + "/slo(.*)"); public static final String OIDC_FEDERATION_NONCE = "oidc_federation_nonce"; + public static final String AUTHENTICATOR_OIDC = "authenticator.oidc"; + public static final String REQUIRED_PARAMS = "required_params"; + public static final String REDIRECT_URL = "redirect_url"; + public static final String ADDITIONAL_DATA = "_additional_data"; + public static final String PROMPT_TYPE = "prompt_type"; + public static final String REDIRECTION_PROMPT = "REDIRECTION_PROMPT"; public class AuthenticatorConfParams { diff --git a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/OpenIDConnectAuthenticator.java b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/OpenIDConnectAuthenticator.java index 6eadf354..e2032448 100644 --- a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/OpenIDConnectAuthenticator.java +++ b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/OpenIDConnectAuthenticator.java @@ -43,6 +43,7 @@ import org.wso2.carbon.identity.application.authentication.framework.exception.AuthenticationFailedException; import org.wso2.carbon.identity.application.authentication.framework.exception.LogoutFailedException; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatorData; 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.authenticator.oidc.internal.OpenIDConnectAuthenticatorDataHolder; @@ -84,6 +85,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -91,11 +93,17 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.ADDITIONAL_DATA; +import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.OIDC_FEDERATION_NONCE; +import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.AUTHENTICATOR_OIDC; +import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.REQUIRED_PARAMS; +import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.REDIRECT_URL; +import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.PROMPT_TYPE; +import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.REDIRECTION_PROMPT; import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.Claim.NONCE; import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.LogConstants.ActionIDs.PROCESS_AUTHENTICATION_RESPONSE; import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.LogConstants.ActionIDs.INITIATE_OUTBOUND_AUTH_REQUEST; import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.LogConstants.OUTBOUND_AUTH_OIDC_SERVICE; -import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.OIDC_FEDERATION_NONCE; import static org.wso2.carbon.identity.base.IdentityConstants.FEDERATED_IDP_SESSION_ID; public class OpenIDConnectAuthenticator extends AbstractApplicationAuthenticator @@ -493,6 +501,7 @@ protected void initiateAuthenticationRequest(HttpServletRequest request, HttpSer loginPage = loginPage + queryString; } } + context.setProperty(OIDCAuthenticatorConstants.AUTHENTICATOR_NAME + ADDITIONAL_DATA, loginPage); response.sendRedirect(loginPage); if (LoggerUtils.isDiagnosticLogsEnabled() && diagnosticLogBuilder != null) { diagnosticLogBuilder.resultMessage("Redirecting to the federated IDP login page."); @@ -648,6 +657,17 @@ protected void processAuthenticationResponse(HttpServletRequest request, HttpSer } } + /** + * Get the i18n key defined to represent the authenticator name. + * + * @return the 118n key. + */ + @Override + public String getI18nKey() { + + return AUTHENTICATOR_OIDC; + } + /** * Retrieves or maps the ID token according to the flow supported by the authenticator. * Overridden in Google Authenticator for Google one tap. @@ -1116,6 +1136,50 @@ public List getConfigurationProperties() { return configProperties; } + /** + * This method is responsible for validating whether the authenticator is supported for API Based Authentication. + * + * @return true if the authenticator is supported for API Based Authentication. + */ + @Override + public boolean isAPIBasedAuthenticationSupported() { + + return true; + } + + /** + * This method is responsible for obtaining authenticator-specific data needed to + * initialize the authentication process within the provided authentication context. + * + * @param context The authentication context containing information about the current authentication attempt. + * @return An {@code Optional} containing an {@code AuthenticatorData} object representing the initiation data. + * If the initiation data is available, it is encapsulated within the {@code Optional}; otherwise, + * an empty {@code Optional} is returned. + */ + @Override + public Optional getAuthInitiationData(AuthenticationContext context) { + + AuthenticatorData authenticatorData = new AuthenticatorData(); + authenticatorData.setName(getName()); + authenticatorData.setDisplayName(getFriendlyName()); + authenticatorData.setI18nKey(getI18nKey()); + String idpName = context.getExternalIdP().getIdPName(); + authenticatorData.setIdp(idpName); + + List requiredParameterList = new ArrayList<>(); + requiredParameterList.add(OIDCAuthenticatorConstants.OAUTH2_GRANT_TYPE_CODE); + requiredParameterList.add(OIDCAuthenticatorConstants.OAUTH2_PARAM_STATE); + + Map additionalData = new HashMap<>(); + additionalData.put(REQUIRED_PARAMS, requiredParameterList.toString()); + additionalData.put(REDIRECT_URL, + (String) context.getProperty(OIDCAuthenticatorConstants.AUTHENTICATOR_NAME + ADDITIONAL_DATA)); + additionalData.put(PROMPT_TYPE, REDIRECTION_PROMPT); + authenticatorData.setAdditionalData(additionalData); + + return Optional.of(authenticatorData); + } + /** * @subject */ diff --git a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/test/java/org/wso2/carbon/identity/application/authenticator/oidc/OpenIDConnectAuthenticatorTest.java b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/test/java/org/wso2/carbon/identity/application/authenticator/oidc/OpenIDConnectAuthenticatorTest.java index 72863c82..e414b4d8 100644 --- a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/test/java/org/wso2/carbon/identity/application/authenticator/oidc/OpenIDConnectAuthenticatorTest.java +++ b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/test/java/org/wso2/carbon/identity/application/authenticator/oidc/OpenIDConnectAuthenticatorTest.java @@ -43,6 +43,8 @@ import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; import org.wso2.carbon.identity.application.authentication.framework.exception.AuthenticationFailedException; import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticationRequest; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatorData; 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.authenticator.oidc.internal.OpenIDConnectAuthenticatorDataHolder; @@ -67,7 +69,10 @@ import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; import java.util.Map; +import java.util.Optional; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -85,6 +90,7 @@ import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.OIDC_FEDERATION_NONCE; +import static org.wso2.carbon.identity.application.authenticator.oidc.OIDCAuthenticatorConstants.REDIRECTION_PROMPT; /*** * Unit test class for OpenIDConnectAuthenticatorTest class. @@ -171,6 +177,7 @@ public class OpenIDConnectAuthenticatorTest extends PowerMockTestCase { private static OAuthClientResponse token; private Map paramValueMap; private int TENANT_ID = 1234; + private AuthenticationRequest mockAuthenticationRequest = new AuthenticationRequest(); @BeforeTest public void init() { @@ -706,6 +713,45 @@ private void mockAuthenticationRequestContext(AuthenticationContext mockAuthenti when(mockAuthenticationContext.getProperty("oidc:param.map")).thenReturn(paramValueMap); when(mockAuthenticationContext.getContextIdentifier()).thenReturn(""); when(mockAuthenticationContext.getExternalIdP()).thenReturn(getDummyExternalIdPConfig()); + when(mockAuthenticationContext.getAuthenticationRequest()).thenReturn(mockAuthenticationRequest); + } + + @Test + public void testIsAPIBasedAuthenticationSupported() { + + boolean isAPIBasedAuthenticationSupported = openIDConnectAuthenticator.isAPIBasedAuthenticationSupported(); + Assert.assertTrue(isAPIBasedAuthenticationSupported); + } + + @Test + public void testGetAuthInitiationData() { + + when(mockAuthenticationContext.getExternalIdP()).thenReturn(externalIdPConfig); + when(externalIdPConfig.getIdPName()).thenReturn("LOCAL"); + when(mockAuthenticationContext.getAuthenticationRequest()).thenReturn(mockAuthenticationRequest); + Optional authenticatorData = openIDConnectAuthenticator.getAuthInitiationData + (mockAuthenticationContext); + + List requiredParameterList = new ArrayList<>(); + requiredParameterList.add(OIDCAuthenticatorConstants.OAUTH2_GRANT_TYPE_CODE); + requiredParameterList.add(OIDCAuthenticatorConstants.OAUTH2_PARAM_STATE); + + Map additionalData = new HashMap<>(); + additionalData.put(OIDCAuthenticatorConstants.REQUIRED_PARAMS, requiredParameterList.toString()); + additionalData.put(OIDCAuthenticatorConstants.PROMPT_TYPE, REDIRECTION_PROMPT); + + Assert.assertTrue(authenticatorData.isPresent()); + AuthenticatorData authenticatorDataObj = authenticatorData.get(); + authenticatorDataObj.setAdditionalData(additionalData); + Assert.assertEquals(authenticatorDataObj.getName(), "OpenIDConnectAuthenticator"); + Assert.assertEquals(authenticatorDataObj.getI18nKey(), "authenticator.oidc"); + Assert.assertEquals(authenticatorDataObj.getDisplayName(), "openidconnect"); + + // Iterate through the map and assert values + for (Map.Entry entry : additionalData.entrySet()) { + String key = entry.getKey(); + Assert.assertTrue(authenticatorDataObj.getAdditionalData().containsKey(key)); + } } private ExternalIdPConfig getDummyExternalIdPConfig() { diff --git a/pom.xml b/pom.xml index f752867f..b43c8e83 100644 --- a/pom.xml +++ b/pom.xml @@ -304,7 +304,7 @@ ${project.version} - 5.25.260 + 5.25.386 1.0.0.wso2v3 2.4.7 3.0.0.wso2v2