Serverside Authenticate Keycloak user programmatically in Java with Bearer token - java

I want to authenticate a User in my Java REST endpoint using Keycloak and a Bearer token.
The workflow I want to achieve is the following:
The client logs to Keycloak with Username and Password.
Keycloak returns a Bearer token (a JWT one if I'm not wrong, how can I check?).
The client performs an Http request with 'Authorization' : 'Bearer <token>' header.
The REST endpoint (written in Java) checks if the received token is correct and authenticates the User receiving a Principal from Keycloak (if I understand correctly).
Once authenticated, the endpoint will check if User has permission to access that REST api and send back a response.
1, 2, 3 and 5 are already implemented and working but i can't find a way to implement 4.
I have already tried different ways:
My Java endpoint is running in a EAR published on WildFly 10.x so I used a security-constraint in my web.xml and configured Keycloak via keycloak.json.
This works fine but I need to leave some REST endpoints public (accessible even without an 'Authorization' header) in the same web context and as far as I know there is no way to filter only some requests in my security-constraint.
I tried implementing a BearerTokenRequestAuthenticator with absolutely no success and even if I could I don't think I would receive a Principal as result of my authentication request.
Right now i have already implemented a way to filter the requests and the ones that require authentication are intercepted by a ServiceSecurityInterceptor class I implemented.
At some point in that class I check if the 'Authorization' header contains a Basic or Bearer :
User loggedUser = null;
if (authorizationType.equals("Basic")) {
// ... decode Base64 username and password ...
loggedUser = userManagerBean.login(username, password);
} else if (authorizationType.equals("Bearer")) {
String token = ...; // Get token from header
// ... Here is where I need to send the token to Keycloak and receive a Principal with the username ...
loggedUser = userManagerBean.login(username):
}
I read in some places that I probably need a public key from my Keycloak realm but once I have it, what should I do?

A few months ago we have introduced Keycloak. The trick is to let Keycloak do the work for you. I guess you are using OpenId connect? Have a look at these Java-Adapters. Maybe this one could handle the url pattern matching for you.
For my self I prefer to use Spring boot security with keycloak. The Keycloak Spring Boot Adapter integrates well with Java applications. You just have to do some config in the Java app and on Keycloak server. The Authentication process is handled automatically by KeyCloak and Keycloak Adapter. With Spring boot you can als create a ear package for your WildFly Server. The KeyCloakPrincipial is automatically created within Springs security context (SecurityContextHolder.getContext().getAuthentication().getPrincipal())

Related

Bypass basic authentication for only frontend application

I have a frontend application written in React and a backend application written in SpringBoot. I have implemented basic authentication in the backend application(for all endpoints) using Spring Security. So now a username and password are required to access every endpoint.
Requirement :
I don't want to pass a username and password from the frontend application to access backend application endpoints so basically, I want to bypass basic authentication for my frontend application.
If someone wants to access any endpoint outside my frontend app for example Postman, RestTemplate, etc then a username and password are required.
For example -
if the request is coming from www.abc.com (frontend app URL) then basic authentication should be bypassed for all endpoints but if the request is coming from www.xyz.com, Postman, RestTemplate, or any other client then basic authentication should not be bypassed.
I know how to bypass authentication on a specific endpoint within the backend application but I don't know how to bypass authentication for the requester, I did research over the internet as well but not found something useful. Looking for working code to fulfill the requirement.
If you use some kind of reverse proxy (e.g. nginx) to serve your frontend, you can set the basic authentication parameters there.
e.g.
location / {
...
proxy_pass http://127.0.0.1:8080;
proxy_set_header Authorization "Basic TOKEN";
}
where TOKEN = base64(username:password)

Keycloak JWT Validation using Java Spring Security + KC Adapter

I have gone through multiple blog posts and StackOverflow questions before writing my own. I have multiple queries and none of the posts answer them.
I am using Keycloak Spring Security Adapter to secure my legacy Spring application. I referred to the keycloak documentation here and was able to have OAuth flow running for me. I am using Client Id and Secret as Client Authenticator.
For eg: Access to localhost:8080/about.htm will redirect me to keycloak login screen and after successful authentication, I will be able to view my page. I am also using the below code to read the user details from the token,
KeycloakPrincipal<KeycloakSecurityContext> kp = (KeycloakPrincipal<KeycloakSecurityContext>) auth.getPrincipal();
IDToken idToken = kp.getKeycloakSecurityContext().getIdToken();
user.setUsername(idToken.getPreferredUsername());
Now when I test this application using postman and modify the generated access token, obviously the server gives an error. Ref : How to test application using postman.
However, this is the flow :
Client sends a request to the resource server, resource server checks for a token - if it exists, the client does the validation. If it doesn’t exist or is invalid, it redirects to the authorization server (KC).
My question is,
Who is validating this token? How does postman flow throw an error
if I fiddle with the token?
Do I really need to write a JwtTokenValidator in my application for
each request? Won't that be overkill?
If I use Client Authenticator as Signed Jwt with client secret, will this validation still be required? I am not using it as it introduces latency.
Please assist.
Answer to #1:
When you use any Keycloak adapters in your application (in your case the Spring adapter for Keycloak), that's the one who does the validation and redirects to the login if necessary. As part of the validation, it checks the signature of the token issued by Keycloak. So when you fiddle with the token, the signature doesn't match, hence it throws an error.
Answer to #2
No, you shouldn't need to implement a JwtTokenValidator. The adapter does it for you and a request should reach your endpoint/URL only if it has a valid token. You may only need to do that if you have a special requirements about validating the token (e.g. checking specific claim in the token against some service). Otherwise, you can safely use the claims in the token you received from the KeycloakSecurityContext. You can even setup authorization based on your URL patterns and Keycloak will enforce them too and allow the request to pass if user has necessary roles (like this example).
Answer to #3:
That option only changes the method used to authenticate your app to the Keycloak and has nothing to do with the user's token validation inside your app. In your current setup, when your app wants to communicate with Keycloak (e.g. to exchange auth code with auth token), it authenticate itself to Keycloak with a client-id/client-secret pair (otherwise Keycloak would not know it's your app and will reject the request).
If you choose the "Signed Jwt with Client Secret" option, your client can not just use a client-secret to authenticate to Keycloak. It should support the RFC7523 specification. So it's quite complex in compare with a simple clien-secret approach. In an environment in which you trust your clients (e.g. they're all known apps developed inside the company and you're not going to support public clients to join your Keycloak and use its services) it's quite common and safe to use client-secret approach.

