Azure AD B2C AuthenticationResponseChallenge - azure-web-app-service

I'm working on Azure AD B2C for the last few days, got a sample and made it running.
The issue I am facing is exactly like AAD B2C issue point #3, but I could get any valuable comment in this question that may solve my problem. Example is running fine with me but when I implemented it in my solution, after giving the AAD B2C Credentials I'am ending up with:
private async Task OnRedirectToIdentityProvider(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
PolicyConfigurationManager mgr = notification.Options.ConfigurationManager as PolicyConfigurationManager;
if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
OpenIdConnectConfiguration config = await mgr.GetConfigurationByPolicyAsync(CancellationToken.None, notification.OwinContext.Authentication.AuthenticationResponseRevoke.Properties.Dictionary[Startup.PolicyKey]);
notification.ProtocolMessage.IssuerAddress = config.EndSessionEndpoint;
}
else
{
OpenIdConnectConfiguration config = await mgr.GetConfigurationByPolicyAsync(CancellationToken.None, notification.OwinContext.Authentication.AuthenticationResponseChallenge.Properties.Dictionary[Startup.PolicyKey]);
notification.ProtocolMessage.IssuerAddress = config.AuthorizationEndpoint;
}
}
In the 'else' part, AuthenticationResponseChallenge is always null, which is throwing an error. Can anyone give me a detailed reply as what is causing this and how to resolve it?

I had the same problem because the actual PolicyKey wasnt initiated correctly, make sure that you have the "PolicyAuthHelpers" (provided by Microsoft as a fix as their current libraries are unable to handle B2C). Step the code into PolicyConfigurationManager.cs and you can probably find why it breaks. Also verify that you have the correct policies configured in web.config, for example:
<add key="ida:SignInPolicyId" value="B2C_1_signin" />
If that doesnt help you could of course just hardcode it:
OpenIdConnectConfiguration config = await mgr.GetConfigurationByPolicyAsync(CancellationToken.None, notification.OwinContext.Authentication.AuthenticationResponseChallenge.Properties.Dictionary["b2cpolicy"]);

Related

Microsoft Graph returning null account even after passing a valid account ID

