From ad1e591d366628c74c89c16b346cd720ffbf1955 Mon Sep 17 00:00:00 2001 From: silmyhasan Date: Sat, 30 Nov 2024 12:18:53 +0530 Subject: [PATCH 1/3] Add proxy support for SSO with OIDC --- .../pom.xml | 2 + .../oidc/CustomURLConnectionClient.java | 218 ++++++++++++++++++ .../oidc/util/OIDCConstants.java | 18 ++ pom.xml | 1 + 4 files changed, 239 insertions(+) create mode 100644 components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/CustomURLConnectionClient.java create mode 100644 components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/util/OIDCConstants.java diff --git a/components/org.wso2.carbon.identity.application.authenticator.oidc/pom.xml b/components/org.wso2.carbon.identity.application.authenticator.oidc/pom.xml index e61bf2ae..4ed080e9 100644 --- a/components/org.wso2.carbon.identity.application.authenticator.oidc/pom.xml +++ b/components/org.wso2.carbon.identity.application.authenticator.oidc/pom.xml @@ -155,6 +155,7 @@ org.apache.oltu.oauth2.common.exception; version="${oltu.package.import.version.range}", org.apache.oltu.oauth2.common.message.types; version="${oltu.package.import.version.range}", + org.apache.http.*; version="${http.package.import.version.range}", org.apache.oltu.oauth2.common.utils; version="${oltu.package.import.version.range}", org.wso2.carbon.utils.*; version="${carbon.kernel.package.import.version.range}", org.wso2.carbon.identity.oauth.common.*; @@ -187,6 +188,7 @@ version="${identity.framework.package.import.version.range}", org.wso2.carbon.identity.central.log.mgt.utils; version="${identity.framework.package.import.version.range}", + org.wso2.carbon.base; !org.wso2.carbon.identity.application.authenticator.oidc.internal, diff --git a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/CustomURLConnectionClient.java b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/CustomURLConnectionClient.java new file mode 100644 index 00000000..8348571f --- /dev/null +++ b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/CustomURLConnectionClient.java @@ -0,0 +1,218 @@ +/** + * Copyright (c) 2024, WSO2 Inc. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. 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.application.authenticator.oidc; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLContexts; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.conn.ssl.X509HostnameVerifier; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.DefaultProxyRoutePlanner; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.util.EntityUtils; +import org.apache.oltu.oauth2.client.HttpClient; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest; +import org.apache.oltu.oauth2.client.response.OAuthClientResponse; +import org.apache.oltu.oauth2.client.response.OAuthClientResponseFactory; +import org.apache.oltu.oauth2.common.exception.OAuthProblemException; +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; +import org.wso2.carbon.identity.application.authenticator.oidc.util.OIDCConstants; +import org.wso2.carbon.identity.core.util.IdentityUtil; +import org.wso2.carbon.utils.CarbonUtils; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.util.Arrays; +import java.util.Map; + + +public class CustomURLConnectionClient implements HttpClient { + @Override + public T execute(OAuthClientRequest request, Map headers, String s, Class responseClass) throws OAuthSystemException, OAuthProblemException { + + org.apache.http.client.HttpClient httpClient = getHttpClient(); + try { + HttpPost httpPost = new HttpPost(request.getLocationUri()); + if (headers != null && !headers.isEmpty()) { + for (Map.Entry header : headers.entrySet()) { + httpPost.setHeader(header.getKey(), header.getValue()); + } + } + if (request.getHeaders() != null) { + for (Map.Entry header : request.getHeaders().entrySet()) { + httpPost.setHeader(header.getKey(), header.getValue()); + } + } + + String requestBody = request.getBody(); + StringEntity requestEntity = new StringEntity(requestBody, ContentType.APPLICATION_JSON); + httpPost.setEntity(requestEntity); + + HttpResponse response = httpClient.execute(httpPost); + if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) { + String responseString = EntityUtils.toString(response.getEntity(), "UTF-8"); + return OAuthClientResponseFactory + .createCustomResponse(responseString, requestEntity.getContentType().toString(), + response.getStatusLine().getStatusCode(), responseClass); + } else { + throw new OAuthSystemException("Error while obtaining the access token through the proxy"); + } + } catch (MalformedURLException e) { + throw new OAuthSystemException(e); + } catch (IOException e) { + throw new OAuthSystemException(e); + } + } + + @Override + public void shutdown() { + // Nothing to do here + } + + public static org.apache.http.client.HttpClient getHttpClient() throws OAuthSystemException { + Boolean proxyEnabled = Boolean.parseBoolean(IdentityUtil.getProperty(OIDCConstants.proxyEnable)); + String proxyProtocol = IdentityUtil.getProperty(OIDCConstants.proxyProtocol); + String proxyUsername = IdentityUtil.getProperty(OIDCConstants.proxyUsername); + String proxyPassword = IdentityUtil.getProperty(OIDCConstants.proxyPassword); + String proxyHost = IdentityUtil.getProperty(OIDCConstants.proxyHost); + String proxyPort = IdentityUtil.getProperty(OIDCConstants.proxyPort); + + String protocol = null; + if (proxyProtocol != null) { + protocol = proxyProtocol; + } + + PoolingHttpClientConnectionManager pool = null; + try { + pool = getPoolingHttpClientConnectionManager(protocol); + } catch (Exception e) { + throw new OAuthSystemException(e); + } + + RequestConfig params = RequestConfig.custom().build(); + HttpClientBuilder clientBuilder = HttpClients.custom().setConnectionManager(pool) + .setDefaultRequestConfig(params); + + HttpHost host = null; + if (proxyEnabled) { + host = new HttpHost(proxyHost, Integer.parseInt(proxyPort), protocol); + clientBuilder.setDefaultRequestConfig(RequestConfig.custom().setProxy(host).build()); + DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(host); + clientBuilder = clientBuilder.setRoutePlanner(routePlanner); + if (!StringUtils.isBlank(proxyUsername) && !StringUtils.isBlank(proxyPassword)) { + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(new AuthScope(proxyHost, Integer.parseInt(proxyPort)), + new UsernamePasswordCredentials(proxyUsername, proxyPassword)); + clientBuilder = clientBuilder.setDefaultCredentialsProvider(credentialsProvider); + } + } + return clientBuilder.build(); + } + + /** + * Return a PoolingHttpClientConnectionManager instance + * + * @param protocol- service endpoint protocol. It can be http/https + * @return PoolManager + */ + private static PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager(String protocol) throws Exception { + + PoolingHttpClientConnectionManager poolManager; + if (OIDCConstants.HTTPS.equals(protocol)) { + SSLConnectionSocketFactory socketFactory = createSocketFactory(); + org.apache.http.config.Registry socketFactoryRegistry = + RegistryBuilder.create() + .register(OIDCConstants.HTTPS, socketFactory).build(); + poolManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + } else { + poolManager = new PoolingHttpClientConnectionManager(); + } + return poolManager; + } + + private static SSLConnectionSocketFactory createSocketFactory() throws OAuthSystemException { + SSLContext sslContext = null; + HostnameVerifier hostnameVerifier = null; + String keyStorePath = CarbonUtils.getServerConfiguration() + .getFirstProperty(OIDCConstants.trustStoreLocation); + String keyStorePassword = CarbonUtils.getServerConfiguration() + .getFirstProperty(OIDCConstants.trustStorePassword); + try { + KeyStore trustStore = KeyStore.getInstance("JKS"); + trustStore.load(new FileInputStream(keyStorePath), keyStorePassword.toCharArray()); + sslContext = SSLContexts.custom().loadTrustMaterial(trustStore).build(); + + String hostnameVerifierOption = System.getProperty(OIDCConstants.hostNameVerifierSysEnv); + + if (OIDCConstants.ALLOW_ALL_HOSTNAME_VERIFIER.equalsIgnoreCase(hostnameVerifierOption)) { + hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; + } else if (OIDCConstants.STRICT_HOSTNAME_VERIFIER.equalsIgnoreCase(hostnameVerifierOption)) { + hostnameVerifier = SSLSocketFactory.STRICT_HOSTNAME_VERIFIER; + } else if (OIDCConstants.DEFAULT_HOSTNAME_VERIFIER.equalsIgnoreCase(hostnameVerifierOption)) { + hostnameVerifier = new HostnameVerifier() { + final String[] localhosts = {"::1", "127.0.0.1", "localhost", "localhost.localdomain"}; + + @Override + public boolean verify(String urlHostName, SSLSession session) { + return SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER.verify(urlHostName, session) + || Arrays.asList(localhosts).contains(urlHostName); + } + }; + } else { + hostnameVerifier = SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER; + } + return new SSLConnectionSocketFactory(sslContext, (X509HostnameVerifier) hostnameVerifier); + + } catch (KeyStoreException e) { + throw new OAuthSystemException(e); + } catch (IOException e) { + throw new OAuthSystemException(e); + } catch (CertificateException e) { + throw new OAuthSystemException(e); + } catch (NoSuchAlgorithmException e) { + throw new OAuthSystemException(e); + } catch (KeyManagementException e) { + throw new OAuthSystemException(e); + } + } +} diff --git a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/util/OIDCConstants.java b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/util/OIDCConstants.java new file mode 100644 index 00000000..723f5033 --- /dev/null +++ b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/util/OIDCConstants.java @@ -0,0 +1,18 @@ +package org.wso2.carbon.identity.application.authenticator.oidc.util; + +public class OIDCConstants { + + public static String proxyEnable = "ProxyConfig.Enable"; + public static String proxyHost = "ProxyConfig.Host"; + public static String proxyUsername = "ProxyConfig.Username" ; + public static String proxyPassword = "ProxyConfig.Password"; + public static String proxyPort = "ProxyConfig.Port"; + public static String proxyProtocol = "ProxyConfig.Protocol"; + public static String HTTPS = "https"; + public static String trustStoreLocation = "Security.TrustStore.Location"; + public static String trustStorePassword = "Security.TrustStore.Password"; + public static String hostNameVerifierSysEnv = "httpclient.hostnameVerifier"; + public static String ALLOW_ALL_HOSTNAME_VERIFIER = "AllowAll"; + public static String STRICT_HOSTNAME_VERIFIER = "Strict"; + public static String DEFAULT_HOSTNAME_VERIFIER = "DefaultAndLocalhost"; +} diff --git a/pom.xml b/pom.xml index f5e71607..1d6d5063 100644 --- a/pom.xml +++ b/pom.xml @@ -336,6 +336,7 @@ [4.4.0, 5.0.0) [2.3.0, 3.0.0) [1.0.0, 2.0.0) + [4.4.0, 5.0.0) [2.6.0, 3.0.0) [1.0.1, 2.0.0) [1.2,2.0) From c1bc48d82ca0e73eff3fae2aac40c58cbf4ac282 Mon Sep 17 00:00:00 2001 From: silmyhasan Date: Sun, 1 Dec 2024 15:23:25 +0530 Subject: [PATCH 2/3] Add extended route planner. --- .../oidc/CustomURLConnectionClient.java | 54 ++++---- .../oidc/OIDCAuthenticatorConstants.java | 21 ++++ .../oidc/util/ExtendedProxyRoutePlanner.java | 118 ++++++++++++++++++ .../oidc/util/OIDCConstants.java | 18 --- 4 files changed, 166 insertions(+), 45 deletions(-) create mode 100644 components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/util/ExtendedProxyRoutePlanner.java delete mode 100644 components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/util/OIDCConstants.java diff --git a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/CustomURLConnectionClient.java b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/CustomURLConnectionClient.java index 8348571f..3fb835e3 100644 --- a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/CustomURLConnectionClient.java +++ b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/CustomURLConnectionClient.java @@ -25,7 +25,6 @@ import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; @@ -47,7 +46,7 @@ import org.apache.oltu.oauth2.client.response.OAuthClientResponseFactory; import org.apache.oltu.oauth2.common.exception.OAuthProblemException; import org.apache.oltu.oauth2.common.exception.OAuthSystemException; -import org.wso2.carbon.identity.application.authenticator.oidc.util.OIDCConstants; +import org.wso2.carbon.identity.application.authenticator.oidc.util.ExtendedProxyRoutePlanner; import org.wso2.carbon.identity.core.util.IdentityUtil; import org.wso2.carbon.utils.CarbonUtils; @@ -95,10 +94,9 @@ public T execute(OAuthClientRequest request, Map .createCustomResponse(responseString, requestEntity.getContentType().toString(), response.getStatusLine().getStatusCode(), responseClass); } else { - throw new OAuthSystemException("Error while obtaining the access token through the proxy"); + throw new OAuthSystemException("Error while obtaining the access token through the proxy " + + EntityUtils.toString(response.getEntity())); } - } catch (MalformedURLException e) { - throw new OAuthSystemException(e); } catch (IOException e) { throw new OAuthSystemException(e); } @@ -110,21 +108,18 @@ public void shutdown() { } public static org.apache.http.client.HttpClient getHttpClient() throws OAuthSystemException { - Boolean proxyEnabled = Boolean.parseBoolean(IdentityUtil.getProperty(OIDCConstants.proxyEnable)); - String proxyProtocol = IdentityUtil.getProperty(OIDCConstants.proxyProtocol); - String proxyUsername = IdentityUtil.getProperty(OIDCConstants.proxyUsername); - String proxyPassword = IdentityUtil.getProperty(OIDCConstants.proxyPassword); - String proxyHost = IdentityUtil.getProperty(OIDCConstants.proxyHost); - String proxyPort = IdentityUtil.getProperty(OIDCConstants.proxyPort); - - String protocol = null; - if (proxyProtocol != null) { - protocol = proxyProtocol; - } + Boolean proxyEnabled = Boolean.parseBoolean(IdentityUtil.getProperty( + OIDCAuthenticatorConstants.Proxy.proxyEnable)); + String proxyProtocol = IdentityUtil.getProperty(OIDCAuthenticatorConstants.Proxy.proxyProtocol); + String proxyUsername = IdentityUtil.getProperty(OIDCAuthenticatorConstants.Proxy.proxyUsername); + String proxyPassword = IdentityUtil.getProperty(OIDCAuthenticatorConstants.Proxy.proxyPassword); + String proxyHost = IdentityUtil.getProperty(OIDCAuthenticatorConstants.Proxy.proxyHost); + String proxyPort = IdentityUtil.getProperty(OIDCAuthenticatorConstants.Proxy.proxyPort); + String nonProxyHosts = IdentityUtil.getProperty(OIDCAuthenticatorConstants.Proxy.proxyPort); PoolingHttpClientConnectionManager pool = null; try { - pool = getPoolingHttpClientConnectionManager(protocol); + pool = getPoolingHttpClientConnectionManager(proxyProtocol); } catch (Exception e) { throw new OAuthSystemException(e); } @@ -135,9 +130,14 @@ public static org.apache.http.client.HttpClient getHttpClient() throws OAuthSyst HttpHost host = null; if (proxyEnabled) { - host = new HttpHost(proxyHost, Integer.parseInt(proxyPort), protocol); + host = new HttpHost(proxyHost, Integer.parseInt(proxyPort), proxyProtocol); clientBuilder.setDefaultRequestConfig(RequestConfig.custom().setProxy(host).build()); - DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(host); + DefaultProxyRoutePlanner routePlanner; + if (!StringUtils.isBlank(nonProxyHosts)) { + routePlanner = new ExtendedProxyRoutePlanner(host, nonProxyHosts, proxyHost, proxyPort, proxyProtocol); + } else { + routePlanner = new DefaultProxyRoutePlanner(host); + } clientBuilder = clientBuilder.setRoutePlanner(routePlanner); if (!StringUtils.isBlank(proxyUsername) && !StringUtils.isBlank(proxyPassword)) { CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); @@ -158,11 +158,11 @@ public static org.apache.http.client.HttpClient getHttpClient() throws OAuthSyst private static PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager(String protocol) throws Exception { PoolingHttpClientConnectionManager poolManager; - if (OIDCConstants.HTTPS.equals(protocol)) { + if (OIDCAuthenticatorConstants.Proxy.HTTPS.equals(protocol)) { SSLConnectionSocketFactory socketFactory = createSocketFactory(); org.apache.http.config.Registry socketFactoryRegistry = RegistryBuilder.create() - .register(OIDCConstants.HTTPS, socketFactory).build(); + .register(OIDCAuthenticatorConstants.Proxy.HTTPS, socketFactory).build(); poolManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); } else { poolManager = new PoolingHttpClientConnectionManager(); @@ -174,21 +174,21 @@ private static SSLConnectionSocketFactory createSocketFactory() throws OAuthSyst SSLContext sslContext = null; HostnameVerifier hostnameVerifier = null; String keyStorePath = CarbonUtils.getServerConfiguration() - .getFirstProperty(OIDCConstants.trustStoreLocation); + .getFirstProperty(OIDCAuthenticatorConstants.Proxy.trustStoreLocation); String keyStorePassword = CarbonUtils.getServerConfiguration() - .getFirstProperty(OIDCConstants.trustStorePassword); + .getFirstProperty(OIDCAuthenticatorConstants.Proxy.trustStorePassword); try { KeyStore trustStore = KeyStore.getInstance("JKS"); trustStore.load(new FileInputStream(keyStorePath), keyStorePassword.toCharArray()); sslContext = SSLContexts.custom().loadTrustMaterial(trustStore).build(); - String hostnameVerifierOption = System.getProperty(OIDCConstants.hostNameVerifierSysEnv); + String hostnameVerifierOption = System.getProperty(OIDCAuthenticatorConstants.Proxy.hostNameVerifierSysEnv); - if (OIDCConstants.ALLOW_ALL_HOSTNAME_VERIFIER.equalsIgnoreCase(hostnameVerifierOption)) { + if (OIDCAuthenticatorConstants.Proxy.ALLOW_ALL_HOSTNAME_VERIFIER.equalsIgnoreCase(hostnameVerifierOption)) { hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; - } else if (OIDCConstants.STRICT_HOSTNAME_VERIFIER.equalsIgnoreCase(hostnameVerifierOption)) { + } else if (OIDCAuthenticatorConstants.Proxy.STRICT_HOSTNAME_VERIFIER.equalsIgnoreCase(hostnameVerifierOption)) { hostnameVerifier = SSLSocketFactory.STRICT_HOSTNAME_VERIFIER; - } else if (OIDCConstants.DEFAULT_HOSTNAME_VERIFIER.equalsIgnoreCase(hostnameVerifierOption)) { + } else if (OIDCAuthenticatorConstants.Proxy.DEFAULT_HOSTNAME_VERIFIER.equalsIgnoreCase(hostnameVerifierOption)) { hostnameVerifier = new HostnameVerifier() { final String[] localhosts = {"::1", "127.0.0.1", "localhost", "localhost.localdomain"}; 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 48f6ae18..5432a1f9 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 @@ -193,4 +193,25 @@ public static class ActionIDs { public static final String INITIATE_OUTBOUND_AUTH_REQUEST = "initiate-outbound-auth-oidc-request"; } } + + public class Proxy { + private Proxy() { + + } + public static final String proxyEnable = "ProxyConfig.Enable"; + public static final String proxyHost = "ProxyConfig.Host"; + public static final String proxyUsername = "ProxyConfig.Username" ; + public static final String proxyPassword = "ProxyConfig.Password"; + public static final String proxyPort = "ProxyConfig.Port"; + public static final String proxyProtocol = "ProxyConfig.Protocol"; + public static final String nonProxyHosts = "ProxyConfig.NonProxyHosts"; + + public static final String HTTPS = "https"; + public static final String trustStoreLocation = "Security.TrustStore.Location"; + public static final String trustStorePassword = "Security.TrustStore.Password"; + public static final String hostNameVerifierSysEnv = "httpclient.hostnameVerifier"; + public static final String ALLOW_ALL_HOSTNAME_VERIFIER = "AllowAll"; + public static final String STRICT_HOSTNAME_VERIFIER = "Strict"; + public static final String DEFAULT_HOSTNAME_VERIFIER = "DefaultAndLocalhost"; + } } diff --git a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/util/ExtendedProxyRoutePlanner.java b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/util/ExtendedProxyRoutePlanner.java new file mode 100644 index 00000000..41a12174 --- /dev/null +++ b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/util/ExtendedProxyRoutePlanner.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2024, 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.application.authenticator.oidc.util; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpException; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.impl.conn.DefaultProxyRoutePlanner; +import org.apache.http.protocol.HttpContext; + + +/** + * Extended ProxyRoutePlanner class to handle non proxy hosts implementation + */ +public class ExtendedProxyRoutePlanner extends DefaultProxyRoutePlanner { + private static final Log log = LogFactory.getLog(ExtendedProxyRoutePlanner.class); + String nonProxyHosts; + String proxyHost; + String proxyPort; + String protocol; + + public ExtendedProxyRoutePlanner(HttpHost host, String nonProxyHosts, String proxyHost, String proxyPort, + String protocol ) { + super(host); + this.nonProxyHosts = nonProxyHosts; + this.proxyHost = proxyHost; + this.proxyPort = proxyPort; + this.protocol = protocol; + } + + private HttpHost getProxy(String scheme) { + log.debug("Get proxy for scheme: " + scheme); + String proto = scheme; + + String protoProxyHost = proxyHost; + if (protoProxyHost == null) { + return null; + } + String proxyPortStr = proxyPort; + if (proxyPortStr == null) { + return null; + } + int protoProxyPort = -1; + if (proxyPortStr != null) { + try { + protoProxyPort = Integer.valueOf(proxyPortStr); + } catch (NumberFormatException nfe) { + log.warn("invalid proxy port: " + proxyPortStr + ". proxy will be ignored"); + return null; + } + } + if (protoProxyPort < 1) { + return null; + } + log.debug("set " + proto + " proxy '" + protoProxyHost + ":" + protoProxyPort + "'"); + return new HttpHost(protoProxyHost, protoProxyPort, scheme); + } + + private String[] getNonProxyHosts() { + String nonProxyHosts = this.nonProxyHosts; + if (nonProxyHosts == null) { + return null; + } + return nonProxyHosts.split("\\|"); + } + + private boolean doesTargetMatchNonProxy(HttpHost target) { + String uriHost = target.getHostName(); + String uriScheme = target.getSchemeName(); + String[] nonProxyHosts = getNonProxyHosts(); + int nphLength = nonProxyHosts != null ? nonProxyHosts.length : 0; + if (nonProxyHosts == null || nphLength < 1) { + log.debug("sheme:'" + uriScheme + "', host:'" + uriHost + "' : DEFAULT (0 non proxy host)"); + return false; + } + for (String nonProxyHost : nonProxyHosts) { + if (uriHost.matches(nonProxyHost)) { + log.debug("sheme:'" + uriScheme + "', host:'" + uriHost + "' matches nonProxyHost '" + nonProxyHost + "' : NO PROXY"); + return true; + } + } + log.debug("sheme:'" + uriScheme + "', host:'" + uriHost + "' : DEFAULT (no match of " + nphLength + " non proxy host)"); + return false; + } + + @Override + protected HttpHost determineProxy(HttpHost target, final HttpRequest request, final HttpContext context) + throws HttpException { + + if (doesTargetMatchNonProxy(target)) { + return null; + } + if (StringUtils.isNotEmpty(protocol)) { + return getProxy(protocol); + } else { + return getProxy(target.getSchemeName()); + } + } +} diff --git a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/util/OIDCConstants.java b/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/util/OIDCConstants.java deleted file mode 100644 index 723f5033..00000000 --- a/components/org.wso2.carbon.identity.application.authenticator.oidc/src/main/java/org/wso2/carbon/identity/application/authenticator/oidc/util/OIDCConstants.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.wso2.carbon.identity.application.authenticator.oidc.util; - -public class OIDCConstants { - - public static String proxyEnable = "ProxyConfig.Enable"; - public static String proxyHost = "ProxyConfig.Host"; - public static String proxyUsername = "ProxyConfig.Username" ; - public static String proxyPassword = "ProxyConfig.Password"; - public static String proxyPort = "ProxyConfig.Port"; - public static String proxyProtocol = "ProxyConfig.Protocol"; - public static String HTTPS = "https"; - public static String trustStoreLocation = "Security.TrustStore.Location"; - public static String trustStorePassword = "Security.TrustStore.Password"; - public static String hostNameVerifierSysEnv = "httpclient.hostnameVerifier"; - public static String ALLOW_ALL_HOSTNAME_VERIFIER = "AllowAll"; - public static String STRICT_HOSTNAME_VERIFIER = "Strict"; - public static String DEFAULT_HOSTNAME_VERIFIER = "DefaultAndLocalhost"; -} From 594bc98cdb156e55050c9edba50dcd37445a5544 Mon Sep 17 00:00:00 2001 From: silmyhasan Date: Mon, 2 Dec 2024 10:36:50 +0530 Subject: [PATCH 3/3] Support proxy while obtaining OIDC token. --- .../authenticator/oidc/OpenIDConnectAuthenticator.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 684cbc38..ebde530f 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 @@ -1245,7 +1245,12 @@ protected OAuthClientResponse requestAccessToken(HttpServletRequest request, Aut OAuthClientRequest accessTokenRequest = getAccessTokenRequest(context, authzResponse); // Create OAuth client that uses custom http client under the hood. - OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient()); + OAuthClient oAuthClient; + if (Boolean.parseBoolean(IdentityUtil.getProperty(OIDCAuthenticatorConstants.Proxy.proxyEnable))) { + oAuthClient = new OAuthClient(new CustomURLConnectionClient()); + } else { + oAuthClient = new OAuthClient(new URLConnectionClient()); + } oAuthResponse = getOauthResponse(oAuthClient, accessTokenRequest); if (oAuthResponse != null) { processAuthenticatedUserScopes(context, oAuthResponse.getParam(OAuthConstants.OAuth20Params.SCOPE));