Skip to content

Commit f2c14d7

Browse files
committed
implicit usings and file-scoped namespaces
1 parent 265f13a commit f2c14d7

File tree

7 files changed

+168
-193
lines changed

7 files changed

+168
-193
lines changed

.editorconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[*.cs]
2+
csharp_style_namespace_declarations = file_scoped:warning

src/Directory.Build.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<LangVersion>latest</LangVersion>
55
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
66
<nullable>Enable</nullable>
7+
<ImplicitUsings>enable</ImplicitUsings>
78
</PropertyGroup>
89

910
<PropertyGroup>
Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,21 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text;
5-
using System.Threading.Tasks;
1+
namespace Microsoft.Azure.Functions.Worker.Http;
62

7-
namespace Microsoft.Azure.Functions.Worker.Http
3+
internal static class FunctionContextExtensions
84
{
9-
internal static class FunctionContextExtensions
5+
// https://github.com/Azure/azure-functions-dotnet-worker/issues/414
6+
public static HttpRequestData? GetHttpRequestData(this FunctionContext context)
107
{
11-
// https://github.com/Azure/azure-functions-dotnet-worker/issues/414
12-
public static HttpRequestData? GetHttpRequestData(this FunctionContext context)
13-
{
14-
var feature = context.Features.SingleOrDefault(f => f.Key.Name == "IFunctionBindingsFeature").Value;
15-
Type type = feature.GetType();
16-
var inputData = type.GetProperties().Single(p => p.Name == "InputData").GetValue(feature) as IReadOnlyDictionary<string, object>;
17-
return inputData?.Values.SingleOrDefault(o => o is HttpRequestData) as HttpRequestData;
18-
}
8+
var feature = context.Features.SingleOrDefault(f => f.Key.Name == "IFunctionBindingsFeature").Value;
9+
Type type = feature.GetType();
10+
var inputData = type.GetProperties().Single(p => p.Name == "InputData").GetValue(feature) as IReadOnlyDictionary<string, object>;
11+
return inputData?.Values.SingleOrDefault(o => o is HttpRequestData) as HttpRequestData;
12+
}
1913

20-
public static void SetHttpResponseData(this FunctionContext context, HttpResponseData response)
21-
{
22-
var feature = context.Features.SingleOrDefault(f => f.Key.Name == "IFunctionBindingsFeature").Value;
23-
Type type = feature.GetType();
24-
var result = type.GetProperties().Single(p => p.Name == "InvocationResult");
25-
result.SetValue(feature, response);
26-
}
14+
public static void SetHttpResponseData(this FunctionContext context, HttpResponseData response)
15+
{
16+
var feature = context.Features.SingleOrDefault(f => f.Key.Name == "IFunctionBindingsFeature").Value;
17+
Type type = feature.GetType();
18+
var result = type.GetProperties().Single(p => p.Name == "InvocationResult");
19+
result.SetValue(feature, response);
2720
}
2821
}
Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
1-
using System;
2-
using System.Linq;
3-
using System.Security.Claims;
1+
using System.Security.Claims;
42

5-
namespace Microsoft.Azure.Functions.Worker.Http
3+
namespace Microsoft.Azure.Functions.Worker.Http;
4+
5+
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
6+
public class JwtBearerAuthenticationAttribute : Attribute
67
{
7-
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
8-
public class JwtBearerAuthenticationAttribute : Attribute
8+
public JwtBearerAuthenticationAttribute()
99
{
10-
public JwtBearerAuthenticationAttribute()
11-
{
12-
}
10+
}
1311

14-
public string? Roles { get; set; }
12+
public string? Roles { get; set; }
1513

16-
public bool IsAuthorized(ClaimsPrincipal principal)
17-
{
18-
var values = Roles?.Split(',', StringSplitOptions.RemoveEmptyEntries);
19-
return values is null || !values.Any() || values.Any(role => principal.IsInRole(role));
20-
}
14+
public bool IsAuthorized(ClaimsPrincipal principal)
15+
{
16+
var values = Roles?.Split(',', StringSplitOptions.RemoveEmptyEntries);
17+
return values is null || !values.Any() || values.Any(role => principal.IsInRole(role));
2118
}
22-
}
19+
}
Lines changed: 92 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,157 +1,147 @@
11
using Microsoft.AspNetCore.Authentication.JwtBearer;
2-
using Microsoft.Azure.Functions.Worker.Http;
32
using Microsoft.Azure.Functions.Worker.Middleware;
43
using Microsoft.Extensions.DependencyInjection;
54
using Microsoft.Extensions.Logging;
65
using Microsoft.Extensions.Options;
76
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
87
using Microsoft.IdentityModel.Tokens;
9-
using System;
10-
using System.Collections.Generic;
11-
using System.Linq;
12-
using System.Net.Http.Headers;
138
using System.Net;
9+
using System.Net.Http.Headers;
1410
using System.Reflection;
15-
using System.Runtime.Loader;
1611
using System.Security.Claims;
17-
using System.Text.RegularExpressions;
18-
using System.Threading;
19-
using System.Threading.Tasks;
20-
using Azure.Core;
2112

