B2C SAML missing claims - saml-2.0

I'm attempting to use B2C Custom Policies to configure B2C as my SAML Idp. As a test I've set up our on premise ADFS environment as the SAML RP which seems to be required in order for the B2C logon page to work (B2C SAML doesnt support an Idp initiated session).
I've been following the guides at https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-get-started-custom and https://github.com/Azure-Samples/active-directory-b2c-advanced-policies/blob/master/Walkthroughs/RP-SAML.md to set up my B2C environment.
I get as far as showing the B2C sign-in page that the end-user receives however after I enter the credentials of an account into the B2C sign-in page I get redirected back to my RP with a SAML token however it is not parsing any of the configured claims.
The SAML token is showing the following error:
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder" />
<samlp:StatusMessage>Id:410906d7-639d-4828-b28d-22f84dfa617b ; Message: Policy &apos;B2C_1A_signup_signin_saml' in tenant ' mytenant.onmicrosoft.com'' specifies the claim 'sub' for the SubjectNamingInfo, but the claim is either not present or is null.</samlp:StatusMessage>
<IsPolicySpecificError>true</IsPolicySpecificError>
</samlp:Status>
My SignUpOrSigninSaml.xml RP config is as follows:
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignInSaml"/>
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="SAML2" />
<Metadata>
<Item Key="PartnerEntity">https://adfs-test.mycorporation.com.au/FederationMetadata/2007-06/FederationMetadata.xml</Item>
<Item Key="KeyEncryptionMethod">Rsa15</Item>
<Item Key="DataEncryptionMethod">Aes256</Item>
<Item Key="XmlSignatureAlgorithm">Sha256</Item>
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
</OutputClaims>
<!-- The ClaimType in the SubjectNamingInfo element below is a reference to the name of the claim added to the claims bag used by the token minting process.
This name is determined in the following order. If no PartnerClaimType is specified on the output claim above, then the DefaultPartnerClaimType for the protocol specified in the claims schema if one exists is used, otherwise the ClaimTypeReferenceId in the output claim is used.
For the SubjectNamingInfo below we use the DefaultPartnerClaimType of http://schemas.microsoft.com/identity/claims/objectidentifier, since the output claim does not specify a PartnerClaimType. -->
<!-- <SubjectNamingInfo ClaimType="http://schemas.microsoft.com/identity/claims/objectidentifier" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" ExcludeAsClaim="true"/> -->
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
I've tried a few different configurations for the "SubjectNamingInfo" such as:
<SubjectNamingInfo ClaimType="http://schemas.microsoft.com/identity/claims/objectidentifier" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" ExcludeAsClaim="true"/>
<SubjectNamingInfo ClaimType="sub" />
<SubjectNamingInfo ClaimType="name" />
But they all produce the same error.
I believe that once the SubjectNamingInfo issue is sorted the configured OutputClaims will show.
Anyone know how I can resolve this so I am able to see the claims of my user account in the token?
---Edit---
I attempted to add "sub" as an output claim however due to it not being defined in the Base file B2C wont allow it. Alternatively I tried changing the subject naming info to a claim that is already defined as an Output claim
<SubjectNamingInfo ClaimType="givenName" />
However I still seem to get the same error:
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder" />
<samlp:StatusMessage>Id:a3fe7ab0-4483-45b6-93f8-e75b539a3aea ; Message: The relying party technical profile of policy &apos;mytenant.onmicrosoft.com' in tenant 'B2C_1A_signup_signin_saml' specifies the claim type 'givenName' as the subject naming info claim, but the claim is not present or is null.</samlp:StatusMessage>
<IsPolicySpecificError>true</IsPolicySpecificError>

