We have following issue:
We have an Angular Frontend and Spring Boot Backend. We using OAuth2 resource server in the backend to validate the token from the Frontend. The frontend is calling the Azure Entra Id to login and send the token to our backend to do some api calls. Our backend is behind a proxy, so that we have to setup the proxy settings only for the remote app.
We can easily do this by:
@PostConstruct
fun setupProxy() {
if (local) return
val httpsProxyHost = "myproxy.com"
val httpsProxyPort = 3000
val properties = System.getProperties()
properties["http.proxyHost"] = httpsProxyHost
properties["http.proxyPort"] = httpsProxyPort
properties["https.proxyHost"] = httpsProxyHost
properties["https.proxyPort"] = httpsProxyPort
}
Our application yaml looks like:
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: ${ISSUER_URI:http://localhost:8180/auth/realms/gp-admin-realm}
For local oauth2 testing we using keycloak. So we set the default issuer-uri which keyload provided for us.
If we call the local swagger api, the OAuth2 calls the urls with RestTemplate and we get:
o.s.web.client.RestTemplate : HTTP GET http://localhost:8180/auth/realms/gp-admin-realm/.well-known/openid-configuration
o.s.web.client.RestTemplate : Accept=[application/json, application/*+json]
o.s.web.client.RestTemplate : Response 200 OK
o.s.web.client.RestTemplate : Reading to [java.util.Map<java.lang.String, java.lang.Object>]
o.s.web.client.RestTemplate : HTTP GET http://localhost:8180/auth/realms/gp-admin-realm/protocol/openid-connect/certs
o.s.web.client.RestTemplate : Accept=[text/plain, application/json, application/*+json, */*]
o.s.web.client.RestTemplate : Response 200 OK
o.s.web.client.RestTemplate : Reading to [java.lang.String] as "application/json"
o.s.s.o.s.r.a.JwtAuthenticationProvider : Authenticated token
So i would it expect it on our deployed application too. If we deploy our app to our cluster and call make the same query there, we get:
DEBUG 1 --- [nio-8080-exec-4] o.s.web.client.RestTemplate : HTTP GET https://login.microsoftonline.com/716e4882-aa4a-4987-a49c-1ea670a4595c/v2.0/.well-known/openid-configuration
DEBUG 1 --- [nio-8080-exec-4] o.s.web.client.RestTemplate : Accept=[application/json, application/*+json]
TRACE 1 --- [nio-8080-exec-4] s.n.www.protocol.http.HttpURLConnection : ProxySelector Request for https://login.microsoftonline.com/716e4882-aa4a-4987-a49c-1ea670a4595c/v2.0/.well-known/openid-configuration
TRACE 1 --- [nio-8080-exec-4] s.n.www.protocol.http.HttpURLConnection : Looking for HttpClient for URL https://login.microsoftonline.com/716e4882-aa4a-4987-a49c-1ea670a4595c/v2.0/.well-known/openid-configuration and proxy value of HTTP @ myproxy.com/<unresolved>:443
TRACE 1 --- [nio-8080-exec-4] s.n.www.protocol.http.HttpURLConnection : Creating new HttpsClient with url:https://login.microsoftonline.com/716e4882-aa4a-4987-a49c-1ea670a4595c/v2.0/.well-known/openid-configuration and proxy:HTTP @ myproxy.com/<unresolved>:443 with connect timeout:-1
The tenantId is generated and not a real one. We can see here, that something in the RestTemplate calls a HttpURLConnection which resolves the proxy wrong with myproxy.com/<unresolved>:443 and not like the expected proxy value myproxy.com:3000. So we get a timeout.
Overriding RestTemplate in our Spring Boot configuration is no option, because the oauth client is generating his own RestTemplate with:
private static final RestTemplate restTemplate = new RestTemplate()
If we look a little bit deeper in the HttpURLConnection Class we see that it uses an InetSockerAddress to add the new proxy.
public HttpURLConnection(URL u, String host, int port) throws IOException {
this(u, new Proxy(Proxy.Type.HTTP,
InetSocketAddress.createUnresolved(checkHost(host), port)));
}
But it should could resolve all automatically from the system variables. If the addr is not resolved from the system, it will return true for the method isUnresolved() and gets the wrong proxy string back:
public class InetSocketAddress extends SocketAddress {
private static class InetSocketAddressHolder {
private String hostname;
private InetAddress addr;
private int port;
private InetSocketAddressHolder(String hostname, InetAddress addr, int port) {...}
private boolean isUnresolved() {
return addr == null;
}
@Override
public String toString() {
String formatted;
if (isUnresolved()) {
formatted = hostname + "/<unresolved>";
} else {
formatted = addr.toString();
if (addr instanceof Inet6Address) {
int i = formatted.lastIndexOf("/");
formatted = formatted.substring(0, i + 1)
+ "[" + formatted.substring(i + 1) + "]";
}
}
return formatted + ":" + port;
}
Everyone an idea how to solve this issue? This is all java base code and not included in our Spring Boot app. The RestTemplate is not overridable for OAuth2.
Thanks a lot guys.
EDIT
How to solve it:
For all, who came here with the same issue: The port has to be a String. If the port is an Int, it will not be used