Restrict client access in a single realm with keycloak - oauth-2.0

I have a single realm with 3 single-page applications and a shared backend. I want to restrict the access to one of the SPAs so that users without a specific role can't log in.
But once you create a user in the realm, he can log in to every SPA client. I can restrict the endpoints of the backend but I don't want to programmatically reject the user in the specific SPA but automatically on the login page.
I tried to use client roles which don't seem to have an effect in this case. The only solution I have found so far is to create separate realms which I think is conceptually the correct way but unfortunately brings up some practical issues, e.g. the administrators of one realm must be able to manage (CRUD) users of another realm which seems fairly unintuitive.

users without a specific role can't log in - it isn't good requirement. How system will known if user has a specific role without log in (authentication)? Keycloak provides Open ID Connect SSO protocol, which is designated for authentication. After successful OIDC authentication is token generated, which may contains also user role. So only then authorization can be applied. So let's change requirement to: users without a specific role can't access SPA, which better fits into OIDC concept.
The mature OIDC SPA libraries offer authorization guard (name can differs, it is some kind of post login function), where authorization can be implemented. Authorization requires to have a specific role in the token usually, otherwise user is redirected to the custom route, e.g./unauthorized. That's the page, where you can say a reason for denying access. Common use case is also customization of the app based on the user roles. For example users with admin role will see more items in the menu than standard users - that's also kind of authorization. Random example of SPA library with authorization guard (I'm not saying that's a best implementation) - https://github.com/damienbod/angular-auth-oidc-client/issues/441
Keep in mind that SPA is not "secure" - user may tamper code/data in the browser, so in theory user may skip any authorization in the browser. He may get access to SPA, so it's is important to have proper authorization also on the backend (API) side. Attacker may have an access to SPA, but it will be useless if API denies his requests.
BTW: You can find hackish advices on the internet how to add authorization to the Keycloak client with custom scripting (e.g. custom scripted mapper, which will test role presence). That is terrible architecture approach - it is solving authorization in the authentication process. It won't be clear why user can't log in - if it is because credentials are wrong or because something requires some role in the authentication process.

You should indeed not create multiple realms, since that is besides the point of SSO systems. Two approaches are possible in your - presumably - OAuth 2.0 based setup:
restrict access at the so-called Resource Server i.e your backend
use a per-SPA "scope" for each SPA that is sent in the authentication request
The first is architecturally sound but perhaps less preferred in some use cases as you seem to indicate. The second approach is something that OAuth 2.0 scopes were designed for. However, due to the nature of SPAs it is considered less secure since easier to spoof.

I was able to restrict users access to application using following approach:
I've created to clients in my default realm (master) i called my clients test_client1 and test_client2 both of them are OIDC clients with confidential access by secret
I've created a role for each of them, i.e. i have role test_client1_login_role for test_client1 and test_client2_login_role for test_client2.
I've created a two users - user1 and user2 and assign them to client 1 and client2 role. But to restrict access to client1 i have to delete default roles:
That did the trick, when i am logging with user2 i see test_client2 and not test_client1 as available application:
But i did n't delete roles from user1 and therefore i could see both clients when i am log in with user1:
Therefore you should use different clients for your applications, assign to each of a client specific role and remove from users default roles and add one releted to specific application.

Related

Application to Application access within the same suite of applications

