AzureAD Custom Claims in token - azure-active-directory

I'm struggling with custom claims policy for one of applications. Basically, what I'm trying to do is to get AzureAD User property MailNickName in to uppercase and be included in JWT. At this point I really cannot see what I'm doing wrong.
This is custom policy which I'm expecting to do the job:
$policy1 = #('{
"ClaimsMappingPolicy":{
"Version": 1,
"IncludeBasicClaimSet": true,
"ClaimsSchema":[
{
"Source": "user",
"ID": "mailnickname"
},
{
"Source":"transformation",
"ID":"testmailnickname",
"TransformationId":"ChangeToUpper",
"JwtClaimType":"mailnickname"
}
],
"ClaimsTransformations":[{
"ID":"ChangeToUpper",
"TransformationMethod":"ChangeCase",
"InputClaims":[{
"ClaimTypeReferenceId":"mailnickname",
"TransformationClaimType":"inputClaim1"
}],
"InputParameters":[{
"ID":"toCase",
"DataType":"string",
"Value":"UPPER"
}],
"OutputClaims":[{
"ClaimTypeReferenceId":"testmailnickname",
"TransformationClaimType":"outputClaim"
}]
}]
}
}')
However, when checking what's inside JWT, I basically get nothing. I was trying with other policies, for instance found example which suppose to add "sandbox" to MailNickName - it really works.
$policy2 = #('{
"ClaimsMappingPolicy":{
"Version":1,
"IncludeBasicClaimSet":"true",
"ClaimsSchema":[{
"Source":"user",
"ID":"mailnickname"
},{
"Source":"transformation",
"ID":"DataJoin",
"TransformationId":"JoinTheData",
"JwtClaimType":"JoinedData"
}],
"ClaimsTransformations":[{
"ID":"JoinTheData",
"TransformationMethod":"Join",
"InputClaims":[{
"ClaimTypeReferenceId":"mailnickname",
"TransformationClaimType":"string1"}],
"InputParameters": [{
"ID":"string2",
"Value":"sandbox"
},{
"ID":"separator",
"Value":"."
}],
"OutputClaims":[{
"ClaimTypeReferenceId":"DataJoin",
"TransformationClaimType":"outputClaim"
}]
}]
}
}')
When having this policy created, we are assigning it to our App Registration.
$pol = New-AzureADPolicy -Definition ($policy1) -DisplayName ("Policy_Test_1" + ([System.Guid]::NewGuid().guid)) -Type "ClaimsMappingPolicy" -IsOrganizationDefault $false
Add-AzureADServicePrincipalPolicy -Id $SP.ObjectId -RefObjectId $pol.Id
Basing on MS documentation regarding this topic, everything seems to be fine, but still doesn't get uppercased MailNickName value inside the token. This means that I'm doing something wrong, but I really cannot see my mistake.

the referred documentation is for Azure AD B2C, Microsoft CIAM. For Azure AD the available transformations methods are Join and ExtractMailPrefix.

Related

Retrieve User Details and Roles for an Azure AD application using Microsoft Graph API

