Configure Spring Gateway with Spring Authorization Server - spring

I have Spring Gateway application with the following Gradle dependencies:
implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-gateway'
implementation 'com.netflix.eureka:eureka-core'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
Route configuration:
#Bean
public RouteLocator routes(RouteLocatorBuilder builder, LoggingGatewayFilterFactory loggingFactory) {
return builder.routes()
.route("service_route_clients_summary", r -> r.path("/management/home/clients/summary")
.filters(f -> f.rewritePath("/api/management/home/clients/summary", "/management/home/clients/summary")
.filter(loggingFactory.apply(new LoggingGatewayFilterFactory.Config("My Custom Message", true, true))))
.uri("lb://merchant-hub-admin-service:8000/management/home/clients/summary"))
.build();
}
I want to forward /api/management/home/clients/summary to internal link /management/home/clients/summary after successful authorization with Spring Authorization Server. Is it possible to use Spring Authorization server without exposing it to outside?
What is the proper way to implement this?
Code example: https://github.com/rcbandit111/Spring_Cloud_Gateway_POC

Is it possible to use Spring Authorization server without exposing it to outside?
The Spring Authorization Server is implementing the OAuth2 protocol. If we look at the specs, we can see that it's naturally a client, which wants to authenticate itself: https://datatracker.ietf.org/doc/html/rfc6749#section-1.2. In your setup, it seems like that client is not the gateway itself, but lets say an app. So if that app should use the Spring Authorization Server, it would authenticate with it (most of the time, that means acquiring a token), before the first interaction with the gateway happens.
So to answer that question, if you want to use OAuth2 as it was meant to be used, you would need a direct connection between the app and the Spring Authorization Server, which means, it needs to be exposed to the outside. This makes perfect sense, since OAuth2 is meant to be used not with a single service, but with lots of different services, e.g. to allow single-sign-on.
What is the proper way to implement this?
You could setup your own Spring Authorization Server, implement your custom Authorization Code Grant logic, so that a client can authenticate itself and acquire a token. This could for example be a JSON Web Token (JWT). This can (should) be independent from your gateway and other services.
To authorize requests at the gateway, there are different ways. You could implement a logic yourself, which reads a JWT from the request and authorize it with the Spring Authorization Server or another identity provider, which you might have.
You can also use Spring Cloud Security with the Spring Authorization Server, which is described here: https://spring.io/blog/2019/08/16/securing-services-with-spring-cloud-gateway. This is definitely a proper way to implement it.
One more thing: as you can see, OAuth2 comes with a price, being that it is not trivial to understand and configure. You must understand it in detail, before you deploy such a setup. On the other hand, its a solid standard and you can have feature like single-sign-on out of the box. So if you only need authorization for single or multiple apps to a single service, there are probably easier ways to gain a token and secure an app and OAuth2 is maybe overkill. But OAuth2 really pays off, if you have lots of services and lots of apps which should be authenticated with a central (sometimes company-wide) solution.

Related

How to secure Spring Cloud microservices using Spring Security?

Here is the authorization service. It has endpoints to login and receive a JWT using either a custom username/password or social OAuth (Facebook, GitHub etc.).
I have a Eureka server setup and Zuul gateway service. From what I understand, there are two ways to go about implementing secure microservices. You either proxy requests through the auth service, or you send requests to the requested service (Ex. Service A) and service A authorizes using the auth service.
I would like to use the second way, however I'm having trouble implementing it. Is my understanding correct? Is there a way to setup service A somehow so that certain paths (configured using Ant matchers) will have to authorize using the auth service, which will set the SecurityContext appropriately and inject a UserPrincipal into the request. If anyone can point me to a good guide for this that would be much appreciated.

Spring Keycloak authentication - serves both web application and web service

