Oauth 2 : Spring Boot - Separate Resource server protecting Microservices - java

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

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)

Add Oauth2 scopes (Keycloak implementation) to request header before client Authorization request fires (Sring boot + Keycloak)

I'm using keycloak as an auth server, my client app is a sring-boot one with the keycloak client adapter dependency.
One challenge I have not yet tackled, is the insertion of specific scopes on the request header before an authorization request executes (towards the auth server - keycloak auth endpoint).
Right now I've tested my endpoints (using access-tokens with limited capabilities by the use of scopes ) via curl and/or postman and they behave as expected, so I know they work. But I don't know when/how can I append them as a "scope" request header when using spring boot (mainly because that's all plumbing code that runs under the hood in spring boot).
I assume I would need to use some kind of interceptor/filter that gives me access to that request object just before "executing", but I haven't been able to find a concrete example.
Any suggestion/guidance or pointing towards relevant documentation would be greatly appreciated.
thanks in advance.
UPDATE:
Since my last post; I've tested several combinations to achieve this, and sadly none have worked, it is quite amazing that something as basic to oAuth2 like injecting scopes on the authorization request, isn't supported easily out of the box by the spring boot keycloak adapter. I've tried following approaches:
1 - Using a custom implementation of Sping "ClientHttpRequestInterceptor" . This doesn't help because this interceptor provides access to the front-channel requests (or requests reaching the app through the front-controller), it doesn't provide access to the back-channel request (of which the auth-request is part of).
2 - "ClientHttpRequestInterceptor" is usually also used in conjunction with a "RestTemplate" custom implementation. The problem here is that this would work only to those requests executed through an instance of the RestTemplate, and this is not what happens with the back-channel requests used by the spring-adapter
3 - Using Configuration objects based on springsecurity. spring-security offers usefull filters for configuration components that could help here (#Configuration, #EnableWebSecurity, #ComponentScan(basePackageClasses = KeycloakSecurityComponents.class OR #KeycloakConfiguration); This global type of configuration basically mix your spring boot keycloak adapter app with springsecurity code, and while this works fine for most cases, if you happen to use/need "policies" (By using the "keycloak.policy-enforcer-config" type of configs), then your policies will stop working, and whole set of new issues will arise.
FROM: https://oauth.net/2/scope/
OAuth Scopes
tools.ietf.org/html/rfc6479#section-3.3
Scope is a mechanism in OAuth 2.0 to limit an application's access to
a user's account. An application can request one or more scopes, this
information is then presented to the user in the consent screen, and
the access token issued to the application will be limited to the
scopes granted.
The OAuth spec allows the authorization server or user to modify the
scopes granted to the application compared to what is requested,
although there are not many examples of services doing this in
practice.
OAuth does not define any particular values for scopes, since it is
highly dependent on the service's internal architecture and needs.
It is clearly stated that scopes can be requested by the application to receive tokens with limited access, yet all on-line documentation to achieve this with the keyclock adpaters (and particularly spring boot) is almost(completely?) non existant.
some redhat's keycloak expert could offer suggesstion?

JHipster: How to make secure calls to microservices from UAA server with unauthenticated user

Dear StackOverflow Community,
I found that someone else already asked something similar to my problem here but didn't receive any good answers.
I want to create an entity on microservice A as soon as a User gets activated on the UAA server (when activateAccount() is called in the AccountResource).
At this point the user is not authenticated and therefor I'm not able to use an AuthenticatedFeignClient, as I would on other microservices. When I disable authentication on microservice A and use a FeignClient as described in the JHipster Docs, it works as expected, but I don't want to leave the endpoint reachable from the outside. Is there a way to let the UAA server authenticate itself or only allow the UAA server to access this specific endpoint in microservice A's API?
Edit:
I finally got it to work by using AuthenticatedFeignClient. I simply copied the client package and FeignConfiguration from the microservice to the uaa server and changed the security settings in application-dev.yml and application-prod.yml as follows:
security:
client-authorization:
access-token-uri: uaa/oauth/token
token-service-id: uaa
client-id: internal
client-secret: internal
despite you already found the correct solution, I should quickly explain why this is correct.
JHipster UAA supports two different authorization flows: user-to-service and service-to-service. The first one is the most commonly used. This is when you want to control what a user is permitted to do in your application.
A service-to-service call doesn't consist of any user related issue, as not the user is "logging in" but your microservice itself. That's why should add the config.
The stuff with copying the annotation interface from other apps into UAA is a little bad design. I'm considering to make a move of these annotations from generated code into the JHipster library to solve this.
I found what was the problem regarding authentication and authorization between microservices, it took me three days to figure it out how to solve this. I was using the tag #AuthorizedFeignClient and due that I'm protecting the api resource using: #PreAuthorize("hasRole("" + AuthoritiesConstants.USER + "")"), I was not able to reach them through a feign client because #AuthorizedFeignClient just verify if the resource is authenticate or not (see config/SecurityConfiguration.java) but it wouldn't be able to reach the endpoint because the resource that I wanted to reach has another security layer which is that is protected by role (#PreAuthorize), so, in these cases we will need to use #AuthorizedUserFeignClient instead of #AuthorizedFeignClient.
The use about #AuthorizedUserFeignClient has not been documented by Jhipster yet, and it would be good idea to do it, see: https://www.jhipster.tech/using-uaa/#inter-service-communication
I hope this could help other people that has these kind of problems between inter-service-communication.

Update Spring Bean Property Across Multiple Servers

Here is my scenario: I have a Spring Bean called APIBean which acts as an API client to a remote REST service. This Bean contains a property called hostName which is the IP Address of the Remote Server. This functions as the base URI when the APIBean client makes REST calls. The initial value of this hostName property is pulled from application.properties.
The challenge I have is that the hostName property is subject to change. I have a web form where a User will update the hostName property when its address changes. This is pretty straightforward in a single instance environment, but my application is distributed in AWS and behind an Elastic Load Balancer.
So how should I go about applying this change to all other instances of this Spring Boot application?
I've looked at Spring Cloud Config which externalizes application.properties to a centralized Git repository. It even includes a /refresh endpoint which you can hit with a POST request to update Beans annotated with RefreshScope. But this endpoint only refreshes the single instance you are accessing. It does not affect any other distributed instance.
These frameworks are great and I feel the solution is close but I need a little help with the last mile. This must be a common development issue with distributed applications. How can we update a Spring Bean property across multiple servers?
I think you are looking for Spring Cloud Bus: https://github.com/spring-cloud/spring-cloud-bus.

Passing on LPTA token on webservices call isn't working

I've got a j2ee web application using j2ee security, so the identity of the user is propagated from WebSEAL to the application, running in WAS7. I'm now trying to make a SOAP webservices call and propogate the user identity in that webservices call. To do this, I grab the LTPA (WSCredential) and LPTA2 (SingleSignOnToken) using the WSSubject calls and attach them to the webservices call using.
bp.getRequestContext().put(Constants.REQUEST_TRANSPORT_PROPERTIES,sendTransportHeaders);
where bp is my BindingProvider. This all should work. But when I make a webservices call, I get back this exception.
Cause =java.io.IOException: Unable to deserialize the Subjects in this Context
I looked at the fields within the LTPA token and all seems right (same realm between the token and the j2ee security realm webservice I'm calling, the token is forwardable, etc), and I cannot find much about this error online, except for (what seems to be an unrelated) case when trying to pass it into the EJB and one case where the realms don't match.
Any ideas? Thanks.
Can you state clearly as to what you are trying to do here?
You should be able to pass the LTPA tokens across transparently with just configuration instead of trying to write some code to achieve the same.
The Web Applications making the Web Service calls to another WebSphere server.
have a quick read at this.
http://www.ibm.com/developerworks/websphere/techjournal/0607_desprets/0607_desprets.html
Things in WAS7 should be very similar to WAS V6.
HTH
Manglu
#jeffsix: are you trying to make a webservice call from application running in one websphere server to another application in another websphere server? Make sure LTPA keys are same on both server.

Categories