Keycloak: API to check if user token has roles for a particular resource - spring-boot

I have a keycloak server setup. I am using the token endpoint: http://localhost:8080/auth/realms/demo/protocol/openid-connect/token to authenticate a user and generate a token. This token I understand can be used in subsequent calls to verify if it is a valid user.
However, I am not sure how do I use this to authorize the user? ie verify if this user has the roles to access a resource.
I see that it is possible to configure a resource URI under the client section. But once that is done, I want to be able to read the token and verify if this user has the roles to access this resource.
Right now, this is what I am doing:
I have used spring boot here.
doSomething(String token)
{
1. get token info using: http://localhost:8080/auth/realms/demo/protocol/openid-connect/userinfo
2. from this get the roles the user has
3. Manually check the roles required for the above function. (Right now, this is set in a simple switch statement)
4. If the role obtained from step 2 matches what we get in step 3, go ahead. Else return failure.
}
I want to know if step 3 above can be done in a better way. I know taht you can set a resource in clients from the keycloak console. What I was hoping is we could replace the 4 steps above with something like:
keycloakAPIToAuthorizeToken(token,resource)
which would tell me whether this user has the roles (obtained from token) to access this resource.
Please suggest if this is doable.
Thanks in advance.
Om

There are MANY ways to do this. One of them is to use Keycloak's roles, and assign those roles to users. That way, in your server/api you can check if the user has that role and proceed or reject the call.
Example, in my api project, I have some endpoints that are exclusive for system administrators, so I have a role SystemAdministrators:
and then, if you go to Users, Role Mappings, you can add that role to the users to set as admins:
Then, any api call should include a bearer token (obtained from the Keycloak login), in your code, you can decode this jwt (it will depend what language you are using, I use python so its pretty simple), it will have an element "realm_access" and inside it, a "role" element, example:
"realm_access": {
"roles": [
"offline_access",
"uma_authorization",
"SystemAdministrators"
]
},
If that element contains the role SystemAdministrators, you know is a system administrator.
I found this is the simplest way to do it. You can get fancy and use role attributes to determine individual options inside screens, etc (attributes are key/value pairs so the way I implemented this is, the key is an option name and the value is the permission level, for example: "screen1": "read", "screen2": "write", and so on. For this, you would need to use the keycloak admin api: https://www.keycloak.org/docs-api/6.0/rest-api/index.html#_roles_resource which has many endpoints that can help you.

Related

How to access user specific resources in webapi when the access token does not include user info

I have implemented OpenId Connect for authorizing my multi tenant app, I have obtained both the Id Token and the access token. The access token does not contain any claims, but I would like to access user specific resources in the web api.
For example, in order for a user to access a certain resource, 1. They must be a tenant admin and 2, they must have permission for that resource (say a specific job post).
My questions.
Do I send the user permissions to the webapi in the request body/query and the webapi trust those permissions?
Should I use the access token to call the Identity Server to get the user information, then proceed if the user has the permissions?
Any other options?
You can always add the necessary user claims inside the access token, and by doing that, you don't have to pass that information separately. You use ApiScopes and APiResources to control what user claims that goes into the access token.
See my answer here: ApiResource vs ApiScope vs IdentityResource
To complement this answer, I write a blog post that goes into more detail about this topic:
IdentityServer – IdentityResource vs. ApiResource vs. ApiScope

Spring Boot Security registration and logging for website with roles, how to do it?

I have a difficulty in understanding Spring Security and any tutorial I found was not tailored to my needs. So maybe I'll explain what I think and what I want to accomplish.
I want to create a website with Kotlin/Java backend and frontend in React. This website would need to have users with different roles (user, admin).
And (I think) the thing I need is some kind of backend that has 2 endpoints:
register (to create users in database)
login (to, based on username and password, fetch user info and role) - as some kind of token? This returned token would be then used by frontend to display specific options (i.e. do not display "ban user" for regular users) and it also would be sent to backend for checking if the person who requests for specific endpoint really should be able to call this endpoint (i.e. it should be forbidden for regular users to use "ban user" endpoint)
What should I read about, what keywords should I look into to achieve this?
For purely the Spring Boot part of the implementation, the following should do
(/register) Signup/Register endpoint taking all required parameters for your business logic. e.g Username , Password , Full Name as well the roles
(/login) For logging in , you need a token forwarded to the front end, which will then use this token in the header for the session. JWT tokens seems like what you need(sample below). For the other part of your requirement, you can keep the user object (with roles) in the session as well as check user role on the backend in the "ban user" endpoint and process accordingly.
JWT Authentication with Spring Boot
I found a good starting point in the following sample
https://github.com/bezkoder/spring-boot-spring-security-jwt-authentication
For a more complete example
https://www.bezkoder.com/spring-boot-react-jwt-auth/
Credits to
https://www.bezkoder.com/
I have come a cross Youtube Video that covers all the scenarios that your looking for and extra, with Email verification links as well. i hope this will definitely help you
Java Tutorial - Complete User Login and Registration Backend + Email Verification

Onedrive OAuth 2.0 code flow for getting access token 'redirect uri' is not specified in the list of urls specified

Before adding, yes it works when I give the entire url like http://localhost:8080/onedrive/oauth2/success/1 in the list of uri in azure uris. I am using code flow to authroize these tokens.
But as per the docs, it should work with me just mentioning the domain name there, like http://localhost:8080. Which it doesn't.
I want to do something like send the user id along with every request for me to keep track of which user I should link this accees token to, and have no idea to do so, if this issue is there. My current application logic is, when my application sends the user details and calls my spring API, I want to handle all these transfer of tokens in the server side, so I want to transfer this userId as my path variable. How do I go about doing this? Has anyone done this, can they explain to me any other different solution?
You can't add custom details to OAuth redirects and it is best practice to always register the full redirect uri.
In terms of tracking the user, after login the token has a user id and you can also get fields such as user name and email - so both the UI and API will know which user each token is for. I can provide further details on mechanics if needed.
The user id in a token is often a generated value, whereas the user id you want to use in API path segments is maybe a user id from your app's back end database - if so you will need to map between token details and database details.
If you provide redirect uri as http://localhost:8080/ then it means you are handling the api response in
/
endpoint and not
/onedrive/oauth2/success/1
To get to know the user to whom you are linking, few ideas which you can use are
1) Use security to obtain the logged in user credentials (Ex: Principal if you're using Spring security in java)
2) After successful authentication, use the user id you have and send one more request to backend and store it database with userid as a key

