Validation error when uploading localized custom user attribute in Azure AD B2C - azure-ad-b2c

I'm trying to localize a custom user attribute named Hobby in Azure AD B2C.
This is the definition of the attribute in the user flow:
According to the docs here:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/language-customization?pivots=b2c-user-flow#change-extension-attributes, the localization should be done by adding the following element to the resource file:
{
"LocalizedStrings": [
{
"ElementType": "ClaimType",
"ElementId": "extension_<ExtensionAttribute>",
"StringId": "DisplayName",
"Override": true,
"Value": "<ExtensionAttributeValue>"
}
[...]
]
}
So I added the following to the top of the file (as the first item of the LocalizedStrings array):
{
"ElementType": "ClaimType",
"ElementId": "extension_Hobby",
"StringId": "DisplayName",
"Override": true,
"Value": "Passatempo"
},
However, when uploading the file back to B2C, I keep getting the following error:
1 Validation errors found in upload overrides for
api.signinandsignupwithpassword1.1. Please ensure that your uploaded
resource matches the template: The localized string with ElementType:
ClaimType, ElementId: extension_Hobby and StringId: DisplayName is not
a valid override.
No matter how I try to modify the snippet (lowercase / uppercase, remove the "extension" part, etc.) - I can't make it work.
What am I missing? Why doesn't it work?
Thanks!

I tried to reproduce the same in my environment and got below results:
I created custom user attribute named Hobby via Graph Explorer using below query:
POST https://graph.microsoft.com/v1.0/identity/userFlowAttributes
Content-type: application/json
{
"displayName": "Hobby",
"description": "Your hobby",
"dataType": "string",
}
Response:
I added this custom user attribute named Hobby like below:
When I ran the user flow and selected Sign up now, I got the screen asking for Hobby like below:
To localize this custom user attribute, I added the following as the first item of the LocalizedStrings array like below:
{
"ElementType": "ClaimType",
"ElementId": "extension_Hobby",
"StringId": "DisplayName",
"Override": true,
"Value": "Passatempo"
},
Json file:
When I tried to upload this file, I got the same error as you like below:
To resolve the error, you need to download valid resource file i.e., Local account sign up page like below:
Find hobby in that downloaded file and modify it like below:
{
"ElementType": "ClaimType",
"ElementId": "extension_Hobby",
"StringId": "DisplayName",
"Override": true,
"Value": "Passatempo"
},
Json file:
When I uploaded that file to Local account sign up page in User flow, it overrode successfully like below:
Now, I ran the user flow by enabling Localization as below:
When I selected Sign up now, Hobby changed to overridden value successfully like below:
Please note that, you can only override values which appears on that specific page. You will get Hobby on Sign up page. So, you need to modify Local account sign up page.

Related

Graph API: Unable to programmatically upload OneDrive item with specific properties (failing for createdBy and lastModifiedDataTime)

