From f423420657efc06653f6d368b70ae035e4885ed7 Mon Sep 17 00:00:00 2001 From: Sachin-Mamoru Date: Mon, 12 Feb 2024 01:21:34 +0530 Subject: [PATCH 1/2] Validate multiOptionURI parameter --- .../pom.xml | 6 ++ .../util/AuthenticationEndpointUtil.java | 67 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/pom.xml b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/pom.xml index 95a93bf93321..a47d7ae4c83c 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/pom.xml +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/pom.xml @@ -62,6 +62,11 @@ org.wso2.carbon.identity.core provided + + org.wso2.carbon.identity.framework + org.wso2.carbon.identity.application.authentication.framework + provided + org.wso2.carbon org.wso2.carbon.utils @@ -200,6 +205,7 @@ org.wso2.carbon.identity.user.registration.stub.*;version="${carbon.identity.package.import.version.range}", org.apache.axis2.*;version="${axis2.osgi.version.range}", org.wso2.carbon.identity.core.util;resolution:=optional;version="${carbon.identity.package.import.version.range}", + org.wso2.carbon.identity.application.authentication.framework.config;version="${carbon.identity.package.import.version.range}", org.wso2.carbon.identity.core.*; version="${carbon.identity.package.import.version.range}", org.wso2.carbon.identity.base;resolution:=optional;version="${carbon.identity.package.import.version.range}", org.wso2.carbon.user.core.*; version="${carbon.kernel.package.import.version.range}", diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/src/main/java/org/wso2/carbon/identity/application/authentication/endpoint/util/AuthenticationEndpointUtil.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/src/main/java/org/wso2/carbon/identity/application/authentication/endpoint/util/AuthenticationEndpointUtil.java index 2c1ea4622448..727176d04177 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/src/main/java/org/wso2/carbon/identity/application/authentication/endpoint/util/AuthenticationEndpointUtil.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/src/main/java/org/wso2/carbon/identity/application/authentication/endpoint/util/AuthenticationEndpointUtil.java @@ -35,6 +35,7 @@ import org.owasp.encoder.Encode; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.identity.application.authentication.endpoint.util.bean.UserDTO; +import org.wso2.carbon.identity.application.authentication.framework.config.ConfigurationFacade; import org.wso2.carbon.identity.core.ServiceURLBuilder; import org.wso2.carbon.identity.core.URLBuilderException; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; @@ -74,6 +75,7 @@ public class AuthenticationEndpointUtil { private static final String QUERY_STRING_INITIATOR = "?"; private static final String PADDING_CHAR = "="; private static final String UNDERSCORE = "_"; + private static String serverHost; private static final String TENANT_DOMAIN_PLACEHOLDER = "${tenantDomain}"; private static final String SUPER_TENANT = "carbon.super"; @@ -254,6 +256,25 @@ public static String getErrorCodeToi18nMapping(String errorCode, String subError */ public static boolean isValidURL(String urlString) { + return validateURL(urlString); + } + + /** + * This method is to validate a multiOptionURI. This method validate absolute URLs. + * default value of multiOptionURL is /authenticationendpoint/ + * @param urlString URL String. + * @return true if valid URL, false otherwise. + */ + public static boolean isValidMultiOptionURI(String urlString) { + + if (validateURL(urlString)) { + return validateCallbackURL(urlString); + } + return false; + } + + private static boolean validateURL(String urlString) { + if (StringUtils.isBlank(urlString)) { String errorMsg = "Invalid URL."; if (log.isDebugEnabled()) { @@ -281,6 +302,52 @@ public static boolean isValidURL(String urlString) { return true; } + private static boolean validateCallbackURL(String callbackURL) { + + String multiOptionURIHost; + String authenticationEndpointURL = ConfigurationFacade.getInstance().getAuthenticationEndpointURL(); + try { + if (isURLRelative(callbackURL)) { + return !callbackURL.startsWith("//"); // Check for protocol-relative URLs. + } else { + multiOptionURIHost = new URL(callbackURL).getHost(); + /* + If the multiOptionURI is an absolute URL, then the host of the multiOptionURI should be + either host of the server or host of the externalized authenticationEndpointURL. + */ + if (multiOptionURIHost.equals(getServerHost()) || (!isURLRelative(authenticationEndpointURL) && + multiOptionURIHost.equals(new URL(authenticationEndpointURL).getHost()))) { + return true; + } else { + log.error("No valid host found for the multiOptionURI. Host: " + multiOptionURIHost + " is " + + "not allowed."); + return false; + } + } + } catch (MalformedURLException | URISyntaxException e) { + if (log.isDebugEnabled()) { + log.debug(e.getMessage(), e); + } + return false; + } + } + + private static String getServerHost() { + + try { + if (StringUtils.isEmpty(serverHost)) { + String urlString = buildAbsoluteURL("/"); + serverHost = new URL(urlString).getHost(); + } + } catch (MalformedURLException | URLBuilderException e) { + if (log.isDebugEnabled()) { + log.debug(e.getMessage(), e); + } + } + + return serverHost; + } + private static boolean isURLRelative(String uriString) throws URISyntaxException { return !new URI(uriString).isAbsolute(); From 5ecc923dab09b393c4428b0f58a0bf229cc538f1 Mon Sep 17 00:00:00 2001 From: Sachin-Mamoru Date: Tue, 13 Feb 2024 20:18:33 +0530 Subject: [PATCH 2/2] improved the logic to consider port as well --- .../util/AuthenticationEndpointUtil.java | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/src/main/java/org/wso2/carbon/identity/application/authentication/endpoint/util/AuthenticationEndpointUtil.java b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/src/main/java/org/wso2/carbon/identity/application/authentication/endpoint/util/AuthenticationEndpointUtil.java index 727176d04177..7b32aa4d8100 100644 --- a/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/src/main/java/org/wso2/carbon/identity/application/authentication/endpoint/util/AuthenticationEndpointUtil.java +++ b/components/authentication-framework/org.wso2.carbon.identity.application.authentication.endpoint.util/src/main/java/org/wso2/carbon/identity/application/authentication/endpoint/util/AuthenticationEndpointUtil.java @@ -75,7 +75,7 @@ public class AuthenticationEndpointUtil { private static final String QUERY_STRING_INITIATOR = "?"; private static final String PADDING_CHAR = "="; private static final String UNDERSCORE = "_"; - private static String serverHost; + private static String serverHostAndPort; private static final String TENANT_DOMAIN_PLACEHOLDER = "${tenantDomain}"; private static final String SUPER_TENANT = "carbon.super"; @@ -304,23 +304,23 @@ private static boolean validateURL(String urlString) { private static boolean validateCallbackURL(String callbackURL) { - String multiOptionURIHost; String authenticationEndpointURL = ConfigurationFacade.getInstance().getAuthenticationEndpointURL(); try { if (isURLRelative(callbackURL)) { return !callbackURL.startsWith("//"); // Check for protocol-relative URLs. } else { - multiOptionURIHost = new URL(callbackURL).getHost(); + String multiOptionURIHostAndPort = getHostAndPort(callbackURL); /* If the multiOptionURI is an absolute URL, then the host of the multiOptionURI should be either host of the server or host of the externalized authenticationEndpointURL. */ - if (multiOptionURIHost.equals(getServerHost()) || (!isURLRelative(authenticationEndpointURL) && - multiOptionURIHost.equals(new URL(authenticationEndpointURL).getHost()))) { + if (multiOptionURIHostAndPort.equals(getServerHostAndPort()) || + (!isURLRelative(authenticationEndpointURL) && multiOptionURIHostAndPort + .equals(getHostAndPort(authenticationEndpointURL)))) { return true; } else { - log.error("No valid host found for the multiOptionURI. Host: " + multiOptionURIHost + " is " + - "not allowed."); + log.error("No valid host found for the multiOptionURI. URL: " + multiOptionURIHostAndPort + + " is not allowed."); return false; } } @@ -332,12 +332,11 @@ private static boolean validateCallbackURL(String callbackURL) { } } - private static String getServerHost() { + private static String getServerHostAndPort() { try { - if (StringUtils.isEmpty(serverHost)) { - String urlString = buildAbsoluteURL("/"); - serverHost = new URL(urlString).getHost(); + if (StringUtils.isEmpty(serverHostAndPort)) { + serverHostAndPort = getHostAndPort(buildAbsoluteURL("/")); } } catch (MalformedURLException | URLBuilderException e) { if (log.isDebugEnabled()) { @@ -345,7 +344,24 @@ private static String getServerHost() { } } - return serverHost; + return serverHostAndPort; + } + + /** + * Extracts the host and port from a given URL string. + * If the URL does not specify a port, only the host is returned. + * + * @param urlString The URL from which to extract the host and port. + * @return A string containing the host and, if specified, the port. + * @throws MalformedURLException If the given string does not represent a valid URL. + */ + private static String getHostAndPort(String urlString) throws MalformedURLException { + + URL url = new URL(urlString); + String host = url.getHost(); + int port = url.getPort(); // Returns -1 if the port is not explicitly specified in the URL + + return port == -1 ? host : host + ":" + port; } private static boolean isURLRelative(String uriString) throws URISyntaxException {