Restful api design for admin and non admin accounts - rest

Facing problem on how to design api for admin and non admin account. I following MVC pattern, where controller will map to a uri.
Make up scenario:
Let said I have a system that allow user to redeem gift after they spend money on buying merchandise and collect points.
My system has a user profile, gift, and redeem table.
Each user can redeem many gift and each gift can be redeem by many user. (Redeem is the junction table).
To access user profile, the uri will be like this:
GET /user/0001
To redeem a gift
POST /user/0001/redeem {"amount":1, "address":"old address"}
Everything seem nice and tidy up to this point. Now the problem arise when the redeem need to be approve by a admin user
So to update the redeem to approved status
PUT /user/0001/redeem/100 {"status":"approve"}
User can update the shipping address where the gift will be ship to
PUT /user/0001/redeem/100 {"address":"New address"}
Now I facing the following problem:
If 2 path point to uri, the controller will have 2 different handling code in the same function.1 if block for admin, 1 if block for user.
If I add a admin in front of the uri (admin/user/0001/redeem/100). 2 different path will identify the same resource.
To identify user identity was done on the Authorization header (Authorization="USERNAME:SECURITY_HASH"). Is this a typical restful approach?
I cannot differentiate user role because the admin and user was store in diffrent table. So if the uri indicate the user role, this will make things easier. I do not want to always query for admin table before user.

I would do the following:
1) have URL like POST /admin/user/1000/redeem/approve
Reasons:
I don't want to expose the knowledge about which field in user record has to be changed to approve voucher
I prefer to keep all admin actions separate from normal user actions
2) One of the "usual" ways is to have a (periodically renewed) session cookie (not related to username or password hash) that is issued after successful login and then separately a mechanism that would associate this cookie with username and check whether for this username the given action is allowed.
Reasons: you reduce the danger of exposing the information about your users. (This approach might be still vulnerable if the attacker steals the cookie, but so is the other one).
3) That you store admin and user data in different tables is not an excuse if we talk about the security :) Using the cookie mechanism described above might help here, but you'll still have to establish the way of verifying that given user can invoke given method.

Related

Is it possible to add more than one email per user in Keycloak?

I'm using Keycloak for Identity Brokering through Google, Microsoft, etc. But Keycloak only allows one email per user. So the user can be authenticated only through one of the social login options (Google if gmail is added as user's email address, etc.). Is there any way to include more than one email per user, or any other workaround?
EDIT: (Editing based on comments to make scenario more clear)
In my scenario, I'm using a federated user store which contains a large number of users and and I need Keycloak to access all the emails linked to a user when that user is logging in using Google,Azure,etc. because Keycloak is using the email as the unique identifier for the authentication response from the social login provider. Without having the required email as the main email, Keycloak won't allow that user to log in through social IdP
Although, Keycloak emphasises on keeping a unique email,but there are certain scenarios where you may want to keep , say, secondary email.
This can be achieved in a couple of steps:
1. Add a custom attribute for secondary email in user like this:
2. Next , in your client create attribute mapper like this:
When I generated the token after above configuration, the new attribute was avialble in token. You can use this attribute in your app as you desire.
Parsed JWT:
I figured out the best way to deal with this is through the custom user provider (federated user store). Even though we can't add multiple emails per user through the Keycloak admin console, we can write the user provider in such a way that it can get all the emails linked to a user from our database and assign them to the email attribute of each user. Once this is done, all the emails will appear on the admin console as well.
For the social login to recognize those emails, we have to get all the emails linked to a user in the provider to an array and iterate through it until the authentication is complete. This would help to create the social login link to the user through First Login Broker authentication flow.
This is a crude way to approach this, but nevertheless it works!

Keycloak authorization based on business attributes

Here is how my application should work:
Users can use some functionalities of my application if they have enough chips (token) which they can buy from another application, or they can be granted to them upon some event, whatever.
Users have an attribute associated with them called 'chip', which represents some number. This information should be represented as a claim, probably.
I want Keycloak to do this authorization for me - to check whether user can use the functionality or not. I've come across JavaScript-based policies. It's seems they are able to operate on informations in tokens - like user email etc, but this is not my case where token can contain obsolete information, i.e. when token was generated user had enough chips but since then he spent them.
Maybe token should be refreshed upon spending chips, but in that case, would it be updated with current informations bound to user? Or maybe authorization service can somehow access database during evaluation of a policy? Could this work or are there any elegant solutions to this use case?
Keycloak is not here to check if the user has enough money. Keycloak is here to say if the user is authenticated and if he has the roles for a certain application (admin, user...).
Checking if the user has enough money should be on server-side. For an incoming request, you have to check in the database if the user has enough chips to access the application and if he hasn't you return 403.