Backend to Backend authentification with OAuth2

What I'm trying to do
Right now I'm working on a Java Spring Backend for a Both which manages the request he gets from a NLP from api.ai and gives back corresponding information. Now I'd like to interact with different services that use OAuth2 to get information/data from there as well.
What I did so far
I have added my credentials for the service in my application.properties file. But only found a solution that a user can for example log-in with his facebook credentials on my service.
But I need to have my service to authenticate on the other service (with the given credentials from my properties file), to gather data from there.
Do you guys know a solution, tipps, tricks for that?
As I understand the logic should be following.
As you have SSO (OAuth2 based) you need to login just once and get token(s) from OAuth2 service (access token and refresh token). The access token is included in the request headers when you call any of your services.
Now Service1 must call Service2 using the same auth info.
In the Service1 you call OAuth2 service to check whether the token is valid. If yes all you need is to use the same token to call Service2.
So just extract the token from request headers and add to the headers of request you send to Service2. Could be done e.g. by adding a Filter and storing the auth info in a ThreadLocal variable (or inheritable ThreadLocal if you generate new threads by e.g. running Jobs).
Service2 in turn also checks the token by calling OAuth2 service but the token is valid.
For me that's all you need.

How to communicate between two java servers using public private key API token

I have two Java Spring applications, one is working as client and other as server. Client is Spring RESTful service.
My requirement is:
Once a server wants to communicate with a client, it should send some token. The token will get validated by client. If the token is valid then client performs some task and sends success result. Otherwise the response will be like not valid token and client does not perform any task for that request.
I think what you need is JWT token, you can learn JWT token and java in JWT token, using the java lib to generate token and validate.
The way to transfer token is to add custom header in request header, so you can just add a filter to intercept the request and validate the token.
If you want use authority not just a simple token you can use spring security and JWT token, the demo and reference can see REST Security with JWT using Java and Spring Security and demo.
In my project,I using spring security+ spring session rest+ hazelcast,it's also a way to protect my rest api by token.
You can chose the method you need and if any question you can comment under the answer.

Java: Authenticate user from JAAS protected Restful API (Jersey) on Glassfish

I have implemented a Restful API for my simple application using Jersey, this API (Restful webservice) is protected by JAAS (Java Authentication and Authorization Service).
Now if user try to access a URL something like example.com/api/user/info/1, A popup(BASIC-Authentication) appears in browser to take input for username and password on successful login user is able to see the result (success).
so far so good.
Now I was thinking about the 3rd party application that will access my Restful web service. must authenticate before accessing any endpoint. (I know if an un-authenticated user will try to access my endpoint URLs JAAS will intercept that).
I am also aware that if I provide username and password in the request header, JAAS will automatically authenticate that as well.
Confusions:
1 - I do not want to embed username and password onto each request (I am not suer why, but I just don't want it (Please share your comments)) so that if I am accessing secure endpoint get authenticated automatically. I just want to authenticate a user and generate a token and then use that token in rest of the communication.
2 - I want to provide some endpoint for 3rd party applications to deliberately initiate the authentication process.
example.com/api/authenticate but the username and password still in header. and when endpoint's relative method is called it extract username and password from that request's header. I am aware of 2 annotations #QueryParam and #FormParam, but I want something like #HeaderParam.
Why? I think that is more secure way. (Is that right?)
#Path("authenticate")
public String authenticate( ) {
}
3 - I tried multiple techniques to login programmatically but none seems to work on Glassfish, so is it right its not possible on Glassfish? I am using Realm based JAAS.
4 - I am looking for some way once I have authenticated the user prorgammatically, add some information to the session. and in any other request get that information from session. (I am using Jersey based classes for endpoints and EJBs for business logic) - I know in EJBs through context we can lookup principal and then from that we can retrive the user record from database etc. but is there any thing Jersey Endpoint classes can add to the session and get them back in any other endpoint class?
5 - Is it enough for 3rd party application to save cookies returned by my Webservice and embed them in next request to have long lasting session for JAAS authenticated user (so that authentication process may not be required on each request)

Categories

Resources