I'm attempting to get user details for a particular enterprise application in Azure AD, using the Microsoft Graph API.
I'm able to successfully retrieve users of the application using:
https://graph.microsoft.com/v1.0/servicePrincipals/{objectId}/appRoleAssignedTo
However, the users details are left out; such as, contact details, email. It also has a duplicate entry for each role assigned to a user.
I'm able to get these user details if I query:
https://graph.microsoft.com/v1.0/users
However, this retrieves all users in the organization, and I've not been successful with filtering the list in the query for a given application.
Using the $expand operator does not seem implemented either.
Seems like this would be a common use case for an application; Who are my users and what are their roles and details? How would one best approach this with the Graph API?
Individually,
You can get the appRoles of an Azure AD application using the below query.
https://graph.microsoft.com/v1.0/serviceprincipals/07fce81e-8069-4ccb-9775-63f96d1f4e53
and check the appRoles property.
And you can get the user details using the below query.
https://graph.microsoft.com/v1.0/users/4ef105cc-508b-41c4-a5d2-7d41f2244c4c
And you can get the group details using the below query.
https://graph.microsoft.com/v1.0/groups/0023c709-3556-4296-a6ab-6df2a0a1113c
In your case you need to call the same call that you specified
https://graph.microsoft.com/v1.0/servicePrincipals/07fce81e-8069-4ccb-9775-63f96d1f4e53/appRoleAssignedTo
This will return all the users and groups assigned app roles and you can pull the principal id from these app role assignment objects as shown below which are nothing but the userid of the user that the role was assigned to and in the groups case its the group id of the group which gives the group details.
You can differentiate user and group by principaltype and according to that you can call the above http calls(User or group) and get those details.
The duplicate ones need to be coded on our end to avoid it.
My Example JSON Data:-
For getting users and groups assigned app roles
GET https://graph.microsoft.com/v1.0/servicePrincipals/07fce81e-8069-4ccb-9775-63f96d1f4e53/appRoleAssignedTo
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#servicePrincipals('07fce81e-8069-4ccb-9775-63f96d1f4e53')/appRoleAssignedTo",
"value": [
{
"id": "zAXxTotQxEGl0n1B8iRMTPwz3O48iw9Oq3aFtqfYVjA",
"deletedDateTime": null,
"appRoleId": "00000000-0000-0000-0000-000000000000",
"createdDateTime": "2020-06-01T19:21:01.4268687Z",
"principalDisplayName": "Nishant Singh",
"principalId": "4ef105cc-508b-41c4-a5d2-7d41f2244c4c",
"principalType": "User",
"resourceDisplayName": "testspaquestion",
"resourceId": "07fce81e-8069-4ccb-9775-63f96d1f4e53"
},
{
"id": "Y3tbwNOvDkqKK9yLxJ5wp2-uBAbApk9LoMs6AN_7iSs",
"deletedDateTime": null,
"appRoleId": "00000000-0000-0000-0000-000000000000",
"createdDateTime": "2020-06-01T18:47:47.2702435Z",
"principalDisplayName": "Sruthi J",
"principalId": "c05b7b63-afd3-4a0e-8a2b-dc8bc49e70a7",
"principalType": "User",
"resourceDisplayName": "testspaquestion",
"resourceId": "07fce81e-8069-4ccb-9775-63f96d1f4e53"
},
{
"id": "CccjAFY1lkKmq23yoKERPBqNLldhOdBAm0lJzewK0Nk",
"deletedDateTime": null,
"appRoleId": "00000000-0000-0000-0000-000000000000",
"createdDateTime": "2020-07-23T17:34:53.9538274Z",
"principalDisplayName": "Bgroup",
"principalId": "0023c709-3556-4296-a6ab-6df2a0a1113c",
"principalType": "Group",
"resourceDisplayName": "testspaquestion",
"resourceId": "07fce81e-8069-4ccb-9775-63f96d1f4e53"
}
]
}
After querying the above, pull the principalid of each record and accordingly call user endpoint or group endpoint according to principaltype.
Get https://graph.microsoft.com/v1.0/users/4ef105cc-508b-41c4-a5d2-7d41f2244c4c //principalId
Let me know if you have any queries.

Using Azure AD Graph API to create a User in Azure AD B2C

