2 // SecurityBindingElement.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005-2006 Novell, Inc. http://www.novell.com
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 using System.Collections.Generic;
29 using System.Collections.ObjectModel;
30 using System.ServiceModel.Description;
31 using System.ServiceModel.Channels;
32 using System.ServiceModel.Security;
34 using System.ServiceModel.Channels.Security;
35 using System.IdentityModel.Selectors;
36 using System.IdentityModel.Tokens;
37 using System.ServiceModel.Security.Tokens;
41 namespace System.ServiceModel.Channels
43 public abstract class SecurityBindingElement : BindingElement
45 internal SecurityBindingElement ()
48 DefaultAlgorithmSuite = SecurityAlgorithmSuite.Default;
49 MessageSecurityVersion = MessageSecurityVersion.Default;
50 KeyEntropyMode = SecurityKeyEntropyMode.CombinedEntropy;
51 endpoint = new SupportingTokenParameters ();
52 operation = new Dictionary<string,SupportingTokenParameters> ();
53 opt_endpoint = new SupportingTokenParameters ();
54 opt_operation = new Dictionary<string,SupportingTokenParameters> ();
55 service_settings = new LocalServiceSecuritySettings ();
57 IncludeTimestamp = true;
58 LocalClientSettings = new LocalClientSecuritySettings ();
61 internal SecurityBindingElement (SecurityBindingElement other)
64 alg_suite = other.alg_suite;
65 key_entropy_mode = other.key_entropy_mode;
66 security_header_layout = other.security_header_layout;
67 msg_security_version = other.msg_security_version;
68 endpoint = other.endpoint.Clone ();
69 opt_endpoint = other.opt_endpoint.Clone ();
70 operation = new Dictionary<string,SupportingTokenParameters> ();
71 foreach (KeyValuePair<string,SupportingTokenParameters> p in other.operation)
72 operation.Add (p.Key, p.Value.Clone ());
73 opt_operation = new Dictionary<string,SupportingTokenParameters> ();
74 foreach (KeyValuePair<string,SupportingTokenParameters> p in other.opt_operation)
75 opt_operation.Add (p.Key, p.Value.Clone ());
76 service_settings = other.service_settings.Clone ();
78 IncludeTimestamp = other.IncludeTimestamp;
79 LocalClientSettings = other.LocalClientSettings.Clone ();
83 SecurityAlgorithmSuite alg_suite;
84 SecurityKeyEntropyMode key_entropy_mode;
85 SecurityHeaderLayout security_header_layout;
86 MessageSecurityVersion msg_security_version;
87 SupportingTokenParameters endpoint, opt_endpoint;
88 IDictionary<string,SupportingTokenParameters> operation, opt_operation;
89 LocalServiceSecuritySettings service_settings;
92 public bool IncludeTimestamp { get; set; }
94 public LocalClientSecuritySettings LocalClientSettings { get; private set; }
97 public SecurityAlgorithmSuite DefaultAlgorithmSuite {
98 get { return alg_suite; }
99 set { alg_suite = value; }
102 public SecurityKeyEntropyMode KeyEntropyMode {
103 get { return key_entropy_mode; }
104 set { key_entropy_mode = value; }
107 public LocalServiceSecuritySettings LocalServiceSettings {
108 get { return service_settings; }
111 public SecurityHeaderLayout SecurityHeaderLayout {
112 get { return security_header_layout; }
113 set { security_header_layout = value; }
116 public MessageSecurityVersion MessageSecurityVersion {
117 get { return msg_security_version; }
118 set { msg_security_version = value; }
121 public SupportingTokenParameters EndpointSupportingTokenParameters {
122 get { return endpoint; }
125 public IDictionary<string,SupportingTokenParameters> OperationSupportingTokenParameters {
126 get { return operation; }
129 public SupportingTokenParameters OptionalEndpointSupportingTokenParameters {
130 get { return opt_endpoint; }
133 public IDictionary<string,SupportingTokenParameters> OptionalOperationSupportingTokenParameters {
134 get { return opt_operation; }
138 [MonoTODO ("Implement for TransportSecurityBindingElement")]
139 public override bool CanBuildChannelFactory<TChannel> (BindingContext context)
142 // not sure this should be like this, but there isn't Symmetric/Asymmetric elements in 2.1 anyways.
143 return context.CanBuildInnerChannelFactory<TChannel> ();
145 if (this is TransportSecurityBindingElement)
146 throw new NotImplementedException ();
148 var symm = this as SymmetricSecurityBindingElement;
149 var asymm = this as AsymmetricSecurityBindingElement;
150 var pt = symm != null ? symm.ProtectionTokenParameters : asymm != null ? asymm.InitiatorTokenParameters : null;
154 var t = typeof (TChannel);
155 var req = new InitiatorServiceModelSecurityTokenRequirement ();
156 pt.InitializeSecurityTokenRequirement (req);
158 if (req.Properties.TryGetValue (ServiceModelSecurityTokenRequirement.IssuedSecurityTokenParametersProperty, out dummy) && dummy != null) {
159 if (t == typeof (IRequestSessionChannel))
160 return context.CanBuildInnerChannelFactory<IRequestChannel> () ||
161 context.CanBuildInnerChannelFactory<IRequestSessionChannel> ();
162 else if (t == typeof (IDuplexSessionChannel))
163 return context.CanBuildInnerChannelFactory<IDuplexChannel> () ||
164 context.CanBuildInnerChannelFactory<IDuplexSessionChannel> ();
166 if (t == typeof (IRequestChannel))
167 return context.CanBuildInnerChannelFactory<IRequestChannel> () ||
168 context.CanBuildInnerChannelFactory<IRequestSessionChannel> ();
169 else if (t == typeof (IDuplexChannel))
170 return context.CanBuildInnerChannelFactory<IDuplexChannel> () ||
171 context.CanBuildInnerChannelFactory<IDuplexSessionChannel> ();
177 public override IChannelFactory<TChannel> BuildChannelFactory<TChannel> (
178 BindingContext context)
180 return BuildChannelFactoryCore<TChannel> (context);
183 protected abstract IChannelFactory<TChannel>
184 BuildChannelFactoryCore<TChannel> (BindingContext context);
187 [MonoTODO ("Implement for TransportSecurityBindingElement")]
188 public override bool CanBuildChannelListener<TChannel> (BindingContext context)
190 if (this is TransportSecurityBindingElement)
191 throw new NotImplementedException ();
193 var symm = this as SymmetricSecurityBindingElement;
194 var asymm = this as AsymmetricSecurityBindingElement;
195 var pt = symm != null ? symm.ProtectionTokenParameters : asymm != null ? asymm.RecipientTokenParameters : null;
199 var t = typeof (TChannel);
200 var req = new InitiatorServiceModelSecurityTokenRequirement ();
201 pt.InitializeSecurityTokenRequirement (req);
203 if (req.Properties.TryGetValue (ServiceModelSecurityTokenRequirement.IssuedSecurityTokenParametersProperty, out dummy) && dummy != null) {
204 if (t == typeof (IReplySessionChannel))
205 return context.CanBuildInnerChannelListener<IReplyChannel> () ||
206 context.CanBuildInnerChannelListener<IReplySessionChannel> ();
207 else if (t == typeof (IDuplexSessionChannel))
208 return context.CanBuildInnerChannelListener<IDuplexChannel> () ||
209 context.CanBuildInnerChannelListener<IDuplexSessionChannel> ();
211 if (t == typeof (IReplyChannel))
212 return context.CanBuildInnerChannelListener<IReplyChannel> () ||
213 context.CanBuildInnerChannelListener<IReplySessionChannel> ();
214 else if (t == typeof (IDuplexChannel))
215 return context.CanBuildInnerChannelListener<IDuplexChannel> () ||
216 context.CanBuildInnerChannelListener<IDuplexSessionChannel> ();
221 public override IChannelListener<TChannel> BuildChannelListener<TChannel> (
222 BindingContext context)
224 return BuildChannelListenerCore<TChannel> (context);
227 protected abstract IChannelListener<TChannel>
228 BuildChannelListenerCore<TChannel> (BindingContext context)
229 where TChannel : class, IChannel;
231 public override T GetProperty<T> (BindingContext context)
233 // It is documented that ISecurityCapabilities and IdentityVerifier can be returned.
234 // Though, this class is not inheritable, and they are returned by the derived types.
235 // So I don't care about them here.
236 return context.GetInnerProperty<T> ();
239 public virtual void SetKeyDerivation (bool requireDerivedKeys)
241 endpoint.SetKeyDerivation (requireDerivedKeys);
242 opt_endpoint.SetKeyDerivation (requireDerivedKeys);
243 foreach (SupportingTokenParameters p in operation.Values)
244 p.SetKeyDerivation (requireDerivedKeys);
245 foreach (SupportingTokenParameters p in opt_operation.Values)
246 p.SetKeyDerivation (requireDerivedKeys);
249 public override string ToString ()
251 var sb = new StringBuilder ();
252 sb.Append (GetType ().FullName).Append (":\n");
253 foreach (var pi in GetType ().GetProperties ()) {
254 var simple = Type.GetTypeCode (pi.PropertyType) != TypeCode.Object;
255 var val = pi.GetValue (this, null);
256 sb.Append (pi.Name).Append (':');
258 sb.AppendFormat ("{0}{1}{2}", simple ? " " : "\n", simple ? "" : " ", String.Join ("\n ", val.ToString ().Split ('\n')));
261 sb.Length--; // chop trailing EOL.
262 return sb.ToString ();
266 public override T GetProperty<T> (BindingContext context)
272 #region Factory methods
274 public static SymmetricSecurityBindingElement
275 CreateAnonymousForCertificateBindingElement ()
277 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
278 be.RequireSignatureConfirmation = true;
279 be.ProtectionTokenParameters = CreateProtectionTokenParameters (true);
283 public static TransportSecurityBindingElement
284 CreateCertificateOverTransportBindingElement ()
286 return CreateCertificateOverTransportBindingElement (MessageSecurityVersion.Default);
289 public static TransportSecurityBindingElement
290 CreateCertificateOverTransportBindingElement (MessageSecurityVersion version)
292 var be = new TransportSecurityBindingElement () { MessageSecurityVersion = version };
293 be.EndpointSupportingTokenParameters.SignedEncrypted.Add (new X509SecurityTokenParameters ());
298 public static AsymmetricSecurityBindingElement
299 CreateCertificateSignatureBindingElement ()
301 throw new NotImplementedException ();
305 public static SymmetricSecurityBindingElement
306 CreateIssuedTokenBindingElement (
307 IssuedSecurityTokenParameters issuedTokenParameters)
309 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
310 be.ProtectionTokenParameters = issuedTokenParameters;
314 public static SymmetricSecurityBindingElement
315 CreateIssuedTokenForCertificateBindingElement (
316 IssuedSecurityTokenParameters issuedTokenParameters)
318 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
319 be.RequireSignatureConfirmation = true;
320 be.ProtectionTokenParameters = CreateProtectionTokenParameters (true);
321 be.EndpointSupportingTokenParameters.Endorsing.Add (
322 issuedTokenParameters);
327 public static SymmetricSecurityBindingElement
328 CreateIssuedTokenForSslBindingElement (
329 IssuedSecurityTokenParameters issuedTokenParameters)
331 return CreateIssuedTokenForSslBindingElement (
332 issuedTokenParameters, false);
336 public static SymmetricSecurityBindingElement
337 CreateIssuedTokenForSslBindingElement (
338 IssuedSecurityTokenParameters issuedTokenParameters,
339 bool requireCancellation)
341 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
342 be.RequireSignatureConfirmation = true;
343 be.ProtectionTokenParameters = CreateProtectionTokenParameters (false);
344 be.EndpointSupportingTokenParameters.Endorsing.Add (
345 issuedTokenParameters);
350 public static TransportSecurityBindingElement
351 CreateIssuedTokenOverTransportBindingElement (
352 IssuedSecurityTokenParameters issuedTokenParameters)
354 throw new NotImplementedException ();
358 public static SymmetricSecurityBindingElement CreateKerberosBindingElement ()
360 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
361 be.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic128;
362 be.ProtectionTokenParameters = CreateProtectionTokenParameters (false);
363 be.ProtectionTokenParameters.InclusionMode =
364 SecurityTokenInclusionMode.Once;
369 public static TransportSecurityBindingElement
370 CreateKerberosOverTransportBindingElement ()
372 throw new NotImplementedException ();
375 public static SecurityBindingElement
376 CreateMutualCertificateBindingElement ()
378 return CreateMutualCertificateBindingElement (MessageSecurityVersion.Default, false);
381 public static SecurityBindingElement
382 CreateMutualCertificateBindingElement (MessageSecurityVersion version)
384 return CreateMutualCertificateBindingElement (version, false);
387 [MonoTODO("Does not support allowSerializedSigningTokenOnReply.")]
388 public static SecurityBindingElement
389 CreateMutualCertificateBindingElement (
390 MessageSecurityVersion version,
391 bool allowSerializedSigningTokenOnReply)
394 throw new ArgumentNullException ("version");
396 if (allowSerializedSigningTokenOnReply)
397 throw new NotSupportedException ("allowSerializedSigningTokenOnReply is not supported");
399 if (version.SecurityVersion == SecurityVersion.WSSecurity10) {
401 var recipient = new X509SecurityTokenParameters (
402 X509KeyIdentifierClauseType.Any,
403 SecurityTokenInclusionMode.Never);
404 recipient.RequireDerivedKeys = false;
406 var initiator = new X509SecurityTokenParameters (
407 X509KeyIdentifierClauseType.Any,
408 SecurityTokenInclusionMode.AlwaysToRecipient);
409 initiator.RequireDerivedKeys = false;
411 return new AsymmetricSecurityBindingElement (recipient, initiator) {
412 MessageSecurityVersion = version
415 X509SecurityTokenParameters p =
416 new X509SecurityTokenParameters (X509KeyIdentifierClauseType.Thumbprint);
417 p.RequireDerivedKeys = false;
419 var sym = new SymmetricSecurityBindingElement () {
420 MessageSecurityVersion = version,
421 RequireSignatureConfirmation = true
424 X509SecurityTokenParameters p2 = new X509SecurityTokenParameters (X509KeyIdentifierClauseType.Thumbprint);
425 p2.ReferenceStyle = SecurityTokenReferenceStyle.External;
426 sym.ProtectionTokenParameters = p2;
427 sym.EndpointSupportingTokenParameters.Endorsing.Add (p);
434 public static AsymmetricSecurityBindingElement
435 CreateMutualCertificateDuplexBindingElement ()
437 throw new NotImplementedException ();
441 public static AsymmetricSecurityBindingElement
442 CreateMutualCertificateDuplexBindingElement (
443 MessageSecurityVersion version)
445 throw new NotImplementedException ();
448 public static SecurityBindingElement
449 CreateSecureConversationBindingElement (SecurityBindingElement binding)
451 return CreateSecureConversationBindingElement (binding, false);
454 public static SecurityBindingElement
455 CreateSecureConversationBindingElement (
456 SecurityBindingElement binding, bool requireCancellation)
458 return CreateSecureConversationBindingElement (binding, requireCancellation, null);
461 public static SecurityBindingElement
462 CreateSecureConversationBindingElement (
463 SecurityBindingElement binding, bool requireCancellation,
464 ChannelProtectionRequirements protectionRequirements)
466 SymmetricSecurityBindingElement be =
467 new SymmetricSecurityBindingElement ();
468 be.ProtectionTokenParameters =
469 new SecureConversationSecurityTokenParameters (
470 binding, requireCancellation, protectionRequirements);
474 public static SymmetricSecurityBindingElement
475 CreateSslNegotiationBindingElement (bool requireClientCertificate)
477 return CreateSslNegotiationBindingElement (
478 requireClientCertificate, false);
481 public static SymmetricSecurityBindingElement
482 CreateSslNegotiationBindingElement (
483 bool requireClientCertificate,
484 bool requireCancellation)
486 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
487 be.ProtectionTokenParameters = new SslSecurityTokenParameters (requireClientCertificate, requireCancellation);
491 public static SymmetricSecurityBindingElement
492 CreateSspiNegotiationBindingElement ()
494 return CreateSspiNegotiationBindingElement (true);
497 public static SymmetricSecurityBindingElement
498 CreateSspiNegotiationBindingElement (bool requireCancellation)
500 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
501 be.ProtectionTokenParameters = CreateProtectionTokenParameters (false);
505 public static TransportSecurityBindingElement
506 CreateSspiNegotiationOverTransportBindingElement ()
508 return CreateSspiNegotiationOverTransportBindingElement (false);
512 public static TransportSecurityBindingElement
513 CreateSspiNegotiationOverTransportBindingElement (bool requireCancellation)
515 throw new NotImplementedException ();
518 static X509SecurityTokenParameters CreateProtectionTokenParameters (bool cert)
520 X509SecurityTokenParameters p =
521 new X509SecurityTokenParameters ();
522 p.X509ReferenceStyle = X509KeyIdentifierClauseType.Thumbprint;
524 p.InclusionMode = SecurityTokenInclusionMode.Never;
528 public static SymmetricSecurityBindingElement
529 CreateUserNameForCertificateBindingElement ()
531 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
532 be.ProtectionTokenParameters = CreateProtectionTokenParameters (true);
533 UserNameSecurityTokenParameters utp =
534 new UserNameSecurityTokenParameters ();
535 be.EndpointSupportingTokenParameters.SignedEncrypted.Add (utp);
539 public static SymmetricSecurityBindingElement
540 CreateUserNameForSslBindingElement ()
542 return CreateUserNameForSslBindingElement (false);
545 public static SymmetricSecurityBindingElement
546 CreateUserNameForSslBindingElement (bool requireCancellation)
548 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
549 be.ProtectionTokenParameters = CreateProtectionTokenParameters (false);
550 UserNameSecurityTokenParameters utp =
551 new UserNameSecurityTokenParameters ();
552 be.EndpointSupportingTokenParameters.SignedEncrypted.Add (utp);
558 public static TransportSecurityBindingElement
559 CreateUserNameOverTransportBindingElement ()
561 var be = new TransportSecurityBindingElement ();
562 #if !NET_2_1 // FIXME: there should be whatever else to do for 2.1 instead.
563 be.EndpointSupportingTokenParameters.SignedEncrypted.Add (new UserNameSecurityTokenParameters ());
570 // It seems almost internal, hardcoded like this (I tried
571 // custom parameters that sets IssuedTokenSecurityTokenParameters
572 // like below ones, but that didn't trigger this method).
573 protected static void SetIssuerBindingContextIfRequired (
574 SecurityTokenParameters parameters,
575 BindingContext issuerBindingContext)
577 if (parameters is IssuedSecurityTokenParameters ||
578 parameters is SecureConversationSecurityTokenParameters ||
579 parameters is SslSecurityTokenParameters ||
580 parameters is SspiSecurityTokenParameters) {
581 parameters.IssuerBindingContext = issuerBindingContext;