Initial commit: JDE Scoping Tool migration project
Set up repository with legacy .NET Framework 4.8 source (OLD/), new .NET 10 Blazor solution (NEW/), OpenSpec specifications, documentation, and project configuration.
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
using System.Security.Claims;
|
||||
using JdeScoping.Api.Controllers;
|
||||
using JdeScoping.Api.Models;
|
||||
using JdeScoping.Core.Interfaces;
|
||||
using JdeScoping.Core.Models;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Shouldly;
|
||||
|
||||
namespace JdeScoping.Api.Tests.Controllers;
|
||||
|
||||
public class AuthControllerTests
|
||||
{
|
||||
private readonly IAuthService _authService;
|
||||
private readonly ILogger<AuthController> _logger;
|
||||
private readonly AuthController _controller;
|
||||
|
||||
public AuthControllerTests()
|
||||
{
|
||||
_authService = Substitute.For<IAuthService>();
|
||||
_logger = Substitute.For<ILogger<AuthController>>();
|
||||
_controller = new AuthController(_authService, _logger);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Login_WithValidCredentials_ReturnsUserInfo()
|
||||
{
|
||||
// Arrange
|
||||
var request = new LoginRequest { Username = "testuser", Password = "password123" };
|
||||
var user = new UserInfo
|
||||
{
|
||||
Dn = "CN=testuser,DC=example,DC=com",
|
||||
Username = "testuser",
|
||||
FirstName = "Test",
|
||||
LastName = "User",
|
||||
EmailAddress = "test@example.com",
|
||||
Title = "Developer"
|
||||
};
|
||||
_authService.AuthenticateAsync("testuser", "password123", Arg.Any<CancellationToken>())
|
||||
.Returns(new AuthResult(true, user, null));
|
||||
|
||||
// Setup HttpContext with mock authentication
|
||||
var httpContext = CreateMockHttpContext();
|
||||
_controller.ControllerContext = new ControllerContext { HttpContext = httpContext };
|
||||
|
||||
// Act
|
||||
var result = await _controller.Login(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
result.Result.ShouldBeOfType<OkObjectResult>();
|
||||
var okResult = (OkObjectResult)result.Result!;
|
||||
var returnedUser = okResult.Value.ShouldBeOfType<UserInfo>();
|
||||
returnedUser.Username.ShouldBe("testuser");
|
||||
returnedUser.FirstName.ShouldBe("Test");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Login_WithInvalidCredentials_Returns401()
|
||||
{
|
||||
// Arrange
|
||||
var request = new LoginRequest { Username = "testuser", Password = "wrongpassword" };
|
||||
_authService.AuthenticateAsync("testuser", "wrongpassword", Arg.Any<CancellationToken>())
|
||||
.Returns(new AuthResult(false, null, "Incorrect username or password"));
|
||||
|
||||
// Setup HttpContext
|
||||
var httpContext = CreateMockHttpContext();
|
||||
_controller.ControllerContext = new ControllerContext { HttpContext = httpContext };
|
||||
|
||||
// Act
|
||||
var result = await _controller.Login(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
result.Result.ShouldBeOfType<UnauthorizedObjectResult>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Logout_ClearsAuthentication()
|
||||
{
|
||||
// Arrange
|
||||
var httpContext = CreateAuthenticatedHttpContext("testuser");
|
||||
_controller.ControllerContext = new ControllerContext { HttpContext = httpContext };
|
||||
|
||||
// Act
|
||||
var result = await _controller.Logout();
|
||||
|
||||
// Assert
|
||||
result.ShouldBeOfType<OkResult>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCurrentUser_WhenAuthenticated_ReturnsUserInfo()
|
||||
{
|
||||
// Arrange
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new(ClaimTypes.Name, "testuser"),
|
||||
new(ClaimTypes.GivenName, "Test"),
|
||||
new(ClaimTypes.Surname, "User"),
|
||||
new(ClaimTypes.Email, "test@example.com"),
|
||||
new("title", "Developer"),
|
||||
new("dn", "CN=testuser,DC=example,DC=com")
|
||||
};
|
||||
var identity = new ClaimsIdentity(claims, "Test");
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
var httpContext = new DefaultHttpContext { User = principal };
|
||||
_controller.ControllerContext = new ControllerContext { HttpContext = httpContext };
|
||||
|
||||
// Act
|
||||
var result = _controller.GetCurrentUser();
|
||||
|
||||
// Assert
|
||||
result.Result.ShouldBeOfType<OkObjectResult>();
|
||||
var okResult = (OkObjectResult)result.Result!;
|
||||
var user = okResult.Value.ShouldBeOfType<UserInfo>();
|
||||
user.Username.ShouldBe("testuser");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCurrentUser_ExtractsAllClaimsCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new(ClaimTypes.Name, "jsmith"),
|
||||
new(ClaimTypes.GivenName, "John"),
|
||||
new(ClaimTypes.Surname, "Smith"),
|
||||
new(ClaimTypes.Email, "jsmith@example.com"),
|
||||
new("title", "Senior Engineer"),
|
||||
new("dn", "CN=jsmith,OU=Users,DC=example,DC=com")
|
||||
};
|
||||
var identity = new ClaimsIdentity(claims, "Test");
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
var httpContext = new DefaultHttpContext { User = principal };
|
||||
_controller.ControllerContext = new ControllerContext { HttpContext = httpContext };
|
||||
|
||||
// Act
|
||||
var result = _controller.GetCurrentUser();
|
||||
|
||||
// Assert
|
||||
result.Result.ShouldBeOfType<OkObjectResult>();
|
||||
var okResult = (OkObjectResult)result.Result!;
|
||||
var user = okResult.Value.ShouldBeOfType<UserInfo>();
|
||||
|
||||
user.Username.ShouldBe("jsmith");
|
||||
user.FirstName.ShouldBe("John");
|
||||
user.LastName.ShouldBe("Smith");
|
||||
user.EmailAddress.ShouldBe("jsmith@example.com");
|
||||
user.Title.ShouldBe("Senior Engineer");
|
||||
user.Dn.ShouldBe("CN=jsmith,OU=Users,DC=example,DC=com");
|
||||
user.DisplayName.ShouldBe("John Smith");
|
||||
}
|
||||
|
||||
private static HttpContext CreateMockHttpContext()
|
||||
{
|
||||
var authServiceMock = Substitute.For<IAuthenticationService>();
|
||||
authServiceMock.SignOutAsync(Arg.Any<HttpContext>(), Arg.Any<string>(), Arg.Any<AuthenticationProperties>())
|
||||
.Returns(Task.CompletedTask);
|
||||
authServiceMock.SignInAsync(Arg.Any<HttpContext>(), Arg.Any<string>(), Arg.Any<ClaimsPrincipal>(), Arg.Any<AuthenticationProperties>())
|
||||
.Returns(Task.CompletedTask);
|
||||
|
||||
var serviceProvider = Substitute.For<IServiceProvider>();
|
||||
serviceProvider.GetService(typeof(IAuthenticationService)).Returns(authServiceMock);
|
||||
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = serviceProvider
|
||||
};
|
||||
|
||||
return httpContext;
|
||||
}
|
||||
|
||||
private static HttpContext CreateAuthenticatedHttpContext(string username)
|
||||
{
|
||||
var httpContext = CreateMockHttpContext();
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new(ClaimTypes.Name, username),
|
||||
new("dn", $"CN={username},DC=example,DC=com")
|
||||
};
|
||||
var identity = new ClaimsIdentity(claims, "Test");
|
||||
httpContext.User = new ClaimsPrincipal(identity);
|
||||
return httpContext;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user