2026-02-20 17:35:38 +01:00
|
|
|
using System.Security.Cryptography;
|
|
|
|
|
using IdentityShroud.Core.Contracts;
|
|
|
|
|
using IdentityShroud.Core.Model;
|
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
|
|
|
|
|
|
namespace IdentityShroud.Core.Services;
|
|
|
|
|
|
|
|
|
|
public class ClientService(
|
|
|
|
|
Db db,
|
|
|
|
|
IEncryptionService cryptor,
|
|
|
|
|
IClock clock) : IClientService
|
|
|
|
|
{
|
|
|
|
|
public async Task<Result<Client>> Create(Guid realmId, ClientCreateRequest request, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
Client client = new()
|
|
|
|
|
{
|
|
|
|
|
RealmId = realmId,
|
|
|
|
|
ClientId = request.ClientId,
|
|
|
|
|
Name = request.Name,
|
|
|
|
|
Description = request.Description,
|
|
|
|
|
SignatureAlgorithm = request.SignatureAlgorithm,
|
|
|
|
|
AllowClientCredentialsFlow = request.AllowClientCredentialsFlow ?? false,
|
|
|
|
|
CreatedAt = clock.UtcNow(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (client.AllowClientCredentialsFlow)
|
|
|
|
|
{
|
|
|
|
|
client.Secrets.Add(CreateSecret());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await db.AddAsync(client, ct);
|
|
|
|
|
await db.SaveChangesAsync(ct);
|
|
|
|
|
|
|
|
|
|
return client;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<Client?> GetByClientId(string clientId, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
return await db.Clients.FirstOrDefaultAsync(c => c.ClientId == clientId, ct);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-21 20:15:46 +01:00
|
|
|
public async Task<Client?> FindById(int id, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
return await db.Clients.FirstOrDefaultAsync(c => c.Id == id, ct);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-20 17:35:38 +01:00
|
|
|
private ClientSecret CreateSecret()
|
|
|
|
|
{
|
|
|
|
|
byte[] secret = RandomNumberGenerator.GetBytes(24);
|
|
|
|
|
|
|
|
|
|
return new ClientSecret()
|
|
|
|
|
{
|
|
|
|
|
CreatedAt = clock.UtcNow(),
|
|
|
|
|
SecretEncrypted = cryptor.Encrypt(secret),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|