Authenticating Spring Boot APIs - java

Background:
I have some APIs routes (~15 or so) that I want to authenticate. Right now, I can run the spring boot server locally (mvn spring boot run) and call all of the APIs. I can also deploy to Heroku and call the APIs from the Heroku cloud platform. This is great!
Here are the problem:
I need to provide authentication for the APIs. The idea is that when running the spring boot server, I would need to pass in a token in order for the API call to work. If not, then I should get some unauthorized error(401 or 403 I think). Additionally, I would need to be able to seperate these APIs by roles (user, admin, etc).
Ideally, I would want to build a test client(perhaps a webpage) that could call these APIs. I'm not exactly sure how authentication would work here.
I'm a bit confused because I tried working with Auth0 but that only seems to apply for 1 API? Auth0 allows for me to generate tokens but I'm not exactly sure how to integrate it with SpringBoot. It asks for an audience but I'm not sure what that should(especially since I'm running the Spring Boot server locally).
The next thing I was going to look at was Spring Security.

Setup Sprint security for your application. There is even an example form Auth0 on hwoto do this: https://auth0.com/docs/quickstart/backend/java-spring-security5/interactive
Once you have spring security running you can annotate your methods accordingly. e.g. #PreAuthorize("isAuthenticated()")
If the authorization check fails spring will respond with the error code 403 automatically.

