diff --git a/src/Invio.Extensions.Authentication.JwtBearer/JwtBearerEventsWrapperBase.cs b/src/Invio.Extensions.Authentication.JwtBearer/JwtBearerEventsWrapperBase.cs
index 6d53ecb..3b08629 100644
--- a/src/Invio.Extensions.Authentication.JwtBearer/JwtBearerEventsWrapperBase.cs
+++ b/src/Invio.Extensions.Authentication.JwtBearer/JwtBearerEventsWrapperBase.cs
@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.Extensions.DependencyInjection;
namespace Invio.Extensions.Authentication.JwtBearer {
@@ -15,8 +16,8 @@ namespace Invio.Extensions.Authentication.JwtBearer {
/// to provide distracting invocations to the wrapped .
///
public abstract class JwtBearerEventsWrapperBase : JwtBearerEvents {
-
- private JwtBearerEvents inner { get; }
+ private JwtBearerEvents inner;
+ private readonly Type innerType;
///
/// Creates a implementation which
@@ -37,19 +38,34 @@ protected JwtBearerEventsWrapperBase(JwtBearerEvents inner) {
this.inner = inner;
}
+ ///
+ /// Creates a implementation which
+ /// does nothing but call the injected wrapped implementation by default.
+ ///
+ ///
+ /// The base service type that will be resolved from the request services
+ /// and then invoked after the inheriting wrapper performs its side effects.
+ ///
+ ///
+ /// Thrown when is null.
+ ///
+ protected JwtBearerEventsWrapperBase(Type innerType) {
+ this.innerType = innerType ?? throw new ArgumentNullException(nameof(innerType));
+ }
+
///
/// Invoked if exceptions are thrown during request processing.
/// The exceptions will be re-thrown after this event unless suppressed.
///
public override Task AuthenticationFailed(AuthenticationFailedContext context) {
- return inner.AuthenticationFailed(context);
+ return InnerResolved(context).AuthenticationFailed(context);
}
///
/// Invoked when a protocol message is first received.
///
public override Task MessageReceived(MessageReceivedContext context) {
- return inner.MessageReceived(context);
+ return InnerResolved(context).MessageReceived(context);
}
///
@@ -57,16 +73,19 @@ public override Task MessageReceived(MessageReceivedContext context) {
/// and a ClaimsIdentity has been generated.
///
public override Task TokenValidated(TokenValidatedContext context) {
- return inner.TokenValidated(context);
+ return InnerResolved(context).TokenValidated(context);
}
///
/// Invoked before a challenge is sent back to the caller.
///
public override Task Challenge(JwtBearerChallengeContext context) {
- return inner.Challenge(context);
+ return InnerResolved(context).Challenge(context);
}
+ private JwtBearerEvents InnerResolved(BaseContext context) =>
+ inner ??
+ (inner = (JwtBearerEvents)context.HttpContext.RequestServices.GetRequiredService(innerType));
}
}
diff --git a/src/Invio.Extensions.Authentication.JwtBearer/JwtBearerOptionsExtensions.cs b/src/Invio.Extensions.Authentication.JwtBearer/JwtBearerOptionsExtensions.cs
index e28be6d..2eeccd0 100644
--- a/src/Invio.Extensions.Authentication.JwtBearer/JwtBearerOptionsExtensions.cs
+++ b/src/Invio.Extensions.Authentication.JwtBearer/JwtBearerOptionsExtensions.cs
@@ -28,10 +28,18 @@ public static JwtBearerOptions AddQueryStringAuthentication(
throw new ArgumentNullException(nameof(options));
}
- options.Events =
- new QueryStringJwtBearerEventsWrapper(
- options.Events ?? new JwtBearerEvents()
- );
+ if (options.EventsType == null) {
+ options.Events =
+ new QueryStringJwtBearerEventsWrapper(
+ options.Events ?? new JwtBearerEvents()
+ );
+ } else {
+ options.Events =
+ new QueryStringJwtBearerEventsWrapper(
+ options.EventsType
+ );
+ options.EventsType = null;
+ }
return options;
}
@@ -61,11 +69,20 @@ public static JwtBearerOptions AddQueryStringAuthentication(
throw new ArgumentNullException(nameof(options));
}
- options.Events =
- new QueryStringJwtBearerEventsWrapper(
- options.Events ?? new JwtBearerEvents(),
- queryStringParameterName
- );
+ if (options.EventsType == null) {
+ options.Events =
+ new QueryStringJwtBearerEventsWrapper(
+ options.Events ?? new JwtBearerEvents(),
+ queryStringParameterName
+ );
+ } else {
+ options.Events =
+ new QueryStringJwtBearerEventsWrapper(
+ options.EventsType,
+ queryStringParameterName
+ );
+ options.EventsType = null;
+ }
return options;
}
diff --git a/src/Invio.Extensions.Authentication.JwtBearer/QueryStringJwtBearerEventsWrapper.cs b/src/Invio.Extensions.Authentication.JwtBearer/QueryStringJwtBearerEventsWrapper.cs
index b5dbc8f..ce4915b 100644
--- a/src/Invio.Extensions.Authentication.JwtBearer/QueryStringJwtBearerEventsWrapper.cs
+++ b/src/Invio.Extensions.Authentication.JwtBearer/QueryStringJwtBearerEventsWrapper.cs
@@ -58,6 +58,20 @@ public class QueryStringJwtBearerEventsWrapper : JwtBearerEventsWrapperBase {
public QueryStringJwtBearerEventsWrapper(JwtBearerEvents inner) :
this(inner, DefaultQueryStringParameterName) {}
+ ///
+ /// Wraps an instance of with a behavior
+ /// that checks for a token in the query string with a name of "bearer".
+ ///
+ ///
+ /// A base service type implementation of
+ /// that will gain this additional query string inspection behavior.
+ ///
+ ///
+ /// Thrown when is null.
+ ///
+ public QueryStringJwtBearerEventsWrapper(Type innerType) :
+ this(innerType, DefaultQueryStringParameterName) {}
+
///
/// Wraps an instance of with a behavior
/// checks for a token in the query string with a name specified in the
@@ -94,6 +108,42 @@ public QueryStringJwtBearerEventsWrapper(JwtBearerEvents inner, string queryStri
this.QueryStringParameterName = queryStringParameterName;
}
+ ///
+ /// Wraps an instance of with a behavior
+ /// checks for a token in the query string with a name specified in the
+ /// parameter.
+ ///
+ ///
+ /// A base service type implementation of
+ /// that will gain this additional query string inspection behavior.
+ ///
+ ///
+ /// The name of the query string parameter that will be sought from requests
+ /// in order to extract a token.
+ ///
+ ///
+ /// Thrown when or
+ /// is null.
+ ///
+ ///
+ /// Thrown when is an invalid name
+ /// for a query string parameter.
+ ///
+ public QueryStringJwtBearerEventsWrapper(Type innerType, string queryStringParameterName) :
+ base(innerType) {
+
+ if (queryStringParameterName == null) {
+ throw new ArgumentNullException(nameof(queryStringParameterName));
+ } else if (String.IsNullOrWhiteSpace(queryStringParameterName)) {
+ throw new ArgumentException(
+ $"The '{nameof(queryStringParameterName)}' cannot be null or whitespace.",
+ nameof(queryStringParameterName)
+ );
+ }
+
+ this.QueryStringParameterName = queryStringParameterName;
+ }
+
///
/// Checks the web request for the in
/// the request's query string. If it is found, it fetches the token
diff --git a/test/Invio.Extensions.Authentication.JwtBearer.Tests/JwtBearerEventsWrapperBaseTests.cs b/test/Invio.Extensions.Authentication.JwtBearer.Tests/JwtBearerEventsWrapperBaseTests.cs
index 11ec394..bf1b481 100644
--- a/test/Invio.Extensions.Authentication.JwtBearer.Tests/JwtBearerEventsWrapperBaseTests.cs
+++ b/test/Invio.Extensions.Authentication.JwtBearer.Tests/JwtBearerEventsWrapperBaseTests.cs
@@ -17,6 +17,7 @@ public async Task AuthenticationFailed_Wraps() {
var inner = Mock.Of();
var wrapper = this.CreateJwtBearerEvents(inner);
var context = new DefaultAuthenticationFailedContext();
+ SetupContext(context, inner);
// Act
@@ -35,6 +36,7 @@ public async Task MessageReceived_Wraps() {
var inner = Mock.Of();
var wrapper = this.CreateJwtBearerEvents(inner);
var context = new DefaultMessageReceivedContext();
+ SetupContext(context, inner);
// Act
@@ -53,6 +55,7 @@ public async Task TokenValidated() {
var inner = Mock.Of();
var wrapper = this.CreateJwtBearerEvents(inner);
var context = new DefaultTokenValidatedContext();
+ SetupContext(context, inner);
// Act
@@ -71,6 +74,7 @@ public async Task Challenge_Wraps() {
var inner = Mock.Of();
var wrapper = this.CreateJwtBearerEvents(inner);
var context = new DefaultJwtBearerChallengeContext();
+ SetupContext(context, inner);
// Act
@@ -81,6 +85,9 @@ public async Task Challenge_Wraps() {
Mock.Get(inner).Verify(events => events.Challenge(context));
}
+ protected virtual void SetupContext(BaseContext context,
+ JwtBearerEvents inner) {}
+
protected abstract JwtBearerEvents CreateJwtBearerEvents(JwtBearerEvents inner);
}
diff --git a/test/Invio.Extensions.Authentication.JwtBearer.Tests/JwtBearerOptionsExtensionsTests.cs b/test/Invio.Extensions.Authentication.JwtBearer.Tests/JwtBearerOptionsExtensionsTests.cs
index 29f20be..60b048b 100644
--- a/test/Invio.Extensions.Authentication.JwtBearer.Tests/JwtBearerOptionsExtensionsTests.cs
+++ b/test/Invio.Extensions.Authentication.JwtBearer.Tests/JwtBearerOptionsExtensionsTests.cs
@@ -48,6 +48,30 @@ public static void AddQueryStringAuthentication_DefaultQueryStringParameter() {
);
}
+ [Fact]
+ public static void AddQueryStringAuthentication_DefaultQueryStringParameter_CustomEventsType() {
+
+ // Arrange
+
+ var options = new JwtBearerOptions { EventsType = typeof(JwtBearerEvents) };
+
+ // Act
+
+ options.AddQueryStringAuthentication();
+
+ // Assert
+
+ Assert.NotNull(options.Events);
+ var events = Assert.IsType(options.Events);
+
+ Assert.Equal(
+ QueryStringJwtBearerEventsWrapper.DefaultQueryStringParameterName,
+ events.QueryStringParameterName
+ );
+
+ Assert.Null(options.EventsType);
+ }
+
[Fact]
public static void AddQueryStringAuthentication_CustomQueryStringParameter_NullOptions() {
@@ -85,6 +109,26 @@ public static void AddQueryStringAuthentication_CustomQueryStringParameter() {
Assert.Equal(queryStringParameterName, events.QueryStringParameterName);
}
+ [Fact]
+ public static void AddQueryStringAuthentication_CustomQueryStringParameter_CustomEventsType() {
+
+ // Arrange
+
+ var options = new JwtBearerOptions { EventsType = typeof(JwtBearerEvents) };
+ const string queryStringParameterName = "query-string-parameter-name";
+
+ // Act
+
+ options.AddQueryStringAuthentication(queryStringParameterName);
+
+ // Assert
+
+ Assert.NotNull(options.Events);
+ var events = Assert.IsType(options.Events);
+ Assert.Equal(queryStringParameterName, events.QueryStringParameterName);
+ Assert.Null(options.EventsType);
+ }
+
}
}
\ No newline at end of file
diff --git a/test/Invio.Extensions.Authentication.JwtBearer.Tests/JwtBearerOptionsPostConfigurationTests.cs b/test/Invio.Extensions.Authentication.JwtBearer.Tests/JwtBearerOptionsPostConfigurationTests.cs
index ffb3e6a..cfea105 100644
--- a/test/Invio.Extensions.Authentication.JwtBearer.Tests/JwtBearerOptionsPostConfigurationTests.cs
+++ b/test/Invio.Extensions.Authentication.JwtBearer.Tests/JwtBearerOptionsPostConfigurationTests.cs
@@ -51,7 +51,8 @@ public static IEnumerable