-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Use alternate (internal) URL for OIDC configuration during ISS claim validation #11515
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Add-On: I forgot to mention that we need to advertise the outside URI in the ISS claim in order for the frontend UI to work running in the client browser. |
Hello, it's funny because I had come here to open the exact same issue but you just did it only 3 hours before 😆 In my case, I am in the process of removing deprecated Keycloak Adapter by Spring Security OAuth and having same kind of issues. As @holgerstolzenberg described, token validation is failing on "invalid issuer" error. My configuration :
This is the full exception I get :
As Keycloak returns URIs in openid-configuration with the Frontend URL, the desired behavior in my case might be to configure the token validation with the issuer-uri returned by keycloak openid-configuration endpoint instead of the one directly set in yaml configuration. PS : I am using spring-security 5.6.1 with spring-boot 2.6.2. |
@holgerstolzenberg Can you provide more details on the specific issue you are having? For example, please provide the stacktrace so I can determine the point in code that is resulting in the error condition. |
@olivierboudet The stacktrace you provided is coming from |
Hello @jgrandja, indeed I am using Perhaps it would be more clear if I show you the workaround I am using to resolve this issue. I have a
And as
I did not change anything in
These changes allow me to workaround the initial issue, but I think this would not be necessary if Spring Security allows to build the decoder with issuers found in the response of request to |
We are facing the exact same problem in our setup and interesting to see the issue raised so recently :) As @olivierboudet mentioned, the problem is with the
This tightly couples the two behaviours on the same input. Note that the Discovery document returns the same Issuer irrespective of which URI it is called on. |
@holgerstolzenberg, @olivierboudet, @xsreality In case you are not aware, I'd like to refer you to 4.3. OpenID Provider Configuration Validation:
Hence, the reason for There are limitations to customizing the flow when using I'm leaning towards closing this issue as a duplicate as I feel gh-10309 will provide the flexibility you all are looking for. @holgerstolzenberg, @olivierboudet, @xsreality Can you confirm if my assumptions are correct? And if so, can you please provide further comments in the other issue so we capture all the requirements you need to make things work? |
@jgrandja If I understand the mechanics of the referenced issue correctly (without seeing code changes) you are going to introduce a new configuration property that enables us to configure/overwrite the issuer location to be used for ISS claim validation. I guess that might fix our problem. To be clear, what we need to able to do is to configure a oauth provider whose configured |
We are running into this same issue. Our main issue is while we can do the insane loopback through cloudflare/routing/ingress controllers to a pod sitting in the same local subnet... our development staff, use "localhost" and our spring-boot service can't access keycloak via "localhost"... so we give the issuer-uri as "https://keycloak:8443/auth/realms/whatever", which then means we get "the iss claim is invalid". I don't really care how we can solve it, but i'm about to have to replace whatever @bean configures the JWT validation, and copy+paste into our code base whatever all the way down the stacktrace... just so I can set a I get being truthful to the OpenID Provider spec, which is why i'm about to go file an issue wherever that is maintained. |
No, we will not be introducing a new configuration property. But before I explain further, I re-read your original issue and my previous comment does not apply to your situation. Sorry for the confusion. My previous comment refers to issuer validation during the initialization of a Regarding your work around:
Yes, this is exactly what you would do to bypass issuer validation. This is documented in ClientRegistrations. FYI, the Does this answer your question? My previous comment was referring to issuer validation during the initialization of a Specifically the configuration: spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://keycloak:8080/auth/realms/myrealm After gh-10309 is implemented, you could provide the following configuration: @Bean
public JwtDecoder jwtDecoder() {
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder
.withIssuerLocation("https://the.platform.io/auth/realms/the-realm")
.build();
jwtDecoder.setJwtValidator(
JwtValidators.createDefaultWithIssuer("https://keycloak.cluster.local/auth/realms/the-realm")
);
return jwtDecoder;
} With the above configuration, the issuer validation is overridden using |
Yes - that looks good to me. The suggested overridden |
It looks good also for me 👍 |
@olivierboudet I have come up with a bit simpler workaround. We are in the same boat, backend and frontend URLs, not possible to go around the proxies, etc. Our solution is following:
And then just use it like this in your WebSecurityConfig:
This way you do not have to sacrifice the issuer validation, with the cost of validating twice, for the "public" tokens. |
@holgerstolzenberg, @olivierboudet, @xsreality Closing this in favour of gh-10309 |
@jgrandja It is still not clear to me how #10309 solves the issue. @Bean
public JwtDecoder jwtDecoder() {
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder
.withIssuerLocation("https://the.platform.io/auth/realms/the-realm")
.build();
jwtDecoder.setJwtValidator(
JwtValidators.createDefaultWithIssuer("https://keycloak.cluster.local/auth/realms/the-realm")
);
return jwtDecoder;
} The I tried above code with 6.1.0 and can confirm above described behaviour. Here's my code: SecurityConfigurer: @Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange().anyExchange().authenticated()
.and()
.oauth2ResourceServer(spec ->
spec.authenticationManagerResolver(authenticationManagerResolver))
.build();
} Custom AuthenticationManagerResolver: @Override
public Mono<ReactiveAuthenticationManager> resolve(ServerWebExchange exchange) {
return Mono.just(globalAuthenticationManager());
}
ReactiveAuthenticationManager globalAuthenticationManager() {
return new JwtReactiveAuthenticationManager(globalAuthJwtDecoder());
}
ReactiveJwtDecoder globalAuthJwtDecoder() {
List<OAuth2TokenValidator<Jwt>> validators = new ArrayList<>();
validators.add(JwtValidators.createDefaultWithIssuer(globalAuthConfig.getIssuerUrlForValidation()));
validators.add(new JwtClaimValidator<List<String>>(AUD, s -> s.contains(globalAuthConfig.getAudience())));
validators.add(new JwtClaimValidator<String>(EMAIL, StringUtils::hasText));
validators.add(new JwtClaimValidator<String>("tenant_short_name", StringUtils::hasText));
OAuth2TokenValidator<Jwt> validator = new DelegatingOAuth2TokenValidator<>(validators);
// we use separate issuerUrl to discover configuration to allow the possibility of
// keeping the traffic from API Gw -> Authorization server in the internal network
NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder
.withIssuerLocation(globalAuthConfig.getIssuerUrlForDiscovery())
.build();
jwtDecoder.setJwtValidator(validator);
return new SupplierReactiveJwtDecoder(() -> jwtDecoder);
} |
@ruckc Hello, I have such a problem. Do you know how to solve it? I have a spring app and keycloak running in docker. It is logical that the spring cannot be formed through localhost to keycloak in order to validate the token, however keycloak returns iss with localhost and an external port. I don't know how to solve this problem. |
Sorry to bump this closed issue, but it's not clear to me which is the solution. Same situation:
Lines 246 to 248 in 9c6b5f9
I need to fetch metadata from the issuer since some endpoints are read only from metadata, e.g the Lines 79 to 80 in 9c6b5f9
But also other back-channel endpoints without configuration properties in Since I know both internal and external hostnames, how can I make Spring Security fetch metadata from the internal issuer hostname and accept the external hostname in metadata? Update I realized this is a different scenario, so I opened a new issue: #14633 |
Uh oh!
There was an error while loading. Please reload this page.
The problem
We currently facing a very special problem using Spring Security OAuth in conjunction with Keycloak in a container cluster (OKD) in a high regulated and networking constraint environment.
Essentially the problem boils down to the fact, that if an
issuer-uri
is set for a Spring Security oauth-client, the framework attempts to validate the ISS claim and therefore uses the specified URI as connection base for getting the/.well-known/openid-configuration
stuff.As this is hard to describe I have put together a simple schema to showcase the problem:
Considering the following configuration:
In the given example configuration the framework will attempt to get the OIDC configuration via
https://the.platform.io/auth/realms/the-realm
which is the outside URI of Keycloak that in our case is not reachable from inside the cluster due to network restrictions.Yes I might be possible to setup some kind of split horizon DNS, but that makes network setup even more complicated and not well understandable.
The other issue is, that you do not want to do a full HTTP roundtrip to the outside world, if the targeted service (Keycloak) sits nearby in the same subnet.
A lot of tickets out there try to tackle this by having multiple issuer URIs, but all of the stuff I found regarding this solution has been denied or rejected as token validation would get too complicated.
Accidentally, a colleague of mine stumbled upon the following solution:
Instead of having multiple issuer URIs, some folks just use some kind of hash value (instead of a URI) to configure within the ISS claim of the oauth provider and the oauth clients, but unfortunately we cannot do this either with Spring Security nor Keycloak.
We also found the following in Quarkus:
https://quarkus.io/guides/security-openid-connect-multitenancy#quarkus-oidc_quarkus.oidc.token.issuer
Advice appreciated
At the moment we could work around this by leaving away the
issuer-uri
setting completely but are unsure about this and an advice from Spring Security team if that should be regarded as problematic would be very cool.Possible solutions
iss-claim
that is just a value to match, and still useissuer-uri
for connectionFeedback very appreciated
✌️
The text was updated successfully, but these errors were encountered: