Restricting claims in Azure App Registration? - azure-active-directory

Within Azure Active Directory, I have created an App Registration.
For most users, this works great. They can login to my application via federating in from Azure AD, and their claims are coming through.
For some users, however, they have over 150 group memberships in Azure AD. For them, they receive an HTTP 400 bad request. I've increased the maxRequestBytes and maxFieldLength of my server according to this post: https://support.microsoft.com/en-us/help/820129/http-sys-registry-settings-for-windows, but it didn't solve the issue for all users. Some received access after this, but there's a handful that still cannot login.
My application only has ~10 groups in Azure AD that it cares about. I customized my App Registration's manifest to have "groupMembershipClaims": "SecurityGroup".
Is there a way I can restrict the claims coming out of Azure AD to only the 10 groups that I care about?

Per my understanding, this issue is due to too many groups claim in some your Azure AD user access token and you want to limit the group claims.
As far as I know, there is no way to do that. But there will be two workarounds here :
1. this official doc which indicated claims about groups and hasgroups, maybe provides some tips to handle your scenario. As the doc indicated, it suggested you to call an API to fetch all user groups if a user has too many group claims.
In your scenario, you will need to check about 10 groups membership with a user. To avoid the issue that too many group claims in your user's token, you can just remove group claims in token and check groups membership with a user with this API.
2. Using Azure AD app roles claim instead of groups claim. In Azure AD application, we can create Add app roles and assign the role to users or groups. Once be assigned the role , role claim will be added in users' token.
As you only care about 10 groups, you can create corresponding app roles and assign the roles to your groups that you cared about(i,e role1 assign to group1).With this,users in groups will have corresponding role claim(i,e , users in group1 will have a role claim:role1) so that we can use this claim to replace groups claim .
What's more
except for increasing maxRequestBytes and maxFieldLength of your server, you can try to modify maxAllowedContentLength , details see this post .

Related

Inviting a consumer to Azure AD B2C with custom in-app attributes

Inviting a consumer user to Azure AD B2C has been covered by other Stack Overflow questions & answers, and AFAIK requires the use of custom policies that entail a signed JWT being created and used during invite redemption.
What I'm trying to figure out: In our application, we have differently permissioned user groups and different organisations managed by internal RBAC logic. We identify & authorize users based on their oid claim in the access token that's returned to msal-react/msal-browser and used to authenticate against our backend's API.
In Microsoft Graph, a user can be invited and the API will respond with the created user's oid. However, this is the wrong type of user and not appropriate for B2C scenarios.
With the custom policy route not creating the user object in AAD B2C at the time of invite, and therefore without knowing the user's oid at the time of inviting them to the application, what might be the best way to configure their in-app profile and have them identifiable to the application itself upon first login?
My thought at the moment is to have the application store the emails of users that are invited who have not yet redeemed/signed-in. We can configure the emails claim to be returned upon login, which is checked against the invited emails store when an oid claim is returned that isn't present in the database. This can then trigger a function to update the user's internal id with the oid in their first login's claim.
If this is inadvisable or if there's a better way, I'd be very grateful to hear it.
It would work, or just pre create the user up front via MS Graph API. Then you have an email and objectId available.
You could also put an extension attribute on the account indicating whether the user has redeemed their invite. That would allow you to monitor who has redeemed, and also be a way to provide a different experience depending on if the user has redeemed or not redeemed the link.

Handling security in Azure AD for a spa Sharepoint online app

We have build a front facing single page application for Sharepoint online. Security is synced to sharepoint with AAD security groups. But at the moment we are facing a lot of issues, because we have to many Azure AD security groups created for it.
The app is a web portal has two kind of users:
Customers (guest users in AAD)
Employees (our AAD empoloyees)
Each Customer has is hown Sharepoint Online Site with security groups synced from AAD.
We defined some Customer Roles (Finance Director, Hr Director, IT,..)
And some Employee Roles for each Customer. (CUST_000000_AccountManager, CUST_000000_Invoicing, CUST_000000_Employee). 00000 stands for the customer id. So our employees have a lot of security groups defined in Azure AD.
In summary, it means that for each customer there are 20 security groups in AAD. These security groups are synchronized to our 200+ employees and 8000 customers. 28 000 000+ groups in total...
Due to the large number of groups per employee, we are now experiencing many problems.
What's best practice to handling this kind of specific security?
Handling the security in a separate DB or use multi tenancy as a solution for this...
Thanks in advance.
What you are looking for is Group-based Authentication.
You can configure the Azure AD Application Registration for group attributes. You just need to modify the "groupMembershipClaims" field in application manifest:
"groupMembershipClaims": "SecurityGroup"
Then the token will contain the Ids of the groups that the use belongs to like below :
{
"groups": ["group id"]
}
This method has a limitation that:
To ensure that the token size doesn't exceed HTTP header size limits, Azure AD limits the number of objectIds that it includes in the groups claim. If a user is member of more groups than the overage limit (150 for SAML tokens, 200 for JWT tokens), then Azure AD does not emit the groups claim in the token. Instead, it includes an overage claim in the token that indicates to the application to query the Graph API to retrieve the user's group membership. In this case, you only get back an overage indicator claim like hasGroups telling you that user is part of many groups and you should call graph api to get the list of all groups.
Using Microsoft Graph user: getMemberGroups to check the groups the user is a member of.
And if you are using implicit grant flows for your SPA, you have to check hasGroups claim because groups claim doesn't return in this case.
For other details you can check with the two SO Post:
How to check if a user is in an AD group via Azure AD?
How to validate if user is part of group in Azure AD?