It isn't common to use the sub claim as the <saml:Subject><saml:NameID> element for a SAML assertion.
It is recommended to use the objectId claim as follows.
1) Ensure the objectId claim is declared with a partner claim for the SAML2 protocol:
<ClaimType Id="objectId">
<DisplayName>Object Identifier</DisplayName>
<DataType>string</DataType>
<DefaultPartnerClaimTypes>
<Protocol Name="OAuth2" PartnerClaimType="oid" />
<Protocol Name="OpenIdConnect" PartnerClaimType="oid" />
<Protocol Name="SAML2" PartnerClaimType="http://schemas.microsoft.com/identity/claims/objectidentifier" />
</DefaultPartnerClaimTypes>
</ClaimType>
2) Add the objectId claim to the <OutputClaims /> collection for the relying party technical profile and set the SubjectNamingInfo element:
<RelyingParty>
<TechnicalProfile Id="PolicyProfile">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
</OutputClaims>
<SubjectNamingInfo ClaimType="http://schemas.microsoft.com/identity/claims/objectidentifier" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" ExcludeAsClaim="true"/>
</TechnicalProfile>
</RelyingParty>
More information about SubjectNamingInfo
The ClaimType attribute for the SubjectNamingInfo element references a claim type that must be declared as an output claim for the technical profile.
This claim type is referenced by name with the following precedence:
1) If the PartnerClaimType attribute for the OutputClaim element is specified, then the ClaimType attribute for the SubjectNamingInfo element must be set to the ClaimTypeReferenceId attribute for this OutputClaim element:
<RelyingParty>
<TechnicalProfile Id="PolicyProfile">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="http://schemas.microsoft.com/identity/claims/objectidentifier" />
...
</OutputClaims>
<SubjectNamingInfo ClaimType="objectId" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" ExcludeAsClaim="true"/>
</TechnicalProfile>
</RelyingParty>
2) If the PartnerClaimType attribute for the OutputClaim element is not specified, then the ClaimType attribute for the SubjectNamingInfo element must be set to the DefaultPartnerClaimType attribute for the ClaimType element that is referenced by the ClaimTypeReferenceId attribute for this OutputClaim element:
<ClaimType Id="objectId">
<DefaultPartnerClaimTypes>
<Protocol Name="SAML2" PartnerClaimType="http://schemas.microsoft.com/identity/claims/objectidentifier" />
</DefaultPartnerClaimTypes>
</ClaimType>
<RelyingParty>
<TechnicalProfile Id="PolicyProfile">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
...
</OutputClaims>
<SubjectNamingInfo ClaimType="http://schemas.microsoft.com/identity/claims/objectidentifier" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" ExcludeAsClaim="true"/>
</TechnicalProfile>
</RelyingParty>

Related

AAD B2C - Mapping SAML Attribute containing True or False to Claim with Boolean Data Type

I am attempting to define an attribute that will be returned by a SAML 2.0 Identity Provider to AAD B2C and handled in a custom policy.
The goal is that the SAML attribute defines a boolean value and that AAD B2C is able to perform logic based on the value of the claim.
The SAML Attribute represents True or False as per the below:
<saml:Attribute Name="http://schemas.custom/claim/booleanexample" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>True</saml:AttributeValue>
</saml:Attribute>
When attempting to map this SAML Attribute to a claim defined within the Custom Policy ClaimsSchema with a data type of boolean, an error is thrown.
Message in App Insights:
"The data type 'String' of claim with id 'http://schemas.custom/claim/booleanexample' does not match the Data Type 'Boolean' of claimType with id 'BooleanExample' specified in the policy."
<ClaimType Id="BooleanExample">
<DataType>boolean</DataType>
</ClaimType>
I cannot see any mechanism to explicitly define a type for the attribute within SAML (it appears that AttributeValue should be of type xs:any).
I have attempted passing the usual values including 0/1, True/False, true/false with no luck.
Is it really required to handle this with a String claim, and then populate a Boolean claim using a Claims Transformation?
In the event that it helps anyone:
It appears that the claim must be mapped as a string, inspected using a CompareClaimToValue claims transformation that sets a boolean claim with the result of the comparison.
<ClaimsTransformation Id="CreateBooleanClaimFromString" TransformationMethod="CompareClaimToValue">
<InputClaims>
<InputClaim ClaimTypeReferenceId="samlBooleanClaimAsString" TransformationClaimType="inputClaim1" />
</InputClaims>
<InputParameters>
<InputParameter Id="compareTo" DataType="string" Value="true" />
<InputParameter Id="operator" DataType="string" Value="equal" />
<InputParameter Id="ignoreCase" DataType="string" Value="false" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="samlBooleanClaimAsBoolean" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>

ADB2C Custom policy user journey - override the content definition of each orchestration step

I have a custom policy which I am setting up which is based 2 steps in the user journey
Sign in signup unified
Self assert page.
In my RP file, I have specified ContentDefinitions for each 'type' of page so I can override these with my own. From my understanding, as the RP file is the last one point in the hierarchy, it will override always.
What I am finding is that it works for step 1, but step 2 always seems to default to the standard Microsoft page.
e.g. RP file.
<ContentDefinitions>
<!--For step 1-->
<ContentDefinition Id="api.signuporsignin">
<LoadUri>https://MYURL/custom_step1.html</LoadUri>
<RecoveryUri>~/common/default_page_error.html</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:1.2.0</DataUri>
<Metadata>
<Item Key="DisplayName">Signin</Item>
</Metadata>
</ContentDefinition>
<!--For step 2-->
<ContentDefinition Id="api.selfasserted">
<LoadUri>https://MYURL/custom_step2.html</LoadUri>
<RecoveryUri>~/common/default_page_error.html</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:1.2.0</DataUri>
<Metadata>
<Item Key="DisplayName">Collect information from user page</Item>
</Metadata>
</ContentDefinition>
</ContentDefinitions>
Ive seen on my UserJourney that Step 1 also seems to define a ContentDefinition (a default I guess?) but specifying my own one on each step didn't seem to have any effect either.
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
Suggestions appreciated!

Using ADB2C phone factor technical profile to validate a phone number before creating an account

