Open brettsam opened 3 years ago
YES this would be helpful. A construction func with the AuthenticationBuilder or something similar to IFunctionsConfigurationBuilder See https://github.com/Azure/azure-functions-host/issues/4485
@brettsam any update?
@anthonychu @jeffhollan Would you be able to take a look at this one please? Or eventually point me to someone to discuss this with? I am more than willing to contribute to the runtime to make this work as expected (since I believe it's quite crucial for some of our use-cases of Functions). Thanks!
I am getting this error with the latest package as well, Is there any known workaround for this issue?
@brettsam @kamalsivalingam @espray I have a workaround for you.
I drilled down investigating what is causing this issue and found out that Azure Function Host has internal logic that is calling "builder.Services.AddAuthentication()" after the client Startup.cs is executed and since in your Startup.cs is already present "builder.Services.AddAuthentication()" the internal one will be ignored.
Here is the link to internal authentication registration: https://github.com/Azure/azure-functions-host/blob/852eed9ceef6ef56b431428a8eb31f1bd9c97f3b/src/WebJobs.Script.WebHost/WebHostServiceCollectionExtensions.cs#L46
Here is a "AddAuthentication()" internal logic that ignores the subsequent services registration: https://github.com/dotnet/aspnetcore/blob/0ca2ed9af69e7e334b8e3c1de1d015017f138988/src/Http/Authentication.Core/src/AuthenticationCoreServiceCollectionExtensions.cs#L20
So workaround would be to use dynamic Authentication Schema registration and not to call "builder.Services.AddAuthentication()" at startup.
Dynamic schema registration example: https://github.com/aspnet/AuthSamples/tree/master/samples/DynamicSchemes
My use case: I hate using out of the box EasyAuth AAD authentication and want to use "Microsoft.Identity.Web" authentication. In order to do that I have to register all logic in startap without calling "builder.Services.AddAuthentication()" and then register extension where I inject "IAuthenticationSchemeProvider" and dynamically add custom scheme.
My old code in Startup.cs:
builder.Services
.AddMicrosoftIdentityWebApiAuthentication(configuration, configSectionName: nameof(AuthenticationSettings))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
My new code in Startup.cs:
// avoid calling builder.Services.AddAuthentication() since it overrides internal Azure Function authentication
new AuthenticationBuilder(builder.Services)
.AddMicrosoftIdentityWebApi(
configuration,
configSectionName: nameof(AuthenticationSettings),
jwtBearerScheme: CustomAuthenticationSchemes.AadBearer)
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
builder.Services.AddWebJobs(options => { }).AddExtension<AuthenticationExtensionConfigProvider>();
Please note that I use custom scheme since Azure Function uses 3 default schemes (including Bearer) so I have to use different one for my custom authentication
AuthenticationExtensionConfigProvider.cs
public class AuthenticationExtensionConfigProvider : IExtensionConfigProvider
{
private readonly IAuthenticationSchemeProvider authenticationSchemeProvider;
public AuthenticationExtensionConfigProvider(IAuthenticationSchemeProvider authenticationSchemeProvider)
{
this.authenticationSchemeProvider = authenticationSchemeProvider;
}
public void Initialize(ExtensionConfigContext context)
{
this.InitializeAsync().GetAwaiter().GetResult();
}
private async Task InitializeAsync()
{
var jwtScheme = await this.authenticationSchemeProvider.GetSchemeAsync(JwtBearerDefaults.AuthenticationScheme);
if (jwtScheme == null)
{
this.authenticationSchemeProvider.AddScheme(new AuthenticationScheme())
}
}
}
Now you can authenticate to your function with custom scheme
@nazar-kuzo Awesome ✨
I have not looked at this for a few months.
I was trying to host Identity Server in an AzFunc, Yes I used Dynamic Schema https://github.com/Azure/azure-functions-host/issues/4485#issuecomment-496268259 as well. But, I did not use IExtensionConfigProvider
like you did with adding the schema, as I had the same problem with adding the schema to the IAuthenticationSchemeProvider.
AddAuthentication()
, I assume they dont?AddWebJobs()
in an AzFunc startup, any side effects from calling this?
builder.Services.AddWebJobs(options => { }).AddExtension<AuthenticationExtensionConfigProvider>();
@espray
Do you know if isolated AzFunc have the same problem with AddAuthentication(), I assume they dont?
Have no experience working with it but I assume it is not a problem since the hosting model is different (more like regular app service), but I dont know for sure
Is it safe to call AddWebJobs() in an AzFunc startup, any side effects from calling this?
Based on my experience - Yes, it is safe. any extensions you use like EventGrid, EventHub, etc they call it under the hood, so you should be fine.
Basically it is the same API but they implement interface so you dont need to explicitly call it
@brettsam @espray Published a nuget extension that solves Authentication/Authorization problems https://www.nuget.org/packages/AzureFunctions.Authentication/
Today if you try to overwrite a service that we've registered, it can cause problems. We have a fairly vague explanation of this here: https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#overriding-host-services.
Customers that try to add their own authentication in a FunctionsStartup can run into odd errors later like
One example would be doing this in your startup:
We should add a way to allow auth handlers from Startup compose with the built-in functions handlers. Or another alternative may be to prevent custom handlers from impacting
/admin
routes.