Check user group of already logged in user in KeyCloak - authentication

I have two application, both are using keycloak to authenticate user of the same realm. I've created two different client, and two different user group. Only users of a specific group can access to corresponding application.
I'm using this custom extension to verify user group after user login. I've created two different user flow based on Browser Flow, one for group, and I've configurated each client to use the relative user flow. This is working fine when a user tries to login.
I'm giving an example to better explain:
I have two group A and B. One user belongs to group A. When the user isn't logged, he can access to application A but he can not access to application B.
What I cannot prevent is user access to application B when he is already logged into application A.
This is happening because Browser Flow has a cookie step that gives authorization of users already logged.
Is there a step to check user group (or other user information) after the cookie step?

I found this solution:
I created a new authentication flow, at first level I've created a sub flow containg the standard Browser Flow and always at first level I've added the execution of group verification.
Both step at first level are marked as required.

Related

Multi-tenant ASP.NET Core Web Application, how to restrict multiple tabs to the same tenant?

My admin system allows the user to select a tenant at any time, the admin page then redirects to the admin home page for the selected tenant. The user can then continue to maintain the tenant customer records.
My worry is that the user will open tab 1 and start editing a customer in tenant A. Then in another tab (2) select tenant B. If the user in tab 1 then saves the edit it will be saved in tenant B (assuming id's match) or throw an error.
Ideally, I would like a solution that will stop the user posting their change in tab 1 and redirect to the tenant B home page.
More information... the admin app uses a scoped tenant class that has a connection string in it, when an organisation is selected its id is saved in a cookie. Middleware on each request examines the cookie and sets the tenant connection string based on the cookie tenant id. Tenant connection string is used by the repositories to pull in data from different tenants.
I ended up using SignalR to achieve my goal. Overkill but found it interesting and some added benefits.
When the tenant is changed, I set the cookie value, then call a server method using signalr to broadcast to a group. This triggers a method on the clients within the group to redirect to the home page.
The groups are based on the username which is unique. So if someone duplicates a new tab or window the connection is stored against the group.
It's not perfect but seems to work well.

How can I restrict user login/authetication access to specific applications within a single tenant?

I have a single Tenant with four (4) Applications and ten (10) Users defined. I want 3 users to have login access to all four Applications, and 7 users to have login access to only of the 2 applications. However, it appears that anytime I add a user to the Tenant the user receives "login/authentication" rights to all 4 applications.
Before installing and setting-up FusionAuth, I thought I would be able to use the "Groups" feature to create a group called "Group-A" that would "grant" login access to all 4 applications and another group called "Group-B" with "grant" login access to only 2 applications. I would assign the 10 users to either Group-A or Group-B and limit which user could login/authenticate to a particular application.
This capability does not appear to exists. What am I misunderstanding?
FusionAuth supports this model. We call this Registrations and if a user is has a Registration for an Application, they will be allowed to access it. If they don't have a Registration for that Application, they will be logged in, but won't be granted access to the Application.
The specific implementation depends on your integration with FusionAuth:
If you are using the OAuth interface, when FusionAuth redirects back to your application, it will pass along a parameter called userState. This is a hint back to your application as to whether or not the user is registered for it. If the value of this parameter is AuthenticatedNotRegistered, you should not allow access to the application.
Additionally, if you are using the OAuth workflow, when you exchange the authorization code for a token, this token will not include the Application id or any roles that the user has for the Application.
If you are using the /api/login API, then the response will contain a status code of 202 that indicates that the user was authenticated but not registered for the application. Similarly, the JWT that this API returns will also not include the Application id or any roles.
Here are the doc pages for the OAuth and Login API:
https://fusionauth.io/docs/v1/tech/oauth/endpoints#authorization-code-grant-request
https://fusionauth.io/docs/v1/tech/apis/login

How to prevent concurrent login for a web application using express-session

I am creating a web application which will be used by App's Administrators and for security reasons we don't want to allow multiple active logins from a single user at any point of time.
I am storing session data in the web browser's cookie and want backend to have active user's information who are currently logged in to the application so that on successful login request I can find out if this particular user already has an active session. If that is possible then I can block the login for that user.
One way to do that is storing IsLoggedIn in the Database with LastLoginTime and on each login, I can use this two flags to identify if an active session exists.
Open to other better solutions if any
I think a more robust solution than checking last login times would be to generate and store an id for each new login and then include a middleware to make sure the session's id for each user matches what you expect. That way every time the user logs in on another device the previous one will be invalidated and only one session will be valid at a time. You may even just be able to use express-session's req.session.id.

Allow users of a certain group to login with Azure AD B2C

I am using Azure AD B2C and I want a group based user distribution for my application. Lets say I have two subdomains subA.myapp.com and subB.myapp.com. On the other hand, I have two groups subA and subBin Azure B2C. Now a user wants to signin to subA.myapp.com, but is not a member of group subA, I would like to deny the user to sign in.
I know that Azure B2C does not include group info in the access token. So I will actually use Graph API to get the group membership of the user. But I am not quite sure if there is an appropriate event where I could intercept the validation process and manually deny a user to sign-in. Also, I thought I could use one of the *Validator methods of TokenValidationParameters but not sure which one.
I have read Authorize By Group in Azure Active Directory B2C. My problem is different because that problem is trying to protect only some actions based on group memberships, I want to prevent the whole login process to fail based on group membership.
You can use a ValidationTechnicalProfile on a page created by the SelfAssertedAttributeProvider technical profile. Using the validation technical profile, you can first authenticate the user, and then call a Rest API that can look up users group membership and return a successfull/fail response.
If the response is successful, the flow will continue. If it's a failure, an error will be shown to the user.

External Login Account vs. Native Login Account

I am brand new to Visual Studio 2012 and MVC 4, and I've been working with the SimpleMembershipProvider via the WebMatrix.WebData library.
I'd like to integrate Facebook as an external login source down the road, but it's not a requirement as of right now. However, to get a decent feel for what it would take, I've been following the tutorial and guide found here - http://www.asp.net/mvc/tutorials/mvc-4/using-oauth-providers-with-mvc.
My question :
If a user has already been created using :
WebSecurity.CreateUserAndAccount(model.Email, model.Password);
WebSecurity.Login(model.Email, model.Password);
Can they be "upgraded" to an oAuthMemebership account in the future, if they choose to use their Facebook credentials instead of the email and password they created when first signing up?
I couldn't find a clear answer to this question in the guide, or elsewhere, so I'm hoping someone can clarify how that process may work.
The SimpleMembership setup allows for a local and multiple OAuth logins all sharing the same UserProfile - so a single user can login with either a local password, or FacebOogLiveWitter.
(I should state, that I'm assuming in this answer that the OAuth provider does not send back a matching piece of information for a local account. If they do then the principles of actually performing the merge are the same, but the complexity and steps are vastly reduced.)
The OAuth registration process will refuse the user if they use an existing user name, rather than try and merge two accounts. Therefore this isn't simple, you'll have to build the functionality yourself. The process is complex as there are many directions the user can approach this from (so you could simplify by only supporting one or two), and you need to enforce security as well in case someone tries to merge into an account they don't own.
I will assume you are comfortable with the link you've posted, and you've followed the Facebook help at (for example) Facebook Login and The Login Flow for Web (without JavaScript SDK) so you have a working test application.
Your general process has to have multiple user journey approaches to make sense to a user:
for a logged in user (with a local account)
let them login to facebook and associate the accounts
let them merge an existing account on your site which uses a facebook login
for a logged-in user (with a facebook account)
let them create a local account
let them merge an existing local account on your site
for a non logged in user who tries to register a local account
let them merge this new account with a facebook login that is already registered, and do that as part of the registration process
for a non logged in user who tries to register (or log in for the first time with) a facebook account
let them link this with an existing local account as part of the registration process
etc.
ASK PERMISSION
(You can skip this if the OAuth provider has sent back a matching identifying piece of information, such as an email address).
You should enforce confirmation security, usually through email confirmation sent to the target account of the merge. Otherwise:
someone can login to your site with facebook for the first time
during that process say they "own" the email address or username of a local account (remember, facebook won't necessarily confirm what their email is for you)
and therefore gain access to the existing local account
So, once the merge "request" is made, you need to ask for permission to proceed from the target account of the merge.
The MVC 4 AccountController
I will use Facebook as our OAuth example. To compare what happens when you register a user on your local authentication framework vs. OAuth:
Local: creates an entry in webpages_Membership and an entry with the same UserId in UserProfile (assuming you are using the default tables for the MVC 4 application template)
OAuth: creates an entry in webpages_OAuthMembership and an entry with the same UserId in UserProfile
Now let's look at what happens when a user signs in using Facebook for the first time:
They click on Login using Facebook (or whatever your button says)
they get taken to facebook to login
they succeed (let's assume that, and ignore the failure case)
they then get sent, invisibly to them, to /Account/ExternalLoginCallback
OAuthWebSecurity.SerializeProviderUserId is called, passing the OAuth details to that Action
They get redirected to /Account/ExternalLoginConfirmation and asked to provide a username for their new presence on your site
If that user name is available then UserProfile and webpages_OAuthMembership entries are created
This process is your chance to "join" the accounts by matching some unique piece of information. As long as you end up with the same UserId in UserProfile, webpages_Membership and webpages_OAuthMembership you should be ok. So we have to intercept the process at the point of /Account/ExternalLoginConfirmation.
If the OAuth provider has sent back a matching identifying piece of information, such as an email address, this becomes simple, test for this in the ExternalLoginConfirmation action, and auto-merge using a similar process to the one outlined below.
However, I think you can't/shouldn't assume that the user uses the same email address for your site and OAuth, (nor should you for many reasons). Also, probably in the T&Cs for something like FacebOogLiveWitter it stops you asking for the email of their account anyway, and if they don't currently they might in future.
So instead, you could link the accounts based on alternatives, like username or email address, or phone number. Either way you are going to need them to input some identifying piece of information that is unique against an account, and will pull back the target account.
Wrapping up
So to put this all together: In the first part of this answer I outlined how you will need to consider multiple user journeys to merge accounts. I will use the example 4.1.
Your process will need to:
(Assumption - when a user first registers with a local account, you ask them for an email address and validate it or assume it is valid)
Let the user login with facebook for the first time
at Account/ExternalLoginConfirmation ask them if they want to
Create a new account with you
Use their facebook login to access an existing account
Assuming the latter, then you log a request in a new table (maybe "MergeAccountRequests") with:
The facebook account UserId
The target merge local account UserId
An authorisation code to use in the email you need to send
(From this point on, if they login without confirming that merge, they will have to get sent to a page to ask them to confirm, rather than create objects in other db tables which you have to worry about later)
You then send an email to the address of the target merge (local) account asking for permission to complete the merge (a standard confirmation email, with a link)
When they click on that link, or enter the code you sent them (you could use SMS as well as email) then you need to merge the two accounts
Choose the "new" and "target accounts (in this case "new" is the facebook account as you don't have data associated with it yet)
Delete the UserProfile of the "new" account
Change the UserId of the "new" account webpages_OAuthMembership table to the same as the "target" account
Log the user out (so there are no complications depending on which account they are currently logged in with)
Display a message to the user telling them the merge is almost complete and that they can now log in with either account to confirm and complete the merge
Rather than send them to a login page, i would give them the login options alongside the confirmation message.