I am uploading an item to OneDrive using Graph API. I am also setting the properties of the item after it has been uploaded successfully. I am able to set "lastModifiedDateTime" but am not able to set "createdBy" and "createdDateTime".
"createdBy" is always set to the Azure AD application I have created for OAuth and in OneDrive UI it always shows "modified By" "SharePoint App".
And the "createdDataTime" is always current time (time of upload). Is there any way I can set these properties correctly?
The json I am using to patch the item properties:
{"createdDateTime":"2020-12-28T12:25:39Z",
"lastModifiedDateTime":"2020-12-28T12:25:39Z",
"createdBy":
{
"user":{
"email":"AlexW#vx2.onmicrosoft.com"}
},
"lastModifiedBy":{
"user":{
"email":"AlexW#vx2.onmicrosoft.com"}
},
"fileSystemInfo":{
"lastModifiedDateTime":"2020-12-28T12:25:39Z",
"createdDateTime":"2020-12-28T12:25:39Z"},
"file":{"mimeType":"image/jpeg"}
}
Please find the properties (queries from graph explorer) after the upload and above patch request:
{
"createdDateTime": "2020-12-28T12:28:09Z",
"lastModifiedDateTime": "2020-12-28T12:25:39Z",
"createdBy":
{
"application": {
"displayName": "ConsoleApp"}
},
"fileSystemInfo": {
"createdDateTime": "2020-12-28T12:28:09Z",
"lastModifiedDateTime": "2020-12-28T12:25:39Z"
},
"file": {
"mimeType": "image/jpeg",
"hashes": {
"quickXorHash": "4EQEGnBnLd04VXEmYqGHHIeZ2po="
}
}
}
As you can see user name has been replaced by the Azure AD app name and created by time is the time the upload was done and not the time specified in the patch request.
Please let me know if anyone has any idea about this.
If you refer the below article : https://learn.microsoft.com/en-us/graph/api/resources/driveitem?view=graph-rest-1.0 under the Properties section.
These are read-only fields meaning you will not be able to manually configure the values for the same.
WorkAround :
Having said that this cannot be achieved through Graph API however, you can make use of the Sharepoint API to update the same.
ValidateUpdateListItem()
For modifiying the created by , last modified by and last modified the sample body would be of below :
{ formValues": [
{
"FieldName": "Editor",
"FieldValue": "[{'Key':'i:0#.w|AlexW#vx2.onmicrosoft.com'}]"
},
{
"FieldName": "Author",
"FieldValue": "[{'Key':'i:0#.w|AlexW#vx2.onmicrosoft.com'}]"
},
{
"FieldName": "Created",
"FieldValue": "02/18/2020 11:25 PM"
}
],
"bNewDocumentUpdate": true
}
Request URL :
https://SPOURL/_api/web/Lists/GetbyTitle('Library Name')/items(1)/ValidateUpdateListItem"

Azure Graph API - ClaimsMappingPolicy with ClaimsTransformation

