121 lines
4.1 KiB
C#
121 lines
4.1 KiB
C#
using FinalFactory.Rendezvous.Contracts;
|
|
|
|
namespace FinalFactory.Rendezvous.Server.Provisioning;
|
|
|
|
internal sealed class ProvisioningRuntime : IDisposable
|
|
{
|
|
private readonly IDisposable? _secretProviderLifetime;
|
|
|
|
private ProvisioningRuntime(
|
|
GamePolicyRegistry policies,
|
|
SigningKeyRing signingKeys,
|
|
PrincipalCredentialService credentials,
|
|
PublisherAuthorizationService publisherAuthorization,
|
|
IDisposable? secretProviderLifetime)
|
|
{
|
|
Policies = policies;
|
|
SigningKeys = signingKeys;
|
|
Credentials = credentials;
|
|
PublisherAuthorization = publisherAuthorization;
|
|
_secretProviderLifetime = secretProviderLifetime;
|
|
}
|
|
|
|
public GamePolicyRegistry Policies { get; }
|
|
public SigningKeyRing SigningKeys { get; }
|
|
public PrincipalCredentialService Credentials { get; }
|
|
public PublisherAuthorizationService PublisherAuthorization { get; }
|
|
|
|
public static ProvisioningRuntime Create(
|
|
ProvisioningOptions options,
|
|
ISecretProvider secretProvider,
|
|
DateTimeOffset now)
|
|
{
|
|
try
|
|
{
|
|
SigningKeyRing signingKeys = SigningKeyRing.Create(options.SigningKeys, secretProvider);
|
|
try
|
|
{
|
|
if (!signingKeys.HasKeys
|
|
|| !signingKeys.HasActiveSigningKey(now))
|
|
{
|
|
throw new ProvisioningConfigurationException(
|
|
"At least one active signing key with available production key material is required.");
|
|
}
|
|
|
|
GamePolicyRegistry policies = GamePolicyRegistry.Create(options.Games);
|
|
if (!policies.HasEnabledPolicies)
|
|
{
|
|
throw new ProvisioningConfigurationException(
|
|
"At least one enabled game/environment policy is required.");
|
|
}
|
|
|
|
foreach (GamePolicy policy in policies.EnabledPolicies)
|
|
{
|
|
RequirePublisherKey(
|
|
signingKeys,
|
|
policy,
|
|
PublisherTrustMode.ManagedDedicated,
|
|
PrincipalCredentialKind.DedicatedPublisher,
|
|
now);
|
|
RequirePublisherKey(
|
|
signingKeys,
|
|
policy,
|
|
PublisherTrustMode.PlayerGrant,
|
|
PrincipalCredentialKind.PlayerHostGrant,
|
|
now);
|
|
}
|
|
|
|
PrincipalCredentialService credentials = new(
|
|
options.Issuer,
|
|
options.Audience,
|
|
TimeSpan.FromSeconds(options.ClockSkewSeconds),
|
|
signingKeys);
|
|
PublisherAuthorizationService authorization = new(policies);
|
|
return new ProvisioningRuntime(
|
|
policies,
|
|
signingKeys,
|
|
credentials,
|
|
authorization,
|
|
secretProvider as IDisposable);
|
|
}
|
|
catch
|
|
{
|
|
signingKeys.Dispose();
|
|
throw;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
(secretProvider as IDisposable)?.Dispose();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
SigningKeys.Dispose();
|
|
_secretProviderLifetime?.Dispose();
|
|
}
|
|
|
|
private static void RequirePublisherKey(
|
|
SigningKeyRing signingKeys,
|
|
GamePolicy policy,
|
|
PublisherTrustMode trustMode,
|
|
PrincipalCredentialKind credentialKind,
|
|
DateTimeOffset now)
|
|
{
|
|
if (policy.AllowsPublisherTrust(trustMode)
|
|
&& !signingKeys.HasActiveSigningKey(
|
|
now,
|
|
credentialKind,
|
|
policy.GameId.ToString(),
|
|
policy.EnvironmentId.ToString()))
|
|
{
|
|
throw new ProvisioningConfigurationException(
|
|
$"Policy {policy.GameId}/{policy.EnvironmentId} has no active {credentialKind} key.");
|
|
}
|
|
}
|
|
}
|
|
|
|
internal sealed record ProvisioningReadiness(bool IsReady);
|