protected virtual async ValueTask <WsTrustSecurityTokenDescriptor> CreateSecurityTokenDescriptorAsync(WsTrustRequest request, Scope scope, CancellationToken cancellationToken)
        {
            var lifetime   = CreateTokenLifetime(request?.Lifetime, scope);
            var descriptor = new WsTrustSecurityTokenDescriptor
            {
                Audience                      = scope.RelyingParty.AppliesTo,
                IssuedAt                      = lifetime.Created,
                Expires                       = lifetime.Expires,
                Issuer                        = scope.RelyingParty.ExpectedIssuer ?? Options.Issuer,
                SigningCredentials            = scope.SigningCredentials,
                EncryptingCredentials         = scope.RelyingParty.RequiresEncryptedToken ? scope.EncryptingCredentials : null,
                ProofKeyEncryptingCredentials = scope.RelyingParty.RequiresEncryptedSymmetricKeys ? scope.EncryptingCredentials : null,
                TokenType                     = request.TokenType
            };

            if (lifetime.Created != null)
            {
                descriptor.NotBefore = lifetime.Created.Value.Subtract(scope.RelyingParty.ClockSkew ?? Options.MaxClockSkew);
            }

            var requestorProofEncryptingCredentials = await GetRequestorProofEncryptingCredentialsAsync(request, cancellationToken);

            if (requestorProofEncryptingCredentials != null)
            {
                descriptor.ProofKeyEncryptingCredentials = requestorProofEncryptingCredentials;
            }
            descriptor.ProofKey = await CreateProofKeyAsync(request, scope, descriptor, cancellationToken);

            return(descriptor);
        }
        protected virtual async ValueTask <SecurityKey> CreateProofKeyAsync(WsTrustRequest request, Scope scope, WsTrustSecurityTokenDescriptor descriptor, CancellationToken cancellationToken)
        {
            var keyType = request.KeyType;

            // asymmetric and psha1
            // not supported at this moment
            if (keyType == Constants.WsTrustKeyTypes.PublicKey || keyType == Constants.WsTrustKeyTypes.PSHA1)
            {
                throw new NotSupportedException($"Key type '{keyType}' not supported at this time.");
            }

            if (keyType == Constants.WsTrustKeyTypes.Bearer)
            {
                return(null);
            }

            // symmetric
            if (request.ComputedKeyAlgorithm != null && request.ComputedKeyAlgorithm != "http://schemas.microsoft.com/idfx/computedkeyalgorithm/psha1")
            {
                throw new NotSupportedException($"Computed key algortihm '{request.ComputedKeyAlgorithm}' not supported at this time.");
            }

            if (descriptor.ProofKeyEncryptingCredentials == null && scope.RelyingParty.RequiresEncryptedSymmetricKeys)
            {
                throw new InvalidOperationException("Cannot created proof token with no encrypting credentials.");
            }

            if (scope.EncryptingCredentials == null && scope.RelyingParty.RequiresEncryptedToken)
            {
                throw new InvalidOperationException("Missing encrypting credentials.");
            }

            return(await CreateSymmetricProofKeyAsync(request.KeySizeInBits.Value));
        }
        protected virtual async ValueTask <WsTrustResponse> CreateResponseAsync(WsTrustRequest request, WsTrustSecurityTokenDescriptor descriptor, CancellationToken cancellationToken)
        {
            if (descriptor == null)
            {
                return(null);
            }

            var response = new RequestSecurityTokenResponse();
            var handler  = await GetSecurityTokenHandlerAsync(request.TokenType, cancellationToken);

            try
            {
                var attached = handler.CreateSecurityTokenReference(descriptor.Token, true);
                if (attached is WsSecuritySecurityKeyIdentifierClause attachedClause)
                {
                    descriptor.AttachedReference = attachedClause.CreateReference();
                }

                var unattached = handler.CreateSecurityTokenReference(descriptor.Token, false);
                if (unattached is WsSecuritySecurityKeyIdentifierClause unattachedClause)
                {
                    descriptor.UnattachedReference = unattachedClause.CreateReference();
                }
            }
            catch { }

            descriptor.ApplyTo(response);

            if (!string.IsNullOrEmpty(request.Context))
            {
                response.Context = request.Context;
            }

            if (!string.IsNullOrEmpty(request.KeyType))
            {
                response.KeyType = request.KeyType;
            }

            if (request.KeySizeInBits > 0 && IsSupportedAsymmetricKeyType(request.KeyType))
            {
                response.KeySizeInBits = request.KeySizeInBits;
            }

            // no replyto
            //if (request.ReplyTo != null)
            //    response.ReplyTo = descriptor.ReplyToAddress;

            if (!string.IsNullOrEmpty(descriptor.Audience))
            {
                response.AppliesTo = new AppliesTo(new EndpointReference(descriptor.Audience));
            }

            var proofToken = await CreateRequestedProofTokenAsync(descriptor, cancellationToken);

            if (proofToken != null)
            {
                response.RequestedProofToken = proofToken;
            }

            return(new WsTrustResponse(response));
        }
        protected virtual ValueTask <RequestedProofToken> CreateRequestedProofTokenAsync(WsTrustSecurityTokenDescriptor descriptor, CancellationToken cancellationToken)
        {
            if (descriptor.ProofKey == null)
            {
                return(new ValueTask <RequestedProofToken>());
            }
            if (!(descriptor.ProofKey is SymmetricSecurityKey symmetric))
            {
                throw new NotSupportedException($"Asymmetric proof keys not supported for now.");
            }

            // The microsoft ws-trust serializer can't handle encrypted RequestedProofToken. Hard code unencrypted for now.
            var secret = new BinarySecret(symmetric.Key, Constants.WsTrustKeyTypes.Symmetric);

            return(new ValueTask <RequestedProofToken>(new RequestedProofToken(secret)));
        }
 protected virtual ValueTask <SecurityToken> CreateSecurityTokenAsync(Scope scope, WsTrustRequest request, WsTrustSecurityTokenDescriptor descriptor, SecurityTokenHandler handler, CancellationToken cancellationToken)
 => new ValueTask <SecurityToken>(handler.CreateToken(descriptor));