Git Product home page Git Product logo

dark-loop / functions-authorize Goto Github PK

View Code? Open in Web Editor NEW
35.0 5.0 4.0 199 KB

An ASP.NET Core based authentication and authorization middleware for HTTP triggered Azure Functions (In-Proc and Isolated)

License: Apache License 2.0

C# 100.00%
azure-functions azure-functions-v3 authentication authorization policy-based-authentication authorizeattribute azure azure-functions-v4 authorize-attribute policy-based-authorization

functions-authorize's Introduction

functions-authorize

Extension bringing AuthorizeAttribute Behavior to Azure Functions In-Proc and Isolated mode. For the latter is only available with ASPNET Core integration.

It hooks into .NET Core dependency injection container to enable authentication and authorization in the same way ASP.NET Core does.

Breaking for current package consumers
Starting with version 4.1.0, due to security changes made on the Functions runtime, the Bearer scheme is no longer supported for your app functions.
Use AddJwtFunctionsBearer(Action<JwtBearerOptions>) instead of AddJwtBearer(Action<JwtBearerOptions>) when setting up authentication. Using AddJwtBearer will generate a compilation error when used against FunctionsAuthenticationBuilder. We are introducing JwtFunctionsBearerDefaults to refer to the suggested new custom scheme name.
No changes should be required if already using a custom scheme name.
Refer to respective README documentation for isolated and in-process for more information.

Getting Started

License

This projects is open source and may be redistributed under the terms of the Apache 2.0 license.

Package Status

Releases

Nuget

Builds

master build status

Change Log

You can access the change log here.

functions-authorize's People

Contributors

anpopela-xbox avatar artmasa avatar boncyrus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

functions-authorize's Issues

V4 Isolated receiving 401 when calling function deployed to Azure

It has been reported that in some cases when only specifying [HttpTrigger(params string[])] would not make the function anonymously available.
Functions built-in authorization levels are disabled locally and you might see your app having the expected behavior with ASP.NET Core auth when testing locally.
If you suspect this might be happening, use [HttpTrigger(AuthorizationLevel, params string[])] and ensure is set to Anonymous, or User as this value is also not handled by Functions built-in auth; and it makes your attribute declaration shorter ๐Ÿ˜‰. I actually think that it makes sense to use User as it logically aligns with the use of the [Authorize] attribute.

I'm investigating why this is happening as the HttpTriggerAttribute does not set the authorization level when only specifying the allowed HTTP methods and the default value for AuthorizationLevel is taken, which is Anonymous.

Any example for in-process .NET 8?

Hi,

Now that a stable version of .NET 8 for in-process azure functions is out, we are updating everything to this version. Everything seems to work, except when using AAD authentication. The same old story of version conflicts.... We are still trying to see if there's a working combination of package versions, but so far without success.

Does anybody have a working example?

Add support for remote authentication flows

In some scenarios we would like to create initialize workflows by allowing users to reach HTTP triggers. We need users to authenticate before reaching these endpoints and ensure they meet the authorization requirements.
By enabling remote authentication the functions app can orchestrate the interaction between user and IdP to obtain the credentials.

  • Add authentication middleware to support the interactions there are possible with ASP.NET Core
  • Dynamically add the functions endpoints required by RemoteAuthenticationHandler in the isolated process

Thanks to @nearlyheadlessarvie for raising the question on #46

Compatibility with v4?

Hi!

We have been using your attribute on azure functions v3 without issue but when testing on an azure functions project v4 (.NET 6), we immediatly get an 401 error and the following error in the console:

[2022-11-04T18:51:15.280Z] Executed 'Registrar_Lead' (Failed, Id=69f566b5-f755-45c7-92cf-c951c3974f26, Duration=668ms)
[2022-11-04T18:51:15.281Z] System.Private.CoreLib: Exception while executing function: Registrar_Lead. Microsoft.AspNetCore.Server.Kestrel.Core: StatusCode cannot be set because the response has already started.

Any idea what this might cause?

Kinds regards!

Running Azure functions with AAD Authentication broken due to update to the local azure function runtime

Running Azure functions locally with AAD Authentication broke all of the sudden.

This is not a problem with this project, but people might come here to wonder what is going on.

