|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Authentication.Core.Test;
public class AuthenticationServiceTests
{
[Fact]
public async Task AuthenticateThrowsForSchemeMismatch()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<BaseHandler>("base", "whatever");
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.AuthenticateAsync("base");
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.AuthenticateAsync("missing"));
Assert.Contains("base", ex.Message);
}
[Fact]
public async Task CustomHandlersAuthenticateRunsClaimsTransformationEveryTime()
{
var transform = new RunOnce();
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<BaseHandler>("base", "whatever");
})
.AddSingleton<IClaimsTransformation>(transform)
.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
// Because base handler returns a different principal per call, its run multiple times
await context.AuthenticateAsync("base");
Assert.Equal(1, transform.Ran);
await context.AuthenticateAsync("base");
Assert.Equal(2, transform.Ran);
await context.AuthenticateAsync("base");
Assert.Equal(3, transform.Ran);
}
[Fact]
public async Task ChallengeThrowsForSchemeMismatch()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<BaseHandler>("base", "whatever");
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.ChallengeAsync("base");
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.ChallengeAsync("missing"));
Assert.Contains("base", ex.Message);
}
[Fact]
public async Task ForbidThrowsForSchemeMismatch()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<BaseHandler>("base", "whatever");
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.ForbidAsync("base");
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.ForbidAsync("missing"));
Assert.Contains("base", ex.Message);
}
[Fact]
public async Task CanOnlySignInWithIsAuthenticated()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<SignInHandler>("signin", "whatever");
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("signin", new ClaimsPrincipal(), null));
await context.SignInAsync("signin", new ClaimsPrincipal(new ClaimsIdentity("whatever")), null);
}
[Fact]
public async Task CanSignInWithoutIsAuthenticated()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<SignInHandler>("signin", "whatever");
o.RequireAuthenticatedSignIn = false;
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.SignInAsync("signin", new ClaimsPrincipal(), null);
await context.SignInAsync("signin", new ClaimsPrincipal(new ClaimsIdentity("whatever")), null);
}
[Fact]
public async Task CanOnlySignInIfSupported()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<UberHandler>("uber", "whatever");
o.AddScheme<BaseHandler>("base", "whatever");
o.AddScheme<SignInHandler>("signin", "whatever");
o.AddScheme<SignOutHandler>("signout", "whatever");
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.SignInAsync("uber", new ClaimsPrincipal(new ClaimsIdentity("whatever")), null);
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("base", new ClaimsPrincipal(new ClaimsIdentity("whatever")), null));
Assert.Contains("uber", ex.Message);
Assert.Contains("signin", ex.Message);
await context.SignInAsync("signin", new ClaimsPrincipal(new ClaimsIdentity("whatever")), null);
ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync("signout", new ClaimsPrincipal(new ClaimsIdentity("whatever")), null));
Assert.Contains("uber", ex.Message);
Assert.Contains("signin", ex.Message);
}
[Fact]
public async Task CanOnlySignOutIfSupported()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<UberHandler>("uber", "whatever");
o.AddScheme<BaseHandler>("base", "whatever");
o.AddScheme<SignInHandler>("signin", "whatever");
o.AddScheme<SignOutHandler>("signout", "whatever");
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.SignOutAsync("uber");
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync("base"));
Assert.Contains("uber", ex.Message);
Assert.Contains("signout", ex.Message);
await context.SignOutAsync("signout");
await context.SignOutAsync("signin");
}
[Fact]
public async Task ServicesWithDefaultIAuthenticationHandlerMethodsTest()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<BaseHandler>("base", "whatever");
o.DefaultScheme = "base";
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.AuthenticateAsync();
await context.ChallengeAsync();
await context.ForbidAsync();
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
Assert.Contains("cannot be used for SignOutAsync", ex.Message);
ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever"))));
Assert.Contains("cannot be used for SignInAsync", ex.Message);
}
[Fact]
public async Task ServicesWithDefaultUberMethodsTest()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<UberHandler>("base", "whatever");
o.DefaultScheme = "base";
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.AuthenticateAsync();
await context.ChallengeAsync();
await context.ForbidAsync();
await context.SignOutAsync();
await context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever")));
}
[Fact]
public async Task ServicesWithDefaultSignInMethodsTest()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<SignInHandler>("base", "whatever");
o.DefaultScheme = "base";
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.AuthenticateAsync();
await context.ChallengeAsync();
await context.ForbidAsync();
await context.SignOutAsync();
await context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever")));
}
[Fact]
public async Task ServicesWithDefaultSignOutMethodsTest()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<SignOutHandler>("base", "whatever");
o.DefaultScheme = "base";
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.AuthenticateAsync();
await context.ChallengeAsync();
await context.ForbidAsync();
await context.SignOutAsync();
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity("whatever"))));
Assert.Contains("cannot be used for SignInAsync", ex.Message);
}
[Fact]
public async Task ServicesWithDefaultForbidMethod_CallsForbidMethod()
{
var services = new ServiceCollection().AddOptions().AddAuthenticationCore(o =>
{
o.AddScheme<ForbidHandler>("forbid", "whatever");
o.DefaultForbidScheme = "forbid";
}).BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = services;
await context.ForbidAsync();
}
private class RunOnce : IClaimsTransformation
{
public int Ran = 0;
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
Ran++;
return Task.FromResult(new ClaimsPrincipal());
}
}
private class BaseHandler : IAuthenticationHandler
{
public Task<AuthenticateResult> AuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.Success(
new AuthenticationTicket(
new ClaimsPrincipal(new ClaimsIdentity("whatever")),
new AuthenticationProperties(),
"whatever")));
}
public Task ChallengeAsync(AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
public Task ForbidAsync(AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
return Task.FromResult(0);
}
}
private class SignInHandler : IAuthenticationSignInHandler
{
public Task<AuthenticateResult> AuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.NoResult());
}
public Task ChallengeAsync(AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
public Task ForbidAsync(AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
return Task.FromResult(0);
}
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
public Task SignOutAsync(AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
}
public class SignOutHandler : IAuthenticationSignOutHandler
{
public Task<AuthenticateResult> AuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.NoResult());
}
public Task ChallengeAsync(AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
public Task ForbidAsync(AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
return Task.FromResult(0);
}
public Task SignOutAsync(AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
}
private class UberHandler : IAuthenticationHandler, IAuthenticationRequestHandler, IAuthenticationSignInHandler, IAuthenticationSignOutHandler
{
public Task<AuthenticateResult> AuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.NoResult());
}
public Task ChallengeAsync(AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
public Task ForbidAsync(AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
public Task<bool> HandleRequestAsync()
{
return Task.FromResult(false);
}
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
return Task.FromResult(0);
}
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
public Task SignOutAsync(AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
}
private class ForbidHandler : IAuthenticationHandler, IAuthenticationRequestHandler, IAuthenticationSignInHandler, IAuthenticationSignOutHandler
{
public Task<AuthenticateResult> AuthenticateAsync()
{
throw new NotImplementedException();
}
public Task ChallengeAsync(AuthenticationProperties? properties)
{
throw new NotImplementedException();
}
public Task ForbidAsync(AuthenticationProperties? properties)
{
return Task.FromResult(0);
}
public Task<bool> HandleRequestAsync()
{
throw new NotImplementedException();
}
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
return Task.FromResult(0);
}
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties? properties)
{
throw new NotImplementedException();
}
public Task SignOutAsync(AuthenticationProperties? properties)
{
throw new NotImplementedException();
}
}
}
|