Spring Boot with common Authentication - java

I am trying to set up authentication server for spring boot application. I have multiple microservices application. Let say hospitals, patients, reports applications. I have each of microservices service application to be authenticated before allowing user to access the resources.
Can I know how can I have common authentication logic as a separate application. let say authentication application. I am planning to us (spring security with Auth 2.0 and JWT token).
For example:
When user tries access hospital dashboard page, we will check the user is authenticated
First we need to check whether user is authentication if not I need
to redirect to login service in authentication application.
Once user is logged in, then when he try to access dashboard we will
check the token is valid. If valid then allow user to access the
dashboard service.
Now user try to access patient details which is there in patient.war as a separate project, as the user already logged in we need to valid token, then we need to allow access to resources API what he is trying to access. If token is invalid then we need to redirect to login page.
Question:
I have gone through some example they have authentication server and resource server as separate application. i.e #EnableAuthenticationServer and #EnableResourceServer. But I have noted this got deprecated in latest spring boot version if I am right. Please correct me if I am wrong.
How can I have authentication functionality as common war file and let the other resource server access it before allowing the user to access the reset service API?
Which is the right way to build a microservice application?
I need some experts help to understand the best approach we need to implement authentication and authorization in latest spring boot version.

This is a relatively older question but I'll answer since it may help others.
For any microservices-based architecture, the api gateway is an important aspect and it should be there.
All your microservices will be hiding behind the gateway and any calls made to the downstream services (hospitals, patients etc) will go through the gateway.
This gives you multiple advantages.
You can add login (authentication) functionality in the gateway
You can put rate limiter to avoid DOS attacks
A single point of entry for the outside world so your clients don't neet to know the URL of each microservice
Now, the way it works is:
The client sends username/password or client_id/client_secret to the /login endpoint which is inside the gateway (for example GatewayController)
Gateway sends credentials to an "Auth-Service" which authenticates the user from a db or anywhere and creates a JWT (Oauth token)
Gateway returns the jwt back to the client
Client calls the, let's say, /patients endpoint through gateway with the jwt as header "Authorization" parameter
Gateway -> Auth-Service (To validate the token)
If invalid, 403 forbidden is sent. Otherwise, request is forwarded to the downstream service (in this case Patients-Service)
Patients-Service sends the jwt token to Auth-Service to get permissions from inside the token since we know that the token has already been validated.
Once the permissions list is received, the Patients-Service matches them with the permissions mentioned on each api (for example PatientsController)
If any permission matches, the response is served. If not, 403 forbidden is served.
To make it more clear, Auth-Service is called once when the call is for login(authentication). Auth-Service is called twice for all other api calls(validate + permissions).

Related

Keycloak external login page for external IDP

