Closed paumayr closed 1 year ago
I guess this commit is related, and will probably fix the Issue I fixed manually above: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/commit/c7f689f294f359493a6de93e3315611a1888fba7
.Result
should never be used...ever. The fix above looks like it uses await
and appears better.
Thanks guys, well fix this.
@dstrockis we are experiencing this same deadlock issue. What is the plan for fixing this?
Please look for an update to this sample next week that will not use the PolicyConfigurationManager
Just kidding, I realized this is not in the PolicyConfigurationManager
class but in the OpenIdConnectCachingSecurityTokenProvider
.
For now, I've staged some changes in an updated sample with @paumayr's fix, which should help. But it's not the best solution. There are a couple options here that would be better:
OAuthBearerAuthenticationMiddleware
to do token validation asyncronously. See https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.OAuth/OAuthBearerAuthenticationHandler.cs. This would allow us to fetch updated OpenID metadata using async methods, as @onovotny suggested.ConfigurationManager
class, used to fetch the OpenID metadata, to run synchronously. See: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/master/src/Microsoft.IdentityModel.Protocols/Configuration/ConfigurationManager.cs. It could follow the same pattern as the existing WsFed metadata retrieval class here: https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.ActiveDirectory/WsFedMetadataRetriever.cs, using a configurable timeout.I'll be discussing this problem with @brentschmaltz & the team to decide how to proceed. For now, I don't really have a better answer for you guys.
@dstrockis seems like the core issue is that https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet hasn't had a new NuGet package pushed out. It's hard for us to build it because it's strong named and is not the top-most level dependency. The fix appears checked into the master of the repo, but you can see that the latest NuGet release is from 6/23/15: https://www.nuget.org/packages/Microsoft.IdentityModel.Protocol.Extensions
I think all we really need to resolve this is a new build of that library pushed to NuGet.org.
@onovotny ah, I didn't realize that, thanks. I was looking for a way to entirely avoid calling the ConfigurationManager
synchronously. But looks the the changes in that commit will suffice here.
@polita B2C needs to get this commit onto NuGet. Do you think that's a possibility?
@dstrockis @brentschmaltz Have we really not released 4x since last summer? We should probably do a release then. When does B2C need it?
Chatted with Polita briefly. Given there's a reasonable workaround for this issue, we'll sync up next week to figure out when we could publish a new release. Stay tuned.
@dstrockis @polita Any updates on getting this published? There are cases where the PolicyConfigurationManager mechanism is still required and multiple OIDC middleware won't work.
Thanks
@onovotny @dstrockis even with the fix, using .Result could cause a deadlock. If you really need .Result, you should try the following code as by default ConfigurationManager uses WebClient, which exhibits issues with .Result.
HttpClient httpClient = new HttpClient(); var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(authority, httpClient); var config = configManager.GetConfigurationAsync().Result;
The fix in the code does not use .Result
. It uses await
instead so it's fully correct. It's already in master, just hasn't had any recent NuGet releases in over a year. You can see it in this commit: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/commit/c7f689f294f359493a6de93e3315611a1888fba7
What I want to communicate is that even with our updated bits, .Result can hang when called from an HttpContext (inside a controller). I suspect it is due to ConfigurationManager using WebClient when only the address is provided. It is best not to use .Result. BUT if you have to for some reason, can't think of one right now. New up an HttpClient and pass it to ConfigurationManager constructor.
@brentschmaltz using .Result
is always a bad idea...but where is it being used? Is there some place else that you're referring to, I think that's why I'm confused :)
@onovotny we are on the same page: .Result is always a bad idea. I am saying same as you. Don't use it unless you absolutely have to.
@brentschmaltz We are currently using .Result in our sample here (line 85): https://github.com/AzureADQuickStarts/B2C-WebAPI-DotNet/blob/complete/TaskService/App_Start/OpenIdConnectCachingSecurityTokenProvider.cs
Is there a better way to write this so there's no risk of a deadlock?
@polita not saying it's a clean way, but in that specific scenario where you're using a Task.Run
, I believe that .Result
is safe. The reason is that using Task.Run
should hide the ambient synchronization context from the method being run, so any ConfigureAwait(true)
-- the default unless you say false
won't deadlock.
@chenyan98 Please make the fixes to the B2C-WebAPI-DotNet sample code.
Just a question....is there any chance of OpenIdConnectCachingSecurityTokenProvider making it into an "official" NuGet package? It feels a little odd having to copy a class from a sample project to get up and running with B2C.
@onovotny @polita just got back to this and looked a little closer. Since JwtBearer internally hits the wsFedEndpoint which is not available for B2C, it needs an IIssuerSecurityTokenProvider that reaches out to the discovery endpoint. IIsserSecurityTokenProvider is implemented synchronous. In order to work with out the .Result, we would need a complete synchronous solution.
@golfguy0082 The OpenIdConnectCachingSecurityTokenProvider is a pretty thin layer on the configuration manager. Feel free to take it and use it.
@polita that's what he's asking not to have to do ;)
@onionhammer I understand, but after @ChenYan98 's pending changes to that class, it's going to be about 50 lines of code with no logic in it.
@polita my comment was focused less at the "amount" of code needed and more towards the "out-of-box" experience of using B2C. Having to copy and paste sample code from a github repository (that the user has to discover) creates a significant barrier to entry for new users evaluating the product. I love B2C and I'm hoping to find ways to help encourage others to try it too! Anything we can do to make the product work "out-of-the-box" will help towards that goal.
I 100% agree with @golfguy0082, I'm not even sure why we're debating this; it seems obvious
Hi all,
Is there any final solution is defined for this issue? as i am also getting same issue in my azure web app.
for now i have tried below line of code in my project that @paumayr has provided at starting of this thread.
OpenIdConnectConfiguration config = Task.Run(_configManager.GetConfigurationAsync).Result;
Thanks, Manish
@manish-parmar Using .Result should avoid the deadlock for you.
I've recently started getting the same, so is a definitive fix...
Can I also echo the idea of making the token cache a package in it's own right.
Also, Azure B2C seems to lack a bit of love and attention or at least urgency e.g. 9 months in beta, no production tenants except us, no progress on client-flow, no progress on third-party API flow, basic components being in sampleware etc, etc.
@phatcher @paumayr. I already use package 1.0.4.403061554 and encountered the same error (lock) and implemented the proposed fix (Task.Run()
) but:
Task.Run()
) lead to a lock provided all internal awaitables have been called/awaited using ConfigureAwait(false)
in the up-to-datepackage ?
Could someone explain me the issue and the best fix, please ?EDIT: Just to be a bit clearer, the observed issue is that, at some point in time, we cannot (on an Azure Web API) enter the writelock anymore. So I deduce another call has never returned (never exited the write lock). This leads to a definitive application lock. I have to restart the pool. I can also see a lot of waiting threads on the API in the Azure portal.
@brentschmaltz do you have an idea?
In need
@mitchellw3 can you elaborate?
Closing as this repo is being archived.
I keep on getting deadlocks on my dev-machine when using this TokenProvider. The issue is caused by
in RetrieveMetadata. I changed the line to
which does the trick for me, but I'm not 100% sure this is the correct fix. Edit: I should note that I only observed this on iisexpress, but I suspect this to happen depending on the SynchronizationContext in use. Edit2: I can submit a PR if required.