mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-07-20 12:33:00 +01:00
Allow group ID claim name to be configurable
This commit is contained in:
@@ -357,14 +357,15 @@ Gateway auth simply allows the users to authenticate with the service using the
|
||||
```yml
|
||||
Security:
|
||||
OpenIDConnect:
|
||||
Example:
|
||||
Example: # Scheme key: Name of this OIDC scheme (public)
|
||||
Authority: "..." # This is the root of the URL containing the "/.well-known/openid-configuration" endpoint
|
||||
ClientId: "..."
|
||||
ClientSecret: "..."
|
||||
FriendlyName: "Example Provider" # Friendly name is how this provider is displayed in UIs
|
||||
ThemeColour: "#ff0000" # (Optional) Hex color code indicating the color used to theme UI elements relating to this provider
|
||||
ThemeIconUrl: "..." # (Optional) Public URL of an image that can be used to theme UI elements relating to this provider
|
||||
UsernameClaim: "preferred_username" # (Optional) Name of claim used to set TGS usernames upon registration. By default "preferred_username" is used. Only applies when using OidcStrictMode.
|
||||
FriendlyName: "Example Provider" # Friendly name is how this provider is displayed in UIs (public)
|
||||
ThemeColour: "#ff0000" # (Optional) Hex color code indicating the color used to theme UI elements relating to this provider (public)
|
||||
ThemeIconUrl: "..." # (Optional) Public URL of an image that can be used to theme UI elements relating to this provider (public)
|
||||
UsernameClaim: "preferred_username" # (Optional) Name of claim used to set TGS usernames upon registration. By default "preferred_username" is used. Only applies when using OidcStrictMode.
|
||||
GroupIdClaim: "tgstation-server-group-id" # (Options) Name of claim used to set TGS group ID upon logging in. By default "tgstation-server-group-id" is used. Only applies when using OidcStrictMode.
|
||||
```
|
||||
|
||||
- `Security:OidcStrictMode`: Boolean flag that, when `true`, disables password and OAuth logins, password changes, individual permission set assignment, and enables user registration using OpenID Connect providers. The claim name `tgstation-server-group-id` is used to dictate what TGS group users are registered to.
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<Import Project="WebpanelVersion.props" />
|
||||
<PropertyGroup>
|
||||
<TgsCoreVersion>6.15.2</TgsCoreVersion>
|
||||
<TgsConfigVersion>5.6.0</TgsConfigVersion>
|
||||
<TgsConfigVersion>5.7.0</TgsConfigVersion>
|
||||
<TgsRestVersion>10.13.0</TgsRestVersion>
|
||||
<TgsGraphQLVersion>0.6.0</TgsGraphQLVersion>
|
||||
<TgsCommonLibraryVersion>7.0.0</TgsCommonLibraryVersion>
|
||||
|
||||
@@ -9,6 +9,11 @@ namespace Tgstation.Server.Host.Configuration
|
||||
/// </summary>
|
||||
public sealed class OidcConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// The default value of <see cref="GroupIdClaim"/>.
|
||||
/// </summary>
|
||||
private const string DefaultGroupClaimName = "tgstation-server-group-id";
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Uri"/> containing the .well-known endpoint for the provider.
|
||||
/// </summary>
|
||||
@@ -48,5 +53,10 @@ namespace Tgstation.Server.Host.Configuration
|
||||
/// The name of the claim used to set the user's name.
|
||||
/// </summary>
|
||||
public string UsernameClaim { get; set; } = JwtRegisteredClaimNames.PreferredUsername;
|
||||
|
||||
/// <summary>
|
||||
/// Claim name used to set user groups in OIDC strict mode.
|
||||
/// </summary>
|
||||
public string GroupIdClaim { get; set; } = DefaultGroupClaimName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -916,6 +916,7 @@ namespace Tgstation.Server.Host.Core
|
||||
.ValidateOidcToken(
|
||||
context,
|
||||
configName,
|
||||
config.GroupIdClaim,
|
||||
context
|
||||
.HttpContext
|
||||
.RequestAborted);
|
||||
@@ -923,7 +924,7 @@ namespace Tgstation.Server.Host.Core
|
||||
if (securityConfiguration.OidcStrictMode)
|
||||
{
|
||||
options.GetClaimsFromUserInfoEndpoint = true;
|
||||
options.ClaimActions.MapUniqueJsonKey(AuthenticationContextFactory.TgsGroupIdClaimName, AuthenticationContextFactory.TgsGroupIdClaimName);
|
||||
options.ClaimActions.MapUniqueJsonKey(config.GroupIdClaim, config.GroupIdClaim);
|
||||
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
|
||||
{
|
||||
NameClaimType = config.UsernameClaim,
|
||||
|
||||
@@ -32,11 +32,6 @@ namespace Tgstation.Server.Host.Security
|
||||
/// </summary>
|
||||
public const string OpenIDConnectAuthenticationSchemePrefix = $"{OpenIdConnectDefaults.AuthenticationScheme}.";
|
||||
|
||||
/// <summary>
|
||||
/// Claim name used to set user groups in OIDC strict mode.
|
||||
/// </summary>
|
||||
public const string TgsGroupIdClaimName = "tgstation-server-group-id";
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IAuthenticationContext"/> the <see cref="AuthenticationContextFactory"/> created.
|
||||
/// </summary>
|
||||
@@ -233,7 +228,7 @@ namespace Tgstation.Server.Host.Security
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task ValidateOidcToken(RemoteAuthenticationContext<OpenIdConnectOptions> tokenValidatedContext, string schemeKey, CancellationToken cancellationToken)
|
||||
public async Task ValidateOidcToken(RemoteAuthenticationContext<OpenIdConnectOptions> tokenValidatedContext, string schemeKey, string groupIdClaimName, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(tokenValidatedContext);
|
||||
|
||||
@@ -270,7 +265,7 @@ namespace Tgstation.Server.Host.Security
|
||||
}
|
||||
else
|
||||
{
|
||||
var groupClaim = principal.FindFirst(TgsGroupIdClaimName);
|
||||
var groupClaim = principal.FindFirst(groupIdClaimName);
|
||||
long? groupId;
|
||||
if (groupClaim == default)
|
||||
groupId = null;
|
||||
@@ -278,7 +273,7 @@ namespace Tgstation.Server.Host.Security
|
||||
groupId = groupIdParsed;
|
||||
else
|
||||
{
|
||||
tokenValidatedContext.Fail($"User has non-numeric '{TgsGroupIdClaimName}' claim!");
|
||||
tokenValidatedContext.Fail($"User has non-numeric '{groupIdClaimName}' claim!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -291,7 +286,7 @@ namespace Tgstation.Server.Host.Security
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
: null;
|
||||
|
||||
var missingClaimError = $"User missing '{TgsGroupIdClaimName}' claim!";
|
||||
var missingClaimError = $"User missing '{groupIdClaimName}' claim!";
|
||||
if (connection == default)
|
||||
{
|
||||
var username = principal.Identity?.Name;
|
||||
@@ -311,11 +306,13 @@ namespace Tgstation.Server.Host.Security
|
||||
{
|
||||
tokenValidatedContext.Fail(
|
||||
groupId.HasValue
|
||||
? $"'{TgsGroupIdClaimName}' does not point to a valid group!"
|
||||
? $"'{groupIdClaimName}' does not point to a valid group!"
|
||||
: missingClaimError);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.LogInformation("Registering new user '{name}' via OIDC scheme '{scheme}'", username, schemeKey);
|
||||
|
||||
var tgsUser = await databaseContext
|
||||
.Users
|
||||
.GetTgsUser(
|
||||
@@ -353,6 +350,7 @@ namespace Tgstation.Server.Host.Security
|
||||
// group update
|
||||
if (group == null)
|
||||
{
|
||||
logger.LogDebug("User {id} attempted to login via OIDC scheme '{scheme}' but had no group ID claim ('{groupClaimName}') and will be disabled", user.Id, schemeKey, groupIdClaimName);
|
||||
user.PermissionSet = new PermissionSet
|
||||
{
|
||||
AdministrationRights = AdministrationRights.None,
|
||||
@@ -365,6 +363,7 @@ namespace Tgstation.Server.Host.Security
|
||||
return;
|
||||
}
|
||||
|
||||
logger.LogDebug("User {id} mapped to group {groupId} via OIDC login on scheme '{scheme}'", user.Id, groupId, schemeKey);
|
||||
user.Group = group;
|
||||
if (user.PermissionSet != null)
|
||||
databaseContext.PermissionSets.Remove(user.PermissionSet);
|
||||
|
||||
@@ -24,8 +24,9 @@ namespace Tgstation.Server.Host.Security
|
||||
/// </summary>
|
||||
/// <param name="tokenValidatedContext">The <see cref="RemoteAuthenticationContext{TOptions}"/> for <see cref="OpenIdConnectOptions"/>.</param>
|
||||
/// <param name="schemeKey">The scheme key being used to login.</param>
|
||||
/// <param name="groupIdClaimName">The name of the <see cref="global::System.Security.Claims.Claim"/> used to set the user's group ID.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
Task ValidateOidcToken(RemoteAuthenticationContext<OpenIdConnectOptions> tokenValidatedContext, string schemeKey, CancellationToken cancellationToken);
|
||||
Task ValidateOidcToken(RemoteAuthenticationContext<OpenIdConnectOptions> tokenValidatedContext, string schemeKey, string groupIdClaimName, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,16 @@ Security:
|
||||
TGForums: # https://tgstation13.org OAuth configuration
|
||||
Keycloak: # Keycloak OAuth configuration.
|
||||
InvisionCommunity: # Invision Community OAuth configuration.
|
||||
# OpenIDConnect:
|
||||
# Example: # Scheme key: Name of this OIDC scheme (public)
|
||||
# Authority: "..." # This is the root of the URL containing the "/.well-known/openid-configuration" endpoint
|
||||
# ClientId: "..."
|
||||
# ClientSecret: "..."
|
||||
# FriendlyName: "Example Provider" # Friendly name is how this provider is displayed in UIs (public)
|
||||
# ThemeColour: "#ff0000" # (Optional) Hex color code indicating the color used to theme UI elements relating to this provider (public)
|
||||
# ThemeIconUrl: "..." # (Optional) Public URL of an image that can be used to theme UI elements relating to this provider (public)
|
||||
# UsernameClaim: "preferred_username" # (Optional) Name of claim used to set TGS usernames upon registration. By default "preferred_username" is used. Only applies when using OidcStrictMode.
|
||||
# GroupIdClaim: "tgstation-server-group-id" # (Options) Name of claim used to set TGS group ID upon logging in. By default "tgstation-server-group-id" is used. Only applies when using OidcStrictMode.
|
||||
Swarm: # Should be left empty if using swarm mode is not desired
|
||||
# Identifier: # Required: The string identifier of the swarm node
|
||||
# PrivateKey: # Required: The shared API key used for inter-server communication in the swarm. Must be the same secure string on all nodes
|
||||
|
||||
Reference in New Issue
Block a user