diff --git a/.github/workflows/lexbox-api.yaml b/.github/workflows/lexbox-api.yaml
index 32cef0f0c..09b4e0630 100644
--- a/.github/workflows/lexbox-api.yaml
+++ b/.github/workflows/lexbox-api.yaml
@@ -45,7 +45,9 @@ jobs:
steps:
- uses: actions/checkout@v3
-
+ - uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '8.x'
- name: Dotnet build
run: dotnet build
- name: Unit tests
diff --git a/backend/Directory.Build.props b/backend/Directory.Build.props
index 6c5a1264e..ed66f2da0 100644
--- a/backend/Directory.Build.props
+++ b/backend/Directory.Build.props
@@ -1,12 +1,17 @@
-
- /app/obj/
- /app/bin/
+
+ $(DefaultItemExcludes);$(MSBuildProjectDirectory)/obj/**/*
+ $(DefaultItemExcludes);$(MSBuildProjectDirectory)/bin/**/*
+
+
+
+ $(MSBuildProjectDirectory)/obj/container/
+ $(MSBuildProjectDirectory)/bin/container/
false
-
+
diff --git a/backend/Dockerfile b/backend/Dockerfile
index 3bff244cb..5db510894 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -1,10 +1,10 @@
# syntax=docker/dockerfile:1
-FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
+FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
-FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
COPY . .
# WORKDIR /src
diff --git a/backend/FixFwData/FixFwData.csproj b/backend/FixFwData/FixFwData.csproj
index 0d98c4104..f8bc8031c 100644
--- a/backend/FixFwData/FixFwData.csproj
+++ b/backend/FixFwData/FixFwData.csproj
@@ -8,7 +8,7 @@
SIL International
LexBoxApi Testing
Copyright © 2023 SIL International
- net7.0
+ net8.0
enable
enable
diff --git a/backend/LexBoxApi/Auth/JwtTicketDataFormat.cs b/backend/LexBoxApi/Auth/JwtTicketDataFormat.cs
index e013991fc..604575a38 100644
--- a/backend/LexBoxApi/Auth/JwtTicketDataFormat.cs
+++ b/backend/LexBoxApi/Auth/JwtTicketDataFormat.cs
@@ -51,7 +51,7 @@ public static string ConvertAuthTicketToJwt(AuthenticationTicket data,
{
var jwtDate = DateTime.UtcNow;
_jwtSecurityTokenHandler.MapInboundClaims = jwtBearerOptions.MapInboundClaims;
- var claimsIdentity = new ClaimsIdentity(data.Principal.Claims, data.Principal.Identity?.AuthenticationType);
+ var claimsIdentity = new ClaimsIdentity(data.Principal.Claims.Where(c => c.Type != JwtRegisteredClaimNames.Jti), data.Principal.Identity?.AuthenticationType);
var keyId = Guid.NewGuid().ToString().GetHashCode().ToString("x", CultureInfo.InvariantCulture);
claimsIdentity.AddClaim(new Claim(JwtRegisteredClaimNames.Jti, keyId));
//there may already be an audience claim, we want to reuse that if it exists, if not fallback to the default audience
diff --git a/backend/LexBoxApi/GraphQL/GraphQlSetupKernel.cs b/backend/LexBoxApi/GraphQL/GraphQlSetupKernel.cs
index fbcc71e8d..0121e0e92 100644
--- a/backend/LexBoxApi/GraphQL/GraphQlSetupKernel.cs
+++ b/backend/LexBoxApi/GraphQL/GraphQlSetupKernel.cs
@@ -64,6 +64,7 @@ public static void AddLexGraphQL(this IServiceCollection services, IHostEnvironm
{
options.IncludeExceptionDetails = true;
})
+ .AddType()
.AddType(new DateTimeType("DateTime"))
.AddType(new UuidType("UUID"))
.AddType(new DateTimeType("timestamptz"))
diff --git a/backend/LexBoxApi/LexBoxApi.csproj b/backend/LexBoxApi/LexBoxApi.csproj
index 9e51fe404..7a6e5ea4d 100644
--- a/backend/LexBoxApi/LexBoxApi.csproj
+++ b/backend/LexBoxApi/LexBoxApi.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net8.0
enable
enable
Linux
@@ -10,35 +10,36 @@
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
diff --git a/backend/LexBoxApi/dev.Dockerfile b/backend/LexBoxApi/dev.Dockerfile
index 38591a28f..20e768811 100644
--- a/backend/LexBoxApi/dev.Dockerfile
+++ b/backend/LexBoxApi/dev.Dockerfile
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1
-FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
EXPOSE 80
EXPOSE 443
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
@@ -14,5 +14,4 @@ RUN for file in $(ls *.csproj); do dir=${file%.*} mkdir -p ${file%.*}/ && mv $fi
COPY . .
WORKDIR /src/backend/LexBoxApi
RUN mkdir /src/frontend
-ENV DockerDev=true
CMD dotnet watch run -lp docker --property:InformationalVersion=dockerDev
diff --git a/backend/LexCore/LexCore.csproj b/backend/LexCore/LexCore.csproj
index 83321cc3d..276363f1a 100644
--- a/backend/LexCore/LexCore.csproj
+++ b/backend/LexCore/LexCore.csproj
@@ -1,14 +1,14 @@
- net7.0
+ net8.0
enable
enable
dev
-
+
diff --git a/backend/LexData/LexData.csproj b/backend/LexData/LexData.csproj
index 836de9f92..8e7835b61 100644
--- a/backend/LexData/LexData.csproj
+++ b/backend/LexData/LexData.csproj
@@ -1,25 +1,25 @@
- net7.0
+ net8.0
enable
enable
dev
-
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/backend/SyncReverseProxy/Auth/BasicAuthHandler.cs b/backend/SyncReverseProxy/Auth/BasicAuthHandler.cs
index 0e77adf4f..5b9039a6f 100644
--- a/backend/SyncReverseProxy/Auth/BasicAuthHandler.cs
+++ b/backend/SyncReverseProxy/Auth/BasicAuthHandler.cs
@@ -20,9 +20,8 @@ public class BasicAuthHandler : AuthenticationHandler options,
ILoggerFactory logger,
UrlEncoder encoder,
- ISystemClock clock,
ILexProxyService lexProxyService,
- IMemoryCache memoryCache) : base(options, logger, encoder, clock)
+ IMemoryCache memoryCache) : base(options, logger, encoder)
{
_lexProxyService = lexProxyService;
_memoryCache = memoryCache;
diff --git a/backend/SyncReverseProxy/SyncReverseProxy.csproj b/backend/SyncReverseProxy/SyncReverseProxy.csproj
index 9cd1d3788..d275d5110 100644
--- a/backend/SyncReverseProxy/SyncReverseProxy.csproj
+++ b/backend/SyncReverseProxy/SyncReverseProxy.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net8.0
enable
enable
Linux
@@ -10,17 +10,17 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/backend/Testing/LexCore/LexAuthUserTests.cs b/backend/Testing/LexCore/LexAuthUserTests.cs
index 96e2423ee..170c5c618 100644
--- a/backend/Testing/LexCore/LexAuthUserTests.cs
+++ b/backend/Testing/LexCore/LexAuthUserTests.cs
@@ -8,6 +8,7 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
+using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using Shouldly;
@@ -15,6 +16,10 @@ namespace Testing.LexCore;
public class LexAuthUserTests
{
+ static LexAuthUserTests()
+ {
+ IdentityModelEventSource.ShowPII = true;
+ }
private readonly LexAuthService _lexAuthService = new LexAuthService(
new OptionsWrapper(JwtOptions.TestingOptions),
null!,
@@ -30,6 +35,12 @@ public class LexAuthUserTests
Projects = new[] { new AuthUserProject(ProjectRole.Manager, Guid.NewGuid()) }
};
+ private static readonly JwtBearerOptions JwtBearerOptions = new()
+ {
+ TokenValidationParameters = LexAuthService.TokenValidationParameters(JwtOptions.TestingOptions),
+ MapInboundClaims = false
+ };
+
[Fact]
public void CanGetClaimsFromUser()
{
@@ -73,11 +84,7 @@ public void CanRoundTripClaimsWhenUsingSecurityTokenDescriptor()
var jwt = JwtTicketDataFormat.ConvertAuthTicketToJwt(
new AuthenticationTicket(_user.GetPrincipal("test"), "test"),
"testing",
- new JwtBearerOptions
- {
- TokenValidationParameters = LexAuthService.TokenValidationParameters(jwtUserOptions),
- MapInboundClaims = false
- },
+ JwtBearerOptions,
jwtUserOptions
);
var tokenHandler = new JwtSecurityTokenHandler();
@@ -120,4 +127,25 @@ public void CheckingJwtLength()
var (jwt, _) = _lexAuthService.GenerateJwt(user);
jwt.Length.ShouldBeLessThan(LexAuthUser.MaxJwtLength);
}
+
+ [Fact]
+ public void CanRoundTripThroughRefresh()
+ {
+ var (forgotJwt, _) = _lexAuthService.GenerateJwt(_user, audience:LexboxAudience.ForgotPassword);
+ //simulate parsing the token into a claims principal
+ var tokenHandler = new JwtSecurityTokenHandler();
+ var forgotPrincipal = new ClaimsPrincipal(new ClaimsIdentity(tokenHandler.ReadJwtToken(forgotJwt).Claims, "Testing"));
+
+ //simulate redirect refreshing the token
+ var redirectJwt = JwtTicketDataFormat.ConvertAuthTicketToJwt(
+ new AuthenticationTicket(forgotPrincipal, "test"),
+ "testing",
+ JwtBearerOptions,
+ JwtOptions.TestingOptions
+ );
+
+ var loggedInPrincipal = new ClaimsPrincipal(new ClaimsIdentity(tokenHandler.ReadJwtToken(redirectJwt).Claims, "Testing"));
+ var newUser = LexAuthUser.FromClaimsPrincipal(loggedInPrincipal);
+ (_user with { Audience = LexboxAudience.ForgotPassword }).ShouldBeEquivalentTo(newUser);
+ }
}
diff --git a/backend/Testing/Testing.csproj b/backend/Testing/Testing.csproj
index 5c57fc2aa..0cbc8fcd1 100644
--- a/backend/Testing/Testing.csproj
+++ b/backend/Testing/Testing.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net8.0
enable
enable
@@ -10,29 +10,29 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
diff --git a/deployment/base/lexbox-deployment.yaml b/deployment/base/lexbox-deployment.yaml
index f7dde5ada..ba01ad748 100644
--- a/deployment/base/lexbox-deployment.yaml
+++ b/deployment/base/lexbox-deployment.yaml
@@ -36,6 +36,7 @@ spec:
selector:
matchLabels:
app: lexbox
+ progressDeadlineSeconds: 60
strategy:
rollingUpdate:
maxSurge: 2
diff --git a/frontend/schema.graphql b/frontend/schema.graphql
index 579adc24e..fd19d68bf 100644
--- a/frontend/schema.graphql
+++ b/frontend/schema.graphql
@@ -554,6 +554,8 @@ directive @authorize("The name of the authorization policy that determines acces
"The `@specifiedBy` directive is used within the type system definition language to provide a URL for specifying the behavior of custom scalar definitions."
directive @specifiedBy("The specifiedBy URL points to a human-readable specification. This field will only read a result for scalar types." url: String!) on SCALAR
+directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
+
scalar DateTime @specifiedBy(url: "https:\/\/www.graphql-scalars.com\/date-time")
scalar UUID