The audience of an access token is the resource-server the token was emitted for. In your case, probably http://localhost:8080. This will change in production. This audience should be requested by clients when getting an access-token.
Resource-servers should be configured with spring-boot-starter-oauth2-resource-server. Spring default HTTP status for unauthorized request is 302 (redirect to login), but it is best practice for resource-servers to return 401, and it's an easy task:
http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Restricted Content\"");
response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
});
For more details about resource-server configuration, you can have a look at this tutorials I wrote. It cover authorities mapping and role based access-control. It is designed for Keycloak, but switching to any other OIDC authorization-server (including Auth0) is mostly a matter of editing properties (except for the 1st tutorial where authorities converter implementation must be slightly modified to read the claim(s) you configured in Auth0 to put groups / roles).
How clients get an access token depends on the use-case: if acting on behalf of a user, authorization-code flow (with PKCE for "rich" clients) should be used, but we client is a acting in its own name (without the context of a specific authenticated user), then client-credentials should be used. For Spring clients (Thymeleaf UI as well as REST clients like WebClient, use spring-boot-starter-oauth2-client.
I strongly recommend you use JUnit instead of a client UI to test your app. Refer to the tutorials I already linked if you don't know how to mock identities and HTTP requests.
If you still want to build a client with UI to query your API, you might save quite some time by exposing OpenAPI spec (see springdoc-openapi for that) and generate a client library with openapi-generator.

Related

How to use spring-security to redirect to original POST request after OAuth2 successful login?

I have a Spring Boot GraphQL application that is using Spring Security to authenticate via an OAuth2 provider.
Since graphql requires POST requests with query/mutations as request body; my initial unauthenticated request is a POST. This does not work with the default WebSessionServerRequestCache because it only caches the initial request if it is a GET request.
Is there a way to configure the application so that upon successful login, the user is redirected to the original POST request they made (including the body)? Or does this require a custom Request Cache implementation?
I should add, I found this issue: https://github.com/spring-projects/spring-security/issues/9690 which is basically the exact functionality that I'm looking for but for a different reason (SAML login). And it was closed because they determined they could do things differently for their implementation. However, this application of spring security to a GraphQL application seems common enough that I thought I might be missing something obvious.

Is possible to create a role based application with OAuth2?

What I'm trying to do is to create an application with Angular frontend and Spring Boot backend with OAuth2 authentication.
The issue is that I don't know how to get on the frontend the ROLES user has so that I'll be able, for instance, to show something role-based on the page. Yes, there are scopes that OAuth provides in the response but the problem is that these scopes are for the CLIENT but not for the specific USER itself. And that CLIENT is my frontend side (correct me if I'm wrong) which basically means that every user operating my application(client) going to have the same scopes(roles). Moreover, I can specify roles on the backend with the help of Spring and UserDetailsService and then use those roles with #PreAuthorize, etc. But not on the frontend side.
Just as an example, if I simply used single JWT then with a token itself I'd return both the username and roles to frontend. And then I could store that data and use it on the frontend side according to my needs.
So what I'm asking is if it's actually possible and if this is correct to do so?
And how can I possibly implement such behavior?
OAuth doesn't solve this problem and it is best solved via claims in your API. OAuth should deal with authentication only. My below post may help you to think about the best separation: https://authguidance.com/2017/10/03/api-tokens-claims/
In a nutshell you will have to look up user rights such as roles after the OAuth processing completes.
There is a great video from Spring developer on YouTube about OAuth2/OpenID Connect. It shows how to implement the resource server using the newest Spring Security 5 solution.
Probably the easiest and the best way to achieve this is to use an OpenID Connect server which will provide all user management stuff. On the market there are many solutions. Auth0 and Okta are Identity Clouds which provides their services for small amount of money. On the other hand you have Keycloak, which is a server which you can install in Docker or even on bare metal - it's free and open-source.

Don't REST control a URL in Spring Boot? Exclude url?

I am using some angular ui routing in some places, and I wanted the java server to not control some of the urls.
Perhaps it makes more sense to run the java app elsewhere? The reason I have the angularJS in the same url is because there are some authentication checks for my springboot app. So I want most URLs controlled.
But there's a few where I may want to control the authentication----but not the templating.
I think my problem is my Spring Boot code is trying to use velocity, when some of those URLs should just forward to AngularJS routing.
So a URL=/myreport/
--> goes to Java 404 error, instead of just forwarding to Angular UI Routing
--> But in some cases, Java should return 404/500/403 et al
Is there a way to do like a RestController that just forwards to AngularJS after authenticating? or to disable velocity??
This would probably be more straightforward if you limit your Spring Boot code to just doing authentication and providing an API, and implement all of your UI in the Angular app.
You can then still use Spring Security to control access to the API.
On the Angular side, you can use AuthGuards in your routes to control access to parts of your UI based on the user's role.
To get a nice, clean separation, it is helpful to use token-based authentication instead of, say, Form-Based or Basic authentication. That way, the Angular app can present the login UI, and make a REST call to the Spring Boot app to log in, and get a token back, which is used on subsequent calls.
If you use JWT, you can have the back-end produce a token that includes the users' role, and then read that in the Angular app.
I recently wrote a 2-part blog post showing how to create an Angular 2 app with a Spring Boot back-end using JWT.
See http://chariotsolutions.com/blog/post/angular-2-spring-boot-jwt-cors_part1 and http://chariotsolutions.com/blog/post/angular-2-spring-boot-jwt-cors_part2

Spring security - login architecture

I have been following the example in this tutorial: https://spring.io/blog/2015/01/28/the-api-gateway-pattern-angular-js-and-spring-security-part-iv
In brief:
I have a server called UI that has some html and angular js.
I have a server called resource that has a RestController who is serving the content from a DB. All the calls must be authenticated.
The UI server has a login page which works with spring http basic login and creates a spring session that is stored in a Redis server and it is shared to the resource server. When i have some dummy users in memory authentication everything works fine.
The question is:
I want my UI server to be able to perform a login with real users, that exist in the DB. The UI server should not have any DB related code (not knowing its existence) but it should call a REST service in the resource server. The only way i was thinking (but is sounds wrong to me) is to implement a userDetailsService bean in the UI and the loadUserByUsername method should call a rest service from the resource server (e.g. /getUser). The rest service should return all the user details including credentials and roles for the given username. However, to my understanding, this service cannot be secured (for the call to be successful) which compromises the entire security.
I am open to all suggestions and recommendations. Bare in mind this is my first attempt to work with Spring.
Thank you in advance,
Nicolas
In case that someone is interested how i tackled this..
I decided to do the prudent thing and study spring security.. :)
My answer is to use a custom AuthenicationProvider in my UI server, which will call an unprotected rest login service in the resource server, which in turn validate the user against the DB.
If the response is successful (e.g. a user object could be returned with username, password, roles) then i will create a UsernamePasswordAuthenticationToken object out of it and return it.
If the response is NOT successful (e.g. return object was null or an exception was thrown) then i will either return null or throw an AuthenticationException, it depends on how Spring behaves... I haven't reached that part of studying yet..
http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#tech-intro-authentication
Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.
Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements
Features
Comprehensive and extensible support for both Authentication and Authorization
Protection against attacks like session fixation, clickjacking, cross site request forgery, etc
Servlet API integration
Optional integration with Spring Web MVC

Calling a REST web service secured with Spring Security from Android

I'm hosting a REST web service in a Grails application, using Spring Security, i.e.:
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
def save = {
println "Save Ride REST WebMethod called"
}
I'm calling it from an Android app. (Calling the unsecured service works just fine.)
To call the service, I'm manually building up a request (HttpUriRequest) and executing it with an HttpClient.
I'm wondering what the best practices are, and how to implement them... Specifically, should I:
Perform a login once, to retrieve a JSESSION_ID, then add a header containing it into the HttpUriRequest for each subsequent request?
Or (not sure how I would even do this) include the login and password directly on each request, foregoing the cookie/server-side session
I think I can get option 1 working, but am not sure if Spring Security permits (2), if that's the way to go... Thanks!
--also, there isn't any library I'm missing that would do all this for me is there? :)
Spring security does support both basic authentication and form based authentication (embedding the username/password in the URL).
A REST service is generally authenticated on each and every request, not normally by a session. The default spring security authentication (assuming you're on 3.x) should look for basic authentication parameters or form parameters (j_username and j_password) (in the form http://you.com/rest_service?j_username=xyz&j_password=abc).
Manually tacking the j_username/j_password onto the URL, adding them as post parameters (I believe), or setting the basic authentication username/password should all work to authenticate a REST service against the default Spring Security interceptors, right out of the box.
I will admit that I haven't tried this on REST services, though I do clearly recall reading exactly this in the docs as I did the same for basic page logins on spring security recently. Disclaimer over.
I think you can use a login-once-and-get-a-token method that's similar to how oauth works.
sending username and password across the network outside of secured channel(https/ssl) is a terrible idea. anyone on the network can sniff your request package and see the clear text password.
on the other hand, if you use a token method, since the token string is randomly generated, even the token is compromised, the worst case is someone can use the token accessing your REST API.
another solution is going through ssl tunnel(HTTPS). i have actually done a comparison and result shows: 80 requests/min(https) vs 300 requests/min(http)

Categories

Resources