Spring OAuth2 Resource and Authorization servers - java

In Spring OAuth2 it it possible to separate Authorization server and Resource server into separate applications.
Like stated in :
https://github.com/spring-projects/spring-security-oauth/wiki/oAuth2
Seemingly both web applications require these:
instance of AuthorizationServerTokenServices
instance of ClientDetailsService
QUESTION:
Is it so that AuthorizationServerTokenServices from Authorization server must use the same data source as the AuthorizationServerTokenServices from Resource server?
The same question goes for ClientDetailsService.
E.g. when having multiple resource servers, and an authorization server, all of them must use the same database for token management, and then same database for the client management?

The answer is yes. If one is writing own resource server and own auth server, they have to share the database.
This question is duplicate of
oAuth2 Token validation/verification in Spring
There is another thread with similar topic confirming the answer:
validate OAuth 2.0 access token from a Spring RESTful resource server

Related

Should we expose REST API as an OAuth 2 resource server?

I have a spring boot application exposing several REST API endpoints. I want to enable google oauth authentication (authorization code grant) on it. I am guessing what is correct way to do this out of following options:
Have separate application as OAuth 2 client (i.e. with spring-boot-starter-oauth2-client dependency and make the existing app a resource server (i.e. with spring-boot-starter-oauth2-resource-server dependency)
a. This Udemy's course keeps two application separate: resource server, OAuth 2 client. Then it seem to need a proxy REST endpoint in oauth
2 client project corresponding to every REST endpoint in resource server. REST end point in OAuth 2 client retrieves access token and adds it to every request to corresponding REST endpoint in resource server.
b. This stackoverflow threads talks about making same application both OAuth2 client as well as resource server
Make the existing app OAuth 2 client. (that is include spring-boot-starter-oauth2-client dependency) and simply require user to be authenticated to access REST endpoint URLs.
I have following doubts:
Q1. Should REST API always be exposed as resource server? And if yes, then is approach 2 not-so-recommended way? (as it does not expose existing REST API as resource server but as a part of OAuth client with restricted access to those APIs)?
Q2. If approach 2 is not fine, then which of approaches (1.a) and (1.b) are preferred or when to prefer one above other? (I believe (1.a) is more suitable when we want single OAuth client as a point of access for several different resource servers.)
In OAuth2 world, a REST API is a resource-server by definition.
In your scenario, Google currently is an authorization-server. You could hide it behind a Keycloak instance or something else capable of user identity federation if you need to extend to other identity providers (Github, Facebook, etc.) or want some roles definition, but as Google serve JWT access-tokens, you can use it for you resource-server security (if google IDs are enough for your security rules).
In both cases (Google directly or with an OIDC authorization-server in the middle), you can find sample configuration here (or there if you prefer to stick to spring-boot-starter-oauth2-resource-server but it requires more Java conf as you can see in tutorials).
I personnaly don't like to merge client(s), resource-server(s) and authorization-server(s). My clients are generally mobile and web with client-side rendering (Angular), but even for spring clients I'd keep it separate.
There is a special case, thought: when a resource-server delegates some of its processing to another, then, by definition, it is a client too. In that case, it is possible that security requirements and mechanisms are pretty different:
is your API authenticating in its own name (using client credentials flow)? In that case, you might use spring-boot-starter-oauth2-client to negotiate access-token to be used when issuing requests to other service.
is your API issuing requests in the name of authenticated user and does the other service know about the authorization-server which issued user authentication? In that case, you can forward the token you received
is the service you are consuming not OAuth2 at all? (just requires basic auth header for instance)

How to secure methods annotated with #StreamListener?

I'm developing a web application based on microservices architecture. Its primary framework is Spring Cloud Data Flow, microservices are communicating with each other via message bus (RabbitMQ), REST-endpoints are exposed only by a gateway wjich is also a central point of authentication.
I want to follow the global authentication, local authorization approach using OAuth2 tokens, but a problem has occurred: I don't understand how to configure authorization process on microservices a.k.a use #PreAuthorize on methods annotated with #StreamListener, and I can't find any examples for this.

Oauth 2 : Spring Boot - Separate Resource server protecting Microservices

For my recent project, I have created a separate resource server using spring boot. Resource Server is configured in a way that it will check for 2 legged and 3 legged access to an API and also validates the JWT token. Resource server is an independent spring boot jar running in its container.
We have created several microservices using Spring Boot which are executable jars, deployed and running independently in their container. Resource server will protect end points exposed in these microservices. For that, I have created a RestController in resource server in which end point is exposed which will call the microservice end point when request comes in. for e.g
Microservice.java - Running at port 8080
#RequestMapping("/getUser")
public String getUserName(){
return "xyz";
}
Resource Server - Running at port 8090
ResourceServerController.java
#RequestMapping("/userInfo")
public String getUserName(){
// calling above microservice using rest template
}
There can be several end point in a several microservices and as we have to protect them, is it right to proxy every end point in the rest controller of a resource server? I am not sure whether it is a correct approach. Other approach which we think of is to create a jar of resource server and deployed as a dependency with every microservice. In this way, we do not need to proxy end points in the Rest Controller of Resource Server.
Just wanted to know the best way to Protect microservices using separate resource server.
Sharing Libraries is not a recommended option. A huge benefit of Microservices is independence and that would go for a toss if you do this.
A better option would be to see if you can provide access to API based on scope. That way, when your Authorization Server issues JWT token, it sends all the applicable scope for the user.
Then, in your Resource Server(s) , you can enable access to Microservice using the following annotation in Spring Boot
    
#PreAuthorize("#oauth2.hasScope('read')")
Another approach is, you can create roles and PreAuthorize using Roles.
If the above options doesn't work out, the current approach that you are following based on Proxy Service is perfectly fine. Only aspect that you should consider is to see if the JWT token validation can be moved to the respective Microservices so that all your services are protected.
Again, Code duplicacy is perfectly fine when you are implementing Microservices and if that is your main concern, don't hesitate to add the same logic in every service. With Microservices, Duplication is better than wrong abstraction
JWT is the self-contained token, which can store scope of access for REST-service users. JWT is issued by the Authorization server.In your Resource servers, you should validate every request from REST-service users. If your Resource server(s) runs on spring-boot you can use the following annotation:
#PreAuthorize("hasRole('ROLE_VIEW')")
As for the part where your services call each other, there no need to use JWT because no REST-service users involved.
Microservices can be secured by simple BasicAuth, CORS or locate them in one network without access from an external network

Authenticating rest endpoints and the UI using Okta

We have a Java 8 backend application using SprintBoot with an embedded Jetty server.
The UI for the application is a Single Page Application built using React.
Currently I have enabled authentication by integrating with Okta using the spring security SAML extension. When the assertion is posted by Okta to my app, I create a session and the JSESSIONID is sent in the cookie.
This was fine until now when we had a very simple UI serving few UI components.
However, now we have several REST endpoints in our backend and we would want them to be authenticated as well. REST endpoints themselves are developed using Jersey.
If I understand correctly, SAML is clearly not the choice for pure REST based endpoints as SAML is mainly a browser based protocol. These REST endpoints will be called by our UI as well we want them to be independently called via Postman or something for testing.
When a client would call these REST APIs, I am guessing the client should send an Authorization header which should be checked by one of the authentication filters in the backend. After validating the client and the user, the filter should inject the user information in the SecurityContext because Jersey injects SecurityContext in all of the REST endpoints. Then it becomes easier to fetch the user from this SecurityContext.
Upon reading, it seems Okta OpenID Connect can be one choice which issues a JWT. However I am not clear on how to use this. That is, when Okta issues a JWT should our UI or any client for that matter keep sending the JWT in the Authorization header to our APIs and then our APIs in turn should send the JWT to Okta to validate it?
Question is what is the best choice to serve both, a login for the UI and a session and authenticating REST endpoints? Not to mention the REST APIs will be stateless in nature.
When a client would call these REST APIs, I am guessing the client
should send an Authorization header which should be checked by one of
the authentication filters in the backend
In OpendID Connect (OIDC), that value in the Authorization header is id_token which can be in JWT format. This id_token is issued by the OIDC server as the last step for whichever OIDC grant type you choose and applicable to your case.
Upon reading, it seems Okta OpenID Connect can be one choice which
issues a JWT. However I am not clear on how to use this. That is, when
Okta issues a JWT should our UI or any client for that matter keep
sending the JWT in the Authorization header to our APIs and then our
APIs in turn should send the JWT to Okta to validate it?
Think that you have 3 components in this architecture. Relying Party (client), Identity Server / Authorization Server / OIDC Provider and Resource Server (your backend and it's data). When Authorization Server issues and id_token to Relying Party, your Resource Server also knows this token. So when you request for data in resource server, you will present your id_token to Resource Server and it knows if it is valid id_token or not
Question is what is the best choice to serve both, a login for the UI
and a session and authenticating REST endpoints?
OIDC Provider (or Identity Server if you need more complex operation), since OIDC is Authorization (OAuth 2.0 at core) and Authentication.

Spring Security OAuth 2.0 - Creating a custom resource server

I'm configuring Spring Security OAuth 2.0 to secure a number of Jersey exposed REST services. I'll be using an external identity server as the authorization server. It'll be responsible for issuing and storing access tokens to its own token store. So, token validation process should be done against this server through a validation web service.
How should I configure Spring Security to work only as a resource server?
All the examples I found uses Spring Security to create both authorization server and resource server (which have access to the token store). This is not possible in my case.
Thanks.
I figured out how do it. A sample configuration is posted here, I hope it would be useful for someone in the future.

Categories