From fee04f66586f01c382b61a7b76d16158ddef797a Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 5 Apr 2024 13:27:02 +0530 Subject: [PATCH 1/4] Refactor login page creation in initiateAuthenticationRequest method. --- .../oidc/OpenIDConnectAuthenticator.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) 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 f266d1a4..a5225a8f 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2013-2024, WSO2 LLC. (http://www.wso2.com). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -449,6 +449,23 @@ protected Map getSubjectAttributes(OAuthClientResponse tok protected void initiateAuthenticationRequest(HttpServletRequest request, HttpServletResponse response, AuthenticationContext context) throws AuthenticationFailedException { + try { + String loginPage = prepareLoginPage(request, context); + response.sendRedirect(loginPage); + if (LoggerUtils.isDiagnosticLogsEnabled()) { + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( + getComponentId(), INITIATE_OUTBOUND_AUTH_REQUEST); + diagnosticLogBuilder.resultMessage("Redirecting to the federated IDP login page."); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } + } catch (IOException e) { + throw new AuthenticationFailedException(ErrorMessages.IO_ERROR.getCode(), e.getMessage(), e); + } + } + + protected String prepareLoginPage(HttpServletRequest request, AuthenticationContext context) + throws AuthenticationFailedException { + try { if (LoggerUtils.isDiagnosticLogsEnabled()) { DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( @@ -567,11 +584,7 @@ protected void initiateAuthenticationRequest(HttpServletRequest request, HttpSer } } context.setProperty(OIDCAuthenticatorConstants.AUTHENTICATOR_NAME + REDIRECT_URL_SUFFIX, loginPage); - response.sendRedirect(loginPage); - if (LoggerUtils.isDiagnosticLogsEnabled() && diagnosticLogBuilder != null) { - diagnosticLogBuilder.resultMessage("Redirecting to the federated IDP login page."); - LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); - } + return loginPage; } else { if (LOG.isDebugEnabled()) { LOG.debug(ErrorMessages.RETRIEVING_AUTHENTICATOR_PROPERTIES_FAILED.getMessage()); @@ -590,13 +603,10 @@ protected void initiateAuthenticationRequest(HttpServletRequest request, HttpSer throw new AuthenticationFailedException(ErrorMessages.BUILDING_AUTHORIZATION_CODE_REQUEST_FAILED.getCode(), e.getMessage(), e); - } catch (IOException e) { - throw new AuthenticationFailedException(ErrorMessages.IO_ERROR.getCode(), e.getMessage(), e); } catch (OAuthSystemException e) { throw new AuthenticationFailedException(ErrorMessages.BUILDING_AUTHORIZATION_CODE_REQUEST_FAILED.getCode(), e.getMessage(), e); } - return; } /** From 784af7df50b7baf09eceb2341ddb4cae6f5d0475 Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 5 Apr 2024 14:36:25 +0530 Subject: [PATCH 2/4] Resolve diagnostic log builders. --- .../oidc/OpenIDConnectAuthenticator.java | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) 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 a5225a8f..5c8a8cec 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 @@ -450,41 +450,43 @@ protected void initiateAuthenticationRequest(HttpServletRequest request, HttpSer AuthenticationContext context) throws AuthenticationFailedException { try { - String loginPage = prepareLoginPage(request, context); - response.sendRedirect(loginPage); + DiagnosticLog.DiagnosticLogBuilder flowCompletionDiagnosticLogBuilder = null; if (LoggerUtils.isDiagnosticLogsEnabled()) { - DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( + flowCompletionDiagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( getComponentId(), INITIATE_OUTBOUND_AUTH_REQUEST); - diagnosticLogBuilder.resultMessage("Redirecting to the federated IDP login page."); - LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + } + String loginPage = prepareLoginPage(request, context, flowCompletionDiagnosticLogBuilder); + response.sendRedirect(loginPage); + if (LoggerUtils.isDiagnosticLogsEnabled() && flowCompletionDiagnosticLogBuilder != null) { + flowCompletionDiagnosticLogBuilder.resultMessage("Redirecting to the federated IDP login page."); + LoggerUtils.triggerDiagnosticLogEvent(flowCompletionDiagnosticLogBuilder); } } catch (IOException e) { throw new AuthenticationFailedException(ErrorMessages.IO_ERROR.getCode(), e.getMessage(), e); } } - protected String prepareLoginPage(HttpServletRequest request, AuthenticationContext context) + protected String prepareLoginPage(HttpServletRequest request, AuthenticationContext context, + DiagnosticLog.DiagnosticLogBuilder flowCompletionDiagnosticLogBuilder) throws AuthenticationFailedException { try { if (LoggerUtils.isDiagnosticLogsEnabled()) { - DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( + DiagnosticLog.DiagnosticLogBuilder flowInitiationDiagnosticLogBuilder = + new DiagnosticLog.DiagnosticLogBuilder( getComponentId(), INITIATE_OUTBOUND_AUTH_REQUEST); - diagnosticLogBuilder.resultMessage("Initiate outbound OIDC authentication request.") + flowInitiationDiagnosticLogBuilder.resultMessage("Initiate outbound OIDC authentication request.") .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) .resultStatus(DiagnosticLog.ResultStatus.SUCCESS) .inputParam(LogConstants.InputKeys.STEP, context.getCurrentStep()) .inputParam(LogConstants.InputKeys.IDP, context.getExternalIdP().getIdPName()) .inputParams(getApplicationDetails(context)); - LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); + LoggerUtils.triggerDiagnosticLogEvent(flowInitiationDiagnosticLogBuilder); } Map authenticatorProperties = context.getAuthenticatorProperties(); if (authenticatorProperties != null) { - DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = null; if (LoggerUtils.isDiagnosticLogsEnabled()) { - diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder(getComponentId(), - INITIATE_OUTBOUND_AUTH_REQUEST); - diagnosticLogBuilder.logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + flowCompletionDiagnosticLogBuilder.logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) .resultStatus(DiagnosticLog.ResultStatus.SUCCESS) .inputParam(LogConstants.InputKeys.STEP, context.getCurrentStep()) .inputParam("authenticator properties", authenticatorProperties.keySet()) @@ -519,8 +521,8 @@ protected String prepareLoginPage(HttpServletRequest request, AuthenticationCont String queryString = getQueryString(authenticatorProperties); if (StringUtils.isNotBlank(scopes)) { - if (LoggerUtils.isDiagnosticLogsEnabled() && diagnosticLogBuilder != null) { - diagnosticLogBuilder.inputParam("scopes", scopes); + if (LoggerUtils.isDiagnosticLogsEnabled() && flowCompletionDiagnosticLogBuilder != null) { + flowCompletionDiagnosticLogBuilder.inputParam("scopes", scopes); } queryString += "&scope=" + scopes; } From 8598f8b2bdd7292af28a0ec31aff4a5e9bdf28e2 Mon Sep 17 00:00:00 2001 From: dhaura Date: Fri, 5 Apr 2024 17:10:31 +0530 Subject: [PATCH 3/4] Refactor diagnostic log builders. --- .../oidc/OIDCAuthenticatorConstants.java | 2 + .../oidc/OpenIDConnectAuthenticator.java | 75 +++++++++++++------ 2 files changed, 53 insertions(+), 24 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 ebc84f65..267c1665 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 @@ -81,6 +81,8 @@ private OIDCAuthenticatorConstants() { public static final String SCOPE_PARAM_SUFFIX = "_scope_param"; public static final String REDIRECTION_PROMPT = "REDIRECTION_PROMPT"; public static final String SCOPE = "scope"; + public static final String AMPERSAND_SIGN = "&"; + public static final String EQUAL_SIGN = "="; /** * This class holds the constants related to authenticator configuration parameters. 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 5c8a8cec..4716bb0b 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 @@ -93,6 +93,7 @@ import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; +import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.text.ParseException; @@ -450,49 +451,58 @@ protected void initiateAuthenticationRequest(HttpServletRequest request, HttpSer AuthenticationContext context) throws AuthenticationFailedException { try { - DiagnosticLog.DiagnosticLogBuilder flowCompletionDiagnosticLogBuilder = null; - if (LoggerUtils.isDiagnosticLogsEnabled()) { - flowCompletionDiagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = null; + if (LoggerUtils.isDiagnosticLogsEnabled() && context.getAuthenticatorProperties() != null) { + diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( getComponentId(), INITIATE_OUTBOUND_AUTH_REQUEST); + diagnosticLogBuilder.logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) + .resultStatus(DiagnosticLog.ResultStatus.SUCCESS) + .inputParam(LogConstants.InputKeys.STEP, context.getCurrentStep()) + .inputParam("authenticator properties", context.getAuthenticatorProperties().keySet()) + .inputParam(LogConstants.InputKeys.IDP, context.getExternalIdP().getIdPName()) + .inputParams(getApplicationDetails(context)); } - String loginPage = prepareLoginPage(request, context, flowCompletionDiagnosticLogBuilder); + + String loginPage = prepareLoginPage(request, context); response.sendRedirect(loginPage); - if (LoggerUtils.isDiagnosticLogsEnabled() && flowCompletionDiagnosticLogBuilder != null) { - flowCompletionDiagnosticLogBuilder.resultMessage("Redirecting to the federated IDP login page."); - LoggerUtils.triggerDiagnosticLogEvent(flowCompletionDiagnosticLogBuilder); + if (LoggerUtils.isDiagnosticLogsEnabled() && diagnosticLogBuilder != null) { + String scopes = extractScopesFromURL(loginPage); + if (StringUtils.isNotEmpty(scopes)) { + diagnosticLogBuilder.inputParam("scopes", scopes); + } + diagnosticLogBuilder.resultMessage("Redirecting to the federated IDP login page."); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); } } catch (IOException e) { throw new AuthenticationFailedException(ErrorMessages.IO_ERROR.getCode(), e.getMessage(), e); } } - protected String prepareLoginPage(HttpServletRequest request, AuthenticationContext context, - DiagnosticLog.DiagnosticLogBuilder flowCompletionDiagnosticLogBuilder) + /** + * Prepare the login page needed for initiating authentication request. + * + * @param request Http Servlet Request. + * @param context Authentication Context of the flow. + * @return Login page needed for initiating authentication request. + */ + protected String prepareLoginPage(HttpServletRequest request, AuthenticationContext context) throws AuthenticationFailedException { try { if (LoggerUtils.isDiagnosticLogsEnabled()) { - DiagnosticLog.DiagnosticLogBuilder flowInitiationDiagnosticLogBuilder = + DiagnosticLog.DiagnosticLogBuilder diagnosticLogBuilder = new DiagnosticLog.DiagnosticLogBuilder( getComponentId(), INITIATE_OUTBOUND_AUTH_REQUEST); - flowInitiationDiagnosticLogBuilder.resultMessage("Initiate outbound OIDC authentication request.") + diagnosticLogBuilder.resultMessage("Initiate outbound OIDC authentication request.") .logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) .resultStatus(DiagnosticLog.ResultStatus.SUCCESS) .inputParam(LogConstants.InputKeys.STEP, context.getCurrentStep()) .inputParam(LogConstants.InputKeys.IDP, context.getExternalIdP().getIdPName()) .inputParams(getApplicationDetails(context)); - LoggerUtils.triggerDiagnosticLogEvent(flowInitiationDiagnosticLogBuilder); + LoggerUtils.triggerDiagnosticLogEvent(diagnosticLogBuilder); } Map authenticatorProperties = context.getAuthenticatorProperties(); if (authenticatorProperties != null) { - if (LoggerUtils.isDiagnosticLogsEnabled()) { - flowCompletionDiagnosticLogBuilder.logDetailLevel(DiagnosticLog.LogDetailLevel.APPLICATION) - .resultStatus(DiagnosticLog.ResultStatus.SUCCESS) - .inputParam(LogConstants.InputKeys.STEP, context.getCurrentStep()) - .inputParam("authenticator properties", authenticatorProperties.keySet()) - .inputParam(LogConstants.InputKeys.IDP, context.getExternalIdP().getIdPName()) - .inputParams(getApplicationDetails(context)); - } String clientId = authenticatorProperties.get(OIDCAuthenticatorConstants.CLIENT_ID); String authorizationEP = getOIDCAuthzEndpoint(authenticatorProperties); String callbackurl = getCallbackUrl(authenticatorProperties); @@ -521,9 +531,6 @@ protected String prepareLoginPage(HttpServletRequest request, AuthenticationCont String queryString = getQueryString(authenticatorProperties); if (StringUtils.isNotBlank(scopes)) { - if (LoggerUtils.isDiagnosticLogsEnabled() && flowCompletionDiagnosticLogBuilder != null) { - flowCompletionDiagnosticLogBuilder.inputParam("scopes", scopes); - } queryString += "&scope=" + scopes; } queryString = interpretQueryString(context, queryString, request.getParameterMap()); @@ -2050,7 +2057,7 @@ private AuthenticatorFlowStatus processLogout(HttpServletRequest request, HttpSe * @param context Authentication context. * @return Map of application details. */ - private Map getApplicationDetails(AuthenticationContext context) { + protected Map getApplicationDetails(AuthenticationContext context) { Map applicationDetailsMap = new HashMap<>(); FrameworkUtils.getApplicationResourceId(context).ifPresent(applicationId -> @@ -2061,6 +2068,26 @@ private Map getApplicationDetails(AuthenticationContext context) return applicationDetailsMap; } + /** + * Extract query param scopes from a given url. + * + * @param url Given url. + * @return Extracted scopes as a String. + */ + protected String extractScopesFromURL(String url) throws UnsupportedEncodingException { + + if (StringUtils.isNotBlank(url)) { + String[] params = url.split(OIDCAuthenticatorConstants.AMPERSAND_SIGN); + for (String param : params) { + String[] keyValue = param.split(OIDCAuthenticatorConstants.EQUAL_SIGN); + if (keyValue.length >= 2 && OAuthConstants.OAuth20Params.SCOPE.equals(keyValue[0])) { + return URLDecoder.decode(param, FrameworkUtils.UTF_8); + } + } + } + return StringUtils.EMPTY; + } + private static List getUserAttributeClaimMappingList(AuthenticatedUser authenticatedUser) { return authenticatedUser.getUserAttributes().keySet().stream() From 1bfe9d9c3952e8ce135bb41ad0049829fbd9ac96 Mon Sep 17 00:00:00 2001 From: dhaura Date: Sat, 6 Apr 2024 11:02:55 +0530 Subject: [PATCH 4/4] Improve extractScopesFromURL() method. --- .../oidc/OIDCAuthenticatorConstants.java | 1 + .../oidc/OpenIDConnectAuthenticator.java | 13 ++++++++----- 2 files changed, 9 insertions(+), 5 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 267c1665..ed787940 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 @@ -81,6 +81,7 @@ private OIDCAuthenticatorConstants() { public static final String SCOPE_PARAM_SUFFIX = "_scope_param"; public static final String REDIRECTION_PROMPT = "REDIRECTION_PROMPT"; public static final String SCOPE = "scope"; + public static final String QUESTION_SIGN = "\\?"; public static final String AMPERSAND_SIGN = "&"; public static final String EQUAL_SIGN = "="; 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 4716bb0b..45912358 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 @@ -2077,11 +2077,14 @@ protected Map getApplicationDetails(AuthenticationContext contex protected String extractScopesFromURL(String url) throws UnsupportedEncodingException { if (StringUtils.isNotBlank(url)) { - String[] params = url.split(OIDCAuthenticatorConstants.AMPERSAND_SIGN); - for (String param : params) { - String[] keyValue = param.split(OIDCAuthenticatorConstants.EQUAL_SIGN); - if (keyValue.length >= 2 && OAuthConstants.OAuth20Params.SCOPE.equals(keyValue[0])) { - return URLDecoder.decode(param, FrameworkUtils.UTF_8); + String[] splitUrl = url.split(OIDCAuthenticatorConstants.QUESTION_SIGN, 2); + if (splitUrl.length == 2) { + String[] params = splitUrl[1].split(OIDCAuthenticatorConstants.AMPERSAND_SIGN); + for (String param : params) { + String[] keyValue = param.split(OIDCAuthenticatorConstants.EQUAL_SIGN, 2); + if (keyValue.length == 2 && OAuthConstants.OAuth20Params.SCOPE.equals(keyValue[0])) { + return URLDecoder.decode(keyValue[1], FrameworkUtils.UTF_8); + } } } }