Emit role's permissions as claims in JWT with AAD (Azure AD)

I need to emit a role's permissions as claims in the JWT.
The aim is to get a certain user's permissions as claims in the JWT for authorization purposes.
The user belongs to a group which is assocciated to a certain role which has certain permissions in the Azure Active Directory.
Clarification:
If I add some items to the appRoles array in the app's manifest, the role names are emitted as role-type claims in the JWT in the following format:
http://schemas.microsoft.com/ws/2008/06/identity/claims/role: [value property in the appRole item as appears int he manifest appRoles array]
But I couldn't find any way to emit role's permissions' names (or any other property) as claims.
I've been googling and digging in MS docs for days but couldn't find anything. I hope that it's possible.
If it isn't possible, a clumsy workaround may be to represent the permission we need to be emitted as an AAD role, and to represent the role (in the meaning of "a set of permissions") as an AAD special group, and then to associate the groups we wanted to be associated with the role (in an ideal world) to that special "role"-group.
But it's very clumsy as we will actually lose the natural meaning of role which is a set of permissions, and the natural meaning of group which is a set of users and/or groups
Thanks for any help :)
The value property is the custom role name you configured and will be returned in JWT. It's by design.
The permission name won't be returned in the JWT. After you have added an appRole into the Azure AD app, you need to assign users and groups to the role.
You need to add the needed permissions in Azure AD APP and then control the permissions in your code.
We assume you have assigned a custom role in an Azure AD app and added a user to this role.
When a user signs in, a token which includes the role claim will be returned. You can judge the user's role in the code. If it matches a custom appRole, he is allowed to perform an operation. If the user does not match any of the appRoles, he does not have permission to perform any operations.

How to support multiple login scenarios in multi-tenanted Azure Active Directory (AAD)

