public async Task AuthorizeKeyAsync()

in sources/Google.Solutions.IapDesktop.Extensions.Session/Protocol/Ssh/MetadataAuthorizedPublicKeyProcessor.cs [321:470]


        public async Task<PlatformCredential> AuthorizeKeyAsync(
            IAsymmetricKeySigner key,
            TimeSpan validity,
            string username,
            KeyAuthorizationMethods allowedMethods,
            IAuthorization authorization,
            CancellationToken cancellationToken)
        {
            key.ExpectNotNull(nameof(key));
            username.ExpectNotNull(nameof(username));

            Debug.Assert(!this.IsOsLoginEnabled);

            var instanceMetadata = this.instanceDetails.Metadata;
            var projectMetadata = this.projectDetails.CommonInstanceMetadata;

            //
            // Check if there is a legacy SSH key. If there is one,
            // other keys are ignored.
            //
            // NB. legacy SSH keys were instance-only, so checking
            // the instance metadata is sufficient.
            //
            if (this.IsLegacySshKeyPresent)
            {
                throw new UnsupportedLegacySshKeyEncounteredException(
                    $"Connecting to the VM instance {this.instance.Name} is not supported " +
                    "because the instance uses legacy SSH keys in its metadata (sshKeys)",
                    HelpTopics.ManagingMetadataAuthorizedKeys);
            }

            //
            // There is no legacy key, so we're good to push a new key.
            // 
            // Now figure out which username to use and where to push it.
            //
            var blockProjectSshKeys = this.AreProjectSshKeysBlocked;

            bool useInstanceKeySet;
            if (allowedMethods.HasFlag(KeyAuthorizationMethods.ProjectMetadata) &&
                allowedMethods.HasFlag(KeyAuthorizationMethods.InstanceMetadata))
            {
                //
                // Both allowed - use project metadata unless:
                // - project keys are blocked
                // - we do not have the permission to update project metadata.
                //
                var canUpdateProjectMetadata = await this.resourceManagerAdapter
                    .IsAccessGrantedAsync(
                        this.instance.Project,
                        new[] {
                            Permissions.ComputeProjectsSetCommonInstanceMetadata,
                            Permissions.ServiceAccountsActAs
                        },
                        cancellationToken)
                    .ConfigureAwait(false);

                useInstanceKeySet = blockProjectSshKeys || !canUpdateProjectMetadata;
            }
            else if (allowedMethods.HasFlag(KeyAuthorizationMethods.ProjectMetadata))
            {
                // Only project allowed.
                if (blockProjectSshKeys)
                {
                    throw new InvalidOperationException(
                        $"Project {this.instance.ProjectId} does not allow project-level SSH keys");
                }
                else
                {
                    useInstanceKeySet = false;
                }
            }
            else if (allowedMethods.HasFlag(KeyAuthorizationMethods.InstanceMetadata))
            {
                // Only instance allowed.
                useInstanceKeySet = true;
            }
            else
            {
                // Neither project nor instance allowed.
                throw new ArgumentException(nameof(allowedMethods));
            }

            var metadataKey = new ManagedMetadataAuthorizedPublicKey(
                username,
                key.PublicKey.Type,
                Convert.ToBase64String(key.PublicKey.WireFormatValue),
                new ManagedMetadataAuthorizedPublicKey.PublicKeyMetadata(
                    authorization.Session.Username,
                    DateTime.UtcNow.Add(validity)));

            var existingKeySet = MetadataAuthorizedPublicKeySet.FromMetadata(
                useInstanceKeySet
                    ? instanceMetadata
                    : projectMetadata);

            if (existingKeySet
                .RemoveExpiredKeys()
                .Contains(metadataKey))
            {
                //
                // The key is there already, so we are all set.
                //
                ApplicationTraceSource.Log.TraceVerbose(
                    "Existing SSH key found for {0}",
                    username);
            }
            else
            {
                //
                // Key not known yet, so we have to push it to
                // the metadata.
                //
                ApplicationTraceSource.Log.TraceVerbose(
                    "Pushing new SSH key for {0}",
                    username);

                await ModifyMetadataAndHandleErrorsAsync(
                    async token =>
                    {
                        if (useInstanceKeySet)
                        {
                            await this.computeClient
                                .UpdateMetadataAsync(
                                    this.instance,
                                    metadata => AddPublicKeyToMetadata(metadata, metadataKey),
                                    token)
                                .ConfigureAwait(false);
                        }
                        else
                        {
                            await this.computeClient
                                .UpdateCommonInstanceMetadataAsync(
                                    this.instance.Project,
                                    metadata => AddPublicKeyToMetadata(metadata, metadataKey),
                                    token)
                               .ConfigureAwait(false);
                        }
                    },
                    cancellationToken)
                .ConfigureAwait(false);
            }

            return new PlatformCredential(
                key,
                useInstanceKeySet
                    ? KeyAuthorizationMethods.InstanceMetadata
                    : KeyAuthorizationMethods.ProjectMetadata,
                username);
        }