For our applications we have a setup where an application admin user can define its own roles and assign certain application privileges to those roles.
We are now looking for a centralized auth system and my eyes fell for Keycloak.
The overall concept is great where I can login my client application with OIDC towards Keycloak which it will relay it to a list of possible IDPs.
The problem however kicks in how to handle all the privileges. Overall there will be around 40 of those for each user which means that I can not out them in the JWT token itself due its size.
For the client application it actually would not even matter since it holds its own api and only needs to identify the user. However when that client application calls one of the microservices that service should know if the user holds the desired privileges to make the call or not.
Hope someone can guide me through this process.
Best,
Pim
Related
it looks like I got stuck and I need some help on solving this authentication/authorization problem.
I have an Okta installation, outside of my control, which supports OIDC but doesn't allow to easily manage roles and also does not support the token exchange flow.
I was hoping to use Keycloak as sort of sidecar/federated system to store users' roles, but I still need to perform the authentication against Okta, simply because that's the one storing the user credentials and I cannot have direct access to those.
Also, I cannot expose Keycloak to the end users, due to security constraints.
In other words, the client can only reach Okta and must authenticate on Okta, but since I can't store user roles on Okta I wish to use Keycloak for that and query Keycloak from my backend application to query for user roles, all of that without using the token exchange flow....
Any ideas how can I achieve that, if possible at all?
Thank you in advance.
I am designing the authentication system for a piece of software and need some guidance on how SASL and Kerberos services interact.
Here is the situation:
I have a client/server application that is itself pretty standard: only registered users can use perform actions. As an MVP I would typically implement a pretty standard solution:
Database stores username + salted hash of passord
Authentication attempt from client over HTTP includes username/password over TLS
Backend checks that username/password are valid and returns a bearer token that can be used for the duration of the session
In this case, however, there is a complicating factor. Some users of our system use Kerberos internally for user authentication for all internal services. As a feature, we would like to integrate our software with Kerberos so that they don't have to manage an additional set of users.
A more senior engineer recommended I look into SASL so that we might support several auth protocols simultaneously; standard customers can authenticate their users with the PLAIN method (over TLS), for instance, while other customers could limit authentication to only the GSSAPI method.
Up to this point, I have a clear idea of how things might be set up to achieve the desired goals. However, there is one more complicating factor. Some of the customers that want our system's auth to support Kerberos have other resources that our system will rely on (like HDFS) that also require authentication with Kerberos.
My understanding of Kerberos is this:
A client authenticates with Kerberos's ticket granting server
Upon successful authentication a TGT is returned that can be used for any future interaction with any Kerberos service in the system
Now to the point: How can I make all of these technologies work in harmony? What I want is:
- Client logs into my server
- My server authenticates client using customer's Kerberos system
- Client is given the OK
- Client asks for something from my server
- My server needs access to customer's HDFS, which requires Kerberos auth
- Server authenticates without asking the client to authenticate again
One possible solution I see to this is the following:
Make my server itself a Kerberos user
When the server needs to perform an action on HDFS, have it authenticate using its own credentials
There is a big downside to this, though: pretend the customer's Kerberos system has two realms: one with access to HDFS and one without. If users of both reals are allowed to use my system, but only one set can use HDFS, then I will need my own logic (and potentially objects in a DB) to determine who can perform actions that will require access to HDFS and who cannot.
Any pointers are going to be super helpful; in case it isn't obvious, I am quite new to all of this.
Thanks in advance!
It's not clear exactly what your question(s) are, but I'll do my best to address everything I think you're asking.
Firstly, I just want to clear this up:
Upon successful authentication a TGT is returned that can be used for
any future interaction with any Kerberos service in the system
That's not quite correct. The TGT enables the user to request service
tickets from the KDC for specific services. The service ticket is what
gives the user access to a specific service. The TGT is used to prove the
user's identity to the KDC when requesting a service ticket.
Client asks for something from my server - My server needs access to
customer's HDFS, which requires Kerberos auth - Server authenticates
without asking the client to authenticate again
This is a common enough problem and the Kerberos solution is called delegation. You should try to use Kerberos delegation in preference to coming up with your own solution. That said, how well supported it is depends on the technology stack you're using.
There are 2 kinds of delegation supported by Kerberos. The first kind is just called "delegation" and it works by sending the user's TGT to the service along with the service ticket. The service can then use the TGT to get new service tickets from the KDC on behalf of the user. The disadvantage of this approach is that once a service gets a user's TGT, it can effectively impersonate that user to any service that the user would be able to access. You might not want the service to have that level of freedom.
The second kind of delegation is called constrained delegation (also known as services4user or S4U). With this approach, the client doesn't send it's TGT to the service, but the service is allowed to ask the KDC for a service ticket to impersonate the user anyway. The services that can do this have to be whitelisted on the KDC, along with the services that they can request tickets for. This ultimately makes for a more secure approach because the service can't impersonate that user to just any service.
A more senior engineer recommended I look into SASL so that we might
support several auth protocols simultaneously; standard customers can
authenticate their users with the PLAIN method (over TLS), for
instance, while other customers could limit authentication to only the
GSSAPI method
Yes this is a good idea. Specifically, I'd recommend that you use the exact same session authentication mechanism for all users. The only difference for Kerberos users should be the way in which they get a session. You can set up a Kerberos-protected login URL that gets them a session without challenging them for credentials. Any user that hits this URL and doesn't have Kerberos credentials can just be redirected to a login page, which ultimately gets them the same session object (once they log in).
On the back end, the credential checking logic can use SASL to pass Kerberos users through to the KDC, and others through to your local authentication mechanism. This gives you a seamless fallback mechanism for situations when Kerberos doesn't work for the Kerberos users (which can happen easily enough due to things like clock skew etc.)
There is a big downside to this, though: pretend the customer's
Kerberos system has two realms: one with access to HDFS and one
without. If users of both reals are allowed to use my system, but only
one set can use HDFS, then I will need my own logic (and potentially
objects in a DB) to determine who can perform actions that will
require access to HDFS and who cannot.
This kind of thing is exactly the reason that you should use Kerberos delegation instead of coming up with your own custom solution. With Kerberos delegation, the KDC administrator control who can access what. If your service tries to impersonate a user to HDFS, and they are not allowed to access it, that authentication step will just fail and everything will be ok.
If you try to shadow the KDC's authorization rules in your own application, sooner or later they'll get out of sync and bad things will happen.
I am looking into using microservice for my application. However the application involves authentication. E.g. there is a service for user to upload their images if they are authenticated. There is also a service for them to write reviews if they are authenticated.
How should i design the microservice to ensure that the user just need to authenticate once to access different services. Should i have a API gateway layer that does the authentication and make this API gateway talk to the different services?
You can do authentication at the gateway layer, if authentication is all you need. If you are interested in authorization, you may have to pass the tokens forward for application to consider it. Also you can do that, if you have trust on other services behind the gateways. That is service 1 is free to call service 2 without authentication.
Also you loose bit of information about the principal, you can however write it back on the request in the gateway while forwarding.
Also another point to consider is JWT, they are lightweight and more importantly could be validated without calling auth server explicitly and it saves you some time specially in microservices. So even if you have to do auth at every service layer you are doing it at minimal cost, some nanoseconds. You can explore that as well.
However final call is based on how strong your security needs are compared to rest. based on that you can take a call. Auth stripping at api gateway saves you code duplication but is less secure as other services can do as they wish.
Same goes for token, you can authenticate without explicit call to auth server but then tokens are valid for some min time and bearer is free to do as they wish once they got the tokens, you cannon invalidate it.
While Anunay's answer is one the most famous solutions, there is another solution I would like to point out. You could use some distributed session management systems to persist sessions on RAM or DISK. As an example, we have authentication module that creates a token and persists it in Redis. While Redis itself can be distributed and it can persist less used data on disk, then it will be a good choice for all microservices to check client tokens with redis.
With this method, there is nothing to do with API gateway. The gateway just passes tokens to microservices. So even in case you are thinking about different authenitcation methods on different services, it will be a good solution. (Although I cant think of a reason for that need right now but I have heard of it)
Inside a session, you can store user Roles and Permissions. That's how you can strict users access to some API's. And for your private API's, you could generate a token with role ADMIN. Then each microservice can call other one with that token so your API's will be safe.
Also you could rapidly invalidate any sessions and store anything you want in those sessions. In our system, spring framework generates a X-AUTH-TOKEN that can be set in headers. The token is pointing to a session key in redis. This works with Cookies too. (and if I'm not wrong, you could even use this method with oAuth and JWT)
In a clean architecture you can create a security module that uses this validation method over API's and add it to every microservice that you want to protect.
There are other options when it comes to session persisting too. Database, LDAP, Redis, Hazelcast ... the choice depends on your need.
I am building a messaging application using BackboneJS which naturally persists using a REST interface.
The issue I'm having is that I don't know how to restrict what data a user can pull back from the API. For instance a call to /messages would, at the moment, return messages for ALL users. I would like that resource to only return messages belonging to the current user.
Searching online seems to indicate that oAuth2 is the best way to solve this issue but all the tutorials talk about been redirected to another place to confirm access and retrieve an access token.
Given that my users will have already logged into the message application and that the REST API is actually part of the same application I don't like the idea of asking the users to confirm that my own app can access my own API.
Is there a better way?
oAuth2 is probably your best bet -- you definitely don't want to roll your own security. However, the flavor of oAuth2 you are thinking of is probably not what you want.
oAuth2 has four different flavors, known as authorization grant types:
Authorization code: This is the type you are thinking about. It is often called three-legged oAuth, because there are three actors in the token granting process (app, resource owner, and user). The app asks the user whether it is ok for the resource owner to give specific type(s) of access to the resource. It is a rather complex process that allows the validation of user credentials without allowing the app access to them. This is not necessary in your case, since you are both the app and resource owner.
Client credentials: This is a method for authorizing a client application with the server. It does not use user credentials at all. If you completely trust your client application (all client applications) to correctly protect user data and not expose other user's data to the user using the app, or you are providing only non-user data via the API (for example, map data or catalog data), you might be able to use this fairly simple type of oAuth2. However, if you want to be vigilant in protecting user data (and not allow apps to get to the data without the user providing credentials), you might not use this one.
Resource owner password credentials: The username and password of the user is passed via https to your backend server, which authenticates and authorizes access by providing an access token. The access token can then be passed with each call, and it remains valid for accessing the backend until a configurable time period has elapsed. This means that someone intercepting the token could only use it successfully for a limited amount of time (some number of minutes, generally). The interceptor would not know the username and password of the user. In addition, you can supply the app with a refresh token, which can be used to get a new access token once it has expired (until the refresh token expires -- usually with a significantly longer expiration date). Since the credentials are not passed across the wire often (and must only be passed encrypted), this is often the best solution for protecting user credentials and not requiring the user to pass them in often (good user experience). Implementation is much simpler than for the authorization code grant type.
Implicit: This is the least secure method -- no credentials are validated server side at all. This is usually used for client side scripting languages where credentials cannot be stored safely. If you are worried about security at all, avoid this type if possible.
So, check out OAuth 2.0, and look for the resource owner password credentials grant type.
We are a service provider. Suppose in our application, we originally have our own user/role management. Different users with different roles are allowed to use different features. So that when a user login we need to know which roles this user has, and prepare appropriate UI. We have administrator role, users with this role can assign roles to other users.
We are thinking of enabling SAML SSO for our application, now the problem is how do we setup roles for each user.
Solution 1, we relies on IdP to provide role information for each login user, the role information may come along with Assertion, but this may not work for all the IdPs.
Solution 2, we only retrieve user from the IdP, and manage the roles in our own application. For example, when we get an Assertion, we retrieve the username(or email address), and match with a record in our DB, if it doesn't exist we automatically create one for this new user. Then we rely on users with administrator role to assign correct role for this new user.
Now the questions is where is the first administrator coming from? Our customer gets our application, and turns on SAML SSO, now there is no users in the DB yet, then how can we resolve such bootstrapping issue? Is there any kinds of standard way? We have come up with different options but not sure which is better and what are the concerns for each options.
Option 1, have a default built-in administrator user. There is a regular native login page that built-in users can login without going through IdP(there is an option to turn it on/off if SAML SSO is enabled)
Option 2, during SAML SSO setup, ask for the administrator user name, so that we automatically create this user in our DB with administrator role. Then when this user login through IdP we could match him in our DB.
What are the other options?
For your first question about who should handle the roles. As I understand every customer has your One of your service provider software. And it connects to a central IDP that you own. If this is the case, it feels like its to complex letting the administrators handle roles on your IDP. I would go for number two.
About question number two. I have been in the same situation I can not remember that I have seen a obvious standard solution for this.
What we did was option 2. It works fine but it adds some complexity to the install procedure. We choose it because we would not have a native login page.
I thing maybe I would be better to go with option 1.
You can get the roles from the different directories of your IDP using your authorization layer. It removes the constraints on SAML and gives the same results as your solution 1.