Im trying to automate the configuration of an enterpise application via the Azure Graph API.
Specifically, its the Azure Palo Alto Admin UI - https://learn.microsoft.com/en-us/azure/active-directory/saas-apps/paloaltoadmin-tutorial#configure-azure-ad-sso
Ive managed to get this working via the frontend, but im having trouble configuring the custom claims via the Graph Api.
For now, i just want to use a string claim in the custom claim as the customadmin value with a hardcoded value for the admin role
When creating via the portal, you can easily enter a string value as the source type of the claim.
However, via the Graph API the source type must be user, resource, audience, company or transformation.
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-claims-mapping#claim-schema-entry-elements
It seems that you can create a string type of transformation and then link the transformation into the main ClaimsSchema.
There is a similar example documented here https://learn.microsoft.com/en-us/graph/api/resources/claimsmappingpolicy?view=graph-rest-1.0#example-definition-that-uses-a-claims-transformation
But I cannot get the example to work. Even with a bit of massaging, the example fails. This is what ive been trying:
cat <<- EOF > claims.json
{
"definition": [
"{\"ClaimsMappingPolicy\":{
\"Version\":1,
\"IncludeBasicClaimSet\":\"true\",
\"ClaimsSchema\":[
{\"Source\":\"user\",\"ID\":\"extensionattribute1\"},{\"Source\":\"transformation\",\"ID\":\"DataJoin\",\"TransformationId\":\"JoinTheData\",\"JwtClaimType\":\"JoinedData\"}
],
\"ClaimsTransformation\":[
{\"ID\":\"JoinTheData\",\"TransformationMethod\":\"Join\",\"InputClaims\":[{\"ClaimTypeReferenceId\":\"extensionattribute1\",\"TransformationClaimType\":\"string1\"}], \"InputParameters\": [{\"ID\":\"string2\",\"Value\":\"sandbox\"},{\"ID\":\"separator\",\"Value\":\".\"}],\"OutputClaims\":[{\"ClaimTypeReferenceId\":\"DataJoin\",\"TransformationClaimType\":\"outputClaim\"}]}
]
}}"
],
"displayName": "Azure Reference Claim",
"isOrganizationDefault": false
}
EOF
az rest --method post --headers Content-type="application/json" --url "https://graph.microsoft.com/v1.0/policies/claimsMappingPolicies" --body #claims.json
Ive tried both the v1.0 and beta APIs but they both have the same behaviour
Which returns with the following error:
Bad Request({
"error": {
"code": "Request_BadRequest",
"message": "Property has an invalid value.",
"innerError": {
"date": "2020-09-01T13:03:10",
"request-id": "bc7cf58e-fe6d-47d1-b1e5-cae43326864f"
}
}
})
I was able to get the rest of the Palo Alto claim working (excluding the custom string) with the following:
{
"definition": [
"{\"ClaimsMappingPolicy\":{
\"Version\":1,
\"IncludeBasicClaimSet\":\"true\",
\"ClaimsSchema\": [{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier\"},{\"Source\":\"user\",\"ID\":\"givenname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname\"},{\"Source\":\"user\",\"ID\":\"displayname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\"},{\"Source\":\"user\",\"ID\":\"surname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname\"},{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":\"username\"}]
}}"
],
"displayName": "Palo Alto Claims Policy",
"isOrganizationDefault": false
}
And i was able to create a CustomString transformation which isnt linked to anything with the following:
{
"definition": [
"{\"ClaimsMappingPolicy\":{
\"Version\":1,
\"IncludeBasicClaimSet\":\"true\",
\"ClaimsTransformation\":[{\"ID\":\"CreateTermsOfService\",\"TransformationMethod\":\"CreateStringClaim\",\"InputParameters\": [{\"ID\":\"value\",\"DataType\":\"string\", \"Value\":\"sandbox\"}],\"OutputClaims\":[{\"ClaimTypeReferenceId\":\"TOS\",\"TransformationClaimType\":\"createdClaim\"}]}]
}}",
],
"displayName": "sdfa",
"isOrganizationDefault": false
}
However, when i try them together in the format of the example I get an error.
{
"definition": [
"{\"ClaimsMappingPolicy\":{
\"Version\":1,
\"IncludeBasicClaimSet\":\"true\",
\"ClaimsSchema\": [
{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier\"},{\"Source\":\"user\",\"ID\":\"givenname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname\"},{\"Source\":\"user\",\"ID\":\"displayname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\"},{\"Source\":\"user\",\"ID\":\"surname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname\"},{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":\"username\"},{\"Source\":\"transformation\",\"TransformationID\":\"xxxxxxxxx\",\"ID\":\"DataJoin\",\"SamlClaimType\":\"test\"}
],
\"ClaimsTransformation\":[
{\"ID\":\"xxxxxxxxx\",\"TransformationMethod\":\"CreateStringClaim\",\"InputParameters\": [{\"ID\":\"value\",\"DataType\":\"string\", \"Value\":\"sandbox\"}],\"OutputClaims\":[{\"ClaimTypeReferenceId\":\"DataJoin\",\"TransformationClaimType\":\"createdClaim\"}]}
]
}}"
],
"displayName": "Palo Alto Claims Policy",
"isOrganizationDefault": false
}
Which returns the same unhelpful error:
Bad Request({
"error": {
"code": "Request_BadRequest",
"message": "Property has an invalid value.",
"innerError": {
"date": "2020-09-01T13:03:10",
"request-id": "bc7cf58e-fe6d-47d1-b1e5-cae43326864f"
}
}
})
Any ideas what i am doing wrong? Im trying to base off of the example, which i cant get working.
I do not want to use powershell, i want to be able to automate via my desktop terminal.
I imagine i can avoid this situation and get the PA to integrate with AAD without a hardcoded value, but i feel that i should be able to get this working this way.
The mandatory encoding of the ClaimMappingPolicy object makes it quite fiddely to develop, so its possible there is a problem there somewhere.
Ive also tried just creating the ClaimsSchema without the ClaimsTransformation and then running a PATCH to amend the object with the transformed object, but it just overwrites the whole ClaimsMappingPolicy object rather than adding just the extra field.
When I remove the transformation source from the ClaimsSchema the request succeeds.
cat <<- EOF > claims.json
{
"definition": [
"{\"ClaimsMappingPolicy\":{
\"Version\":1,
\"IncludeBasicClaimSet\":\"true\",
\"ClaimsSchema\": [
{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier\"},{\"Source\":\"user\",\"ID\":\"givenname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname\"},{\"Source\":\"user\",\"ID\":\"displayname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\"},{\"Source\":\"user\",\"ID\":\"surname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname\"},{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":\"username\"}
],
\"ClaimsTransformation\":[
{\"ID\":\"xxxxxxxxx\",\"TransformationMethod\":\"CreateStringClaim\",\"InputParameters\": [{\"ID\":\"value\",\"DataType\":\"string\", \"Value\":\"sandbox\"}],\"OutputClaims\":[{\"ClaimTypeReferenceId\":\"DataJoin\",\"TransformationClaimType\":\"createdClaim\"}]}
]
}}"
],
"displayName": "Palo Alto Claims Policy",
"isOrganizationDefault": false
}
EOF
But there isnt an association between the ClaimsSchema and the ClaimsTransformation. This hints at a problem with the ClaimsSchema object
{\"Source\":\"transformation\",\"TransformationID\":\"xxxxxxxxx\",\"ID\":\"DataJoin\",\"SamlClaimType\":\"test\"}
But this looks suitable when looking at the documentation and the (possibly broken) reference example.
Providing information in answer as its too long to comment it.Please try this below query in Graph explorer
Post https://graph.microsoft.com/beta/policies/claimsMappingPolicies
{"definition":["{\"ClaimsMappingPolicy\":{\"Version\":1,\"IncludeBasicClaimSet\":\"true\", \"ClaimsSchema\":[{\"Source\":\"user\",\"ID\":\"extensionattribute1\"},{\"Source\":\"transformation\",\"ID\":\"DataJoin\",\"TransformationId\":\"JoinTheData\",\"JwtClaimType\":\"JoinedData\"}],\"ClaimsTransformations\":[{\"ID\":\"JoinTheData\",\"TransformationMethod\":\"Join\",\"InputClaims\":[{\"ClaimTypeReferenceId\":\"extensionattribute1\",\"TransformationClaimType\":\"string1\"}], \"InputParameters\": [{\"ID\":\"string2\",\"Value\":\"sandbox\"},{\"ID\":\"separator\",\"Value\":\".\"}],\"OutputClaims\":[{\"ClaimTypeReferenceId\":\"DataJoin\",\"TransformationClaimType\":\"outputClaim\"}]}]}}"],"displayName":"TestclaimsPolicy","isOrganizationDefault":false}
Post https://graph.microsoft.com/beta/policies/claimsMappingPolicies
{"definition":["{\"ClaimsMappingPolicy\":{\"Version\":1,\"IncludeBasicClaimSet\":\"true\",\"ClaimsSchema\": [{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier\"},{\"Source\":\"user\",\"ID\":\"givenname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname\"},{\"Source\":\"user\",\"ID\":\"displayname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\"},{\"Source\":\"user\",\"ID\":\"surname\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname\"},{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":\"username\"}],\"ClaimsTransformation\":[{\"ID\":\"CreateTermsOfService\",\"TransformationMethod\":\"CreateStringClaim\",\"InputParameters\": [{\"ID\":\"value\",\"DataType\":\"string\", \"Value\":\"sandbox\"}],\"OutputClaims\":[{\"ClaimTypeReferenceId\":\"TOS\",\"TransformationClaimType\":\"createdClaim\"}]}]}}"],"displayName":"Test1234","isOrganizationDefault":false}
for more information on CreateTermsOfService please refer to this document

How to use same value for AppRoles and oauth2Permissions with different Description and Display name?

My Azure AD application expose scope Roles.ReadWrite.All(Delegated permission). Now I want to use machine to machine communication, So I need to expose Application Permission. From the official documentation How to: Add app roles in your application and receive them in the token, I have created a AppRoles. Now I can give another application Application permission to the application.
But the issue is, I want to use the same value for Application Permission and Delegated Permission, As Microsoft is already doing this with their Microsoft Graph application's AccessReview.Read.All permission. But when I want to create appRoles, it shows an error -
Failed to update Backend API application. Error detail: It contains duplicate value. Please Provide unique value. []
I can only create same permission value if I keep the id, description and display name same for both appRoles and oauth2Permissions. But Microsoft Graph is using two different ID but the same value!
...
"requiredResourceAccess": [
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "ebfcd32b-babb-40f4-a14b-42706e83bd28", // AccessReview.Read.All
"type": "Scope"
},
{
"id": "d07a8cc0-3d51-4b77-b3b0-32704d1f69fa", // AccessReview.Read.All
"type": "Role"
}
]
},
{
"resourceAppId": "96954c3d-fbb4-4899-be79-582b810acb7b",
"resourceAccess": [
{
"id": "fbeb72c6-dfcb-45b6-b83a-db2929314e70",
"type": "Scope"
},
{
"id": "42b90870-bbe2-46c6-a221-4f8981c559ae", // Roles.ReadWrite.All
"type": "Scope"
},
{
"id": "42b90870-bbe2-46c6-a221-4f8981c559ae", // Roles.ReadWrite.All
"type": "Role"
}
]
}
],
...
As it is shown in the above Manifest snippet, Graph API's AccessReview.Read.All has two different id for Delegated and Application permission, Where my Roles.ReadWrite.All has same ID as a result same Display Name and Description
I'm afraid that what you need is not supported currently.
As you have tested, if we use the same value for "AppRoles" and "OAuth2Permission", it will show this error: It contains duplicate value. Please Provide unique value.
When we set the same ID for "AppRoles" and "OAuth2Permission", we will be required to set the same value for (description, adminConsentDescription),(displayName, adminConsentDisplayName),(isEnabled, isEnabled),(origin, origin),(value, value).
In this case, we can say that we get the same object for "AppRoles" and "OAuth2Permission". But it will not affect your use. The access token can return the correct Delegated permission or Application permission.

