B2C App registration with custom SAML policy - configuring claims - azure

I created some custom policy for our SAML applications in Azure b2c.
Now I want to edit the claims sent by azure b2c to application in SAMLResponse.
I added the claims in the trustframwworkbase:
<ClaimType Id="TESTFELDSTRING">
<DisplayName>TESTFELDSTRING</DisplayName>
<DataType>string</DataType>
<DefaultPartnerClaimTypes>
<Protocol Name="OpenIdConnect" PartnerClaimType="TESTFELDSTRING" />
<Protocol Name="SAML2" PartnerClaimType="TESTFELDSTRING" />
</DefaultPartnerClaimTypes>
<UserHelpText>Your TESTFELDSTRING name.</UserHelpText>
<UserInputType>TextBox</UserInputType>
</ClaimType>
And I changed my custom policy and added some new outputclaim there:
<OutputClaim ClaimTypeReferenceId="TESTFELDSTRING" />
But the claim is still missing in my SAML responses.
I have one application which expects some information as SAML Claim and I do not see how to transmit it.
On the "normal Azure AD" I will be able to configure the claims per app. So one app is sending other claims than another app. How to do this in azure b2c?
I tried to add the claim inside the manifest of my app registration with:
"optionalClaims": {
"saml2Token": [
{
"name": "TESTFELDSTRING",
"source": null,
"essential": false,
"additionalProperties": []
}
]
}
But this is not working too.
My transmitted attributes are:
<saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema">
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
FriendlyName="Display Name"
>
<saml:AttributeValue xsi:type="xs:string">XXX</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
FriendlyName="Given Name"
>
<saml:AttributeValue xsi:type="xs:string">XXX</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
FriendlyName="Surname"
>
<saml:AttributeValue xsi:type="xs:string">XXX</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
FriendlyName="Email Address"
>
<saml:AttributeValue xsi:type="xs:string">XXX#XXX.XXX</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="objectId"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
FriendlyName="User's Object ID"
>
<saml:AttributeValue xsi:type="xs:string">xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
Anyone a suggestion?

Did you follow this sample?
Did you add the new claims as output claims in the Technical profile?
Did you also add the new claims as output claims in the <RelyingParty> section?

Related

Azure B2C - SAML - The service provider is not a valid audience of the assertion