22-
namespace Microsoft.Azure.Functions.Worker.Http
13+
namespace Microsoft.Azure.Functions.Worker.Http;
14+
15+
public class JwtBearerAuthenticationMiddleware : IFunctionsWorkerMiddleware
2316
{
24-
public class JwtBearerAuthenticationMiddleware : IFunctionsWorkerMiddleware
17+
private OpenIdConnectConfiguration? _configuration;
18+
19+
public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
2520
{
26-
private OpenIdConnectConfiguration? _configuration;
21+
var authentication = GetAuthenticationAttribute(context);
2722

28-
public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
23+
if (authentication is not null)
2924
{
30-
var authentication = GetAuthenticationAttribute(context);
31-
32-
if (authentication is not null)
25+
var request = context.GetHttpRequestData();
26+
27+
if (request is not null)
3328
{
34-
var request = context.GetHttpRequestData();
29+
var principal = await AuthenticateAsync(context, request).ConfigureAwait(false);
3530

36-
if (request is not null)
31+
if (principal is null)
32+
{
33+
context.SetHttpResponseData(request.CreateResponse(HttpStatusCode.Unauthorized));
34+
return;
35+
}
36+
else
3737
{
38-
var principal = await AuthenticateAsync(context, request).ConfigureAwait(false);
38+
context.Items[nameof(ClaimsPrincipal)] = principal;
3939

40-
if (principal is null)
40+
if (!authentication.IsAuthorized(principal))
4141
{
42-
context.SetHttpResponseData(request.CreateResponse(HttpStatusCode.Unauthorized));
42+
context.SetHttpResponseData(request.CreateResponse(HttpStatusCode.Forbidden));
4343
return;
4444
}
45-
else
46-
{
47-
context.Items[nameof(ClaimsPrincipal)] = principal;
48-
49-
if (!authentication.IsAuthorized(principal))
50-
{
51-
context.SetHttpResponseData(request.CreateResponse(HttpStatusCode.Forbidden));
52-
return;
53-
}
54-
}
5545
}
5646
}
57-
58-
await next(context).ConfigureAwait(false);
5947
}
6048

61-
private JwtBearerAuthenticationAttribute? GetAuthenticationAttribute(FunctionContext context)
62-
=> context.FunctionDefinition.GetMethod().GetCustomAttribute<JwtBearerAuthenticationAttribute>();
49+
await next(context).ConfigureAwait(false);
50+
}
51+
52+
private JwtBearerAuthenticationAttribute? GetAuthenticationAttribute(FunctionContext context)
53+
=> context.FunctionDefinition.GetMethod().GetCustomAttribute<JwtBearerAuthenticationAttribute>();
6354

64-
private async Task<ClaimsPrincipal?> AuthenticateAsync(FunctionContext context, HttpRequestData request)
55+
private async Task<ClaimsPrincipal?> AuthenticateAsync(FunctionContext context, HttpRequestData request)
56+
{
57+
var logger = context.GetLogger<JwtBearerAuthenticationMiddleware>();
58+
59+
try
6560
{
66-
var logger = context.GetLogger<JwtBearerAuthenticationMiddleware>();
61+
var options = context.InstanceServices.GetRequiredService<IOptionsMonitor<JwtBearerOptions>>().CurrentValue;
6762

68-
try
63+
if (_configuration is null && options.ConfigurationManager != null)
6964
{
70-
var options = context.InstanceServices.GetRequiredService<IOptionsMonitor<JwtBearerOptions>>().CurrentValue;
65+
_configuration = await options.ConfigurationManager.GetConfigurationAsync(CancellationToken.None).ConfigureAwait(false);
66+
}
7167

72-
if (_configuration is null && options.ConfigurationManager != null)
73-
{
74-
_configuration = await options.ConfigurationManager.GetConfigurationAsync(CancellationToken.None).ConfigureAwait(false);
75-
}
68+
if (request.Headers.TryGetValues("Authorization", out var values))
69+
{
70+
var authorization = values.SingleOrDefault();
7671

77-
if (request.Headers.TryGetValues("Authorization", out var values))
72+
if (authorization is not null)
7873
{
79-
var authorization = values.SingleOrDefault();
74+
var value = AuthenticationHeaderValue.Parse(authorization);
8075

81-
if (authorization is not null)
76+
if (string.Equals(JwtBearerDefaults.AuthenticationScheme, value.Scheme, StringComparison.InvariantCultureIgnoreCase))
8277
{
83-
var value = AuthenticationHeaderValue.Parse(authorization);
78+
var token = value.Parameter;
79+
var validationParameters = options.TokenValidationParameters.Clone();
8480

85-
if (string.Equals(JwtBearerDefaults.AuthenticationScheme, value.Scheme, StringComparison.InvariantCultureIgnoreCase))
81+
if (_configuration is not null)
8682
{
87-
var token = value.Parameter;
88-
var validationParameters = options.TokenValidationParameters.Clone();
89-
90-
if (_configuration is not null)
91-
{
92-
var issuers = new[] { _configuration.Issuer };
93-
validationParameters.ValidIssuers = validationParameters.ValidIssuers?.Concat(issuers) ?? issuers;
83+
var issuers = new[] { _configuration.Issuer };
84+
validationParameters.ValidIssuers = validationParameters.ValidIssuers?.Concat(issuers) ?? issuers;
9485

95-
validationParameters.IssuerSigningKeys = validationParameters.IssuerSigningKeys?.Concat(_configuration.SigningKeys)
96-
?? _configuration.SigningKeys;
97-
}
86+
validationParameters.IssuerSigningKeys = validationParameters.IssuerSigningKeys?.Concat(_configuration.SigningKeys)
87+
?? _configuration.SigningKeys;
88+
}
9889

99-
List<Exception>? validationFailures = null;
100-
SecurityToken? validatedToken = null;
101-
foreach (var validator in options.SecurityTokenValidators)
90+
List<Exception>? validationFailures = null;
91+
SecurityToken? validatedToken = null;
92+
foreach (var validator in options.SecurityTokenValidators)
93+
{
94+
if (validator.CanReadToken(token))
10295
{
103-
if (validator.CanReadToken(token))
96+
ClaimsPrincipal principal;
97+
try
10498
{
105-
ClaimsPrincipal principal;
106-
try
99+
principal = validator.ValidateToken(token, validationParameters, out validatedToken);
100+
}
101+
catch (Exception ex)
102+
{
103+
logger.LogInformation(ex, "Token validation failed: {Message}", ex.Message);
104+
105+
// Refresh the configuration for exceptions that may be caused by key rollovers. The user can also request a refresh in the event.
106+
if (options.RefreshOnIssuerKeyNotFound && options.ConfigurationManager != null
107+
&& ex is SecurityTokenSignatureKeyNotFoundException)
107108
{
108-
principal = validator.ValidateToken(token, validationParameters, out validatedToken);
109+
options.ConfigurationManager.RequestRefresh();
109110
}
110-
catch (Exception ex)
111+
112+
if (validationFailures == null)
111113
{
112-
logger.LogInformation(ex, "Token validation failed: {Message}", ex.Message);
113-
114-
// Refresh the configuration for exceptions that may be caused by key rollovers. The user can also request a refresh in the event.
115-
if (options.RefreshOnIssuerKeyNotFound && options.ConfigurationManager != null
116-
&& ex is SecurityTokenSignatureKeyNotFoundException)
117-
{
118-
options.ConfigurationManager.RequestRefresh();
119-
}
120-
121-
if (validationFailures == null)
122-
{
123-
validationFailures = new List<Exception>(1);
124-
}
125-
validationFailures.Add(ex);
126-
continue;
114+
validationFailures = new List<Exception>(1);
127115
}
116+
validationFailures.Add(ex);
117+
continue;
118+
}
128119

129-
logger.LogTrace("Token validation succeeded for principal: {Identity}", principal.Identity?.Name ?? "[null]");
120+
logger.LogTrace("Token validation succeeded for principal: {Identity}", principal.Identity?.Name ?? "[null]");
130121

131-
return principal;
132-
}
122+
return principal;
133123
}
124+
}
134125

135-
if (validationFailures is not null)
136-
{
137-
var exception = (validationFailures.Count == 1) ? validationFailures[0] : new AggregateException(validationFailures);
138-
logger.LogTrace(exception, "Token validation failed: {Message}", exception.Message);
139-
}
140-
else
141-
{
142-
logger.LogTrace("No SecurityTokenValidator available for token: {Token}", token ?? "[null]");
143-
}
126+
if (validationFailures is not null)
127+
{
128+
var exception = (validationFailures.Count == 1) ? validationFailures[0] : new AggregateException(validationFailures);
129+
logger.LogTrace(exception, "Token validation failed: {Message}", exception.Message);
130+
}
131+
else
132+
{
133+
logger.LogTrace("No SecurityTokenValidator available for token: {Token}", token ?? "[null]");
144134
}
145135
}
146136
}
147-
148-
return null;
149-
}
150-
catch (Exception ex)
151-
{
152-
logger.LogError(ex, "Authentication failed: {Message}", ex.Message);
153-
throw;
154137
}
138+
139+
return null;
140+
}
141+
catch (Exception ex)
142+
{
143+
logger.LogError(ex, "Authentication failed: {Message}", ex.Message);
144+
throw;
155145
}
156146
}
157-
}
147+
}

0 commit comments

Comments
 (0)