What does it mean "Property has an invalid value"?

During the creation of a batch of users in Azure AD by using the Graph API version 1.0 I receive the followiing error message:
Property has an invalid value
As you can see, there is not property name in the message, so I can't understand the real problem. What I can say is that those users have no particular conditions among the all others successfully created.
Any ideas?
Update 1:
As people asked, below are the post data. Since there is sensitive data, I have to changed names and som other personal data:
POST https://graph.microsoft.com/v1.0/users
And the JSON payload:
{
"accountEnabled": false,
"country": "BR",
"displayName": "Jane Sagan",
"givenName": "Jane",
"mailNickname": "jane.sagan",
"otherMails": [
"jane.sagan.#gmail.com"
],
"passwordProfile": {
"forceChangePasswordNextSignIn": false,
"password": "J#n3Sa8aN"
},
"surname": "Sagan",
"usageLocation": "BR",
"userPrincipalName": "jane.sagan#university.br",
"userType": "Member"
}
The property "otherMails" doesn't support the format "jane.sagan.#gmail.com".
Username cannot end with '.' in O365. You can have a try (create a user whose username ends with '.') in O365 portal to verify it.

GitLab API - How to get private_token using GET with session parameter?

I am using GitLab API v3 to do some operations on my private installation. Using private_token in GET URL is working fine. e.g.
GET http://git.example.com/api/v3/projects?=private_token=xyz123
But in order to make this possible, you need a private_token. There is one sure way to get it - from your account settings. But I want my users to use their email id/ login id and password to retrieve the private key and use it from there for rest of the operations.
I used following GET url and it is doing nothing for me:
GET http://git.example.com/api/v3/session?login=xyzuser&password=xyzpassword
Ideally as per GitLab documentation, I should get a JSON as follows -
{
"id": 1,
"username": "john_smith",
"email": "john#example.com",
"name": "John Smith",
"private_token": "dd34asd13as",
"blocked": false,
"created_at": "2012-05-23T08:00:58Z",
"bio": null,
"skype": "",
"linkedin": "",
"twitter": "",
"dark_scheme": false,
"theme_id": 1,
"is_admin": false,
"can_create_group" : true,
"can_create_team" : true,
"can_create_project" : true
}
If I get this, I can get private_token and work from there.
What am I doing wrong?
You need to POST the data as stated in the api (http://api.gitlab.org/session.html).
Be aware that if you do this action on a http port (instead of using https) that the password is send in plain text to the server.

Resources