I am working on a project where I need to create an application that shall act as an OIDC mediator between a client which only supports OIDC for authentication and a REST api. The REST api is able to generate tokens and give user info but does not support OIDC.
To achieve this I am thinking of using keycloak to handle the OIDC communication with the client and implement my own java application that keycloak can trigger to realize the authorization, token and userinfo endpoint (sort of a custom ownmade identity provider) handling the communication with the rest api.
I have created a realm in keycloak and configured the realm to use an Identity Provider Redirector with an Identity Provider I added in keycloak (user-defined OpenID Connect v1.0). In the identity provider configuration I have set all the URLs to point to my java application but the initial OIDC authorization call from the client just redirects to the redirect_uri with a #error=login_required without any of my endpoints in the java application beeing triggered.
I guess there is something I have missed.. I need to intervene the authorization flow so that I can pick up a query param from the authorization request that needs to be handled in my java application. I also need to map the token from the rest api into the token request (when this request comes from the backend of the client app), and finally map the userinfo object as a response to the userinfo request.
I really hope someone have time to point me in the right direction. Thank you so much in advance.
Edit:
I have added a sequence diagram to explain it better:
I need to intercept the authorization request call to pick up a custom query param (endUserString) that identifies the user. There will be no user login form. I need the param in my code that uses this towards the REST API. Both the token and the userinfo must be received from my APP and not from keycloak itself.
The Java Mediator may ask for a token in advance (A) and use this to access the Rest API (using a predefined clientId and clientsecret). Alternatively this token may be fetched for each method. To token must be used to retrieve customer info from the REST API (B). I want to wrap this with OIDC support without any login form. A browser will just redirect to the authorization flow with the endUserString identifying the end user. The customer info will be returned from the java mediator into keycloak responding this in the GetUserInfoRsp.
I think there might be a simpler solution than what you envisioned: implementing your own custom authenticator for Keycloak.
Keycloak has a notion of authentication flow which is a tree of authenticators than are provided by Keycloak or custom made. Each authenticator can be called to try to authenticate the user.
The most common one is the Username/Password Form which displays a login page to the user and authenticates the user if the provided credentials are valid. But you could imagine any type of authenticator such as an SMS authenticator or a magic link one.
You can find the existing Keycloak's authenticators on their repo and the documentation on how to create your own here.
In your case, you would need to implement your own logic where your authenticator would get the endUserString param from the request and call the REST API to validate the user's identity. You could fetch the REST API token at initialisation or for each request. You could also modify the user stored in Keycloak with data coming from the REST API's user info endpoint (common OIDC attributes or custom attributes).
Please note that the dev team announced Keycloak X, a sort of reboot of the project which will probably bring breaking changes to their APIs.
Also, please consider all the security impacts of your design as, from what you provided, it seems the authentication of a user will only rely on a simple query parameter which, if it doesn't change over time for example, feels like a big security hole.
Related
I started playing with Keycloak, but I have a question. While reading articles, I always found examples where a client (let's say Angular) is logging in on Keycloak, it gets a bearer and then it send the bearer to the SpringBoot application. The backend, so, validates that the bearer is valid and, if so, it allows you accessing the desired endpoint.
But it's not enough in my opinion. I don't need just to login, I would need the entire functionality - let's say I have a backend application and I need a user. I could have a basic todo-application, how do I know for which backend user I am actually accesing an endpoint?
Straight question: how can I bind my own backend user (stored in the DB from backend) to the one from Keycloak?
What is the best way to do it? The only thing that I found online and into the Keycloack documenation is that I could move the logic of logging in from client (Angular) to backend (SpringBoot). Is this the way to go?
Imagine like I'm creating my manual /login endpoint on backend on which I would then call the Keycloak server (Keycloak REST client?) and I would pass myself (as a backend) the bearer to the client.
Please help me with an explanation if I'm right or wrong, what's the best practice, maybe help me with an online example, because I just found out the too easy ones.
OpenID tokens are rich
Keycloak is an OpenID provider and emits JWTs. You already have the standard OpenID info about user identity in the token (matching requested scopes), plus some Keycloak specific stuff like roles plus whatever you add with "mappers".
All the data required for User Authentication (identity) and Authorization (access-control) should be embedded in access-tokens.
How to bind user data between Keycloak and your backend
In my opinion, the best option is to leave user management to Keycloak (do not duplicate what is already provided by Keycloak). An exception is if you already have a large user database, then you should read the doc or blog posts to bind Keycloak to this DB instead of using its own.
Spring clients and resource-servers configuration
I have detailed that for Spring Boot 3 in this other answer: Use Keycloak Spring Adapter with Spring Boot 3
In addition to explaining configuration with Spring Boot client and resource-server starters, it links to alternate Spring Boot starters which are probably easier to use and more portable (while building on top of spring-boot-starter-oauth2-resource-server).
I Also have a set of tutorials from most basic RBAC to advanced access-control involving the accessed resource itself as well as standard and private OpenID claims from the token (user details) there.
Tokens private claims
For performance reason, it is a waste to query a DB (or call a web-service) when evaluating access-control rules after decoding a JWT: this happens for each request.
It is much more efficient to put this data in the tokens as private claims: this happens only once for each access-token issuance.
Keycloak provides with quite a few "mappers" you can configure to enrich tokens and also allows you to write your own. Sample project with a custom Keycloak mapper here. This is a multi-module maven project composed of:
a custom "mapper" responsible for adding a private claim to the tokens
a web-service which exposes the data used to set the value of this claim
a resource-server reading this private claim to take access-control decisions
The simplest way to do it is to consider that the job of storing users will be delegated to your Keycloak server. But you can implement some roles and checks manually with in-memory or any database of your preference too.
I invite you to follow some documentation about OAuth 2 and Keycloak, to make requests to get a valid token for a time period and to make others request inside that time period to get datas. You can use CURL to make requests or web/software tools like Postman.
Be careful, a lot of Keycloak Adapters are deprecated ones since some months.
I would echo BendaThierry's comments. Look into OAuth2 and Keycloak. The Bearer token you receive from Keycloak will have user information in it (typically in the Claims). This way you can have user preferences or features in your backend without needing to manage the authorization and authentication that Keycloak does.
There are lots of great resource include Spring's website tutorials (like https://spring.io/guides/tutorials/spring-boot-oauth2/) and Baeldung (https://www.baeldung.com/).
I'm implementing an authentication and authorization mechanism to unify login mechanism's across three different websites using an external identity provider and OAuth2.
The requirements that are causing design implications.
- Users and permissions managed externally to the existing websites in an external identity provider.
- The user should only have to log in once.
- The login screen needs to be embedded in our application rather than using an identity providers.
I'm creating a login web application. I'm not sure which OAuth2 flow to use. I've used the Authorization code flow previously with Spring security, but that seems to need an external identity provider's login form.
Should I use the implicit flow directly from the login site's javascript? How concerned do I need to be that it's not as secure as the code flow.
Do I need to handroll a solution to call an idp's sdk to get tokens and then sling them into http headers for subsequent use by the other domains Presumably CORS will be an issue? I'll need to include the id token for the other domain to know which user it is - is it secure to pass around the id token via the resource user's browser.
thanks for any guidance, as you can tell its a bit of a muddle in my mind!
I am starting a new project and using javascript based UI as fronted and google cloud endpoints backed by google datastore for data storage.
I don't need to use any of the google services for user login etc. In other words, i will have my own table to store username, pwd and other profile info.
So, the questions are:
1. How will my service based frontend will hold the session?
2. How will it understand that requests are going for which user account to return user specific data?
Also to start with, I have so far created an endpoint which basically returns true or false on passing username to it. (just to mimic valid user or not).
The question is do i really need to configure any security to invoke this api from the javascript client i have?
Even if you want to use custom usernames and passwords, you'll need more than just a process to send and retrieve this data from your endpoint.
Consider using something that's there already. E.g. webapp2 has a basic auth module which allows you to have your own database with usernames and passwords but already has many required security measures in place.
A tutorial I've used to implement this in the past: https://blog.abahgat.com/2013/01/07/user-authentication-with-webapp2-on-google-app-engine/
So the basic answer is Google Cloud Endpoints is best suited for applications which users google accounts as authentication mechanism.
So if you are using cloud endpoints, and wanted to have custom authentication mechanism, you have to create your own.
How will my service based frontend will hold the session?
Upon successful authentication (by any form either user credentials, third party social login etc), you need to setup session for that user eg; by using session cookies.
How will it understand that requests are going for which user account to return user specific data?
Cloud Endpoint cannot tell that, so you have to write an custom filter or interceptor to check if valid session or cookie exists and either reject or continue the request.
To pass the current authenticated user who is requesting the api, you need to inject the user informations somehow (using DI, or request properties etc) into the ApiEndpoints, so with that you can process the request accordingly
I have to build a Centralized Authentication And Authorization Service. I am trying to use the JASIG CAS. But its mentioned that its a authentication protocol.My scenario is as follows.
My application redirect to cas server on the first access.
CAS redirect the user for google authentication
User signs in with the desired email and redirect back to CAS
At this moment i need to validate the user in my local jdbc store for user enabled or not and if not already registered user, and the email domain is abc.com i need to auto register the user.
CAS redirect to the calling service
My service do the validateService api call. I would like to get the user authorities for the requested service in the result response from the CAS
Does this scenario can be achieved by CAS, if extension possible for CAS, can someone suggest how to do that, basically the classes that i need to modify
Does this scenario can be achieved by CAS
Jasig CAS is highly customizable and because it is build with spring framework and spring security you can extend it to any your needs.
basically the classes that i need to modify
classes of your interests are:
PolicyBasedAuthenticationManager
Entry point into authentication subsystem. It accepts one or more
credentials and delegates authentication to configured
AuthenticationHandler components. It collects the results of each
attempt and determines effective security policy.
AuthenticationHandler
Authenticates a single credential and reports one of three possible
results: success, failure, not attempted.
PrincipalResolver
Converts information in the authentication credential into a security
principal that commonly contains additional metadata attributes (i.e.
user details such as affiliations, group membership, email, display
name).
Jasig CAS is well documented. you should be able to find all information that you need there.
I have a Restful Java Web application which is to be deployed to a number of different environments (outside of my control) which will be using a SAML 2.0 SSO solution.
My application (which I believe is the "service provider") needs to store state generated by the user, and uses internal business logic to work out which users are allowed to view or update other user's data. In order for this to work we need to know who the user is, and what groups the user is part of. But how do I get this information?
Ideally my web app will be SSO agnostic, and would look for some configurable key headers in the http requests to get this information e.g. a SAML token in a request which could be parsed, or perhaps some custom headers specific to my "service provider".
Many Thanks
You are correct, your application is the Service Provider and you will have an external Identity Provider (IdP) to authenticate to.
Basically you need to issue an Authentication Request to the IdP (via either front channel HTTP POST or back channel SOAP/whatever they support) and use the authenticationResponse from the IdP to make your decision on whether they are who they say they are. As a rule you should be able to get the subject principal (ie username) and any group memberships from the authnResponse however exactly how this works will depend on what the IdP is or isn't configured to do.
Before you do this you will need to exchange SAML metadata with the IdP (this is generally part of being registered as a SP with the IdP) which gives both parties things like the public X509 cert for signing and validating requests.
There's a good spring library for SAML SP support, http://docs.spring.io/autorepo/docs/spring-security-saml/1.0.x-SNAPSHOT/reference/htmlsingle
you could run a reverse proxy in front of the Java web application to handle the SSO protocol part and relay user identity information to the application in HTTP headers; for SAML 2.0 there is mod_auth_mellon: https://github.com/UNINETT/mod_auth_mellon
If this is done in Java and running on a webcontainer (Tomcat, JBoss, etc.), then the agent could be implemented as a web authentication (servlet) filter (add into web.xml). The user would be typically derived from the SAML Auth response's <saml:NameID> or from <saml:Attribute> matching the userid attribute (uid,email, etc.). This user should be validated against the web app's identity repository (could be LDAP, database, etc.) and corresponding groups computed. Instead of using arbitrary headers or custom representation for the authenticated user, consider using java Principal (for users and groups) in a Subject.
The filter can then run the rest of the filter chain in a Subject.doAs(). That way, the Subject can be looked up any where in the downstream code using Subject.getSubject().