An update to the local Function Runtime references the 7.x version of the Microsoft.IdentityModel libs (was 6.x). This breaks the AAD authentication and will generate an error like the one below:

The error you'll encounter:
[2024-06-24T12:19:41.079Z] Error configuring services in an external startup class. [2024-06-24T12:19:41.081Z] Error configuring services in an external startup class. System.Private.CoreLib: Could not load type 'Microsoft.IdentityModel.Json.JsonObjectAttribute' from assembly 'Microsoft.IdentityModel.Tokens, Version=7.1.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. [2024-06-24T12:19:42.268Z] A host error has occurred during startup operation '0ab8afa3-1de5-4d45-993b-d936340e3075'. [2024-06-24T12:19:42.270Z] Microsoft.Azure.WebJobs.Script: Error configuring services in an external startup class. System.Private.CoreLib: Could not load type 'Microsoft.IdentityModel.Json.JsonObjectAttribute' from assembly 'Microsoft.IdentityModel.Tokens, Version=7.1.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Value cannot be null. (Parameter 'provider')

Microsoft is actively working on a fix.

Thread to monitor:
Azure/azure-functions-core-tools#3715

Exception when try to add policy by using

When trying to add the authorization policy, getting following exception:
image

I am using Azure Function V3, and here are packages my project referencing.
image

Could you please help to take a look? Is there any package I am missing?

Thank you.

v4 preview is not handling when scheme is not specified in IAuthorizeData

When specifying a function with:

[FunctionName("MyFunction")]
[FunctionAuthorize] //no scheme identified and it should remain this way
public Task<IActionResult> Run([HttpTrigger("get")] HttpRequest)
{
  // ...
}

The changes introduce to v4 preview prevent from evaluator to consider a policy as no scheme is specified.
Authorization always fails

Getting 401 while executing the function

Error ->
Exception while executing function: ABC 401 Authorization error encountered. This is the only way to stop function execution. The correct status has been communicated to the caller.

Method -> DarkLoop.Azure.Functions.Authorize.Security.FunctionsHttpAuthorizationHandler.BombFunctionInstance

//start up configuration

builder.Services.AddFunctionsAuthorization(options =>
        {
            options.DefaultPolicy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .AddAuthenticationSchemes(Constants.Bearer)
                .Build();
        });
services
            .AddFunctionsAuthentication(options => options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
//Some code here
}

//Function file

[FunctionAuthorize(AuthenticationSchemes = Constants.Bearer)]
[FunctionName("ABC")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "ROUTE")] HttpRequest request,
        string data,
        ILogger logger
    )
    {
//Code
}

How to resolve this issue?, Please help.

OpenId connect authorization_code

This is more of a question than an issue:

Is it possible to complete an openid connect authorization_code flow? I tried it but getting 404 in /signin-oidc.

Configuration["AzureAD:Instance"]

Hi,

in your examples you are passing some parameters from your local config file. I am curios what the value should we supply for one particular of those, "AzureAD:Instance". What precisely is expected to be supplied for the Instance value?

Thanks

Testing functions using TestServer.

I am trying to setup integration tests in my project to test my functions through the full HTTP pipeline rather than unit testing at the function level and bypassing the pipeline.

When I attempt to setup the test server in my test class, I am getting the following error

Failed UserServiceTest.IntegrationTest.GetFunctionTests.GetUsersByIds_CanBeCalledWithoutError [1 ms]
  Error Message:
   System.TypeInitializationException : The type initializer for 'DarkLoop.Azure.Functions.Authorize.Security.AuthHelper' threw an exception.