I set up a SAML Provider for Azure B2C (Single Sign On). The IDP is happy and sends a SAML Assertion back, but Azure B2C complains.
It looks like Azure B2C cannot process the SAML Answer. The Error Message extracted via AppInsights is simple "The service provider is not a valid audience of the assertion".
The URLs seem to fit, but im not sure if the AudienceRestriction should point to the base policy or maybe the sign-in policy, as teh metadata can only be accessed via the SIGN-UP Policy as part of the URL and not the BASE:
"https://{my-tenant-name}.b2clogin.com/{my-tenant-name}.onmicrosoft.com/B2C_1A_SIGNUP_SIGNIN/samlp/metadata?idptp={IDP-NAME}-SAML2"
Configuration (updated according to the comments of this question).
Configuration
<EntityDescriptor
xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
ID="https://{IDP-URL}/saml/2.0/idp/"
entityID="https://{IDP-URL}/saml/2.0/idp/"
validUntil="2099-12-31T23:59:59Z">
<SPSSODescriptor
AuthnRequestsSigned="false"
WantAssertionsSigned="false"
ResponsesSigned="false"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<AssertionConsumerService
index="0"
isDefault="true"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://{my-tenant-name}.b2clogin.com/{my-tenant-name}.onmicrosoft.com/B2C_1A_TrustFrameworkBase/samlp/sso/assertionconsumer" />
</SPSSODescriptor>
<IDPSSODescriptor
WantAuthnRequestsSigned="true"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<SingleSignOnService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://{IDP-URL}/saml/2.0/idp/" />
</IDPSSODescriptor>
</EntityDescriptor>
SAML Response
<saml2p:Response Destination="https://{my-tenant-name}.b2clogin.com/{my-tenant-name}.onmicrosoft.com/B2C_1A_TrustFrameworkBase/samlp/sso/assertionconsumer"
ID="Response_6793aae6a9cc629a6be69a270731961695dad50e"
InResponseTo="_719e3407-dbad-4761-8e8a-7e7272b2a67b"
IssueInstant="2022-08-17T08:34:29.112Z"
Version="2.0"
xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
>
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://{IDP-URL}/saml/2.0/idp/</saml2:Issuer>
<saml2p:Status>
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
</saml2p:Status>
<saml2:Assertion ID="Assertion_16dc5f9b7c67ed241c79436c20296a2fd514ea87"
IssueInstant="2022-08-17T08:34:29.111Z"
Version="2.0"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<saml2:Issuer>https://{IDP-URL}/saml/2.0/idp/</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<ds:Reference URI="#Assertion_16dc5f9b7c67ed241c79436c20296a2fd514ea87">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="xs"
xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"
/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<ds:DigestValue>/4OAX07/scGvFyDCT3BBzlHJQ7q65Ak0uGlTvE0z904=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>{removed}</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>{removed}</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">71747</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData InResponseTo="_719e3407-dbad-4761-8e8a-7e7272b2a67b"
NotOnOrAfter="2022-08-17T08:34:39.112Z"
Recipient="https://{my-tenant-name}/{my-tenant-name}.onmicrosoft.com/B2C_1A_TrustFrameworkBase/samlp/sso/assertionconsumer"
/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="2022-08-17T08:34:29.111Z"
NotOnOrAfter="2022-08-17T08:34:59.111Z"
>
<saml2:AudienceRestriction>
<saml2:Audience>https://{my-tenant-name}/{my-tenant-name}.onmicrosoft.com/B2C_1A_TrustFrameworkBase/samlp/sso/assertionconsumer</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement AuthnInstant="2022-08-17T08:34:29.111Z"
SessionNotOnOrAfter="2022-08-17T10:34:29.111Z"
>
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
My SAML METADATA
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" ID="_7865bef4-f0d2-4062-9e58-a145e1beb91f" entityID="https://{my-tenant-name}.b2clogin.com/{my-tenant-name}.onmicrosoft.com/B2C_1A_TrustFrameworkBase">
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<Reference URI="#_7865bef4-f0d2-4062-9e58-a145e1beb91f">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<InclusiveNamespaces xmlns="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="saml samlp xenc xs"/>
</Transform>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>bSqD69uUzX0swY6hAKkzLEaWJeMyV2UIoyFBTxLhHi0=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>AiyK11or3hAGSnHADidHKp2XCcH0amBaU8xA6xQrxgKNZBqaKFF0rdbiRdVp4YFbqlQeCruYAEbT1JnAAwRyKLn6IZOJIP7iA3PeSr8bguus58+LGmb30YsYcbpAMxLjhQbmAu1t25v4huaOViZQwNAafkdjKAyhJRa7P8ihEBbl4CUQjYJ0eIASxWZuD6j1tg4afMv9GH809lFGl7KRER8oUp9P6VF5xdJbavpX623eRZRAeqV++CBXKTrFUnMOHrp1eI68IaobKOx/xkN59FX7SabdqpIVE+L9rnPtYYwG0LLpqmAOaSZEhmGKp2y27OA1ZxJZittwFMTmWmtoqA==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>{removed}</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
<SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>{removed}</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://{my-tenant-name}.b2clogin.com/{my-tenant-name}.onmicrosoft.com/B2C_1A_signup_signin/samlp/sso/logout" ResponseLocation="https://{my-tenant-name}.b2clogin.com/{my-tenant-name}.onmicrosoft.com/B2C_1A_signup_signin/samlp/sso/logout/response"/>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://{my-tenant-name}.b2clogin.com/{my-tenant-name}.onmicrosoft.com/B2C_1A_TrustFrameworkBase/samlp/sso/assertionconsumer" index="0" isDefault="true"/>
</SPSSODescriptor>
</EntityDescriptor>
Please check below points:
Subject contains a NameID element, which represents the authenticated user. The NameID value is a targeted identifier that is directed only to the service provider that is the audience for the token. It is persistent - it can be revoked, but is never reassigned.
nameidpolicys element requests a particular name ID format in the response
ex:
<NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
The Format attribute can have only one of the following values;
Persistent, emailAddress, unspecified, transient
For urn:oasis:names:tc:SAML:2.0:nameid-format:persistent : Azure
Active Directory issues the NameID claim as a pairwise identifier.
For urn:oasis:names:tc:SAML:2.0:nameid-format:transient: Azure Active
Directory issues the NameID claim as a randomly generated value that
is unique to the current SSO operation. This means that the value is
temporary and cannot be used to identify the authenticating user.
But as seen from the configuration that you provided , it seems to be transient:
urn:oasis:names:tc:SAML:2.0:nameid-format:transient
And response has it persistent. Please check with that.
Audience in audience restriction contains a URI that identifies an intended audience. Azure AD sets the value of this element to the value of Issuer element of the AuthnRequest that initiated the sign- on. Please check and Configure Azure Active Directory B2C as a SAML IdP to your applications | Microsoft Docs
Conditions element specifies conditions that define the acceptable use of SAML assertions.Please check the allowed audience is valid.
References:
using-azure-ad-b2c-as-a-saml-idp-with-the-sp-initiated-flow(medium.com)
audience restriction and proxy restriction-saml-core-2.0-os.pdf