In our spring boot app, we are using keycloak and we configured multiple external IDP. Everything is working successfully on browser based. The login page that is provided by keycloak is showing direct grant option in addition to login with IDPs then if user clicks to login using IDP, he is redirected to IDP's login page then our keycloak receives the token.
What I want to change in that flow is that instead of showing user login page of keycloak I want to show him login page from my app(my FE) which is dealing with my BE api. My BE would dealing with KC. then If user select to login with IDP I want to get the redirect url from KC to pass it to my FE. Then after getting the token I want to redirect user to my FE immediately.
In other words I don't want users to access KC directly this should be throughout my BE
Your client applications should never have access to users credentials.
I'd consider things an other way arround (I make assumptions on your setup because you didn't give much details about it):
provide Keycloak with a custom theme to match your client application(s) look & feel
probably change your Spring backend configuration from client to resource-server. In OAuth2 wording, REST APIs are resource-server, not clients.
probably switch from 302 (redirect to Spring's oauth2Login) for unauthorized request to 401 (which is the standard HTTP status for unauthorized request)
probably, in your SPA client(s), use one of certified OIDC client libs to handle authorization-code flow with PKCE, silent token refreshing before it expires, HTTP interceptor to insert access token, route guards with auto-login,... My favorite for Angular is angular-auth-oidc-client
If I'm right about your REST API being configured with spring-boot-starter-oauth2-client and if you don't know yet how to configure it with spring-boot-starter-oauth2-resource-server, you can refer to Spring official doc or to this tutorials i wrote.

Authorization code flow - how to get Code parameter value

I've implemented an application that redirects to the wso2 identity server login page. If the login is successfull the user is redirected to a page where he can read his profile details.
Based on his role he can perform certain action, like create a new user.
I've implemented an API (http://localhost:8080/add-user) that calls this URL ( https://localhost:9443/t/carbon.super/oauth2/token) to generate the access token with the desired scope (for example internal_user_mgt_create) that I need in order to call
the wso2 SCIM2.0 API (https://is.docs.wso2.com/en/latest/apis/scim2-rest-apis/#/Users%20Endpoint/createUser).
Everything works if I use grant_type=password and I use the user credentials to generate the access token to call the wso2 SCIM2.0 API, but I want to use "authorization_code" as grant_type to avoid sending user credentials in my application.
How can I do that? And I know that one of the parameters that I need to use this flow is "code", where can I get its value?
You can configure authorization code grant in your application by selecting the Code from the Allowed Grant Types list OAuth/OpenID Connect Configuration in your application. [1]
When using the auth code grant your application needs to wso2 authorize endpoint to obtain the authorization code Using this authorization token and client secret you can obtain the access that is capable of calling the scim endpoint.
Refer to following documents for more information
[1]. https://is.docs.wso2.com/en/latest/guides/access-delegation/authorization-code/
[2]. https://medium.com/identity-beyond-borders/generating-access-tokens-using-wso2-identity-server-4d8c084a3bf5
It's harder to provide an exact answer to this question without knowing more details about the app and the flow you'd expect your users to go. However, it'd be much easier if you have a better understanding of the OAuth2 code grant type. The following is the basic flow.
The user accesses your application through a web browser.
Your application redirects the user to the identity server, with the following parameters in the request.
client_id=xxx
response_type=code
redirect_uri=yyy - Location in your application where you want to get the authz code. This needs to be registered with the IS service provider beforehand.
scopes
The IS prompts the user to log in.
The IS then redirects the user to the given redirect URI, with the authorization code.
Once the code is received by the client, it makes a back channel call to the token endpoint of the IS (https://localhost:9443/t/carbon.super/oauth2/token) with the following parameters.
grant_type=authorization_code
client_id=xxx
client_secret=zzz
code=ccc
IS validates the code and issues an access token.
Read more on OAuth2 here.
Now, if you're getting the "Inactive authorization code" error, your application might already be calling the token endpoint with the code received, before you call your add-user API.
Ideally, your add-user API shouldn't call the token endpoint at all. You should call the token endpoint from your application, get an access token and pass that to the add-user API if needed. Or you can directly call the SCIM API from your application itself.
I hope this helps!

Using Keycloak as Authorization Server with Zuul as API Gateway

I'm currently building a microservice backend with Spring Boot, Zuul as API Gateway and Keycloak as Authentication and Identity Provider.
For my frontend I'm currently using Angular as an SPA with the Authorization Code Grant.
The API Gateway should validate each request (if the user is authorized) via Keycloak before sending it to the microservice.
Each microservice ( ResourceServer) should be able to get the user information for the current request by using the introspection endpoint.
What would be the correct way to implement this, or is this even a bad design and I'm on the wrong way?
Typically, you have two options:
JWT given to client: The client (Angular SPA in your case) authenticates and receives the JWT. The JWT token can be verified by an party using the Keycloak public key. It also contains a lot of user information.
JWT given to back-end: The client is given the temporary authorization code grant. It is forwarded to a backend system, which exchange it for the JWT. The backend system will need to create a user session, store the JWT in the user session and use a session ID cookie (or a similar mechanism) to match the client to the session.
The proposed architecture is a mix of both worlds. Option 1 would be more natural.
Option 1: The client authenticates with Keycloak and gets the JWT. It then attaches the JWT to each request. Zuul can check that the JWT is signed by the trusted Keycloak instance and that it has not yet expired (without contacting Keycloak). The microservice can do the same. If more than the basic user information is needed, the microservice can contact Keycloak.
Option 2: I can't tell you if option 2 is possible with Zuul. Let's assume that it is. If so, the gateway would redirect unauthenticated requests to Keycloak. Once the client has received the authorization code grant, it is redirected to the API gateway. The API gateway then contacts Keycloak to exchange the code for the JWT and saves it in a session. The client is given a session ID. When a request is forwarded to the micro service, the JWT is added to the request. The client never sees the JWT.
These descriptions assume that you are using Open ID Connect, which is supported by Keycloak. If you use an OAuth 2 setup, most things still apply but a few details are more complicated, e.g. instead of the JWT containing all the information you get an opaque token that can only be validated against an introspection endpoint.

Secure REST endpoints with service user or public user

I'm writing a mobile app that communicates to a remote Java service via REST. I have protected my (SpringBoot) web service with https protection (due to the nature of the data, it needs to be secure) but my question is about which user/password I use to secure the https calls.
Should the username and password I use in the https header be a service account that the client (mobile app) and Java service knows or should it be the public user's username and password? The easiest option is just to use a service account but this means the mobile app will have those details built into it and distributed publically (albeit in compiled form).
Going the other way and using the user's username and password means I'll have to have the logon REST endpoint open and unsecure (which is fine I guess), but it just makes it slightly more fiddly.
Good question, and I would reckon you to use token based authentication and authorization scheme. Firstly you should have a login page where client logs in by providing username and password which is authenticated by calling some remote login service which maintains it's own user store or may use an existing one in your organization if any. Upon a successful authentication, the auth service should provide the client with a valid token, which then be refreshed time to time. The mobile or web client should pass in the token to the downstream microservices when a request is sent and this token should be sent inside the Authorization HTTP header.
Exposing the username and password while passing it around the network normally not considered as a good solution and that's where token becomes handy too. Token is the normal procedure that people use to secure rest endpoints. Yous rest endpoint should intercept each and every request comes at it, passes the token to the auth provider and verifies that. If the token is valid it will allow the request otherwise it should deny it.
Security is a pretty much larger topic and you have X.509 certificates other than tokens to encrypt the data sent across the wire over https and so forth. I suggest you to take a look at the spring security documentation since that will be a good starting point. Spring Security gives lots of hooks for developers which can be used out of the box with some sensible defaults. You can use JWT style tokens, Oauth tokens and spring security supports all these different forms too.

Java: Access an API that uses SAML authentication

I have a web project that needs to pull some data from a hosted versionone instance. The versionone instance uses SAML authentication for single sign-on.
The single sign-on itself uses a username and pin+one-time password for authentication so it is nearly impossible to hard-code those values into the application.
Is there a way to handle this situation? Can I set something in the header of the request to bypass the single-signon process?
As of release 13.1, VersionOne supports OAuth2 for authentication against the API endpoints. Both the Webserver flow (where the hosted instance POSTs auth tokens to your waiting HTTP server) and the Out-of-band flow (where the hosted instance gives the user a code to copy/paste to the client) are supported.
That may be a better match for your requirements, as the SAML process is difficult to complete without a web browser and user present.
Once the OAuth2 credentials are obtained by the app, it can operate without user intervention. At any time, the user may revoke the app's permissions inside of VersionOne.
With OAuth2, the process is:
Register your app with VersionOne, thus creating a client secret
Configure the app with the client secret data from the registration
Have the app request a permission grant, which sends you to the VersionOne server.
Login to the server as the user you wish the app to act as, and accept the grant.
Copy the grant code back to the app if using the out-of-band flow.
The app contacts the VersionOne instance and exchanges the code for a persistent token.
The app can apply the token as an "Authorization: Bearer " HTTP header to achieve access to the VersionOne endpoint
If the token has expired and the request returns Unauthorized, the client may attempt to refresh the token and try again, without user intervention.
There is some documentation available on the VersionOne community site.
And a few (in-progress) examples in the VersionOne OAuth2 Examples repository
We also have a (beta) HTTP proxy that can run on your app's server, forwarding requests to the VersionOne instance after wrapping them with OAuth2 and SSL.

Categories