Our stack includes the following services, each service runs in a docker container:
Front-end in React
Backend service based on Spring boot "resource-service"
Keycloak
Other backend service (consumer)
Both the front-end and the consumer services communicate with the backend using REST API.
We use Keycloak as our user management and authentication service.
We would like to integrate our Spring based service "resource-service" with Keycloak by serving both web application and a service flows:
Web application - React based front-send that should get a redirect 302 from the "resource-service" and send the user / browser to login in the Keycloak site and then return to get the requested resource.
Server 2 Server coomunication - A server that need to use the "resource-service" API's should get 401 in case of authentication issues and not a redirection / login page.
There are few options to integrate Spring with Keycloak:
Keycloak Spring Boot Adapter
Keycloak Spring Security Adapter
Spring Security and OAuth2
I noticed that there is a "autodetect-bearer-only" in Keycloak documentation, that seems to support exactly that case. But -
There are a lot of integration options and I'm not sure what is the best way to go, for a new Spring boot service.
In addition, I didn't find where to configure that property.
I've used approaches one and two and in my opinion, if you are using Spring Boot, use the corresponding adapter, use the Spring Security adapter if you're still using plain Spring MVC. I've never seen the necessity for the third approach as you basically have to do everything on your own, why would anyone not use the first two methods?
As for using the Spring Bood adapter, the only configuration necessary is the following:
keycloak:
bearer-only: true
auth-server-url: your-url
realm: your-realm
resource: your-resource
And you're done. The bearer-only is so that you return 401 if a client arrives without a bearer token and isn't redirected to a login page, as you wanted. At least that's what's working for us :-)
After that, you can either use the configuration for securing endpoints but it's a bit more flexible to either use httpSecurity or #EnableGlobalMethodSecurity which we're doing with e. g. #Secured({"ROLE_whatever_role"}).
If you're using the newest Spring Boot version combined with Spring Cloud, you might run into this issue.
I configure my resource-servers to always return 401 when Authorization header is missing or invalid (and never 302), whatever the client.
The client handles authentication when it is required, token refreshing, etc.: Some of certified OpenID client libs even propose features to ensure user has a valid access-token before issuing requests to protected resources. My favorite for Angular is angular-auth-oidc-client, but I don't know which React lib has same features.
Keycloak adapters for Spring are now deprecated. You can refer to this tutorials for various resource-server security configuration options. It covers uses cases from most simple RBAC to building DSL like: #PreAuthorize("is(#username) or isNice() or onBehalfOf(#username).can('greet')")

Grant type selection for OAuth2 implementation

I would like to build a web based application using Spring Boot micro service. I am planning to use OAuth2 and OpenID Connect to implement authentication and authorization in my application. What grant type I have to choose to implement OAuth2 if my application is going to be single page application (Angular.js for front end Spring Boot services for backend)?
You can use Implicit or Authorization Code flow with a single page app :
In order for a single-page app to use the Authorization Code flow, it must be able to make a POST request to the authorization server. This means if the authorization server is on a different domain, the server will need to support the appropriate CORS headers. If supporting CORS headers is not an option, then the service may use the Implicit Flow instead.
oauth.com
but it's recommanded to use Authorization Code flow :
It is generally not recommended to use the implicit flow (and some servers prohibit this flow entirely). In the time since the spec was originally written, the industry best practice has changed to recommend that public clients should use the authorization code flow with the PKCE extension instead. oauth.com

Spring Security for RESTful webservice

I am developing a RESTful web service as a back-end layer for mobile application. This service receives combination of device id (as user id) an a pin (as password), and passes to another back-end service, that validates and returns the status of successful login along the user information, in case, the user is authorized. My service is not validating the user. And mobile sends sub sequent requests to my RESTful service.
So, please suggest, how can I make all this system(especially the RESTful) secured, using Spring security.
I am using a Tomcat server, Spring and Jersey
I recently implemented a method to secure my existing RESTful APIs in Spring. I have used a token based authentication model using OAuth2. In my project, I wanted to secure my API's in a way that every request is individually authenticated and authorised based on the token present in the header. If this is something you are looking for, then I would highly recommend you to take a look at the documentation here. If there is anything you are stuck at while implementing it. Please do let me know.
Also, you can find multiple projects for Spring and OAuth here

Authentication and authorization in Spring Data REST

I am implementing a Spring Data REST based app and I would like to know if there is an elegant way to implement authentication and authorization rules using this framework or related frameworks.
All HTTP requests to the REST server must carry authentication headers, I need to check them and decide to authorize or not based on the HTTP method and the association of the authenticated user with the resource being requested. For example, (the app is the REST server of an e-learning system), the instructors can access only their own course sections, students can access only the courses sections they are subscribed, etc.
I would like to know if there is a default way to implement authorization in Spring Data REST. If the answer is no, could you make a suggestion for my issue? I am thinking about:
Servlet Filters
Spring Security
Spring Data REST Handlers (how to access the HTTP headers?)
The best bet for you is Spring Security.
That would help you achieve authorization is much simpler manner.
Spring Security would require you an implementation that looks at request headers and performs the log-in operation programmatically.
Refer the accepted answer here.. I had followed the same and implemented the security layer in front of my rest services ( which were build using RestEasy )
RESTful Authentication via Spring
There is an alternate method as well..
Refer
http://www.baeldung.com/spring-security-authentication-provider
In both cases you can disable the session creation by declaring the stateless authentication in spring security, this would help you improve the performance considerably when large volume of hits are made to the state-less REST services..

Resources