Access user info from lambda

I'm working on a serverless app with aws.
I use AWS Cognito User Pool to manage user : register, login, logout.
Once those users have been confirmed, I use AWS Cognito Identity Pool to get temporary credentials. Then I use those credentials to access the api (the endpoint on my api require AWS_IAM for Auth and call lambda).
All of that work perfectly. But I need to know which user has requested the action. In the lambda I can get the IdentityId from my Identity Pool. But I need to get attributes from my user in User Pool.
So my question is : is there a way to get a user from User Pool using the IdentityId of the Identity attached to it ? Or at least, get the access token ? I know I can send the access token in headers but I would like to only depend on the AWS_IAM auth.
Getting from a federated identity_id back to the user pool user is tricky because there's no guarantee it is a user pool user (it could well be someone from Facebook, or even an unauthenticated user- depending on your configuration).
Given an IdentityId you can use identity:GetOpenIdToken to get a valid OpenId token (you can ignore the logins part of the request if you are just using UserPools).
You can then use this token against the userpools:GetUser end point.
There's a few pitfalls here, like ensuring you authenticate with a scope that allows you to see all the attributes you care about. If you haven't, then you'll need to use the username returned with userpools:AdminGetUser to get the full user profile.

Spring Security: Securing URL and Parameters

I have a requirement where application needs to secure URL for users based on the role user is having and parameter passsed..
Eg:
There are four roles
PREVIEW_VIEW, PREVIEW_MODIFY, PUBLIC_VIEW, PUBLIC_MODIFY
And URL hit is
http://myapp:8080/console/editGroups.action?orgId=1&recipientType=PREVIEW
Lets say User is having only 'PUBLIC_VIEW' and 'PUBLIC_MODIFY' permission.
If user is passing parameter 'recipientType=PREVIEW' then page should be accessible only if user is having 'PREVIEW_MODIFY' permission.
So how to secure URL and parameter together?
i.e Allow this URL(http://myapp:8080/console/editGroups.action?orgId=1&recipientType=PREVIEW) only if user is having PREVIEW_MODIFY permission
and
allow this URL(http://myapp:8080/console/editGroups.action?orgId=1&recipientType=PUBLIC) only if user is having PUBLIC_MODIFY permission
Thanks
Chetan
to me, this is the wrong way of proceeding. URLs are changable by definition by the client because it's the client itself who decides who or what to call. Therefore, URLs are the worse place to put security information. Besides, if you need to walk this way, I think you can't but leverage encyption.
The server is the one to decide which role(s) the client is associated to, therefore it forces the client to include a parameter with its roles combination. Of course, this MUST be encypted (symmetric encryption will be enough) since the client MUST NOT be able to alter it in anyway.
When the client performs the request, the server retrieves the encrypted attribute and decrypt it to obtain the client's roles.
If you need to make this attribute understandable, you could show it in clear and use an additional cryptographic HASH parameter.

Resources