Azure B2C custom saml policy: Different claims per App

I followed this manual to register SAML to my azure b2c: https://learn.microsoft.com/en-us/azure/active-directory-b2c/connect-with-saml-service-providers
With this I am able to define SAML claims in my new TechnicalProfile with for example
<OutputClaim ClaimTypeReferenceId="surname"/>
Now, I have application which expects EXACTLY some attributes with a specific name. Setting PartnerClaimType to some custom string will result in a saml attribute with that string as attribut name:
<OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="LastName" />
This will result in:
<saml:Attribute Name="LastName"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
FriendlyName="Surname">
<saml:AttributeValue xsi:type="xs:string">Peters</saml:AttributeValue>
</saml:Attribute>
But I can just configure claims on that profile - I need to specify it in the app registration in azure.
So the 1st application needs attribute "surname", next needs "FamilyName" and 3rd needs "LastName".
How can I use the claim defined in the policy and change it in the app? I saw there is some property "optionalClaims" in the manifest and there are "saml2Token". But the documentation of this did not helped me (https://learn.microsoft.com/de-de/azure/active-directory/develop/active-directory-optional-claims).
If you are connecting 3 SAML Relying Parties, you would have 3 Application Registrations, and 3 Relying Party technical profiles as part of your Custom Policy. Each Relying party section would have the required claims mappings.

SAML setup assertion with custom parameters

I have working SAML 2.0 in my dev account https://espatialzdenek-dev.onelogin.com
I am able to login through onelogin.
Only problem I have is that I can't change / I don't know how to change attribute names in the login request from IDP to SP.
in the assertion saml response I get in section
<saml:AttributeStatement>
for example this element
<saml:AttributeStatement>
<saml:Attribute Name="User.FirstName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">z2</saml:AttributeValue>
</saml:Attribute>
but I need there
<saml:AttributeStatement>
<saml:Attribute Name="firstName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">z2</saml:AttributeValue>
</saml:Attribute>
I need make this change at least for first name , last name and user assigned security groups.
Is there way to do this in oneLogin SAML IDP setup?
Add App -> SAML Test.....
That will give you a custom application with all options available to you. Create custom claims to your hearts content.

How do I read the NameID element as a claim in a B2C TechnicalProfile for a SAML2 identity provider?

I followed the example in Set up sign-in with a Salesforce SAML provider by using custom policies in Azure Active Directory B2C
and was able to successfully SSO from Salesforce into Azure B2C. However, I would also like to retrieve the value of
the NameID element from the SAML Assertion as a claim. Is this possible?
For example, say that the incoming SAML 2.0 Assertion posted to B2C's assertion consumer endpoint looks
something like this simplified XML.
<saml:Assertion>
<saml:Issuer>https://mytestinstance-dev-ed.my.salesforce.com</saml:Issuer>
<saml:Subject>
<saml:NameID>emp99999</saml:NameID>
</saml:Subject>
<saml:AuthnStatement AuthnInstant="2018-10-04T16:56:44.192Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="userId">
<saml:AttributeValue>009f90000099zzz</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="username">
<saml:AttributeValue>user000#example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="email">
<saml:AttributeValue>user000#example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="">
<saml:AttributeValue>false</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
The TechnicalProfile lets you access any Attribute from the AttributeStatement as a claim by referencing its
Name in the PartnerClaimType in an OutputClaim element. For example, with the TechnicalProfile below, the socialIdpUserId claim is
set to the value of the userId attribute from the SAML Assertion, "009f90000099zzz". What I would like to have is
is a claim named employeeId that is set to "emp99999," the value of the NameID element.
<TechnicalProfile Id="salesforce">
<DisplayName>Salesforce</DisplayName>
<Description>Login with your Salesforce account</Description>
<Protocol Name="SAML2"/>
<Metadata>
<Item Key="RequestsSigned">false</Item>
<Item Key="WantsEncryptedAssertions">false</Item>
<Item Key="WantsSignedAssertions">false</Item>
<Item Key="PartnerEntity">https://mytestinstance-dev-ed.my.salesforce.com/.well-known/samlidp/TestB2C.xml</Item>
</Metadata>
<!-- <CryptographicKeys> -->
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="userId"/>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email"/>
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="username"/>
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication"/>
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="SAMLIdp" />
<!-- We want the Subject/NameID value as a custom employeeId claim. URI reference doesn't work. -->
<OutputClaim ClaimTypeReferenceId="employeeId"
PartnerClaimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" />
</OutputClaims>
<!--<OutputClaimsTransformations> -->
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop"/>
</TechnicalProfile>
I tried using PartnerClaimType values like "NameID", "NameIdentifier", as well as the well-known URI for NameIdentifier
and none of these seemed to work.
I also saw some references to the use of the SubjectNamingInfo element and experimented with it,
but that only seems relevant in defining the token sent to a RelyingParty
and not in reading claims from a token received from an IDP.
Also, what about any other Assertion elements? For example, depending on how an IDP uses it,
I could see a need to read the AuthnContextClassRef value to make a decision about whether
to issue an MFA challenge.
The solution to use assertionSubjectName is definitely correct. In fact, MSFT updated their main documentation page on Dec 20th 2018 to add further information: Define a SAML Technical Profile. That being said - I wanted to add one more note that may help others who come across this behavior. It appears that Azure will NOT map the NameID to your output claim if the NameID element has a "NameQualifier" attribute.
Example - this will map to your output claim:
<Subject>
<NameID>foo#bar.com</NameID>
This will NOT map to your output claim:
<Subject>
<NameID NameQualifier="https://bar.com/realms/foo">foo#bar.com</NameID>
Hopefully this will be helpful to anyone who has run into a situation where "assertionSubjectName" does not appear to work. That being said - it seems that this behavior is not all that desirable and I have reached out to MSFT to find out if this is WAD or not.
For the SAML2 protocol, the value of the NameID element can be accessed by using a PartnerClaimType with the value "assertionSubjectName".
This is mentioned in the "Specifying a technical profile for a SAML 2.0 claims provider" section of
Features part 6
in the Advanced Policies Git repo.
For example, to map the NameID from the SAML Assertion to the "employeeId" claim, set its PartnerClaimType to "assertionSubjectName"
in the OutputClaim claim element.
<OutputClaims>
<!-- Other claims -->
<OutputClaim ClaimTypeReferenceId="employeeId"
PartnerClaimType="assertionSubjectName" />
</OutputClaims>
Another example can be found in
Specifying a technical profile for a SAML 2 excerpt from documentation.docx.
Edit
Per Adam C's answer, this is now documented at
Define a SAML technical profile in an Azure Active Directory B2C custom policy. He also notes that B2C will not map NameID to your output claim if the NameID element has a "NameQualifier" attribute.
In my case, I was trying to extract the NameID from a SAML response where the NameID element had an SPNameQualifier attribute. Using assertionSubjectName was not working.
However, what did work was using the SPNameQualifier attribute value.
For example, suppose your SAML response looks like
<saml:Subject>
<saml:NameID SPNameQualifier="https://bar.com/realms/foo">emp99999</saml:NameID>
</saml:Subject>
To extract the NameID value you can set your claim mapping as
<OutputClaims>
<!-- Other claims -->
<OutputClaim ClaimTypeReferenceId="employeeId" PartnerClaimType="https://bar.com/realms/foo" />
</OutputClaims>

Azure AD B2C OpenID Connect and SAML 2.0 read role claims

AD FS is configured with custom policies as a claims provider on Azure AD B2C using SAML 2.0. The relying party on Azure AD B2C is using OpenID Connect.
AD FS issues a SAML 2.0 Assertion including role claims. If the roles are returned in two separate Attribute elements:
<saml:Attribute Name="http://test.com/claims/role">
<saml:AttributeValue>role1</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="http://test.com/claims/role">
<saml:AttributeValue>role2</saml:AttributeValue>
</saml:Attribute>
only the last claim is read by Azure AD B2C.
Otherwise if the roles is returned as AttributeValue elements in one Attribute element:
<saml:Attribute Name="http://test.com/claims/roles">
<saml:AttributeValue>role1</saml:AttributeValue>
<saml:AttributeValue>role2</saml:AttributeValue>
</saml:Attribute>
all the role value is read.
The Azure AD B2C role ClaimType used is:
<ClaimType Id="role">
<DisplayName>Role</DisplayName>
<DataType>string</DataType>
<DefaultPartnerClaimTypes>
<Protocol Name="OAuth2" PartnerClaimType="role" />
<Protocol Name="OpenIdConnect" PartnerClaimType="role" />
<Protocol Name="SAML2" PartnerClaimType="http://test.com/claims/role" />
</DefaultPartnerClaimTypes>
<UserHelpText/>
</ClaimType>
<ClaimType Id="roles">
<DisplayName>Roles</DisplayName>
<DataType>stringCollection</DataType>
<DefaultPartnerClaimTypes>
<Protocol Name="OAuth2" PartnerClaimType="roles" />
<Protocol Name="OpenIdConnect" PartnerClaimType="roles" />
<Protocol Name="SAML2" PartnerClaimType="http://test.com/claims/roles" />
</DefaultPartnerClaimTypes>
<UserHelpText/>
</ClaimType>
SAML 2.0 support both sending multiple Attribute with the same name and one Attribute with a list of AttributeValue.
Are there a way for Azure AD B2C to read multiple Attribute with the same name and not only the last one?
I solved the problem by adding a custom SAML 2.0 broker in between the AD FS and Azure AD B2C. The SAML 2.0 broker is a Relying Party (RP) on the AD FS and a Identity Provider (IdP) for Azure AD B2C. This way it is possible to convert the claims and issue a nye SAML 2.0 token with a claims structor supported by Azure AD B2C.
Both the RP and IdP part of the SAML 2.0 broker can be implemented with the ITfoxtec.Identity.Saml2 package.

Resources