> GetClaimList(string jwtString, string cl
}
return claimList;
}
- }
+ }
}
diff --git a/roles/ui/files/FWO.UI/Pages/Help/HelpApiLogin.cshtml b/roles/ui/files/FWO.UI/Pages/Help/HelpApiLogin.cshtml
index b233cfc8e2..f1a23c830d 100644
--- a/roles/ui/files/FWO.UI/Pages/Help/HelpApiLogin.cshtml
+++ b/roles/ui/files/FWO.UI/Pages/Help/HelpApiLogin.cshtml
@@ -3,9 +3,9 @@
@{
Layout = "HelpLayout";
}
-@section sidebar{
- @{
- await Html.RenderPartialAsync("HelpAPISidebar.cshtml");
+@section sidebar {
+ @{
+ await Html.RenderPartialAsync("HelpAPISidebar.cshtml");
}
}
@using FWO.Config.Api
@@ -15,21 +15,117 @@
@userConfig.GetText("login")
@(Html.Raw(userConfig.GetText("H6501")))
-
@userConfig.GetText("jwt_corr_login")
-
-
+
+
curl --request POST \
- --url https://localhost:8888/api/AuthenticationToken/Get/ \
+ --url https://localhost:8888/api/AuthenticationToken/GetTokenPair/ \
--header 'content-type: application/json' \
--data '{"Username": "user1_demo", "Password": "cactus1"}'
-
-
+
+ @userConfig.GetText("response")
+
+ {
+ "accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
+ "refreshToken": "a7f3c8b9e2d1...",
+ "accessTokenExpires": "2025-12-11T14:30:00Z",
+ "refreshTokenExpires": "2026-01-10T12:00:00Z"
+ }
+
+
@userConfig.GetText("err_incorr_login")
-
-
+
+
curl --request POST \
- --url https://localhost:8888/api/AuthenticationToken/Get/ \
+ --url https://localhost:8888/api/AuthenticationToken/GetTokenPair/ \
--header 'content-type: application/json' \
--data '{"Username": "user1_demo", "Password": "wrong-pwd"}'
-
+
+
+ @userConfig.GetText("response")
+
+
+ A0002 Invalid credentials
+
+
+ @userConfig.GetText("token_refresh")
+
+
+curl --request POST \
+ --url https://localhost:8888/api/AuthenticationToken/Refresh/ \
+ --header 'content-type: application/json' \
+ --data '{"RefreshToken": "a7f3c8b9e2d1..."}'
+
+
+ @userConfig.GetText("response")
+
+
+ {
+ "accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
+ "refreshToken": "b8g4d9c0f3e2...",
+ "accessTokenExpires": "2025-12-11T15:30:00Z",
+ "refreshTokenExpires": "2026-01-11T13:00:00Z"
+ }
+
+
+ @userConfig.GetText("missing_refresh_token"):
+
+
+curl --request POST \
+ --url https://localhost:8888/api/AuthenticationToken/Refresh/ \
+ --header 'content-type: application/json' \
+ --data '{}'
+
+
+ @userConfig.GetText("response") (400 Bad Request):
+
+
+ Refresh token is required
+
+
+ @userConfig.GetText("invalid_refresh_token"):
+
+
+curl --request POST \
+ --url https://localhost:8888/api/AuthenticationToken/Refresh/ \
+ --header 'content-type: application/json' \
+ --data '{"RefreshToken": "invalid-or-expired-token"}'
+
+
+ @userConfig.GetText("response") (401 Unauthorized):
+
+
+ Invalid or expired refresh token
+
+
+ @userConfig.GetText("token_revoke")
+
+ @userConfig.GetText("token_revoke_success"):
+
+
+curl --request POST \
+ --url https://localhost:8888/api/AuthenticationToken/Revoke/ \
+ --header 'content-type: application/json' \
+ --data '{"RefreshToken": "a7f3c8b9e2d1..."}'
+
+
+ @userConfig.GetText("response") (200 OK):
+
+
+ (Empty response body indicating success)
+
+
+ @userConfig.GetText("missing_refresh_token"):
+
+curl --request POST \
+ --url https://localhost:8888/api/AuthenticationToken/Revoke/ \
+ --header 'content-type: application/json' \
+ --data '{}'
+
+
+ @userConfig.GetText("response") (400 Bad Request):
+
+
+ Refresh token is required
+
+
diff --git a/roles/ui/files/FWO.UI/Pages/Login.razor b/roles/ui/files/FWO.UI/Pages/Login.razor
index f29f51cac3..1969d4a94f 100644
--- a/roles/ui/files/FWO.UI/Pages/Login.razor
+++ b/roles/ui/files/FWO.UI/Pages/Login.razor
@@ -19,8 +19,8 @@
@inject GlobalConfig globalConfig
@inject CircuitHandler circuitHandler
-@if (showLoginForm)
-{
+@if(showLoginForm)
+{
@@ -32,8 +32,8 @@
{

}
-
- @*
@(userConfig.GetText("login"))
*@
+
+ @*
@(userConfig.GetText("login"))
*@
@if(ShowWelcomeMessage)
{
-
+
- }
+ }
}
-@if (showPasswordChangeForm)
+@if(showPasswordChangeForm)
{
@(userConfig.GetText("change_password"))
@@ -91,7 +91,7 @@
- @if (passwordChangeInProgress == false)
+ @if(passwordChangeInProgress == false)
{
}
@@ -137,27 +137,35 @@
//ApiConnection.Dispose();
//ApiConnection = new GraphQlApiConnection(ConfigFile.ApiServerUri);
- if (firstRender)
- {
+ if(firstRender)
+ {
// This might be a reconnect. Check if there is a jwt in session storage.
- ProtectedBrowserStorageResult
jwtLoadRequest = await sessionStorage.GetAsync("jwt");
+ ProtectedBrowserStorageResult jwtLoadRequest = await sessionStorage.GetAsync("token_pair");
- if (jwtLoadRequest.Success) // reconnect
+ if(jwtLoadRequest.Success) // reconnect
{
try
{
- await ((AuthStateProvider)AuthService).Authenticate(jwtLoadRequest.Value ?? throw new AccessViolationException("Jwt from protected storage is null"),
- ApiConnection, middlewareClient, globalConfig, userConfig, ((CircuitHandlerService)circuitHandler), sessionStorage);
- return;
+ if(jwtLoadRequest.Value?.AccessToken is not null)
+ {
+ await ((AuthStateProvider)AuthService)
+ .Authenticate(jwtLoadRequest.Value.AccessToken, ApiConnection, middlewareClient, globalConfig, userConfig, ((CircuitHandlerService)circuitHandler));
+
+ return;
+ }
+ else
+ {
+ Log.WriteError("Session Restore", "Session restore unsuccessful. Jwt from protected storage is null.");
+ }
}
- catch (Exception ex) { Log.WriteError("Session Restore", "Session restore unsuccessful.", ex); }
+ catch(Exception ex) { Log.WriteError("Session Restore", "Session restore unsuccessful.", ex); }
}
if(!string.IsNullOrWhiteSpace(globalConfig.WelcomeMessage))
{
SanitizedWelcomeMessage = globalConfig.WelcomeMessage.StripDangerousHtmlTags().Replace("\n", "
");
ShowWelcomeMessage = true;
- }
+ }
// else no reconnect / reconnect unsuccessful
showLoginForm = true;
@@ -199,18 +207,18 @@
private async Task LoginSubmit()
{
- if (loginInProgress == false)
+ if(!loginInProgress)
{
loginInProgress = true;
try
{
- RestResponse authResponse = await ((AuthStateProvider)AuthService)
- .Authenticate(Username, Password, ApiConnection, middlewareClient, globalConfig, userConfig, sessionStorage, ((CircuitHandlerService)circuitHandler));
+ RestResponse authResponse = await ((AuthStateProvider)AuthService)
+ .Authenticate(Username, Password, ApiConnection, middlewareClient, globalConfig, userConfig, ((CircuitHandlerService)circuitHandler));
- if (authResponse.StatusCode == HttpStatusCode.OK)
+ if(authResponse.StatusCode == HttpStatusCode.OK)
{
- if (userConfig.User.PasswordMustBeChanged)
+ if(userConfig.User.PasswordMustBeChanged)
{
showLoginForm = false;
showPasswordChangeForm = true;
@@ -220,10 +228,10 @@
else
{
// There was an error trying to authenticate the user. Probably invalid credentials or the middleware server is unreachable
- if(authResponse.Data != null)
+ if(authResponse.Content != null)
{
// Probably invalid credentials
- errorMessage = userConfig.GetApiText(authResponse.Data);
+ errorMessage = userConfig.GetApiText(authResponse.Content);
// Visualisize the error by making border of all inputboxes red
InputClass = "is-invalid";
Log.WriteInfo("Login", $"Login of user {Username} failed: " + errorMessage);
@@ -239,13 +247,13 @@
StateHasChanged();
}
}
- // Authentication exception (raised by us)
- catch (AuthenticationException e)
+ // Authentication exception (raised by us)
+ catch(AuthenticationException e)
{
errorMessage = userConfig.GetText(e.Message);
}
// Unknown exception
- catch (Exception exception)
+ catch(Exception exception)
{
errorMessage = userConfig.GetText("E0012");
Log.WriteError("Login error", $"An unexpected exception was thrown during the log in process for user: \"{Username}\".", exception);
@@ -257,7 +265,7 @@
private async Task focusInput()
{
- if (showLoginForm)
+ if(showLoginForm)
{
await usernameInput.FocusAsync();
}
@@ -265,20 +273,20 @@
private async Task ChangePassword()
{
- if (passwordChangeInProgress == false)
+ if(!passwordChangeInProgress)
{
passwordChangeInProgress = true;
try
{
chgPwErrorMessage = await (new PasswordChanger(middlewareClient)).ChangePassword(oldPassword, newPassword1, newPassword2, userConfig, globalConfig);
- if (chgPwErrorMessage == "")
+ if(chgPwErrorMessage == "")
{
showPasswordChangeForm = false;
((AuthStateProvider)AuthService).ConfirmPasswordChanged();
Log.WriteAudit("ChangePassword", $"user {Username} successfully changed password");
}
}
- catch (Exception exception)
+ catch(Exception exception)
{
chgPwErrorMessage = exception.Message;
}
diff --git a/roles/ui/files/FWO.UI/Pages/Logout.razor b/roles/ui/files/FWO.UI/Pages/Logout.razor
index 9c46b76e7d..aaeb87d292 100644
--- a/roles/ui/files/FWO.UI/Pages/Logout.razor
+++ b/roles/ui/files/FWO.UI/Pages/Logout.razor
@@ -20,15 +20,12 @@
{
protected override async Task OnAfterRenderAsync(bool firstRender)
{
+ await ((AuthStateProvider)AuthService).Deauthenticate();
+
// Dispose unmanaged ressources
apiConnection.Dispose();
middlewareClient.Dispose();
- // Clear the jwt and deauthenticate
- await sessionStorage.DeleteAsync("jwt");
- ((AuthStateProvider)AuthService).Deauthenticate();
- JwtEventService.RemoveJwtTimers(userConfig.User.Dn);
-
// Write an audit log that the user logged out
UiUser user = userConfig.User;
Log.WriteAudit($"Logout", $"User \"{user.Name}\" with DN: \"{user.Dn}\" logged out.");
diff --git a/roles/ui/files/FWO.UI/Pages/Settings/SettingsDefaults.razor b/roles/ui/files/FWO.UI/Pages/Settings/SettingsDefaults.razor
index b211725e37..f5651d6113 100644
--- a/roles/ui/files/FWO.UI/Pages/Settings/SettingsDefaults.razor
+++ b/roles/ui/files/FWO.UI/Pages/Settings/SettingsDefaults.razor
@@ -175,7 +175,7 @@
+ ElementToString="@(o => userConfig.GetText(o.ToString()))" Elements="Enum.GetValues(typeof(RuleOwnershipMode)).Cast()">
@(userConfig.GetText(opt.ToString()))
@@ -186,7 +186,7 @@