I am encountering a weird issue with Microsoft Graph on an integration that was built a few years back.
This issue started happening a few months back. After I sync a Microsoft Account and provide email and calendar read/write access, everything works fine for some time. I am able to retrieve emails and calendar events. However, after some time, I notice that when a call is made to GetAccountAsync with a valid AccountID, null is returned. This is causing AcquireTokenSilent to fail with the following error:
Error Code: user_null
Error Message: No account or login hint was passed to the AcquireTokenSilent call.
I have also noticed that this happens under the following scenarios:
When the WebJob (console app) is run every 15 minutes, I encounter this issue
To narrow down the root cause, I have deleted the WebJob to see if the issue occurs on the web app. It looks like the issue starts to occur after an hour or so even without the web job running.
I have upgraded to the latest version of MSAL and implemented 4.46.1.0 version of Microsoft.Identity.Client. I am using .NET Framework 4.8 and this is a .NET MVC 5 app.
Here's my code:
public async Task<string> GetAccessTokenAsync()
{
string accessToken;
UserExternalApp.Scope = string.IsNullOrWhiteSpace(UserExternalApp.Scope) ? "" : UserExternalApp.Scope;
// Load the app config from web.config
var microsoftScopes = UserExternalApp.Scope.Replace(' ', ',').SplitAndTrim(new char[] { ',' }).ToList();
var accountID = UserExternalApp.ExternalUserAccountID;
var app = ConfidentialClientApplicationBuilder.Create(ClientID)
.WithRedirectUri(DefaultRedirectUrl) // https:\//mywebsite.com
.WithClientSecret(Secret)
.Build();
app.AddDistributedTokenCache(services =>
{
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
options.SchemaName = "dbo";
options.TableName = "TokenCache";
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
try
{
var account = await app.GetAccountAsync(accountID);
var query = app.AcquireTokenSilent(microsoftScopes, account); // This is where the error is thrown
var acquireTokenSilent = await query.ExecuteAsync();
accessToken = acquireTokenSilent.AccessToken;
}
catch
{
// This is the error thrown:
// Exception Type: MsalUiRequiredException
// Error code: user_null
// Exception Details: No account or login hint was passed to the AcquireTokenSilent call.
throw;
}
return accessToken;
}
I know the token is persisted on my SQL Server:
I think the MSAL uses an in memory token cache by default, Once the client logins, authentication information will be stored in cookie(if cookie has not been disabled). Even your web application restarts, the client will keep logged in.
To solve this, you can use custom Token cache serialization in MSAL.NET:https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-net-token-cache-serialization?tabs=aspnet.
Hope this helps.
I would like to share the resolution to this problem in case if it helps someone in the future. I feel that this is a Microsoft Bug that was introduced during one of their many upgrade process as this code went from working to broken without any change from our end. Here are the steps I took:
While exchanging the code for a token after user authentication, I retrieved and saved Account.HomeAccountId.Identifier, Account.HomeAccountId.ObjectId and TenantId for the account.
I implemented my own version of IAccount.
Instead of calling await app.GetAccountAsync(accountID), I used my implementation of IAccountand initialized it with the data I saved in Step 1.
I used this account to call app.AcquireTokenSilent(microsoftScopes, account).
And that's it! No error was thrown once this was done!

Microsoft Graph Toolkit no have result match for some of the Azure AD users

Recently found some weird case when trying to use mgt people picker to search my tenancy Azure AD user with below tag.
<mgt-people-picker type="any" transitive-search="true"></mgt-people-picker>
Following is summary of info used:
a) Single tenant, does not allowed personal Microsoft account.
b) All API permission requires are granted in application and in app registration.
"User.Read",
"User.ReadBasic.All",
"People.Read",
"People.Read.All",
"Contacts.Read",
"Directory.Read.All",
"User.Read.All",
"Member.Read.Hidden",
"Domain.Read.All",
"User.ReadWrite.All",
"APIConnectors.Read.All"
c) admin consent is given.
d) I'm using api/proxy to connect.
Somehow, I only can found some of the users, some of the users was not found. From mgt people picker UI, i just enter three to four character or full email address to search it but the return result is not correct. And i found that when it return incorrect result it have error on retrieving photo values. Sample error as below
I have tried to use Graph Explorer to test it. Apparently, it is also cannot return the correct result match. But only using following query test, it is able to return the correct user to me. but when using mgt people picker, it cannot. Any advise are much appreciated. I'm just guessing it is something related to Azure AD user profile settings or it is something related to my application configuration or something else. Hope can some clues for me to resolve this issue. For your information, I have all admin rights to access all resources in my organization Azure environment. If there is information that I have missing, please do let me know, I will edit the post to include it.
https://graph.microsoft.com/v1.0/users/<email address>
Test result by using Graph Explorer as reference, which only return partial only (majority not return):
In order to fix this issue that /me/people endpoint does not able to show relevant search result. I have did following code changes in my api/proxy to intercepting the process before sending the request to MS Graph as below. This maybe is a workaround to make it works. In future, if there is better option, I will make a change on it.
Hope this can help someone who faced the same issue as I'm.
var url = $"{GetBaseUrlWithoutVersion(_graphClient)}/{all}{qs.ToUriComponent()}";
if(url.StartsWith("https://graph.microsoft.com/v1.0/me/people?$search="))
{
string url2 = #"https://graph.microsoft.com/v1.0/users?$count=true&$filter=startsWith(displayname,%27{0}%27) or startsWith(userPrincipalName,%27{1}%27)";
Uri searchUri = new Uri(url);
string paramSearch = HttpUtility.ParseQueryString(searchUri.Query).Get("$search").Replace('"', ' ').Trim();
//we do not want to search for any email address, just for custom search only
if(!string.IsNullOrEmpty(paramSearch) && !paramSearch.Contains("#xxx"))
{
url = string.Format(url2, paramSearch, paramSearch);
}
}

MSAL.Net and Xamarin.Forms having problem with redirect url

I am following this guide https://github.com/Azure-Samples/active-directory-xamarin-native-v2/tree/master/1-Basic
and have this code in my app.xaml.cs
public App()
{
PCA = PublicClientApplicationBuilder.Create(applicationClientId)
.WithTenantId("tenantidhere")
.WithRedirectUri($"msal{applicationClientId}://auth")
.WithIosKeychainSecurityGroup("com.microsoft.adalcache") // focussing on android first so ignore this one
.Build();
//...
}
I get the message that there is something wrong with the return url... and the continue button does not seem to work. I don't know if the issues are related or sepearate.
Here are my azure settings in the azure AD:
I felt that I had to switch back to the 'old experience' because the guides/tutorials etc. does not seem to reflect the current Azure UI.
You will have updated the value of DataScheme on MsalActivity.cs and AndroidManifest.xml with the correspondent clientId of your application.