My application was designed to add a user to my Azure AD B2C using Azure AD Graph API. I also handled the case where I'd be calling the add user graph API with an email ID that already exists in AD. I was looking for the error message in the response body to handle this. Has there been any change w.r.t the response message?
POST
https://graph.windows.net/{tenant}/users?api-version=1.6
Request Body :
{
"accountEnabled": true,
"signInNames": [
{
"type": "EmailAddress",
"value": "TestGraphApiCreatedUser#TestGraphApiCreatedUser.com"
}],
"displayName": "TestGraphApiCreatedUser",
"mailNickname": "TestGraphApiCreatedUser",
"passwordProfile" : {
"forceChangePasswordNextLogin": false,
"password": "vhkjds#fceu456VCHU"
},
"creationType": "LocalAccount",
"passwordPolicies": "DisablePasswordExpiration"
}
If a user already exists with the given email address, the error I was getting earlier was
{
"odata.error": {
"code": "Request_BadRequest",
"message": {
"lang": "en",
"value": "Another object with the same value for property signInName already exists."
}
}
}
Now, for the same flow, I'm getting below error :
{
"odata.error": {
"code": "Request_BadRequest",
"message": {
"lang": "en",
"value": "Another object with the same value for property userPrincipalName already exists."
}
}
}
Is there any difference between the two error messages. Since there isn't any error code, I had hard coded the whole error message. Now that there is a slight change in the message, I've to update my code. How can I handle this in a better way?
I didn't check to confirm if they changed the error message, but it wouldn't surprise me at all if they did. The userPrincipalName may be coming from the underlying AAD, maybe MS changed the B2C implementation and now it exposes an error message from there?
In your particular case, a better option may be to check if the email address exists in B2C just before calling the API to create the new user. It's an extra API call, but it shouldn't matter much unless you're creating many users at a time, e.g. in a batch. You'll still have to handle the user creation call failure, but if it happens you could just return a generic error message.

Where to find the onPremissesImmutableId?

I´m writing an little application to create new user on an Azure AD.
Even following all the instructions in Create User Reference I allways get an Http Error 400 (Bad Request).
The only thing I´m not providing is an attribute named onPremissesImmutableId. Assuming I must provide it, problem is I don't know where to find such a value.
This is the Json I'm posting:
{
"accountEnabled": true,
"displayName": "Name Surname",
"mailNickname": "Surname",
"userPrincipalName": "name.surname#XXXX.onmicrosoft.com",
"passwordProfile" : {
"forceChangePasswordNextSignIn": false,
"password": "p#ssw0#D"
}
}
Any ideas?
TIA
Just after I posted the question I had the idea to review the password policy active on my AD tenant and I found out that it was the problem. So I just had to set a new password to match the policy and everything worked just fine.

Unable to create a local account via graph api in Azure B2C

I am trying to create a "LocalAccount" in a B2C domain via the Azure AD Graph API.
To do this I registered an app (via Azure Active Directory -> App registrations (legacy)) and add all permissions for "Windows Azure Active Directory".
The request to create the user is
add_user_json = {
"accountEnabled": True,
"creationType": "LocalAccount",
"signInNames": [{
"type": "emailAddress",
"value": "test#email.com"
},
{
"type": "emailAddress",
"value": "test2#email.com"
}],
"displayName": user_id,
"mailNickname": user_id,
"passwordProfile": {
"password": "aPassword",
"forceChangePasswordNextLogin": "true"
},
"passwordPolicies": "DisablePasswordExpiration"
}
and the endpoint "https://graph.windows.net/{tenant}.onmicrosoft.com/users?api-version=1.6" (I tried "https://graph.windows.net/myorganization/users?api-version=1.6", too).
The error I get is "One or more properties contains invalid values."
Furthermore, if I create a new user via the sign up flow it is possible to create a local account.
Does anybody have an idea what I did wrong?
The "One or more properties contains invalid values." error is occurring because a user object can't have more than one signInName entry of the same type.
There's a really good utility here with the code to help you.
Look at the create example there
One obvious one is:
"forceChangePasswordNextLogin": "true"
This needs to be "false".

Adding a Custom Attribute (Extension) in B2C using Azure AD Graph API doesn't show up in Azure Portal User Attributes blade

