e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
370 lines
16 KiB
C#
370 lines
16 KiB
C#
//------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
namespace System.ServiceModel
|
|
{
|
|
using System.Collections.ObjectModel;
|
|
using System.IdentityModel.Tokens;
|
|
using System.Runtime;
|
|
using System.Runtime.CompilerServices;
|
|
using System.ServiceModel.Channels;
|
|
using System.ServiceModel.Security;
|
|
using System.ServiceModel.Security.Tokens;
|
|
using System.Xml;
|
|
using System.ComponentModel;
|
|
|
|
public sealed class FederatedMessageSecurityOverHttp
|
|
{
|
|
internal const bool DefaultNegotiateServiceCredential = true;
|
|
internal const SecurityKeyType DefaultIssuedKeyType = SecurityKeyType.SymmetricKey;
|
|
internal const bool DefaultEstablishSecurityContext = true;
|
|
|
|
bool establishSecurityContext;
|
|
bool negotiateServiceCredential;
|
|
SecurityAlgorithmSuite algorithmSuite;
|
|
EndpointAddress issuerAddress;
|
|
EndpointAddress issuerMetadataAddress;
|
|
Binding issuerBinding;
|
|
Collection<ClaimTypeRequirement> claimTypeRequirements;
|
|
string issuedTokenType;
|
|
SecurityKeyType issuedKeyType;
|
|
Collection<XmlElement> tokenRequestParameters;
|
|
|
|
public FederatedMessageSecurityOverHttp()
|
|
{
|
|
negotiateServiceCredential = DefaultNegotiateServiceCredential;
|
|
algorithmSuite = SecurityAlgorithmSuite.Default;
|
|
issuedKeyType = DefaultIssuedKeyType;
|
|
claimTypeRequirements = new Collection<ClaimTypeRequirement>();
|
|
tokenRequestParameters = new Collection<XmlElement>();
|
|
establishSecurityContext = DefaultEstablishSecurityContext;
|
|
}
|
|
|
|
public bool NegotiateServiceCredential
|
|
{
|
|
get { return this.negotiateServiceCredential; }
|
|
set { this.negotiateServiceCredential = value; }
|
|
}
|
|
|
|
public SecurityAlgorithmSuite AlgorithmSuite
|
|
{
|
|
get { return this.algorithmSuite; }
|
|
set
|
|
{
|
|
if (value == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
|
|
}
|
|
this.algorithmSuite = value;
|
|
}
|
|
}
|
|
|
|
public bool EstablishSecurityContext
|
|
{
|
|
get
|
|
{
|
|
return this.establishSecurityContext;
|
|
}
|
|
set
|
|
{
|
|
this.establishSecurityContext = value;
|
|
}
|
|
}
|
|
|
|
[DefaultValue(null)]
|
|
public EndpointAddress IssuerAddress
|
|
{
|
|
get { return this.issuerAddress; }
|
|
set { this.issuerAddress = value; }
|
|
}
|
|
|
|
[DefaultValue(null)]
|
|
public EndpointAddress IssuerMetadataAddress
|
|
{
|
|
get { return this.issuerMetadataAddress; }
|
|
set { this.issuerMetadataAddress = value; }
|
|
}
|
|
|
|
[DefaultValue(null)]
|
|
public Binding IssuerBinding
|
|
{
|
|
get
|
|
{
|
|
return this.issuerBinding;
|
|
}
|
|
set
|
|
{
|
|
this.issuerBinding = value;
|
|
}
|
|
}
|
|
|
|
[DefaultValue(null)]
|
|
public string IssuedTokenType
|
|
{
|
|
get { return this.issuedTokenType; }
|
|
set { this.issuedTokenType = value; }
|
|
}
|
|
|
|
public SecurityKeyType IssuedKeyType
|
|
{
|
|
get { return this.issuedKeyType; }
|
|
set
|
|
{
|
|
if (!SecurityKeyTypeHelper.IsDefined(value))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
|
|
}
|
|
this.issuedKeyType = value;
|
|
}
|
|
}
|
|
|
|
public Collection<ClaimTypeRequirement> ClaimTypeRequirements
|
|
{
|
|
get { return this.claimTypeRequirements; }
|
|
}
|
|
|
|
public Collection<XmlElement> TokenRequestParameters
|
|
{
|
|
get { return this.tokenRequestParameters; }
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
internal SecurityBindingElement CreateSecurityBindingElement(bool isSecureTransportMode,
|
|
bool isReliableSession,
|
|
MessageSecurityVersion version)
|
|
{
|
|
if ((this.IssuedKeyType == SecurityKeyType.BearerKey) &&
|
|
(version.TrustVersion == TrustVersion.WSTrustFeb2005))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.BearerKeyIncompatibleWithWSFederationHttpBinding)));
|
|
}
|
|
|
|
if (isReliableSession && !this.EstablishSecurityContext)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecureConversationRequiredByReliableSession)));
|
|
}
|
|
|
|
SecurityBindingElement result;
|
|
bool emitBspAttributes = true;
|
|
IssuedSecurityTokenParameters issuedParameters = new IssuedSecurityTokenParameters(this.IssuedTokenType, this.IssuerAddress, this.IssuerBinding);
|
|
issuedParameters.IssuerMetadataAddress = this.issuerMetadataAddress;
|
|
issuedParameters.KeyType = this.IssuedKeyType;
|
|
if (this.IssuedKeyType == SecurityKeyType.SymmetricKey)
|
|
{
|
|
issuedParameters.KeySize = this.AlgorithmSuite.DefaultSymmetricKeyLength;
|
|
}
|
|
else
|
|
{
|
|
issuedParameters.KeySize = 0;
|
|
}
|
|
foreach (ClaimTypeRequirement c in this.claimTypeRequirements)
|
|
{
|
|
issuedParameters.ClaimTypeRequirements.Add(c);
|
|
}
|
|
foreach (XmlElement p in this.TokenRequestParameters)
|
|
{
|
|
issuedParameters.AdditionalRequestParameters.Add(p);
|
|
}
|
|
WSSecurityTokenSerializer versionSpecificSerializer = new WSSecurityTokenSerializer(version.SecurityVersion,
|
|
version.TrustVersion,
|
|
version.SecureConversationVersion,
|
|
emitBspAttributes,
|
|
null, null, null);
|
|
SecurityStandardsManager versionSpecificStandardsManager = new SecurityStandardsManager(version, versionSpecificSerializer);
|
|
issuedParameters.AddAlgorithmParameters(this.AlgorithmSuite, versionSpecificStandardsManager, this.issuedKeyType);
|
|
|
|
SecurityBindingElement issuedTokenSecurity;
|
|
if (isSecureTransportMode)
|
|
{
|
|
issuedTokenSecurity = SecurityBindingElement.CreateIssuedTokenOverTransportBindingElement(issuedParameters);
|
|
}
|
|
else
|
|
{
|
|
if (negotiateServiceCredential)
|
|
{
|
|
// We should have passed 'true' as RequireCancelation to be consistent with other standard bindings.
|
|
// However, to limit the change for Orcas, we scope down to just newer version of WSSecurityPolicy.
|
|
issuedTokenSecurity = SecurityBindingElement.CreateIssuedTokenForSslBindingElement(issuedParameters, version.SecurityPolicyVersion != SecurityPolicyVersion.WSSecurityPolicy11);
|
|
}
|
|
else
|
|
{
|
|
issuedTokenSecurity = SecurityBindingElement.CreateIssuedTokenForCertificateBindingElement(issuedParameters);
|
|
}
|
|
}
|
|
|
|
issuedTokenSecurity.MessageSecurityVersion = version;
|
|
issuedTokenSecurity.DefaultAlgorithmSuite = this.AlgorithmSuite;
|
|
|
|
if (this.EstablishSecurityContext)
|
|
{
|
|
result = SecurityBindingElement.CreateSecureConversationBindingElement(issuedTokenSecurity, true);
|
|
}
|
|
else
|
|
{
|
|
result = issuedTokenSecurity;
|
|
}
|
|
|
|
result.MessageSecurityVersion = version;
|
|
result.DefaultAlgorithmSuite = this.AlgorithmSuite;
|
|
result.IncludeTimestamp = true;
|
|
|
|
if (!isReliableSession)
|
|
{
|
|
result.LocalServiceSettings.ReconnectTransportOnFailure = false;
|
|
result.LocalClientSettings.ReconnectTransportOnFailure = false;
|
|
}
|
|
else
|
|
{
|
|
result.LocalServiceSettings.ReconnectTransportOnFailure = true;
|
|
result.LocalClientSettings.ReconnectTransportOnFailure = true;
|
|
}
|
|
|
|
if (this.establishSecurityContext)
|
|
{
|
|
// issue the transition SCT for a short duration only
|
|
issuedTokenSecurity.LocalServiceSettings.IssuedCookieLifetime = SpnegoTokenAuthenticator.defaultServerIssuedTransitionTokenLifetime;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
internal static bool TryCreate(SecurityBindingElement sbe, bool isSecureTransportMode, bool isReliableSession, MessageSecurityVersion version, out FederatedMessageSecurityOverHttp messageSecurity)
|
|
{
|
|
Fx.Assert(null != sbe, string.Empty);
|
|
|
|
messageSecurity = null;
|
|
|
|
// do not check local settings: sbe.LocalServiceSettings and sbe.LocalClientSettings
|
|
|
|
if (!sbe.IncludeTimestamp)
|
|
return false;
|
|
|
|
if (sbe.SecurityHeaderLayout != SecurityProtocolFactory.defaultSecurityHeaderLayout)
|
|
return false;
|
|
|
|
bool emitBspAttributes = true;
|
|
|
|
// Do not check MessageSecurityVersion: it maybe changed by the wrapper element and gets checked later in the SecuritySection.AreBindingsMatching()
|
|
|
|
SecurityBindingElement bootstrapSecurity;
|
|
|
|
bool establishSecurityContext = SecurityBindingElement.IsSecureConversationBinding(sbe, true, out bootstrapSecurity);
|
|
bootstrapSecurity = establishSecurityContext ? bootstrapSecurity : sbe;
|
|
|
|
if (isSecureTransportMode && !(bootstrapSecurity is TransportSecurityBindingElement))
|
|
return false;
|
|
|
|
bool negotiateServiceCredential = DefaultNegotiateServiceCredential;
|
|
IssuedSecurityTokenParameters issuedTokenParameters;
|
|
|
|
if (isSecureTransportMode)
|
|
{
|
|
if (!SecurityBindingElement.IsIssuedTokenOverTransportBinding(bootstrapSecurity, out issuedTokenParameters))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// We should have passed 'true' as RequireCancelation to be consistent with other standard bindings.
|
|
// However, to limit the change for Orcas, we scope down to just newer version of WSSecurityPolicy.
|
|
if (SecurityBindingElement.IsIssuedTokenForSslBinding(bootstrapSecurity, version.SecurityPolicyVersion != SecurityPolicyVersion.WSSecurityPolicy11, out issuedTokenParameters))
|
|
negotiateServiceCredential = true;
|
|
else if (SecurityBindingElement.IsIssuedTokenForCertificateBinding(bootstrapSecurity, out issuedTokenParameters))
|
|
negotiateServiceCredential = false;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
if ((issuedTokenParameters.KeyType == SecurityKeyType.BearerKey) &&
|
|
(version.TrustVersion == TrustVersion.WSTrustFeb2005))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Collection<XmlElement> nonAlgorithmRequestParameters;
|
|
WSSecurityTokenSerializer versionSpecificSerializer = new WSSecurityTokenSerializer(version.SecurityVersion,
|
|
version.TrustVersion,
|
|
version.SecureConversationVersion,
|
|
emitBspAttributes,
|
|
null, null, null);
|
|
SecurityStandardsManager versionSpecificStandardsManager = new SecurityStandardsManager(version, versionSpecificSerializer);
|
|
|
|
if (!issuedTokenParameters.DoAlgorithmsMatch(sbe.DefaultAlgorithmSuite,
|
|
versionSpecificStandardsManager,
|
|
out nonAlgorithmRequestParameters))
|
|
{
|
|
return false;
|
|
}
|
|
messageSecurity = new FederatedMessageSecurityOverHttp();
|
|
|
|
messageSecurity.AlgorithmSuite = sbe.DefaultAlgorithmSuite;
|
|
messageSecurity.NegotiateServiceCredential = negotiateServiceCredential;
|
|
messageSecurity.EstablishSecurityContext = establishSecurityContext;
|
|
messageSecurity.IssuedTokenType = issuedTokenParameters.TokenType;
|
|
messageSecurity.IssuerAddress = issuedTokenParameters.IssuerAddress;
|
|
messageSecurity.IssuerBinding = issuedTokenParameters.IssuerBinding;
|
|
messageSecurity.IssuerMetadataAddress = issuedTokenParameters.IssuerMetadataAddress;
|
|
messageSecurity.IssuedKeyType = issuedTokenParameters.KeyType;
|
|
foreach (ClaimTypeRequirement c in issuedTokenParameters.ClaimTypeRequirements)
|
|
{
|
|
messageSecurity.ClaimTypeRequirements.Add(c);
|
|
}
|
|
foreach (XmlElement p in nonAlgorithmRequestParameters)
|
|
{
|
|
messageSecurity.TokenRequestParameters.Add(p);
|
|
}
|
|
if (issuedTokenParameters.AlternativeIssuerEndpoints != null && issuedTokenParameters.AlternativeIssuerEndpoints.Count > 0)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
internal bool InternalShouldSerialize()
|
|
{
|
|
return (this.ShouldSerializeAlgorithmSuite()
|
|
|| this.ShouldSerializeClaimTypeRequirements()
|
|
|| this.ShouldSerializeNegotiateServiceCredential()
|
|
|| this.ShouldSerializeEstablishSecurityContext()
|
|
|| this.ShouldSerializeIssuedKeyType()
|
|
|| this.ShouldSerializeTokenRequestParameters());
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeAlgorithmSuite()
|
|
{
|
|
return (this.AlgorithmSuite != SecurityAlgorithmSuite.Default);
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeClaimTypeRequirements()
|
|
{
|
|
return (this.ClaimTypeRequirements.Count > 0);
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeNegotiateServiceCredential()
|
|
{
|
|
return (this.NegotiateServiceCredential != DefaultNegotiateServiceCredential);
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeEstablishSecurityContext()
|
|
{
|
|
return (this.EstablishSecurityContext != DefaultEstablishSecurityContext);
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeIssuedKeyType()
|
|
{
|
|
return (this.IssuedKeyType != DefaultIssuedKeyType);
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeTokenRequestParameters()
|
|
{
|
|
return (this.TokenRequestParameters.Count > 0);
|
|
}
|
|
|
|
}
|
|
}
|