How to get B2C id_token inside ClaimsTransformation.cs - asp.net-core

Is it possible to get the id_token returned by B2C after authentication inside of ClaimsTransformation.cs class?
I have tried to inject IHttpContextAccessor into the class, but it gets stuck in an infinite loop, calling the same method again and again, resulting in Stack Overflow error.

Try to add the following to the Azure AD OpenID Connect technical profile:
<ClaimsTransformations>
<ClaimsTransformation Id="CreateOtherMailsFromEmail" TransformationMethod="AddItemToStringCollection">
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" TransformationClaimType="item" />
<InputClaim ClaimTypeReferenceId="otherMails" TransformationClaimType="collection" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" TransformationClaimType="collection" />
</OutputClaims>
</ClaimsTransformation>
Reference Link : https://github.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack/blob/main/LocalAccounts/TrustFrameworkBase.xml

Related

ADLS SAS token is truncated when rewriting in API Management

I have an ADLS with images that I want to display on my website.
I want to expose them through APIM. I am sending the image name and SAS token in the request which I re-write in the actual backend request with the right folder structure.
The policy -
<policies>
<inbound>
<set-variable name="BlobName" value="#(context.Request.Url.Query.GetValueOrDefault("BlobName"))" />
<set-variable name="sasToken" value="#(System.Net.WebUtility.UrlDecode(context.Request.Url.Query.GetValueOrDefault("sasToken")))" />
<base />
<set-backend-service base-url="#{
string blobName = context.Variables.GetValueOrDefault<string>("BlobName");
string sasToken = context.Variables.GetValueOrDefault<string>("sasToken");
return String.Format("https://myadls.blob.core.windows.net/UserImages/Images/{0}?{1}",blobName,sasToken);
}" />
<authentication-managed-identity resource="https://storage.azure.com/" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
The SAS token - sv=2020-08-04&st=2022-02-24T04%3A17%3A53Z&se=2022-02-24T06%3A17%3A53Z&sr=c&sp=r&sig=5B6IUrj9VSh7oZSHAOKQK7fsWLun%2B%2BL7v0o1gQJHxvU%3D
Since the SAS token and '&' sign, the sasToken string is getting truncated to 'sv=2020-08-04'
As you can see in the policy I tried to encode the SAS in c# as
System.Net.WebUtility.UrlEncode(dataLakeSasBuilder.ToSasQueryParameters(sharedKeyCredential).ToString());
But, the System.Net.WebUtility.UrlDecode did not decode the value.
Thanks in advance.
I found that encoding it in the code and decoding the string in the policy is solving this
Encoding.UTF8.GetString(Convert.FromBase64String(context.Request.Url.Query.GetValueOrDefault("sasToken")))

AADB2C Claims Transformation for JSON from Federated Identity

I am writing IEF policy integrating with Federated Identity Provider. IDP returns claims in id_token as JSON. when I use claims mapping custom_attributes in output claims, I am getting AAD Exception as
An unexpected type "System.Collections.Generic.List1[System.Collections.Generic.KeyValuePair2[System.String,System.Object]]" was encountered of the claim with claim type id "custom_attributes"
here is my claim mapping:
<OutputClaim ClaimTypeReferenceId="custom_attributes" PartnerClaimType="custom_attributes"/>
claim Schema as:
<ClaimType Id="custom_attributes">
<DisplayName>custom_attributes</DisplayName>
<DataType>string</DataType>
<UserHelpText>Add help text here</UserHelpText>
</ClaimType>
id_token looks like below:
{
"custom_attributes":{
"emailAddress": "someone#example.com",
"displayName": "Someone",
"id" : 6353399
}
}
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
<OutputClaimsTransformation ReferenceId="GetRequestorIdClaimFromJsonClaimsTransformation" />
</OutputClaimsTransformations>
claim Schema as
<ClaimsTransformation Id="GetRequestorIdClaimFromJsonClaimsTransformation" TransformationMethod="GetClaimFromJson">
<InputClaims>
<InputClaim ClaimTypeReferenceId="custom_attributes" TransformationClaimType="inputJson" />
</InputClaims>
<InputParameters>
<InputParameter Id="claimToExtract" DataType="string" Value="id"/>
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="requestorid" TransformationClaimType="extractedClaim" />
</OutputClaims>
</ClaimsTransformation>
I found a solution to the problem and added it here
https://stackoverflow.com/questions/68086538/why-i-am-gettting-error-in-outputclaim-for-json-object-key-value-pair