---- System.IO.FileNotFoundException : Could not load file or assembly 'Microsoft.Azure.WebJobs.Script.WebHost, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.

  Stack Trace:
     at DarkLoop.Azure.Functions.Authorize.Security.AuthHelper.AddFunctionsBuiltInAuthorization(IServiceCollection services)
   at Microsoft.Extensions.DependencyInjection.AuthorizationExtensions.AddFunctionsAuthorization(IServiceCollection services, Action`1 configure)
   at Microsoft.Extensions.DependencyInjection.AuthorizationExtensions.AddAuthorization(IFunctionsHostBuilder builder)
   at Igloo.UserService.Startup.ConfigureServices(IFunctionsHostBuilder builder) in /Users/dgallo/Dropbox/Projects/app-user-service/v1/UserService/src/Startup/Startup.cs:line 112
   at Igloo.UserService.Startup.Configure(IFunctionsHostBuilder builder) in /Users/dgallo/Dropbox/Projects/app-user-service/v1/UserService/src/Startup/Startup.cs:line 107
   at UserServiceTest.IntegrationTest.TestStartup.Configure(IFunctionsHostBuilder builder) in /Users/dgallo/Dropbox/Projects/app-user-service/v1/UserService/test/IntegrationTest/GetFunctionTests.cs:line 21
   at Microsoft.Azure.Functions.Extensions.DependencyInjection.FunctionsStartup.Configure(WebJobsBuilderContext context, IWebJobsBuilder builder)
   at Microsoft.Azure.WebJobs.WebJobsBuilderExtensions.ConfigureStartup(IWebJobsStartup startup, WebJobsBuilderContext context, IWebJobsBuilder builder) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsBuilderExtensions.cs:line 162
   at Microsoft.Azure.WebJobs.WebJobsBuilderExtensions.UseWebJobsStartup(IWebJobsBuilder builder, Type startupType, WebJobsBuilderContext context, ILoggerFactory loggerFactory) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsBuilderExtensions.cs:line 111
   at UserServiceTest.IntegrationTest.GetFunctionTests.<>c.<.ctor>b__4_0(IWebJobsBuilder builder) in /Users/dgallo/Dropbox/Projects/app-user-service/v1/UserService/test/IntegrationTest/GetFunctionTests.cs:line 38
   at Microsoft.Extensions.Hosting.WebJobsHostBuilderExtensions.<>c__DisplayClass2_0.<ConfigureWebJobs>b__0(HostBuilderContext context, IWebJobsBuilder b) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsHostBuilderExtensions.cs:line 27
   at Microsoft.Extensions.Hosting.WebJobsHostBuilderExtensions.<>c__DisplayClass5_0.<ConfigureWebJobs>b__1(HostBuilderContext context, IServiceCollection services) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsHostBuilderExtensions.cs:line 54
   at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
   at Microsoft.Extensions.Hosting.HostBuilder.Build()
   at UserServiceTest.IntegrationTest.GetFunctionTests..ctor(TestStartup testStartup) in /Users/dgallo/Dropbox/Projects/app-user-service/v1/UserService/test/IntegrationTest/GetFunctionTests.cs:line 36
----- Inner Stack Trace -----
   at System.Reflection.RuntimeAssembly.InternalLoad(ObjectHandleOnStack assemblyName, ObjectHandleOnStack requestingAssembly, StackCrawlMarkHandle stackMark, Boolean throwOnFileNotFound, ObjectHandleOnStack assemblyLoadContext, ObjectHandleOnStack retAssembly)
   at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, RuntimeAssembly requestingAssembly, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, AssemblyLoadContext assemblyLoadContext)
   at System.Reflection.Assembly.Load(String assemblyString)
   at DarkLoop.Azure.Functions.Authorize.Security.AuthHelper..cctor()

The setup of the test server is done like so and this is where the error is being raised within:

_testServer = new HostBuilder()
                .ConfigureWebJobs(
                    builder => builder.UseWebJobsStartup(typeof(TestStartup), new WebJobsBuilderContext(), NullLoggerFactory.Instance)
                )
                .Build()
                .GetTestServer();

Then the test looks like this:

[Fact]
        public async Task GetUsersByIds_CanBeCalledWithoutError()
        {

            var request = new HttpRequestMessage(HttpMethod.Get, "users/ids");
            var response = await _testHttpClient.SendAsync(request);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        }

After some research, it seems as though the Microsoft.Azure.WebJobs.Script.WebHost assembly is provided by the Azure Functions Runtime. Since, I'm using a TestServer, its not running in the Azure Functions Runtime.

Is there an approach to perform tests like this when Darkloop is being used?

Invalid Audience error for JWT Bearer token

Hi,

For more than 2 weeks I have been experiencing an issue with Authorisation on Azure Function App (.net 6.0, in-process, v4) on my TEST environment.
The function was working correctly for a long time before and there was no change done lately. Suddenly the issue starts to appear successively in all our other environments (QA, PROD) with 7 days and 2 days of delay.

The weird this is that my startup configuration, specifically, is not validating the tokens audience, see the configuration.

.AddJwtBearer(options =>
{
    options.Authority = //taken from appsettings
    options.TokenValidationParameters.ValidateAudience = false;
    options.RequireHttpsMetadata = true;
    options.Events = jwtBearerEvents;
})

The most problematic thing is that the issue is not reproducible locally on the VisualStudio, and started from nothing.

The error I have:

Bearer error="invalid_token", error_description="The audience 'api1 api2 api3 api4' is invalid

the 'api1 api2 api3 api4' is the whole audience present in the token

I contacted Azure Support and they advised me to use "Custom Bearer" because apparently

"Bearer" schema is used by Azure Functions with their handler

They also suggested more or less the same as here in the "Accepted answer": microsoft learn

I would like to ask if anyone is experiencing the same issue? And if this package is prepared for, apparently, not supporting "Bearer" schema anymore?

Authentication

How can we validate AD access token with isolated function app

Not all required components are registered in the ServiceCollection

.Net 8.0 (new project, not upgraded)
Functions Version 4 (Isolated)

Using the example you have in DarkLoop.Azure.Functions.Authorization.Isolated I get the following errors:

System.AggregateException : Some services are not able to be constructed (Error while validating the service descriptor '
ServiceType: DarkLoop.Azure.Functions.Authorization.FunctionsAuthorizationMiddleware
Lifetime: Singleton
ImplementationType: DarkLoop.Azure.Functions.Authorization.FunctionsAuthorizationMiddleware': Unable to resolve service for type 'DarkLoop.Azure.Functions.Authorization.IFunctionsAuthorizationProvider' while attempting to activate 'DarkLoop.Azure.Functions.Authorization.FunctionsAuthorizationMiddleware'.)

I had to fix it with a workaround by changing my startup to look like this:

.ConfigureFunctionsWebApplication(builder =>
{
    new FunctionsAuthorizationExtensionStartup()
        .Configure(builder);

    // Explicitly adding the extension middleware because
    // registering middleware when extension is loaded does not
    // place the middleware in the pipeline where required request
    // information is available.
    builder.UseFunctionsAuthorization();
})

The problem is that out of the box, the DI calls are missing for registering the internal concrete FunctionsAuthorizationProvider to the interface IFunctionsAuthorizationProvider. The only place you have this registration is in the startup, which is not needed or used in the .net 8 functions where it uses top-level statements instead of a startup.

You also have a typo in the readme for isolated where AddFunctionsAuthenticationation should be AddFunctionsAuthentication

Thanks!

401 Exception: Bearer was not authenticated. Failure message: IDX10231: Audience validation failed. Delegate returned false

Using Azure AD to secure an Azure Function Http Trigger, everything works locally, but get 401 when gets deployed to Azure.

StartUp.cs:

            builder
                    .AddAuthentication(options =>
                    {
                        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                    })
                    .AddJwtBearer(jwtOptions =>
                    {
                        jwtOptions.Authority = "https://login.microsoftonline.com/xxx.com";
                        jwtOptions.Audience = "https://xxx.com/app-id-uri";
                        jwtOptions.RequireHttpsMetadata = false;
                    });

And I could see the "aud": "https://xxx.com/app-id-uri" in the access_token generated, they match.

However, when I use postman to hit the deployed azure function, it returns 401, works locally though.

[Verbose]   AuthenticationScheme: ArmToken was not authenticated.
[Information]  Failed to validate the token.
[Information]   Bearer was not authenticated. Failure message: IDX10231: Audience validation failed. Delegate returned false, securitytoken: ....

Any advise would be appreciated!

Support for specifying a custom request header other than default "Authorization" to use to get bearer token.

Hi,
Just curious, is there way via the configuration to support a different request header for the authentication bearer token? I need to use "X-Custom-Authorization" for the Function App because I'm using Static Web Apps to host the front-end and apparently it replaces the Authorization header with a different token when making backend to the Function App endpoints as noted here in this Github issue:

I figured since this library was leveraging the built in [Authorize] attribute that this would be dependent the base library supporting this, but searched documentation and did not find much in the way of specifying the header name to use in the Program.cs configuration. Just articles telling me to create my own authorize attribute/handler. Is is possible to configure/overwrite the authorization handler logic which pulls the request header value to use?

This library is awesome though. I've currently rolled my own attribute a wrote a year back following some articles (like https://damienbod.com/2020/09/24/securing-azure-functions-using-azure-ad-jwt-bearer-token-authentication-for-user-access-tokens/), but I'd prefer to use your library now.

Thanks
Devaron

Azure broke auth

We have been using Darkloop and FunctionAuthorize for a long time. A few days back this just stopped working totally when we are deploying new versions of our code (no changes to Darkloop or auth), and the azure functions are dead upon deployment. Fortunately we have these in slot so prod was not affected.

image

The function app keys are also totally dead.

image

Removing Darkloop nuget package its possible to get the Azure function running again, but of course the authorization is gone.

Reporting this to Microsoft first since we was rather clear something had changed in Azure. Microsoft admits this but blames the way Darkloop is implemented.

image

We are using f# for Azure functions and have this code:

namespace AzureFunctions.Startup

open ServiceSetup
open AzureFunctionsDependencyInjectionExtensions.Config
open Microsoft.Azure.Functions.Extensions.DependencyInjection
open Microsoft.Extensions.DependencyInjection
open Microsoft.AspNetCore.Authentication.JwtBearer
open System
open Microsoft.AspNetCore.Authentication
open Microsoft.Extensions.Configuration

[<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage>]
module DependencyInjectionStartup =
    let setupAuthenticationScheme (options: AuthenticationOptions) =
        options.DefaultAuthenticateScheme <- JwtBearerDefaults.AuthenticationScheme
        options.DefaultChallengeScheme <- JwtBearerDefaults.AuthenticationScheme

    let setupJwtAuthorization authority audience (options: JwtBearerOptions) =
        options.Authority <- authority
        options.Audience <- audience

    type HealthCheckSetupFunctionStartup() =
        inherit FunctionsStartup()

        override this.Configure(builder: IFunctionsHostBuilder) : unit =
            let services = builder.Services
            let sp = services.BuildServiceProvider()
            let conf = sp.GetService<IConfiguration>()

            let authIssuer = conf["Authorization:Issuer"]
            let authAudience = conf["Authorization:Audience"]

            let setupJwtAuth = setupJwtAuthorization authIssuer authAudience

            // For some reason, authentication setup needs to be called here
            // there is some problem with doing it withing AddDependencyInjection
            // reason unknown, needs further investigation
            builder.Services
                .AddFunctionsAuthentication(Action<AuthenticationOptions>(setupAuthenticationScheme))
                .AddJwtBearer(Action<JwtBearerOptions>(setupJwtAuth), true)
            |> ignore

            builder.Services.AddFunctionsAuthorization() |> ignore

            builder.AddDependencyInjection(fun s -> s |> setupServices conf) |> ignore

    [<assembly: FunctionsStartup(typeof<HealthCheckSetupFunctionStartup>)>]
    do ()

See also caveats from Microsoft related to auth*:

https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#caveats

image

I do suspect we might have some bad code after all, and any pointers for helping out would be highly appreciated.

Thanks in advance.

Question: what is the purpose of having custom Authentication logic right before another Authentication done by Policy Evaluator

Hey,
Thanks for the library, that is a bi relief for those who suffer from Azure Functions limitations ๐Ÿ˜‰

Im investigating issue with Authentication request happening twice and I know that this is problem sitting rather on my end but I noticed that FunctionsAuthorizeFilter` has Authentication routing happening twice:

  1. AuthenticateRequestAsync() in line 63
  2. evaluator.AuthenticateAsync(effectivePolicy, context.HttpContext) in line 65

Could you please explain the purpose for such logic?

await this.AuthenticateRequestAsync(context);
var evaluator = httpContext.RequestServices.GetRequiredService<IPolicyEvaluator>();
var authenticateResult = await evaluator.AuthenticateAsync(effectivePolicy, context.HttpContext);

Add support for disabling authorization without removing the [FunctionAuthorize] attribute

In order to disable authentication & authorization easily for local development, as well as production when needed with just a simple configuration(appsetting) change, so that no code change + redeployment is required. Please help research a way to allow disabling authorization without removing the [FunctionAuthorize] attribute, or if we can add that attribute dynamically at runtime.

Original discussion: #19 (comment)

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.