-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Spring Boot Admin with OAuth2 sample implementation #1262
Spring Boot Admin with OAuth2 sample implementation #1262
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elijah-pl Thank you for the hard work for adding this sample.
I think it would be great to also have a short chapter in the documentation, describing the steps we need to take for the admin server to integrate with oauth2 (leaving out the authorization and resource server part). Could you add some words on it?
...min-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml
Outdated
Show resolved
Hide resolved
...min-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml
Outdated
Show resolved
Hide resolved
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.security.oauth.boot</groupId> | ||
<artifactId>spring-security-oauth2-autoconfigure</artifactId> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This module is in maintenance mode. I'm not very happy to use it as the authorization server most probably needs to be rewritten with the next spring security version (5.3)...
I wonder if there is any mock-authorization server we could use instead of rolling our own "implementation"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spring team prepared demo application with new OAuth2 approach some time ago. In that demo they made use of Cloudfoundry UAA
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it depends on how easy it will be to set up authorization server using Spring Security 5.3. If it will be the matter of adding @SpringBootApplication class + application.yml, then probably we could stick to native solution.
At this moment I know nothing about 5.3, I will check it out later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, taking into consideration the fact that 5.3 is not on the horizon, and you are not quite satisfied with spring-security-oauth2-autoconfigure
, I decided to update my solution and make use of Cloudfoundry UAA.
I played a bit with it, it was quite easy to setup. It supports all major grant types that we may be interested in: authorization_code
, client_cridentials
, password
, etc.
At this point, I have just migrated already existing solution with password
grant type.
If you are ok with Cloudfoundry UAA, we can close this thread and agree on grant type in another thread.
Whatever type we pick, it should be easy to change it in uaa.yml
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think, this sample shouldn't involve cloud foundry. May be the OpenId connect Playground may prove useful
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The spring security team also announced that they won't provide any authorization server. They point users to keycloak or other oidc services.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to make this a stand-alone experience which is good for a sample I believe it is possible to implement the authorization server application based on good old spring-security-oauth2
while the resource server and the SBA would benefit from first-class oAuth2 support in Spring5.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The spring security team also announced that they won't provide any authorization server. They point users to keycloak or other oidc services.
Could you please provide the source link? As I can see in their blog post (updated section), it seems like they changed their mind.
Anyway, I agree that this example, probably, should not focus too much on authorization server configuration - it should be more about the integration of SBA with Spring Security OAuth2.
My motivation for using Cloudfoundry UAA was the fact that it did not require an account creation on any 3rd party service in case someone wanted to run the example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please provide the source link? As I can see in their blog post (updated section), it seems like they changed their mind.
I have no other information. But currently for me their decision is unchanged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are no longer planning on adding Authorization Server support to Spring Security.
https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Features-Matrix
...admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml
Outdated
Show resolved
Hide resolved
client-secret: secret | ||
provider: my-provider | ||
client-authentication-method: basic | ||
authorization-grant-type: password |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this sample should stick to common practices and use the authorization_code
grant type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please provide an example flow? As far as I know authorization_code
grant type is not well-suited for server-to-server authentication, so I try to understand your vision of how it should work step-by-step
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we both have a different understanding of the whole picture.
In my understanding, a not logged-in user is forwarded to the configured authorization provider by SBA. The authorization token allows the user a) to use SBA and b) to use the actuator endpoints of the client applications. Therefore SBA needs to forward the authorization token in requests made to the underlying applications. This should use the authorization_code
grant-type.
The SBA server does also query some endpoints in the background (e.g. /health
and /info
). So the SBA server needs to authenticate against the client applications. This authentication should be done via the password
grant-type or using basic auth.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SBA server does also query some endpoints in the background (e.g. /health and /info). So the SBA server needs to authenticate against the client applications. This authentication should be done via the password grant-type or using basic auth.
I don't think I follow this part. Why client applications must require an additional basic authentication in order to expose /health
and /info
endpoints? Should not those be in the scope of the token?
On the other hand, if SBA server is protected by OAuth2 and token is required to use it, how resource server should register itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think I follow this part. Why client applications must require an additional basic authentication in order to expose /health and /info endpoints? Should not those be in the scope of the token?
Yeah the SBA server must have a token that allows to access these endpoints. (As alternative it might use some credentials and basic authentication to access those - think of it like an api key - which is imho easier to setup)
On the other hand, if SBA server is protected by OAuth2 and token is required to use it, how resource server should register itself?
Either just the endpoint for registering is left unprotected or the same applies here:
The sba clients either needs a oauth2 token or some other form of credentials for authentication...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prepared an example version with the scenario you proposed, however I encountered problems during testing the solution:
1. Refreshing available actuator endpoints
Consider the following scenario:
Given:
* Authorization, SBA and Resource servers are up.
* Resource server is protected with OAuth2, but allows accessing to /health
and /info
endpoints with basic authentication.
When:
* Resource server registers itself using basic authentication before SBA login is performed and token is obtained.
* SBA (using basic authentication) fetches available actuator endpoints of the Resource server.
* SBA login is performed and token is obtained.
Then:
* Requests to the Resource server include Bearer token
* UI does not display all details, but only Metadata and Health
* After restarting Resource server all endpoints are displayed
Reason:
* It seems like available endpoints are not refreshed after being once fetched.
Solution:
* Well, I am not sure if there is a way to trigger a refresh. Please, advice.
2. Problem fetching OAuth2AuthorizedClient
from HttpHeadersProvider
Put simply, Spring provides a mechanism to fetch client (with token) using client-id and principal, however I can not find a convenient way to obtain a principal. SecurityContextHolder.getContext().getAuthentication()
returns null
when called from HttpHeadersProvider
.
The workaround I found for now is to implement custom in-memory OAuth2AuthorizedClientService
that is able to fetch any client with suiting scope, however I am not satisfied with the solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put simply, Spring provides a mechanism to fetch client (with token) using client-id and principal, however I can not find a convenient way to obtain a principal. SecurityContextHolder.getContext().getAuthentication() returns null when called from HttpHeadersProvider.
This is due to 2 facts:
-
Spring Boot Admin makes fetches in the background (without any user interaction). So SBA still need some own token. For these background fetches the easiest way would be to have some kind of basic auth using username/password or an api-token
-
Spring Boot Admin uses the WebClient for making requests. Due to the reactive nature the request ist executed in a different thread and the ThreadLocal backing the
SecurityContextHolder
is not available.
If you just need access to the original headers write aInstanceExchangeFilterFunction
which has access to the headers from the original request (filtered by theHttpHeaderFilter
and settings fromspring.boot.admin.instance-proxy.ignored-headers
- defaults to"Cookie", "Set-Cookie", "Authorization"
).
If you need the principal itself I guess, we could include it to the request attributes passed to theInstanceExchangeFilterFunction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you just need access to the original headers write a
InstanceExchangeFilterFunction
which has access to the headers from the original request (filtered by theHttpHeaderFilter
and settings from spring.boot.admin.instance-proxy.ignored-headers - defaults to "Cookie", "Set-Cookie", "Authorization").
Not sure that access to the request headers would be enough to solve the problem.
Here is how OAuth2Login works in Spring 5
. The requests between SBA front and SBA back would be authorized with a Cookie. All tokens obtained from OpenID Connect provider will be stored on the backend and fetched into Authentication
object by Spring Security in the context of request processing. So basically this is what you want to do inside HttpHeadersProvider
(pseudo-code):
@Bean
public HttpHeadersProvider customHttpHeadersProvider() {
return instance -> {
if (requestContext.getRoute().equals("/actuator/info") || requestContext.getRoute().equals("/actuator/health")) {
// user-agnostic request
// use token obtained with Client Credentials Grant
} else {
Authentication authentication = securityContext.getAuthentication(); // as SecurityContextHolder.getContext().getAuthentication() will not work in reactive world
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
OAuth2AuthorizedClient client = authorizedClientService
.loadAuthorizedClient(oauthToken.getAuthorizedClientRegistrationId(), oauthToken.getName());
httpHeaders.add(HttpHeaders.AUTHORIZATION, String.format("Bearer %s", client.getAccessToken()));
}
Without having requestContext
and securityContext
defined above I cannot see how the HttpHeadersProvider
could be implemented.
...n/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java
Outdated
Show resolved
Hide resolved
...mple-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/application-test.yml
Outdated
Show resolved
Hide resolved
...mple-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml
Outdated
Show resolved
Hide resolved
...in-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/wait-for.sh
Outdated
Show resolved
Hide resolved
...samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/wait-for.sh
Outdated
Show resolved
Hide resolved
Please let me know if solution meets your expectations, so I can start working on documentation part. |
@elijah-pl sorry I'm currently quite busy and this PR is very huge. It will take some time for me to review this. |
I also encountered the problem of OAuth, looking forward to this sample |
@Hccake So may be you want to follow allong the instructions added in this PR and help me with the review? |
@joshiste Sorry I tried to download the pr code but it didn't work because I won't be using cloudfoundry。 |
Joining the discussion. I've been trying to integrate SBA with newest Spring Security 5 OAuth2 implementation. I stopped at the same place as @elijah-pl did. When your code gets control in custom In general I believe that interface of |
One more comment regarding the OAuth has a grant type named SBA will have to manage these tokens (take care of expiration and renewal) and use different tokens depending on the endpoint being reached. |
Sorry for excessive activity in the thread. My research shows that I believe there is no way of implementing the I believe that the solution with custom |
@masm22 Thanks for your research. Indeed, as I mentioned in the comment, custom At this point, I am not planning to do any further investigations on subject, as task requires a bit of @joshiste's commitment and cooperation. |
@elijah-pl sorry I let this PR slip a little bit - I'll will have a look right now at your comments. |
@masm22 Also thanks to you that you help reviewing this PR! |
c380d4e
to
c8f2793
Compare
Hello Guys, is this PR still relevant? |
Hmm I the PR itself is a bit outdated - but the topic itself not... |
I have OAuth2 working in servlet mode with Hazelcast session enabled. One thing I've noticed that I don't see addressed here is that when the session is expired/lost, the front end service calls will start getting 302s back. It looks like the front end code is equipped to handle 401s by redirecting the window.location, but 302s are not handled and require an explicit refresh of the browser to get re-authenticated. |
57d7211
to
d2b765b
Compare
The aim of this PR is to close #1195 by providing a sample application demonstrating integration with Spring Security 5 and OAuth2 module specifically.