The same question was asked here and remains unanswered. I can add a custom attribute as follows:
{
"name": "new_secure_claim",
"dataType": "Boolean",
"targetObjects": ["User"]
}
I post this data to the Azure AD Graph API end point with needed headers:
https://graph.windows.net/{tenant}.onmicrosoft.com/applications/{objectId of b2c-extensions-app}/extensionProperties?api-version=1.6. I get a response with the extension just created. I can even see the extension when I query the graph to get all extensions for the b2c-extensions-app (notice the top one below):
{
"odata.metadata": "https://graph.windows.net/melangeauth.onmicrosoft.com/$metadata#directoryObjects/Microsoft.DirectoryServices.ExtensionProperty",
"value": [{
"odata.type": "Microsoft.DirectoryServices.ExtensionProperty",
"objectType": "ExtensionProperty",
"objectId": "b7a36f93-8d7a-463f-8d3e-88f449243ea6",
"deletionTimestamp": null,
"appDisplayName": "",
"name": "extension_8588c037999f4d058cc08e2e5f99de30_new_secure_claim",
"dataType": "Boolean",
"isSyncedFromOnPremises": false,
"targetObjects": ["User"]
}, {
"odata.type": "Microsoft.DirectoryServices.ExtensionProperty",
"objectType": "ExtensionProperty",
"objectId": "b6c6d55f-21a8-4403-a68f-f858966077bf",
"deletionTimestamp": null,
"appDisplayName": "",
"name": "extension_8588c037999f4d058cc08e2e5f99de30_manager_admin_authorization",
"dataType": "Boolean",
"isSyncedFromOnPremises": false,
"targetObjects": ["User"]
}, {
"odata.type": "Microsoft.DirectoryServices.ExtensionProperty",
"objectType": "ExtensionProperty",
"objectId": "2642596f-5706-47fb-abdb-6d0d012a3006",
"deletionTimestamp": null,
"appDisplayName": "",
"name": "extension_8588c037999f4d058cc08e2e5f99de30_manager_admin",
"dataType": "Boolean",
"isSyncedFromOnPremises": false,
"targetObjects": ["User"]
}, {
"odata.type": "Microsoft.DirectoryServices.ExtensionProperty",
"objectType": "ExtensionProperty",
"objectId": "ee2c66e3-ced4-4bc8-90d5-e2b18690a56b",
"deletionTimestamp": null,
"appDisplayName": "",
"name": "extension_8588c037999f4d058cc08e2e5f99de30_manager_ads_admin",
"dataType": "Boolean",
"isSyncedFromOnPremises": false,
"targetObjects": ["User"]
}
]
}
But, when I go to the "Azure AD B2C/User attributes" blade in my B2C directory in the Azure portal (https://portal.azure.com/#blade/Microsoft_AAD_B2CAdmin/TenantManagementMenuBlade/manageUserAttributes), I cannot see that extension attribute. I also cannot see it when I go to add claims to return for a policy.
What do I need to do differently in the adding of a custom extension to the b2c-extensions-app application in order for me to see if in the Azure portal User attributes blade?
Well, hmm.
It gets complicated when people things in an undocumented way. For sake of simplicity I would encourage you to stay with defining your extensions with the portal. If you just want to do that (and seems you want). Because there is much more than just registering an extension with the Graph.
To understand why is that, you have to more deeply understand how B2C ticks from the inside. You get overview when you dive into custom policies. However custom policies are, as it stays in the docs, for identity pros who know what are they doing. Straight to the point, the claims schema is defined in so called base policy. It is not just defined in the Graph, but also backed in the base policy. There is XML schema which dictates what a B2C must do and how it should do it. And all the claims (and custom attributes) are also defined in that schema. So when you change something regarding this schema in the portal (adding new attribute), it is registered with the Graph API, but it is also updated in the claims definition schema, which is kept separately.
That's why when you manually register an extension with the Graph it just does not show up in the portal.
I do not expect that you jump and begin learning Custom policies, because for your case you just do not need them. But I hope that having to define your custom attributes in the portal is not a big of an issue for you.

Resources