Use connections for use OAuth and Oidc connections

This commit is contained in:
Jordan Dominion
2025-08-16 13:38:22 -04:00
parent 9f2eb153db
commit 05f6303f16
9 changed files with 50 additions and 32 deletions
@@ -4,8 +4,10 @@ mutation CreateUserWithPasswordSelectOAuthConnections($name: String!, $password:
id
user {
oAuthConnections {
externalUserId
provider
nodes {
externalUserId
provider
}
}
}
}
@@ -11,8 +11,10 @@ mutation SetUserOAuthConnections($id: ID!, $newOAuthConnections: [OAuthConnectio
name
systemIdentifier
oAuthConnections {
externalUserId
provider
nodes {
externalUserId
provider
}
}
}
}
@@ -4,8 +4,10 @@ mutation UpdateUserOAuthConnections($id: ID!, $newOAuthConnections: [OAuthConnec
id
user {
oAuthConnections {
externalUserId
provider
nodes {
externalUserId
provider
}
}
}
}
@@ -27,7 +27,7 @@ query GetSomeGroupInfo($id: ID!) {
canWriteUsers
}
}
queryableUsersByGroup(first: 1) {
users(first: 1) {
totalCount
nodes {
id
@@ -13,8 +13,10 @@ query ReadCurrentUser {
name
}
oAuthConnections {
externalUserId
provider
nodes {
externalUserId
provider
}
}
effectivePermissionSet {
administrationRights {
@@ -42,20 +42,20 @@ namespace Tgstation.Server.Host.Authority
where TResult : class;
/// <summary>
/// Gets the <see cref="GraphQL.Types.OAuth.OAuthConnection"/>s for the <see cref="User"/> with a given <paramref name="userId"/>.
/// Gets the <see cref="Models.OAuthConnection"/>s for the <see cref="User"/> with a given <paramref name="userId"/>.
/// </summary>
/// <param name="userId">The <see cref="EntityId.Id"/> of the <see cref="User"/>.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="RequirementsGated{TResult}"/> <see cref="global::System.Array"/> of <see cref="GraphQL.Types.OAuth.OAuthConnection"/> <see cref="AuthorityResponse{TResult}"/>.</returns>
RequirementsGated<AuthorityResponse<GraphQL.Types.OAuth.OAuthConnection[]>> OAuthConnections(long userId, CancellationToken cancellationToken);
/// <returns>A <see cref="RequirementsGated{TResult}"/> <see cref="global::System.Array"/> of <see cref="Models.OAuthConnection"/> <see cref="AuthorityResponse{TResult}"/>.</returns>
RequirementsGated<IQueryable<Models.OAuthConnection>> OAuthConnections(long userId, CancellationToken cancellationToken);
/// <summary>
/// Gets the <see cref="GraphQL.Types.OAuth.OidcConnection"/>s for the <see cref="User"/> with a given <paramref name="userId"/>.
/// Gets the <see cref="Models.OidcConnection"/>s for the <see cref="User"/> with a given <paramref name="userId"/>.
/// </summary>
/// <param name="userId">The <see cref="EntityId.Id"/> of the <see cref="User"/>.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="RequirementsGated{TResult}"/> <see cref="global::System.Array"/> of <see cref="GraphQL.Types.OAuth.OidcConnection"/> <see cref="AuthorityResponse{TResult}"/>.</returns>
RequirementsGated<AuthorityResponse<GraphQL.Types.OAuth.OidcConnection[]>> OidcConnections(long userId, CancellationToken cancellationToken);
/// <returns>A <see cref="RequirementsGated{TResult}"/> <see cref="global::System.Array"/> of <see cref="Models.OidcConnection"/> <see cref="AuthorityResponse{TResult}"/>.</returns>
RequirementsGated<IQueryable<Models.OidcConnection>> OidcConnections(long userId, CancellationToken cancellationToken);
/// <summary>
/// Gets all registered <see cref="User"/>s.
@@ -333,22 +333,24 @@ namespace Tgstation.Server.Host.Authority
() => ValueTask.FromResult(Queryable(includeJoins, false)));
/// <inheritdoc />
public RequirementsGated<AuthorityResponse<GraphQL.Types.OAuth.OAuthConnection[]>> OAuthConnections(long userId, CancellationToken cancellationToken)
public RequirementsGated<IQueryable<Models.OAuthConnection>> OAuthConnections(long userId, CancellationToken cancellationToken)
=> new(
() => claimsPrincipalAccessor.User.GetTgsUserId() != userId
? Flag(AdministrationRights.ReadUsers)
: null,
async () => new AuthorityResponse<GraphQL.Types.OAuth.OAuthConnection[]>(
await oAuthConnectionsDataLoader.LoadRequiredAsync(userId, cancellationToken)));
() => Queryable(true, true)
.SelectMany(user => user.OAuthConnections!)
.TagWith("Get User OAuthConnections"));
/// <inheritdoc />
public RequirementsGated<AuthorityResponse<GraphQL.Types.OAuth.OidcConnection[]>> OidcConnections(long userId, CancellationToken cancellationToken)
public RequirementsGated<IQueryable<Models.OidcConnection>> OidcConnections(long userId, CancellationToken cancellationToken)
=> new(
() => claimsPrincipalAccessor.User.GetTgsUserId() != userId
? Flag(AdministrationRights.ReadUsers)
: null,
async () => new AuthorityResponse<GraphQL.Types.OAuth.OidcConnection[]>(
await oidcConnectionsDataLoader.LoadRequiredAsync(userId, cancellationToken)));
() => Queryable(true, true)
.SelectMany(user => user.OidcConnections!)
.TagWith("Get User OIdcConnections"));
/// <inheritdoc />
#pragma warning disable CA1506 // TODO: Decomplexify
@@ -65,7 +65,7 @@ namespace Tgstation.Server.Host.GraphQL.Types
/// </summary>
public required PermissionSet EffectivePermissionSet { get; set; }
/// <summary>
/// <summary>
/// The <see cref="PermissionSet"/> for the user if the user does not belong to a <see cref="Group"/>.
/// </summary>
public required PermissionSet? OwnedPermissionSet { get; set; }
@@ -145,12 +145,16 @@ namespace Tgstation.Server.Host.GraphQL.Types
/// <param name="userAuthority">The <see cref="IGraphQLAuthorityInvoker{TAuthority}"/> for the <see cref="IUserAuthority"/>.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in a new <see cref="Array"/> of <see cref="OAuthConnection"/>s for the <see cref="User"/> if OAuth is configured.</returns>
public ValueTask<OAuthConnection[]> OAuthConnections(
[UsePaging]
[UseProjection]
[UseFiltering]
[UseSorting]
public ValueTask<IQueryable<OAuthConnection>> OAuthConnections(
[Service] IGraphQLAuthorityInvoker<IUserAuthority> userAuthority,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(userAuthority);
return userAuthority.Invoke<OAuthConnection[], OAuthConnection[]>(
return userAuthority.InvokeTransformableQueryable<Models.OAuthConnection, OAuthConnection, OAuthConnectionGraphQLTransformer>(
authority => authority.OAuthConnections(Id, cancellationToken));
}
@@ -160,12 +164,16 @@ namespace Tgstation.Server.Host.GraphQL.Types
/// <param name="userAuthority">The <see cref="IGraphQLAuthorityInvoker{TAuthority}"/> for the <see cref="IUserAuthority"/>.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in a new <see cref="Array"/> of <see cref="OidcConnection"/>s for the <see cref="User"/> if OAuth is configured.</returns>
public ValueTask<OidcConnection[]> OidcConnections(
[UsePaging]
[UseProjection]
[UseFiltering]
[UseSorting]
public ValueTask<IQueryable<OidcConnection>> OidcConnections(
[Service] IGraphQLAuthorityInvoker<IUserAuthority> userAuthority,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(userAuthority);
return userAuthority.Invoke<OidcConnection[], OidcConnection[]>(
return userAuthority.InvokeTransformableQueryable<Models.OidcConnection, OidcConnection, OidcConnectionGraphQLTransformer>(
authority => authority.OidcConnections(Id, cancellationToken));
}
}
@@ -308,9 +308,9 @@ namespace Tgstation.Server.Tests.Live
var testUser = testUserResult2.UpdatedUser.User;
Assert.IsNotNull(testUser.OAuthConnections);
Assert.AreEqual(1, testUser.OAuthConnections.Count);
Assert.AreEqual(sampleOAuthConnections.First().ExternalUserId, testUser.OAuthConnections[0].ExternalUserId);
Assert.AreEqual(sampleOAuthConnections.First().Provider, testUser.OAuthConnections[0].Provider);
Assert.AreEqual(1, testUser.OAuthConnections.Nodes.Count);
Assert.AreEqual(sampleOAuthConnections.First().ExternalUserId, testUser.OAuthConnections.Nodes[0].ExternalUserId);
Assert.AreEqual(sampleOAuthConnections.First().Provider, testUser.OAuthConnections.Nodes[0].Provider);
var groupResult = await client.RunMutationEnsureNoErrors(
gql => gql.CreateUserGroup.ExecuteAsync("TestGroup", cancellationToken),
@@ -471,9 +471,9 @@ namespace Tgstation.Server.Tests.Live
cancellationToken);
var group4 = group4Result.Swarm.UserGroups.ById;
Assert.IsNotNull(group4.QueryableUsersByGroup.Nodes);
Assert.AreEqual(1, group4.QueryableUsersByGroup.TotalCount);
Assert.AreEqual(testUser2.Id, group4.QueryableUsersByGroup.Nodes[0].Id);
Assert.IsNotNull(group4.Users.Nodes);
Assert.AreEqual(1, group4.Users.TotalCount);
Assert.AreEqual(testUser2.Id, group4.Users.Nodes[0].Id);
Assert.IsNotNull(group4.PermissionSet);
var testUser4Result = await client.RunMutationEnsureNoErrors(