Our application (referred to as "XYZ_App" below) is a multi-tenant SaaS application. We are in the process of making it available for Microsoft AppSource as a multi-tenanted "Web app / API" (referred to as "AppSourceXYZ_App" below).
We started our OpenID Connect implementation with endpoints pointing to “common” as per stated in the documentation when multi-tenancy is desired/required.
In XYZ_App, we added information in the system to know what AAD instance each XYZ_App tenant is associated with (using the GUID Microsoft assigned to this AAD instance, we are NOT using the "rename-safe.onmicrosoft.com" representation).
When using the “common” endpoints, we had to manually validate the issuer from the JWT to make sure it was the expected one: a user could access XYZ_App requesting access to XYZ_App’s tenant associated with contoso.onmicrosoft.com, get directed to “login.microsoftonline.com/common” to authenticate and then decide to authenticate with a user from another AAD instance (referred to as "anotherAADInstance.onmicrosoft.com" below). In this scenario, even though a user could successfully authenticate on anotherAADInstance.onmicrosoft.com, XYZ_App’s redirect URI must make sure the JWT issuer is the one from contoso.onmicrosoft.com. I’ll refer to this setup as Scenario_1.
With that scenario in mind, we thought about NOT using “common” and customize the requests going to login.microsoftonline.com on the fly; attempting to “jail” requests to be forced to authenticate against a specific AAD instance. We would still need to perform our validation in the redirect URI to make sure the issuer is the appropriate one, but we thought this approach might make our lives easier. I’ll refer to this setup as Scenario_2.
Do you envision Scenario_2 is viable in the long run or is it too short-sighted ? Based on my current knowledge of OpenID Connect, one limitation I can see with Scenario_2 is that it would become problematic to support “broker accounts” into our app.
Explanation of “broker accounts”: in our industry, some external users are allowed access to the system. Let’s say I have a company called “BrokerCo” (with their own brokerco.onmicrosoft.com AAD instance) who has 2 employees: Broker1 and Broker2. BOTH anotherAADInstance and contoso hired Broker1 and Broker2 to get broker services to perform tasks in XYZ_App; requiring XYZApp to grant them access. What is the ideal way for authentication from an OpenID Connect standpoint ? If XYZ_App were to use “login.microsoftonline.com/common” for authentication (like in Scenario_1; as opposed to “jailed” access like in Scenario_2), Broker1 and Broker2 could authenticate with brokerco.onmicrosoft.com (no AAD "External users" for anotherAADInstance nor contoso), but they would then get to redirect URI with an issuer that is different than what XYZ_App’s anotherAADInstance and contoso tenants are configured for... I feel like I’m back to square 1...
Do you have suggestions or pointers to solve this issue ?
Background context:
While playing with OpenID Connect issuers, I got the following error message:
AADSTS50020: User account 'testuser#anotherAADInstance.onmicrosoft.com' from identity provider 'https://sts.windows.net/XXXXXXXX-fake-GUID-9bZZ-XXXXxxxxXXXX/' does not exist in tenant 'XYZ Publisher' and cannot access the application 'YYYYYYYY-fake0-GUID-YYYYyyyyYYYY' in that tenant. The account needs to be added as an external user in the tenant first. Sign out and sign in again with a different Azure Active Directory user account.
Thanks in advance !
Your question has multiple layers, trying to address most of them:
AppSource is about trial experiences for new users: this mean that any corporate account around the globe can potentially be an user of your SaaS application - or at least to the trial experience of your application, therefore the first thing you need to think when integrating with AppSource is how easy it has to be for a potential user to experience your app for the first time.
With that in mind, AppSource recommends that the trial of application is build on such a way that allows any user from any organization to sign-in, and therefore a multi-tenant approach for your application is the recommended setup for any application.
The single-tenant approach requires more control on your side, and for a trial experience - it means that the user cannot try your application right away because the operation you have to do on your single-tenant application is to add the user to an Azure Active Directory tenant as a guest user. This guest account will need then to wait receiving an email to accept the invitation to join to this tenant you are adding the user to then sign-in to your application.
Therefore your scenario 1 is the best scenario thinking on a trial experience in general, and also in general require less management (as you'd not need to create/ manage each individual account that needs to access your application as guest users of your Azure AD instance).
However some concerns you listed - that this scenario bringing are valid: Because you are accepting the common endpoint, you are saying basically that any user can sign-in to any tenant to your application, and this may not be desirable. In addition, the scenario you listed that a user can generate a token for any application is also valid, however, you can add additional checks to make this more secure and that any token generated by another authentication is blocked:
You can validate the 'audience' claim to guarantee that the token was issued to your application
You can eventually check the 'tid'/'iss' claims against of a list of tenant Ids in your database to see if that the user's organization is a valid organization in your application -- this would be valid for non-trial users/ organizations.
More information in this article.
About scenario '2' and broker accounts:
This scenario could be interpreted in two different ways:
Broker accounts are guest accounts of a customers' Azure AD tenant
Broker accounts are third party accounts but are not actually added as a user of anotherAADInstance or contoso AD
If your case is '1' then you're right: if your application needs to authenticate guest users that belong to another Azure AD tenant, then common endpoint could not be used directly.
If your case is '2' then what you'd need to do is to continue using the common endpoint and somewhat after the user is authenticated ask them to choose the company. I am describing this on generic terms without fully understanding this scenario. Perhaps this is not simple as you want the remote company to control this and not the user - so some additional complexities may need to be handled here.
A note is that if your scenario is scenario 1. - in theory - you can still use an hybrid approach, where you'd ask user to type the username inside the application and the company that they want to sign-in, then check if you need to validate the user against common or tenant-id endpoint, preparing the request and then sending a login_hint argument when authenticating. More information here

Authentication Process Get Azure AD group the user is a member of and do logic

Is there a way to get the Group the User is member of so we can process the authentication, or even throw exception so the token will not be created.
The reason we need groups is that we can not create OU in Azure AD whereas we could before in LDAP. We retrieved the distinguished name and therefore had very rich information about said user.
Lastly, we do see that you could create an OU on-premises but read that Graph API would not recognize it or could not retrieve it.
We are attempting to do logic within the SecurityTokenValidated stage of Authentication process and we break the process whenever we try to use:
string UPN = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.Name).Value
Is this because we are using MSAL?
The best approach for you to take here is to make use of the group claims capability of Azure AD. (And for get OUs. OUs are not represented in Azure AD at all.)
Dushyant Gill's blog post on this is relatively old, but still very much relevant: http://www.dushyantgill.com/blog/2014/12/10/authorization-cloud-applications-using-ad-groups/. In short, the process is:
Enable group claims for your application by setting the groupMembershipClaims property in your application. After setting this, when a user signs in to your application, the list of groups they are a member of will be included in the token (if the number of groups is smaller than the limit).
Update your application's authorization code to make use of the group membership claims (if present).
Update your application to query the Azure AD Graph API if the groups membership claim is not present (i.e. if the "overage" claim is present). This happens only when the user is a member of more than 150-250 groups. (Use the _claim_name and _claim_sources claims as indications that the Graph API needs to be called directly.)
As described in the documentation for Azure AD Graph API permissions, in order for your application to call the getMemberGroups method, the app must have the "Read all groups" permission (Groups.Read.All). This permission requires admin consent, but once consent has been granted, the request can be made using the signed-in user's access token.

Resources