Identity Server 3 - Silent sign-in / sign in without login page. Including single sign on

I have come across a number of articles that discuss a similar matter but I cannot find a definitive answer.
My company would like to begin using Identity Server 3, however one of the requirements is to be able to authenticate an external user without them having to manually enter their credentials.
This must be capable of providing single sign on capabilities also as we have 3 different systems and our users should only have to sign in once.
Essentially, the external user has their own CRM.
The CRM holds their username and password for our software.
They then click a button in their CRM to launch our application
This redirects them to our website with a payload containing their credentials
We call a web service to authenticate the user
It is fundamental that we do not change this process for our partners.
Can I implement a custom service provider to provide the authentication or is there some other way of achieving this? If so, could you point me in the right direction for how this can be done?
Many thanks
Craig
I would assume that you'd create a mechanism for their CRM to get a token at the time the client logs into their site and then have them send that token via url to your callback page. This would use the machine-to-machine type grant, or the client-credentials flow. Then that page could validate the token and log the user in. There would have to be some sort of unique identifier between the two systems like email or something. Just an idea.

Oauth2: authorize access based on unguessable url in email

Our application uses oauth2 & openid connect for auth&auth. It's built using an angular client that calls a REST API. I would like to know how to authorize access to the API, based on the possession of an unguessable url.
I'll explain this a little more. In the application, a user can invite another user. When this happens, an email is sent to the second user. When user 2 clicks a link in the email, he is sent to a webpage with details about the invitation.
Only user 2 should be allowed to see the invitation page. I was planning to solve this by using an 'unguessable url' in the email. Upon visiting the url, the user must somehow be authorized to fetch the invitation details from the API.
The question: how do I authorize a user, based on knowing the unguessable url? How do I assign a claim when the page is loaded, and how do I verify this claim in the API call that follows? The only solution I see, is to set a cookie containing a token. But this is not in line with our existing auth mechanism. I prefer not writing my own token validation code, and let the Identity Provider handle this.
Additional info: user 2 may or may not have an account in the system, and he may or may not be logged in. Neither should prevent the user from seeing the invitation details. In other words: a totally unknown user should be able to see the page. The knowledge of the url should be the only requirement.
Any solution to this problem? Or am I handling it all wrong?
After asking around, the general consensus is to NOT let the external auth mechanism take care of this, but to validate the link ourselves.
The solution is to turn the unguessable part of the url (the 'link id') in some kind of token, which can be validated upon calling the API. This is done by the API itself, not by the Identity Server.
Applied to the invitation issue: when an invitation is created, store the link id together with some info, i.e. what kind of access it allows (invitation access) and the id of the invitation. When the user calls the API to get the invitation, pass the link id for validation. Match the invitation id with the invitation id stored in the link, and if it doesn't, throw an error.

Best practices for token authentication in web apps?