I'm trying to create a custom ADB2C policy which should follow a journey such as...
User enters a phone number to verify
User receives a code to verify the number and enters this on the view
A claim is set which is used in the next step to save to AD.
I can see I need to use the phone factor technical profile as per the Microsoft docs, but I couldn't see whether this could be done before a user has signed up as it seems to want a UserID as an input claim (see Input claims required). All the samples seem to point to MFA and editing phones already associated to a user.
Is it possible to do this?
Secondly, is there any value in mixing the one-time password technical profile in this flow or is that more for just OTP code generation (not sending and accepting the inputs from the user)?
Update
So Ive managed to create the user journey which shows the UI correctly so it seems I can enter a phone number but now when I submit it I get an error "AADB2C90154: A multi-factor verification request failed to get a session id from the service."
As far as I can tell, the session technical profile is fine so not sure what the problem could be?
I also tried disabling the session but its seems like the phone tech profile needs it?
Sample technical profile
<TechnicalProfile Id="PhoneFactor-InputOrVerify">
<DisplayName>PhoneFactor</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.PhoneFactorProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.phonefactor</Item>
<Item Key="ManualPhoneNumberEntryAllowed">true</Item>
<Item Key="setting.authenticationMode">sms</Item>
<Item Key="setting.autodial">true</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="userIdForMFA" PartnerClaimType="UserId" DefaultValue="TEST" />
<InputClaim ClaimTypeReferenceId="phoneNumber" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="verifiedPhone" PartnerClaimType="Verified.OfficePhone" />
<OutputClaim ClaimTypeReferenceId="newVerifiedPhone" PartnerClaimType="newPhoneNumberEntered" />
</OutputClaims>
</TechnicalProfile>
#Raj,
I don't see how you are setting the userIdForMFA other than the default value? However, the Azure documentation isn't very clear here. Try using an inputClaimsTransformation that sets the userId Value.
For example:
Add this to the MFA technical profile:
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="CreateUserIdForMFA2" />
</InputClaimsTransformations>
Add this to your claims transformation:
<ClaimsTransformation Id="CreateUserIdForMFA2" TransformationMethod="CreateStringClaim">
<InputParameters>
<InputParameter Id="value" DataType="string" Value="test12345#{YourTenant}.onmicrosoft.com"/>
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="userIdForMFA" TransformationClaimType="createdClaim" />
</OutputClaims>
</ClaimsTransformation>

Unable to cast object of type 'System.Web.Security.SqlRoleProvider' to type 'WebMatrix.WebData.SimpleRoleProvider'

I developing an mvc web app with Entity Frame]work. I've enabled database migration so that i can add some seed data on each update.
More specifically, i want to add two users and two roles; so the configuration file looks like this:
var roles = (SimpleRoleProvider)Roles.Provider;
var membership = (SimpleMembershipProvider)Membership.Provider;
//// create two roles
if (!roles.RoleExists("Admin"))
{
roles.CreateRole("Admin");
}
if (!roles.RoleExists("User"))
{
roles.CreateRole("User");
}
However there seems to be a problem during the casting; it throws an exception
Unable to cast object of type 'System.Web.Security.SqlRoleProvider' to type 'WebMatrix.WebData.SimpleRoleProvider'.
I suspect that this might be a configuration issue, but i'm not really sure. Does anyone stumbled across the same problem?
That's because SqlRoleProvider does not inherit SimpleRoleProvider. However, you can try using SimpleRoleProvider Constructor (RoleProvider):
var roles = new SimpleRoleProvider(Roles.Provider);
I sorted this out. The problem apparently was related to web configuration. I added the following lines to the web.config file:
<roleManager enabled="true" defaultProvider="SimpleRoleProvider">
<providers>
<add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
</providers>
</roleManager>
to explicitly set the role provider. So now the Roles.Provider returns an instance of WebMatrix.WebData.SimpleRoleProvider; thus i don't need to cast any more
I solved this by placing below code in web.config between
<roleManager enabled="true" defaultProvider="simple">
<providers>
<clear />
<add name="simple" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
</providers>
</roleManager>
<membership defaultProvider="simple">
<providers>
<clear />
<add name="simple" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>

How to set WS-SecurityPolicy in an inbound CXF service in Mule?

When configuring the service for handling UsernameToken and signatures, it's setup like this:
<service name="serviceName">
<inbound>
<cxf:inbound-endpoint address="someUrl" protocolConnector="httpsConnector" >
<cxf:inInterceptors>
<spring:bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
<spring:bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<spring:constructor-arg>
<spring:map>
<spring:entry key="action" value="UsernameToken Timestamp Signature" />
<spring:entry key="passwordCallbackRef" value-ref="serverCallback" />
<spring:entry key="signaturePropFile" value="wssecurity.properties" />
</spring:map>
</spring:constructor-arg>
</spring:bean>
</cxf:inInterceptors>
</cxf:inbound-endpoint>
</inbound>
</service>
But how is it possible to create a policy of what algorithms that are allowed, and what parts of the message that should be signed?
You'd have to ask the Mule folks. Last I checked, they hadn't moved to CXF 2.2.x yet. If they ARE on 2.2.x, you could use the WS-SecPol support built into CXF.

Resources