Assume my company is offering 2 applications, say Mail and Calendar.
Both applications are using OAuth 2 to secure access.
Now Calendar wants to access data from Mail. If those were applications from two different vendors it would be natural for Calendar to ask the user to authorize it's access to Mail etc.
But since the applications come from the same source I'd like them to be able to share data without the user having to explicitly give permissions.
Or to put it differently: I have ID/Access/Refresh tokens for Calendar. How can I exchange them for an Access Token for Mail without bothering the user?
How can this be done in OAuth 2? I control both the applications and the Identity Provider.
The only solution that comes to my mind is for both Mail and Calendar to be the same Application, but that doesn't seem right (and has other issues, e.g. if you want to restrict someone's access to one of them). I could also implement special access outside of OAuth 2 but that is even worse.
A real world example would be Gmail and Google Calendar. They both present OAuth 2 interface to the outside world, but you don't have to allow them to talk to each other.
PS. References to white papers or cases studies would be appreciated
SEPARATED CLIENTS
By default in OAuth you would register multiple clients which get their own tokens. You would then use Single Sign On when navigating between them the first time:
Client ID: app1
Scope: openid scope1
Redirect URI: https://app1.mycompany.com
Client ID: app2
Scope: openid scope2
Redirect URI: https://app2.mycompany.com
If user consent is involved the user has more choice this way of how they grant access to their personal assets.
COMBINED CLIENT
You could potentially combine these into a single entry like this. Note that there is usually a hosting prerequisite of a single base domain in order for token / cookie storage to work:
Client ID: combinedapp
Scope: openid scope1 scope2
Redirect URIs: [https://app1.mycompany.com https://app2.mycompany.com]
PROS AND CONS
The first option is cleanest most of the time, since you avoid tokens with access to too much data. The second option can make sense for related micro-UIs that are really a single app with the same permissions.
APIs AND SCOPES
To share data across apps, companies build API endpoints. You can then have multiple apps that each use scopes representing multiple business areas. See the Scope Best Practices article as a starting point for designing authorization. Eg user logs into calendar app with scopes openid calendar mail - and therefore can get mail data also.

Securing URL with user owned resources in OAuth2

I'm aware of how OAuth2 and OIDC can use custom scopes and token introspection to secure an URL like this:
/users/me/documents
I can give this URL the documents:view scope and when receiving the token from the authenticated user, I can ask the authorization server if this user has the correct permissions. Then I can use the preferred_username claim or similar to see who /me actually is.
But what if I have a resource which is accessible by multiple users? Let's say a user has documents but they can be viewed by his direct manager. To retrieve the employee's documents as a manager, I'd need to have an url like this:
/users/${userId}/documents
How could I enforce it in a way that only the resource owner and direct manager can view this resource? I don't want everyone to access everyone's documents by knowing the userId. I could grant access as a whole to all users with the manager role, but that's not specific enough.
I'm aware there's the UMA extension where users can grant access to resources on his behalf to other users, but it's not the user who grants permission. It's the system who states in this case that managers can access their employees documents.
Would it make sense to write a custom policy which extracts the ${userId} and performs the check? Or should this not be done by the authorization server at all and be done by the resource server instead? Perhaps a different approach to reach the same goal?
Finer grained authorization like this is done with claims rather than scopes. There may be business rules around which docs a user can see, eg:
A user can access their own docs
An admin has view access to all docs
A manager can view docs for people they manage
In an access token this might be represented by these claims:
userId
role
Claims are often domain specific like this and the preferred option is to add them to tokens during token issuance. At Curity we have some good resources on this topic:
Claims Best Practices
CLAIMS AND AUTHORIZATION
The Authorization Server issues access tokens and then APIs (resource servers) verify the access token and use the token data to apply authorization rules (which are often domain specific) on every single request.
Claims are often used when dynamic behaviour is needed - they are runtime values that derive from the user identity, whereas scopes are fixed design time values. In your example an API might also need to vary SQL to retrieve documents based on the user identity.
There are more complex variations on this theme, such as an API calling a system such as Open Policy Agent, so that documents returned are determined by rules configured by a security administrator. That policy would still involve using claims from the access token though.
EXAMPLE CODE
If it helps, here is some sample code of mine that show the type of approach when enforcing domain specific authorization rules. Typically you need to filter collections and check access to individual items.

OAuth 2.0 flow for user groups / organizations

OAuth 2.0 protocol provides permissions delegation of a user so that third-party apps can operate on its behalf. A typical way this is done on the OAuth flow is requesting a user consent to either approve or deny access for the app (Okta example). Here is an official spec describing how it works in general concepts.
I'm looking for the standardized approach to perform the same flow but for the user groups (e.g. organizations). GitHub does that in some way for organizations, so it looks like organizations represent just a group of user accounts. Are there any standardized approaches to this problem?
If not maybe there are any recommended ways how its typically done architecturally or can fit into OAuth 2.0/OpenID Connect protocols.
The OAuth 2.0/OpenID Connect protocols do not cover how access control is performed.
You can, within the OAuth 2.0/OpenID Connect protocols, pass OAuth Scopes or use the OIDC user info endpoint data to allow the resource server to make determination for Access Control.
Many of the commercial products within this area allow the use of LDAP as a back-end for authentication and will even convert LDAP Groups to Scopes.
I would assume, but I do not know, that GtHub stores data with a link (like a group) for the on Organization and/or the user. I know GitHub exposes this using OAuth Scopes.
Oh, and the OAuth Spec is at: https://oauth.net/2/
But if you require Authentication of users then you need to be using OpenID Connect which is built on-top of OAuth 2.0.
Remember that "OAuth 2.0 is NOT an Authentication protocol"
-jim
There are limits to what you can show on the consent screen and dynamically calculated data is not usually supported.
You ought to be able to express a high level scope that you can present to the user though.
In terms of authorizing based on a user's organisations the claims caching technique here can be useful:
https://authguidance.com/2017/10/03/api-tokens-claims/
That is:
* Use OAuth for user identification and high level checks
" Then do the real Authorization based on your back end data
I'm making some assumptions here, but I believe the issue arises from trying to authenticate two things at once.
If the organization is what you need, then go ahead and create a flow to authenticate the organization as the principal subject (via a user who has access to it), instead of actually authenticating the user itself.
Once the access token is generated, you do not necessarily need to know which user generated it anymore (or at least, the token itself does not need to know). If your user needs to be able to view and/or revoke access tokens, they should still be able to do that, since they have access to the organization in your app.

How to handle authorization and authentication on SPA with OAuth2?

I am developing an SPA and would like to have SSO.
As I understood so far, OAuth2 with OIDC is the best solution for SPA SSO.
Better than, for example, SAML.
What I didn't understand so far is how to use authorization token in SPA's JS code to handle authorization on various resources of SPA. For example, I would like the users with a role 'buyer' to have access to the shopping history tab, where other users won't have access to.
Should I parse access token obtained from Authorization server in JS code and check whether a user has an appropriate role to see the tab, or should this decision be made on server (API) side, in which case SPA's code would just read the answer from API and based on that customize UI?
In case of the first approach, is there any standard way of doing the checking (in form of some JS library)?
When it comes to authentication, what is the better approach (more secure, etc):
to let SPA (at that point already loaded in the browser) do the authentication flow and based on result let the user use it's protected functionalities. This is pseudo authentication actually since the code is in the user's browser and means the user is authenticating himself to the code in his hands i.e. to himself. Does this authentication make sense at all?
require the user to authenticate himself in order to be able to even load the SPA in his browser. This is probably not SPA architecture then since backend which serves the SPA should be able to create a backchannel with the Authentication server.
According to user description, your application must vary depending on user type. If this is the case I would suggest you to use a backend for authentication and decide application content to be served from the backend. Otherwise, as you have figured out, running authentication on browser and altering user view is not secure.
IMO this not necessarily break SPA architecture. What you are doing is altering what you server based on tokens presented to you. Also, maintaining a session will be required with this approach. And SPA's calls for backend will require to contain this session to obtain contents.
As soon as the User is logged in, you would request for authentication and based on his UserId, and the role he belongs to you should receive all the permissions that User is entitled to.
You convert these permissions into claims and can send them back to UI and use it appropriately to show the features accordingly.
You also enforce same on the server side api to prevent any unauthorized access besides from your UI.

OAuth2 and role-based access control

I have a Rails app acting as an OAuth 2.0 provider (using the oauth2-provider gem). It stores all the information related to users (accounts, personal information, and roles). There are 2 client apps that both authenticate through this app. The client apps can use the client_credentials grant type to find users by email and do other things that don't require an authorization code. Users can also log in to the client apps using the password grant type.
Now the issue we're facing is that the users' roles are defined globally on the resource host. So if a user is given an admin role on the resource host, that user is admin on both clients. My question is: what should we do to have more fine-grained access control? I.e. a user can be an editor for app1 but not for app2.
I guess the easy way to do this would be to change the role names like so: app1-admin, app2-admin, app1-editor, app2-editor, etc. The bigger question is: are we implementing this whole system correctly; that is, should we be storing so much info on the resource host, or should we denormalize the data onto the client apps?
A denormalized architecture would look like this: all user data on the resource host, localized user data on each client host. So user#example.com would have his personal info on the resource host and have his editor role stored on client app1. If he never uses it, app2 could be completely oblivious of his existence.
The drawback to the denormalized model is that there would be a lot of duplication of data (account ids, roles) and code (User and Role models on each client, separate management interfaces, etc.).
Are there any drawbacks to keeping the data separate? The client apps are both highly trusted--we made them both--but we are likely to add additional client apps, which are not under our control, in the future.
The most proper way to use oAuth and other similar external Authorization methods as I see it, is for strictly Authentication purposes. All the business/authorization logic should be handled on your server part at all times, and you should always keep a central record of the user, linking to the external info per external type of auth service.
Having a multilevel/multipart set of access, is also a must, if you want your setup to be scalable and future-proof. This is a standard design that is separate from any authorization logic and always in direct relation to business rules.
Stackoverflow does something like this, asking you to create an actual account on the site after you login using an external method.
Update: If the sites are really similar you can subset this design to an object per application that keeps the application specific access rules. This object has to also inherit from a global object that has global rules (thus you can for example impose a ban application-wide or enterprise-wide).
I would go for objects that contain acess settings, and roles that can be related to instances of both application level settings and global settings only for automating/compacting the assignment of access.
Actually you can use this design even if they are not too similar. This will help you avoid redundant settings and meaningless (business-wise) roles. You can identify a role purely by the job title/purpose, and then impose your restrictions by linking to an appropriate acess settings setup.

Resources