Custom status code page with Windows Authentication

I've project in ASP NET Core 3.1 with Windows Authentication. I would like to use custom error code page.
This a basic example.
In HomeController :
[Route("/Error/401")]
public IActionResult StatusCode401()
{
HttpContext.Response.StatusCode = 401;
return View("ErrorUnauthorized");
}
But when I call StatusCode401 method, Windows prompt dialog (login, password) appears, if I cancel it, I see my custom view.
If I disable Windows Authentication, it's works fine.
How disable Windows prompt dialog when I use Windows Authentication ?
Thanks
You can open the web.config,
And then find the statusCode 401, change the responseModel from ExecuteURL to File
<system.webServer>
<httpErrors errorMode="Custom" >
<error statusCode="403" subStatusCode="0" prefixLanguageFilePath="" path="***" responseMode="ExecuteURL" />
<error statusCode="401" subStatusCode="2" prefixLanguageFilePath="" path="***" responseMode="File" />
....
</httpErrors>
</system.webServer>

Using OAuthWebSecurity for external login and SqlMembershipProvider for internal login

In my MVC4 project I have defined connection string to database and have defined it as SqlMembershipProvider, it works fine for local account (Login and register). but in external (facebook) login and in ExternalLoginCallback method I got this error :
"To call this method, the "Membership.Provider" property must be an instance of "ExtendedMembershipProvider"."
Here is membership node in web.config:
<membership defaultProvider="SqlProvider">
<providers>
<clear/>
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="DefaultConnection" />
</providers>
</membership>
I got the error here in ExternalLoginCallback method:
if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false))
{
return RedirectToLocal(returnUrl);
}
while the result containing all the required information I wanted.
I found some answers on the net such as using WebMatrix.WebData and simpleMembershipProvider, but I do not want to use simpleMembershipProvider.
Any help will be appreciated :)

Spring security 3.2: Does a custom UserDetails & UserDetailsService need a custom AuthenticationManager?

I'm working with spring security 3.2, JSF2 , Hibernate4.
I'have done 3/4 of the work :) but my authentication system doesn't work yet.
I have a UserService who implements UserDetailsService, a domain Class User who implements UserDetails.
THe login system never stop user to access secured pages, i tried user name and password who doesn't exist in my database...
Thanks for the help.
I have a loginBean who is trying to authenticate the user when he connects via login form :
public String login() {
try {
Authentication request = new UsernamePasswordAuthenticationToken(this.getUsername(), this.getPassword());
Authentication result = authenticationManager.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
} catch (AuthenticationException e) { e.printStackTrace();}
return "secured";
}
My spring security looks like this :
`<security:global-method-security jsr250-annotations="enabled" pre-post-annotations="enabled" secured-annotations="enabled" />
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/Admin" access="isAuthenticated()" />
<security:form-login login-page="/login.xhtml" authentication-failure-url="/" > </security:form-login>
</security:http>
<!-- User Data Access Object -->
<beans:bean id="userDao" class="com.clb.genomic.lyon.dao.UserDaoImpl" >
<beans:property name="sessionFactory" ref="sessionFactory"></beans:property>
</beans:bean>
<!-- User Business Object -->
<beans:bean id="userBo" class="com.clb.genomic.lyon.bo.UserBoImpl" >
<beans:property name="userDao" ref="userDao" />
</beans:bean>
<beans:bean id="login" class="com.clb.genomic.lyon.beans.LoginBean" scope ="request">
<beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>
<beans:bean id="standardPasswordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="userBo" >
<security:password-encoder ref="standardPasswordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>`
This is the error who show up...
org.springframework.security.authentication.AuthenticationServiceException: 1
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:109)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
at com.clb.genomic.lyon.beans.LoginBean.login(LoginBean.java:47).....
Caused by: java.lang.ArrayIndexOutOfBoundsException: 1
at com.clb.genomic.lyon.dao.UserDaoImpl.loadUserByUsername(UserDaoImpl.java:59)
at com.clb.genomic.lyon.bo.UserBoImpl.loadUserByUsername(UserBoImpl.java:68)
at com.clb.genomic.lyon.bo.UserBoImpl$$FastClassByCGLIB$$9ea98abf.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204).....
The exception from stack trace shows you are getting ArrayIndexOutOfBoundsException and it seems that you are reading from an empty array.
You should also check what value is being passed to loadUserByUsername() method, and if that user exists.