I want to make a simple REST web app, where the user interact with the objects through links in an email. The links have a token that can be used to authenticate a user without a username and password, like the ones that are usually used to reset a password.
What are the best practices for such a login-less, token-based authentication system?
I am by no means a security expert.. but some of the points which come to mind are -
Lifetime - The token should expire after a set period of time. Indefinite access using the token certainly doesn't make sense.
Replay attacks - The mechanism should prevent replay attacks.. which means the token should be valid for not only a set period of time, but also fixed number of calls.. Ideally exactly 1. If this number is not exactly 1, then it opens another can of worms..
Unless, its a feature :( For example, by design, the user is expected to share link with others, and anyone with the link should be able to access the resource in question.
Authorization - Granularity of the access granted by the token. Is it black and white.. or is the token also associated with a fixed set of rights. For example - token X was issued for Read-Only access, vs token Y was issued, for same resource with R/W access.
Administration - User / Admin should be able to see and verify any currently active and issued tokens, and associated information (permissions granted / affected resource etc), and explicitly revoke them, if necessary.
Secure Communication - You should consider security of the medium through which the url with token will be sent to the user. i.e. in your scenario, do the users receive emails over secure channel (TLS / SSL)? Should the email itself be protected with DRM?
Man in the Middle / Leaks - Similarly, even though you are providing the url in email, and the user is not logging on using user name and password over SSL, the resource should still be accessed using the url with token over SSL. This will prevent any capturing of the tokens from url, by a man in the middle. You would also need to be very careful about when the users browser may use this url in places you didn't expect..
I can vaguely recall reading about a popular site being affected by their urls being used as Refer Url, when displaying ads on their website.. which means, the advertisers site would probably get the url with the token as Refer.
Generation - Choice of algorithm to generate the token - May seem pretty obvious, but the token should be extremely obscure and near impossible to guess or brute force. The tokens should never be reused and the algorithm should avoid collisions.
Server Side Security - The tokens should probably be treated with same security as you would secure users id and password. If your user database gets hacked, hackers should not get the users passwords and other sensitive information.. Similarly, if your user / resource / token database gets hacked, despite the expiration on the tokens, hackers should not be able to access the resources as users for x hours.
Point is, when the tokens are stored on server side, they should themselves be secured / encrypted.
On the same lines.. just like its bad practice to log information like passwords in log file (specially plain text), You'd also have to consider any place these urls may get logged (plain text) on your server.. For example web server logs. If only super admins should have access to user's database, then they should also be the only ones to be able to see these token.. Not your web server admin and not any hackers parsing the log file after the hack.
Auditing - If there will be a need for auditing, you'd need some mechanism in place to prove that while the user didn't log on to the system, they are indeed the ones who performed the action / operation in question. Would you want to track the ip address and other information along with the request which would help such auditing?
Consent - Do your users even consent to the use of such alternate means of authentication and authorization? Should this be an optional / opt in feature?
EDIT: I found a link to the referrer url problem I was recalling. Although it was in context of user information.
I agree to 10 points of Vikas however from security perspective I have to tell you few points that you must be careful.
I will try to keep as simple as possible. And here I simplify the technical stuff to your special case.
Firstly tokens are used to prevent Cross Site Request Forgery attacks (XSRF). Keep that in your mind. If there is a web platfrom without unique tokens on the forms then any attacker can force the user to make malicious requests.
If you simply try to authenticate the user with a token, this is pretty wrong. Because there must be no simple authentication process and you can not rely on token.
Here is how the login system works in official security documentations, im writing as I remember:
Identification: you have to identify the user firstly, that is generally done with username. YOu will know that there is a user exist in your system.
Authentication: Let's say you have already identified that user A want to login. So you mast authenticate the user A with something that you know and user A know. We call it password simply :) You cannot by pass this step with plain text methods. Passwords are generally encrypted in your db and also through all communication with secure certicates, check ssl.
Authorization: okay you made the authentication somehow, the user has a right to get Authorization. Let's say if the admin type user is logged in, he has differen rigts and if the normal user is logged in then she has regular rights.
Session control: finally you have to control the session with a secure way. Here generally in web applciations people use access tokens for all requests to be sure that the authorized user is aware of the request. As a platform owner you are responsible to secure everything until the session ends. If you don't satisfy the users with your security, then probably your platf is not going to survive longer.
Tokens have different lifetime to expire and different access rights.
Now let's look at what facebok like companies do with mobile aplications. For the mobile app they generate a unique access token which is alway alive. One shortcoming here is, if any attacker steal the mobile token generally she can do anything in the account anytime :) Anyway here our point is how they verify the users with those tokens; firstly the token is unique for that device. (Actually not exactly unique or not dependent on hardware, because if you clearly steal the necessary files from the device then you can use it on another phone). So with this unique access token which is generated with users password at their initial login on mobile app, they can login always automatically with that. And this method is a little similar to what you want to do. However pay attention that they don't authenticate the users with links or email code.
Verification is not an authentication, don't forget that. By sending e-mail you can verify the users if the emailed code is unique and valid for only 30 sec or 1 minute. I hope you got the point.
Here I suggest you to check single sign on across multiple domains, which is really interesting.
Single Sign On across multiple domains
Let's say you are logged in to google.com and then you visit the youtube.com Opps the youtube is already logged in? Yea, cool right, but exist for long time. They can authenticate users accross domains which use different cookies with a little and secure trick. You will read on the link.
If your service is not really confidential and if you want to make your users happy with easy login system. Here is two of my solutions which I love :)
1-) Ask users their email address: just directly send 4-6 digit code as e-mail. Ask user the enter/click on that. There will be no password at all, only unique code on each login.
2-) Let's say you need to verify the user with a stronger way than email. Then mobile phone :) Here trick is; you will not send the verification code to user, but they will send what you tell them to you.
Ask to user to send a SMS with a unique CODE to XXXXXX your number :) Connect your mobile operator with your web service and check whether the code is sent to you by the user :)
There is always a trade-off between security and simplicity, and also with complexity. You have to find the balance.
Don't try to make it simple if your security is going away.
Don't try to make it complex if it'll seem more secure.
Hope those informationn help you.