first commit

This commit is contained in:
Vitalii Litvinchuk
2026-06-13 23:23:50 +03:00
commit 23958e8e2c
72 changed files with 6142 additions and 0 deletions
@@ -0,0 +1,117 @@
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using FluentAssertions;
using SequenceAuth.Lib;
using Xunit;
namespace SequenceAuth.Example.Tests;
public class SequenceAuthE2ETests : IClassFixture<CustomWebApplicationFactory>
{
private readonly HttpClient _client;
public SequenceAuthE2ETests(CustomWebApplicationFactory factory)
{
_client = factory.CreateClient();
}
private async Task<string> InitSessionAsync()
{
var loginResponse = await _client.PostAsJsonAsync("/auth/login", new { username = "testuser" });
loginResponse.EnsureSuccessStatusCode();
var token = loginResponse.Headers.GetValues(new SequenceAuthOptions().NextHeaderName).FirstOrDefault();
token.Should().NotBeNullOrWhiteSpace();
return token!;
}
[Fact]
public async Task RequestWithoutHeader_ReturnsUnauthorized()
{
var response = await _client.GetAsync("/secure/get-data");
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
}
[Fact]
public async Task ValidChain_FollowsSequenceAndSucceeds()
{
// 1. Init Session
var token1 = await InitSessionAsync();
// 2. First Request
var request1 = new HttpRequestMessage(HttpMethod.Get, "/secure/get-data");
request1.Headers.Add(new SequenceAuthOptions().AuthHeaderName, token1);
var response1 = await _client.SendAsync(request1);
response1.EnsureSuccessStatusCode();
var token2 = response1.Headers.GetValues(new SequenceAuthOptions().NextHeaderName).First();
token2.Should().NotBeNullOrWhiteSpace();
// 3. Second Request with New Token
var request2 = new HttpRequestMessage(HttpMethod.Get, "/secure/get-data");
request2.Headers.Add(new SequenceAuthOptions().AuthHeaderName, token2);
var response2 = await _client.SendAsync(request2);
response2.EnsureSuccessStatusCode();
var token3 = response2.Headers.GetValues(new SequenceAuthOptions().NextHeaderName).First();
token3.Should().NotBeNullOrWhiteSpace();
}
[Fact]
public async Task AttackerReplaysToken_CompromisesSequence()
{
var token1 = await InitSessionAsync();
System.Console.WriteLine($"Token 1: {token1}");
var userRequest1 = new HttpRequestMessage(HttpMethod.Get, "/secure/get-data");
userRequest1.Headers.Add(new SequenceAuthOptions().AuthHeaderName, token1);
var userResponse1 = await _client.SendAsync(userRequest1);
userResponse1.EnsureSuccessStatusCode();
var token2 = userResponse1.Headers.GetValues(new SequenceAuthOptions().NextHeaderName).First();
System.Console.WriteLine($"Token 2: {token2}");
var attackerRequest = new HttpRequestMessage(HttpMethod.Get, "/secure/get-data");
attackerRequest.Headers.Add(new SequenceAuthOptions().AuthHeaderName, token1);
var attackerResponse = await _client.SendAsync(attackerRequest);
System.Console.WriteLine($"Attacker Response: {attackerResponse.StatusCode}");
var attackerBody = await attackerResponse.Content.ReadAsStringAsync();
System.Console.WriteLine($"Attacker Body: {attackerBody}");
attackerResponse.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
var userRequest2 = new HttpRequestMessage(HttpMethod.Get, "/secure/get-data");
userRequest2.Headers.Add(new SequenceAuthOptions().AuthHeaderName, token2);
var userResponse2 = await _client.SendAsync(userRequest2);
userResponse2.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
}
[Fact]
public async Task AttackerStrikesFirst_CompromisesSequence()
{
var token1 = await InitSessionAsync();
var attackerRequest1 = new HttpRequestMessage(HttpMethod.Get, "/secure/get-data");
attackerRequest1.Headers.Add(new SequenceAuthOptions().AuthHeaderName, token1);
var attackerResponse1 = await _client.SendAsync(attackerRequest1);
attackerResponse1.EnsureSuccessStatusCode();
var token2 = attackerResponse1.Headers.GetValues(new SequenceAuthOptions().NextHeaderName).First();
var userRequest1 = new HttpRequestMessage(HttpMethod.Get, "/secure/get-data");
userRequest1.Headers.Add(new SequenceAuthOptions().AuthHeaderName, token1);
var userResponse1 = await _client.SendAsync(userRequest1);
System.Console.WriteLine($"User Response 1: {userResponse1.StatusCode}");
userResponse1.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
var attackerRequest2 = new HttpRequestMessage(HttpMethod.Get, "/secure/get-data");
attackerRequest2.Headers.Add(new SequenceAuthOptions().AuthHeaderName, token2);
var attackerResponse2 = await _client.SendAsync(attackerRequest2);
attackerResponse2.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
}
}