-
Notifications
You must be signed in to change notification settings - Fork 9
split middleware, so ClaimsEnrichment middleware can be implemented #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
22db7fc
d10a7e1
32d02a9
8a8f7fd
82c6edc
f4dfcb9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// <copyright file="FunctionsAuthenticationMiddleware.cs" company="DarkLoop" author="Arturo Martinez"> | ||
// Copyright (c) DarkLoop. All rights reserved. | ||
// </copyright> | ||
|
||
using DarkLoop.Azure.Functions.Authorization.Internal; | ||
using DarkLoop.Azure.Functions.Authorization.Properties; | ||
using Microsoft.AspNetCore.Authentication; | ||
using Microsoft.AspNetCore.Http.Features.Authentication; | ||
using Microsoft.Azure.Functions.Worker; | ||
using Microsoft.Azure.Functions.Worker.Middleware; | ||
using Microsoft.Extensions.Logging; | ||
using System; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
|
||
namespace DarkLoop.Azure.Functions.Authorization; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please let's stick to a convention for the whole solution. Let's add braces for namespaces, since I don't think we want to go through every file and change to this format. |
||
|
||
internal sealed class FunctionsAuthenticationMiddleware : IFunctionsWorkerMiddleware | ||
{ | ||
private readonly ILogger<FunctionsAuthenticationMiddleware> _logger; | ||
private readonly IAuthenticationHandlerProvider _authenticationHandlerProvider; | ||
private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="FunctionsAuthenticationMiddleware"/> class. | ||
/// </summary> | ||
/// <param name="authenticationHandlerProvider">authentication handler provider.</param> | ||
/// <param name="authenticationSchemeProvider">authentication scheme provider.</param> | ||
/// <param name="logger">A logger object for diagnostics.</param> | ||
public FunctionsAuthenticationMiddleware( | ||
IAuthenticationHandlerProvider authenticationHandlerProvider, | ||
IAuthenticationSchemeProvider authenticationSchemeProvider, | ||
ILogger<FunctionsAuthenticationMiddleware> logger) | ||
{ | ||
Check.NotNull(authenticationHandlerProvider, nameof(authenticationHandlerProvider)); | ||
Check.NotNull(authenticationSchemeProvider, nameof(authenticationSchemeProvider)); | ||
Check.NotNull(logger, nameof(logger)); | ||
|
||
_authenticationHandlerProvider = authenticationHandlerProvider; | ||
_authenticationSchemeProvider = authenticationSchemeProvider; | ||
_logger = logger; | ||
} | ||
|
||
/// <inheritdoc /> | ||
public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next) | ||
{ | ||
var httpContext = context.GetHttpContext() ?? throw new NotSupportedException(IsolatedMessages.NotSupportedIsolatedMode); | ||
|
||
foreach (var scheme in await _authenticationSchemeProvider.GetRequestHandlerSchemesAsync()) | ||
{ | ||
var handler = await _authenticationHandlerProvider.GetHandlerAsync(httpContext, scheme.Name) as IAuthenticationRequestHandler; | ||
if (handler != null && await handler.HandleRequestAsync()) | ||
{ | ||
return; | ||
} | ||
} | ||
|
||
var defaultAuthenticate = await _authenticationSchemeProvider.GetDefaultAuthenticateSchemeAsync(); | ||
if (defaultAuthenticate != null) | ||
{ | ||
var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name); | ||
if (result?.Principal != null) | ||
{ | ||
httpContext.User = result.Principal; | ||
} | ||
if (result?.Succeeded ?? false) | ||
{ | ||
var authFeatures = httpContext.Features.SetAuthenticationFeatures(result); | ||
context.Features.Set<IHttpAuthenticationFeature>(authFeatures); | ||
context.Features.Set<IAuthenticateResultFeature>(authFeatures); | ||
} | ||
else | ||
{ | ||
var allSchemes = (await _authenticationSchemeProvider.GetAllSchemesAsync()).ToList(); | ||
_logger.LogDebug( | ||
IsolatedMessages.AuthenticationFailed, | ||
allSchemes.Count > 0 | ||
? " for " + string.Join(", ", allSchemes) | ||
: string.Empty); | ||
} | ||
} | ||
|
||
await next(context); | ||
} | ||
acnicholls-kroll marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,31 +2,33 @@ | |
// Copyright (c) DarkLoop. All rights reserved. | ||
// </copyright> | ||
|
||
using System; | ||
using System.Threading.Tasks; | ||
using DarkLoop.Azure.Functions.Authorization.Internal; | ||
using DarkLoop.Azure.Functions.Authorization.Properties; | ||
using Microsoft.AspNetCore.Authentication; | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.Authorization.Policy; | ||
using Microsoft.AspNetCore.Http.Extensions; | ||
using Microsoft.AspNetCore.Http.Features.Authentication; | ||
using Microsoft.Azure.Functions.Worker; | ||
using Microsoft.Azure.Functions.Worker.Middleware; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
using System; | ||
using System.Threading.Tasks; | ||
|
||
namespace DarkLoop.Azure.Functions.Authorization | ||
{ | ||
/// <inheritdoc cref="IFunctionsWorkerMiddleware"/> | ||
internal sealed class FunctionsAuthorizationMiddleware : IFunctionsWorkerMiddleware | ||
{ | ||
|
||
private readonly IFunctionsAuthorizationProvider _authorizationProvider; | ||
private readonly IFunctionsAuthorizationResultHandler _authorizationResultHandler; | ||
private readonly IAuthorizationPolicyProvider _policyProvider; | ||
private readonly IPolicyEvaluator _policyEvaluator; | ||
private readonly IOptionsMonitor<FunctionsAuthorizationOptions> _configOptions; | ||
private readonly ILogger<FunctionsAuthorizationMiddleware> _logger; | ||
private readonly IPolicyEvaluator _policyEvaluator; | ||
private readonly IAuthorizationPolicyProvider _policyProvider; | ||
|
||
|
||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="FunctionsAuthorizationMiddleware"/> class. | ||
|
@@ -38,12 +40,12 @@ internal sealed class FunctionsAuthorizationMiddleware : IFunctionsWorkerMiddlew | |
/// <param name="configOptions">Functions authorization configure options.</param> | ||
/// <param name="logger">A logger object for diagnostics.</param> | ||
public FunctionsAuthorizationMiddleware( | ||
IFunctionsAuthorizationProvider authorizationProvider, | ||
IFunctionsAuthorizationResultHandler authorizationHandler, | ||
IAuthorizationPolicyProvider policyProvider, | ||
IPolicyEvaluator policyEvaluator, | ||
IOptionsMonitor<FunctionsAuthorizationOptions> configOptions, | ||
ILogger<FunctionsAuthorizationMiddleware> logger) | ||
IFunctionsAuthorizationProvider authorizationProvider, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's reset indentation on these parameters |
||
IFunctionsAuthorizationResultHandler authorizationHandler, | ||
IAuthorizationPolicyProvider policyProvider, | ||
IPolicyEvaluator policyEvaluator, | ||
IOptionsMonitor<FunctionsAuthorizationOptions> configOptions, | ||
ILogger<FunctionsAuthorizationMiddleware> logger) | ||
{ | ||
Check.NotNull(authorizationProvider, nameof(authorizationProvider)); | ||
Check.NotNull(authorizationHandler, nameof(authorizationHandler)); | ||
|
@@ -60,6 +62,8 @@ public FunctionsAuthorizationMiddleware( | |
_logger = logger; | ||
} | ||
|
||
|
||
|
||
/// <inheritdoc /> | ||
public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next) | ||
{ | ||
|
@@ -83,34 +87,17 @@ public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next | |
return; | ||
} | ||
|
||
var authenticateResult = await _policyEvaluator.AuthenticateAsync(filter.Policy, httpContext); | ||
|
||
var authenticateFeature = httpContext.Features.SetAuthenticationFeatures(authenticateResult); | ||
var authenticateFeature = context.Features.Get<IAuthenticateResultFeature>(); | ||
|
||
// We also make the features available in the FunctionContext | ||
context.Features.Set<IAuthenticateResultFeature>(authenticateFeature); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If user does not configure authentication middleware the feature needs to be set. We don't want to break this functionality. This is the same way it happens in ASPNET Core |
||
context.Features.Set<IHttpAuthenticationFeature>(authenticateFeature); | ||
|
||
if (filter.AllowAnonymous) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this check removed? We still need to allow for execution of an action regardless of authentication result if it's marked with |
||
{ | ||
await next(context); | ||
return; | ||
} | ||
|
||
if (authenticateResult is not null && !authenticateResult.Succeeded) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this section shouldn't be removed either |
||
{ | ||
_logger.LogDebug( | ||
IsolatedMessages.AuthenticationFailed, | ||
filter.Policy.AuthenticationSchemes.Count > 0 | ||
? " for " + string.Join(", ", filter.Policy.AuthenticationSchemes) | ||
: string.Empty); | ||
} | ||
var authenticateResult = authenticateFeature?.AuthenticateResult ?? | ||
await _policyEvaluator.AuthenticateAsync(filter.Policy, httpContext); | ||
|
||
var authorizeResult = await _policyEvaluator.AuthorizeAsync(filter.Policy, authenticateResult!, httpContext, httpContext); | ||
var authContext = new FunctionAuthorizationContext<FunctionContext>( | ||
context.FunctionDefinition.Name, context, filter.Policy, authorizeResult); | ||
|
||
await _authorizationResultHandler.HandleResultAsync(authContext, httpContext, async (ctx) => await next(ctx)); | ||
} | ||
|
||
} | ||
} | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should separate extension methods, each one in their own assembly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move this to a new project?
Darkloop.Azure.Functions.Authentication.Isolated
right now we don't have a need for any abstractions.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please make sure to keep default indentation of the rest of the project. 4 spaces