Has azure user ids changed their format?

Good evening ppl at Microsoft!
I have an Mobile App Service at Microsoft Azure Located at South Central US named CeneamApp.
My backend is configured in a way so that my user can access only the data they capture, by making use of stable user ids.
so I had followed Adrian Hall book to create an a user id (https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter2/authorization/)with the following format sid:{identifier}as described here: (https://github.com/Azure/azure-mobile-apps-net-server/wiki/Understanding-User-Ids).
now all my userid had been changed and my user cant access their previous data capture by them, because somehow the provider or issuer or whatever is going on, doesnt let me retrieve a user id as described by the github project team wiki (in the previous link). so instead i receive a new userid but seem to be a random number:
I'm adding screenshot of the essential part of my code at my backend project which i debugged so i could understand whats going on and my dummy database where you can see an stable_id save on it and the new suppose stable_ids the next two rows.
Debugged code retrieving apparently a new userid from FACEBOOK could you confirm about this change? because I havent been able to understand this change.
Dummy Database with the lost userid and the new ones from other accounts database screenshot
if anyone has information about this odd behavior i would appreciate to enlight me, because this line of code:
principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
used to give me a user id with this format: "sid:{identifier}", now the format is a the screenshot shows.
Same situation here. About to go live and suddenly this. Interesting that only one Mobile App based in the UK datacenter is affected. Other 2 apps which are in production and plus another Web App are still fine.
The full solution can only be provided by Azure team. But I have a workaround and and idea:
1. Workaround.
In the base controller I read and parse the token from the header. The sid is in the subject of the token. The code is simple:
string _userSid;
public string UserSid
{
get
{
if (_userSid == null)
{
KeyValuePair<string, IEnumerable<string>> auth_header = Request.Headers.FirstOrDefault(h => h.Key.Equals("x-zumo-auth", StringComparison.InvariantCultureIgnoreCase));
string token = auth_header.Value.FirstOrDefault();
if (!string.IsNullOrEmpty(token))
{
var jwtToken = new JwtSecurityToken(token);
if (jwtToken != null)
{
_userSid = jwtToken.Subject;
}
}
}
return _userSid;
}
}
I use it instead of getting this from ClaimPrinciple as per manual. I checked the Mobile App Server code does a very similar thing.
2. Idea.
Azure Mobile Apps have this parameter:
MobileAppsManagement_EXTENSION_VERSION it is recommended to set to latest. I think if we downgraded it to previous version it would work until Microsoft finds and solves the problem. The only issue is that I do not know and could not find the version number. May be someone knows and can post here?

Call to Action with Authorize(Roles="Customer, Business") returns 500 error for those roles

I have several actions in my MVC site that recently started returning authentication errors when I call them when logged in with accounts that have the authorized roles. An example below.
[HttpGet]
[Authorize(Roles = "Customer, Business")]
public async Task<ActionResult> ShowNotifications(bool unViewedOnly = true) {
var userId = User.Identity.GetUserId<int>();
var notifications = await _notifications.GetByUserIdAsync(userId, unViewedOnly);
return (Request.IsAjaxRequest())
? PartialView("Notifications/NotificationsModal", notifications)
: PartialView("Notifications/_Notifications", notifications);
}
I have not made any changes to the functions or the javascript that calls them in quite some time. I did recently update Microsofts Identity NuGet packages. Has anyone else seen this issue and does anyone have any idea how to fix it other than rolling back the Identity updates. I have no idea which library would have caused the problem. I am far from a security expert.
A typical response:
Key Value
X-Responded-JSON {"status":401,"headers":{"location":"http:\/\/localhost:53033\/Account\/Login?ReturnUrl=%2FShared%2FShowNotifications%3FunViewedOnly%3DTrue%26modal%3DTrue%26X-Requested-With%3DXMLHttpRequest%26_%3D1426264188044"}}

Resources