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;
33 #if !NET_2_1 && !XAMMAC_4_5
34 using System.ServiceModel.Channels.Security;
35 using System.IdentityModel.Selectors;
36 using System.IdentityModel.Tokens;
38 using System.ServiceModel.Security.Tokens;
41 namespace System.ServiceModel.Channels
43 public abstract class SecurityBindingElement : BindingElement
45 internal SecurityBindingElement ()
47 MessageSecurityVersion = MessageSecurityVersion.Default;
48 endpoint = new SupportingTokenParameters ();
49 #if !NET_2_1 && !XAMMAC_4_5
50 DefaultAlgorithmSuite = SecurityAlgorithmSuite.Default;
51 KeyEntropyMode = SecurityKeyEntropyMode.CombinedEntropy;
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)
63 security_header_layout = other.security_header_layout;
64 msg_security_version = other.msg_security_version;
65 endpoint = other.endpoint.Clone ();
66 #if !NET_2_1 && !XAMMAC_4_5
67 alg_suite = other.alg_suite;
68 key_entropy_mode = other.key_entropy_mode;
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 ();
82 SecurityHeaderLayout security_header_layout;
83 MessageSecurityVersion msg_security_version;
84 SupportingTokenParameters endpoint;
86 #if !NET_2_1 && !XAMMAC_4_5
87 SecurityAlgorithmSuite alg_suite;
88 SecurityKeyEntropyMode key_entropy_mode;
89 SupportingTokenParameters opt_endpoint;
90 IDictionary<string,SupportingTokenParameters> operation, opt_operation;
91 LocalServiceSecuritySettings service_settings;
94 public bool IncludeTimestamp { get; set; }
96 public LocalClientSecuritySettings LocalClientSettings { get; private set; }
98 public SecurityHeaderLayout SecurityHeaderLayout {
99 get { return security_header_layout; }
100 set { security_header_layout = value; }
103 public MessageSecurityVersion MessageSecurityVersion {
104 get { return msg_security_version; }
105 set { msg_security_version = value; }
108 public SupportingTokenParameters EndpointSupportingTokenParameters {
109 get { return endpoint; }
112 #if !NET_2_1 && !XAMMAC_4_5
113 public SecurityAlgorithmSuite DefaultAlgorithmSuite {
114 get { return alg_suite; }
115 set { alg_suite = value; }
118 public SecurityKeyEntropyMode KeyEntropyMode {
119 get { return key_entropy_mode; }
120 set { key_entropy_mode = value; }
123 public LocalServiceSecuritySettings LocalServiceSettings {
124 get { return service_settings; }
127 public IDictionary<string,SupportingTokenParameters> OperationSupportingTokenParameters {
128 get { return operation; }
131 public SupportingTokenParameters OptionalEndpointSupportingTokenParameters {
132 get { return opt_endpoint; }
135 public IDictionary<string,SupportingTokenParameters> OptionalOperationSupportingTokenParameters {
136 get { return opt_operation; }
140 [MonoTODO ("Implement for TransportSecurityBindingElement")]
141 public override bool CanBuildChannelFactory<TChannel> (BindingContext context)
143 #if NET_2_1 || XAMMAC_4_5
144 // not sure this should be like this, but there isn't Symmetric/Asymmetric elements in 2.1 anyways.
145 return context.CanBuildInnerChannelFactory<TChannel> ();
147 if (this is TransportSecurityBindingElement)
148 throw new NotImplementedException ();
150 var symm = this as SymmetricSecurityBindingElement;
151 var asymm = this as AsymmetricSecurityBindingElement;
152 var pt = symm != null ? symm.ProtectionTokenParameters : asymm != null ? asymm.InitiatorTokenParameters : null;
156 var t = typeof (TChannel);
157 var req = new InitiatorServiceModelSecurityTokenRequirement ();
158 pt.InitializeSecurityTokenRequirement (req);
160 if (req.Properties.TryGetValue (ServiceModelSecurityTokenRequirement.IssuedSecurityTokenParametersProperty, out dummy) && dummy != null) {
161 if (t == typeof (IRequestSessionChannel))
162 return context.CanBuildInnerChannelFactory<IRequestChannel> () ||
163 context.CanBuildInnerChannelFactory<IRequestSessionChannel> ();
164 else if (t == typeof (IDuplexSessionChannel))
165 return context.CanBuildInnerChannelFactory<IDuplexChannel> () ||
166 context.CanBuildInnerChannelFactory<IDuplexSessionChannel> ();
168 if (t == typeof (IRequestChannel))
169 return context.CanBuildInnerChannelFactory<IRequestChannel> () ||
170 context.CanBuildInnerChannelFactory<IRequestSessionChannel> ();
171 else if (t == typeof (IDuplexChannel))
172 return context.CanBuildInnerChannelFactory<IDuplexChannel> () ||
173 context.CanBuildInnerChannelFactory<IDuplexSessionChannel> ();
179 public override IChannelFactory<TChannel> BuildChannelFactory<TChannel> (
180 BindingContext context)
182 return BuildChannelFactoryCore<TChannel> (context);
185 protected abstract IChannelFactory<TChannel>
186 BuildChannelFactoryCore<TChannel> (BindingContext context);
188 #if !NET_2_1 && !XAMMAC_4_5
189 [MonoTODO ("Implement for TransportSecurityBindingElement")]
190 public override bool CanBuildChannelListener<TChannel> (BindingContext context)
192 if (this is TransportSecurityBindingElement)
193 throw new NotImplementedException ();
195 var symm = this as SymmetricSecurityBindingElement;
196 var asymm = this as AsymmetricSecurityBindingElement;
197 var pt = symm != null ? symm.ProtectionTokenParameters : asymm != null ? asymm.RecipientTokenParameters : null;
201 var t = typeof (TChannel);
202 var req = new InitiatorServiceModelSecurityTokenRequirement ();
203 pt.InitializeSecurityTokenRequirement (req);
205 if (req.Properties.TryGetValue (ServiceModelSecurityTokenRequirement.IssuedSecurityTokenParametersProperty, out dummy) && dummy != null) {
206 if (t == typeof (IReplySessionChannel))
207 return context.CanBuildInnerChannelListener<IReplyChannel> () ||
208 context.CanBuildInnerChannelListener<IReplySessionChannel> ();
209 else if (t == typeof (IDuplexSessionChannel))
210 return context.CanBuildInnerChannelListener<IDuplexChannel> () ||
211 context.CanBuildInnerChannelListener<IDuplexSessionChannel> ();
213 if (t == typeof (IReplyChannel))
214 return context.CanBuildInnerChannelListener<IReplyChannel> () ||
215 context.CanBuildInnerChannelListener<IReplySessionChannel> ();
216 else if (t == typeof (IDuplexChannel))
217 return context.CanBuildInnerChannelListener<IDuplexChannel> () ||
218 context.CanBuildInnerChannelListener<IDuplexSessionChannel> ();
223 public override IChannelListener<TChannel> BuildChannelListener<TChannel> (
224 BindingContext context)
226 return BuildChannelListenerCore<TChannel> (context);
229 protected abstract IChannelListener<TChannel>
230 BuildChannelListenerCore<TChannel> (BindingContext context)
231 where TChannel : class, IChannel;
233 public override T GetProperty<T> (BindingContext context)
235 // It is documented that ISecurityCapabilities and IdentityVerifier can be returned.
236 // Though, this class is not inheritable, and they are returned by the derived types.
237 // So I don't care about them here.
238 return context.GetInnerProperty<T> ();
241 public virtual void SetKeyDerivation (bool requireDerivedKeys)
243 endpoint.SetKeyDerivation (requireDerivedKeys);
244 opt_endpoint.SetKeyDerivation (requireDerivedKeys);
245 foreach (SupportingTokenParameters p in operation.Values)
246 p.SetKeyDerivation (requireDerivedKeys);
247 foreach (SupportingTokenParameters p in opt_operation.Values)
248 p.SetKeyDerivation (requireDerivedKeys);
251 public override string ToString ()
253 var sb = new StringBuilder ();
254 sb.Append (GetType ().FullName).Append (":\n");
255 foreach (var pi in GetType ().GetProperties ()) {
256 var simple = Type.GetTypeCode (pi.PropertyType) != TypeCode.Object;
257 var val = pi.GetValue (this, null);
258 sb.Append (pi.Name).Append (':');
260 sb.AppendFormat ("{0}{1}{2}", simple ? " " : "\n", simple ? "" : " ", String.Join ("\n ", val.ToString ().Split ('\n')));
263 sb.Length--; // chop trailing EOL.
264 return sb.ToString ();
268 public override T GetProperty<T> (BindingContext context)
274 #region Factory methods
275 #if !NET_2_1 && !XAMMAC_4_5
276 public static SymmetricSecurityBindingElement
277 CreateAnonymousForCertificateBindingElement ()
279 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
280 be.RequireSignatureConfirmation = true;
281 be.ProtectionTokenParameters = CreateProtectionTokenParameters (true);
285 public static TransportSecurityBindingElement
286 CreateCertificateOverTransportBindingElement ()
288 return CreateCertificateOverTransportBindingElement (MessageSecurityVersion.Default);
291 public static TransportSecurityBindingElement
292 CreateCertificateOverTransportBindingElement (MessageSecurityVersion version)
294 var be = new TransportSecurityBindingElement () { MessageSecurityVersion = version };
295 be.EndpointSupportingTokenParameters.SignedEncrypted.Add (new X509SecurityTokenParameters ());
300 public static AsymmetricSecurityBindingElement
301 CreateCertificateSignatureBindingElement ()
303 throw new NotImplementedException ();
307 public static SymmetricSecurityBindingElement
308 CreateIssuedTokenBindingElement (
309 IssuedSecurityTokenParameters issuedTokenParameters)
311 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
312 be.ProtectionTokenParameters = issuedTokenParameters;
316 public static SymmetricSecurityBindingElement
317 CreateIssuedTokenForCertificateBindingElement (
318 IssuedSecurityTokenParameters issuedTokenParameters)
320 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
321 be.RequireSignatureConfirmation = true;
322 be.ProtectionTokenParameters = CreateProtectionTokenParameters (true);
323 be.EndpointSupportingTokenParameters.Endorsing.Add (
324 issuedTokenParameters);
329 public static SymmetricSecurityBindingElement
330 CreateIssuedTokenForSslBindingElement (
331 IssuedSecurityTokenParameters issuedTokenParameters)
333 return CreateIssuedTokenForSslBindingElement (
334 issuedTokenParameters, false);
338 public static SymmetricSecurityBindingElement
339 CreateIssuedTokenForSslBindingElement (
340 IssuedSecurityTokenParameters issuedTokenParameters,
341 bool requireCancellation)
343 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
344 be.RequireSignatureConfirmation = true;
345 be.ProtectionTokenParameters = CreateProtectionTokenParameters (false);
346 be.EndpointSupportingTokenParameters.Endorsing.Add (
347 issuedTokenParameters);
352 public static TransportSecurityBindingElement
353 CreateIssuedTokenOverTransportBindingElement (
354 IssuedSecurityTokenParameters issuedTokenParameters)
356 throw new NotImplementedException ();
360 public static SymmetricSecurityBindingElement CreateKerberosBindingElement ()
362 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
363 be.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic128;
364 be.ProtectionTokenParameters = CreateProtectionTokenParameters (false);
365 be.ProtectionTokenParameters.InclusionMode =
366 SecurityTokenInclusionMode.Once;
371 public static TransportSecurityBindingElement
372 CreateKerberosOverTransportBindingElement ()
374 throw new NotImplementedException ();
377 public static SecurityBindingElement
378 CreateMutualCertificateBindingElement ()
380 return CreateMutualCertificateBindingElement (MessageSecurityVersion.Default, false);
383 public static SecurityBindingElement
384 CreateMutualCertificateBindingElement (MessageSecurityVersion version)
386 return CreateMutualCertificateBindingElement (version, false);
389 [MonoTODO("Does not support allowSerializedSigningTokenOnReply.")]
390 public static SecurityBindingElement
391 CreateMutualCertificateBindingElement (
392 MessageSecurityVersion version,
393 bool allowSerializedSigningTokenOnReply)
396 throw new ArgumentNullException ("version");
398 if (allowSerializedSigningTokenOnReply)
399 throw new NotSupportedException ("allowSerializedSigningTokenOnReply is not supported");
401 if (version.SecurityVersion == SecurityVersion.WSSecurity10) {
403 var recipient = new X509SecurityTokenParameters (
404 X509KeyIdentifierClauseType.Any,
405 SecurityTokenInclusionMode.Never);
406 recipient.RequireDerivedKeys = false;
408 var initiator = new X509SecurityTokenParameters (
409 X509KeyIdentifierClauseType.Any,
410 SecurityTokenInclusionMode.AlwaysToRecipient);
411 initiator.RequireDerivedKeys = false;
413 return new AsymmetricSecurityBindingElement (recipient, initiator) {
414 MessageSecurityVersion = version
417 X509SecurityTokenParameters p =
418 new X509SecurityTokenParameters (X509KeyIdentifierClauseType.Thumbprint);
419 p.RequireDerivedKeys = false;
421 var sym = new SymmetricSecurityBindingElement () {
422 MessageSecurityVersion = version,
423 RequireSignatureConfirmation = true
426 X509SecurityTokenParameters p2 = new X509SecurityTokenParameters (X509KeyIdentifierClauseType.Thumbprint);
427 p2.ReferenceStyle = SecurityTokenReferenceStyle.External;
428 sym.ProtectionTokenParameters = p2;
429 sym.EndpointSupportingTokenParameters.Endorsing.Add (p);
436 public static AsymmetricSecurityBindingElement
437 CreateMutualCertificateDuplexBindingElement ()
439 throw new NotImplementedException ();
443 public static AsymmetricSecurityBindingElement
444 CreateMutualCertificateDuplexBindingElement (
445 MessageSecurityVersion version)
447 throw new NotImplementedException ();
450 public static SymmetricSecurityBindingElement
451 CreateSslNegotiationBindingElement (bool requireClientCertificate)
453 return CreateSslNegotiationBindingElement (
454 requireClientCertificate, false);
457 public static SymmetricSecurityBindingElement
458 CreateSslNegotiationBindingElement (
459 bool requireClientCertificate,
460 bool requireCancellation)
462 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
463 be.ProtectionTokenParameters = new SslSecurityTokenParameters (requireClientCertificate, requireCancellation);
467 public static SymmetricSecurityBindingElement
468 CreateSspiNegotiationBindingElement ()
470 return CreateSspiNegotiationBindingElement (true);
473 public static SymmetricSecurityBindingElement
474 CreateSspiNegotiationBindingElement (bool requireCancellation)
476 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
477 be.ProtectionTokenParameters = CreateProtectionTokenParameters (false);
481 public static TransportSecurityBindingElement
482 CreateSspiNegotiationOverTransportBindingElement ()
484 return CreateSspiNegotiationOverTransportBindingElement (false);
488 public static TransportSecurityBindingElement
489 CreateSspiNegotiationOverTransportBindingElement (bool requireCancellation)
491 throw new NotImplementedException ();
494 static X509SecurityTokenParameters CreateProtectionTokenParameters (bool cert)
496 X509SecurityTokenParameters p =
497 new X509SecurityTokenParameters ();
498 p.X509ReferenceStyle = X509KeyIdentifierClauseType.Thumbprint;
500 p.InclusionMode = SecurityTokenInclusionMode.Never;
504 public static SymmetricSecurityBindingElement
505 CreateUserNameForCertificateBindingElement ()
507 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
508 be.ProtectionTokenParameters = CreateProtectionTokenParameters (true);
509 UserNameSecurityTokenParameters utp =
510 new UserNameSecurityTokenParameters ();
511 be.EndpointSupportingTokenParameters.SignedEncrypted.Add (utp);
515 public static SymmetricSecurityBindingElement
516 CreateUserNameForSslBindingElement ()
518 return CreateUserNameForSslBindingElement (false);
521 public static SymmetricSecurityBindingElement
522 CreateUserNameForSslBindingElement (bool requireCancellation)
524 SymmetricSecurityBindingElement be = new SymmetricSecurityBindingElement ();
525 be.ProtectionTokenParameters = CreateProtectionTokenParameters (false);
526 UserNameSecurityTokenParameters utp =
527 new UserNameSecurityTokenParameters ();
528 be.EndpointSupportingTokenParameters.SignedEncrypted.Add (utp);
533 public static SecurityBindingElement
534 CreateSecureConversationBindingElement (SecurityBindingElement binding)
536 return CreateSecureConversationBindingElement (binding, false);
539 public static SecurityBindingElement
540 CreateSecureConversationBindingElement (
541 SecurityBindingElement binding, bool requireCancellation)
543 return CreateSecureConversationBindingElement (binding, requireCancellation, null);
546 public static SecurityBindingElement
547 CreateSecureConversationBindingElement (
548 SecurityBindingElement binding, bool requireCancellation,
549 ChannelProtectionRequirements protectionRequirements)
551 #if !NET_2_1 && !XAMMAC_4_5
552 SymmetricSecurityBindingElement be =
553 new SymmetricSecurityBindingElement ();
554 be.ProtectionTokenParameters =
555 new SecureConversationSecurityTokenParameters (
556 binding, requireCancellation, protectionRequirements);
559 throw new NotImplementedException ();
564 public static TransportSecurityBindingElement
565 CreateUserNameOverTransportBindingElement ()
567 var be = new TransportSecurityBindingElement ();
568 #if !NET_2_1 && !XAMMAC_4_5 // FIXME: there should be whatever else to do for 2.1 instead.
569 be.EndpointSupportingTokenParameters.SignedEncrypted.Add (new UserNameSecurityTokenParameters ());
575 #if !NET_2_1 && !XAMMAC_4_5
576 // It seems almost internal, hardcoded like this (I tried
577 // custom parameters that sets IssuedTokenSecurityTokenParameters
578 // like below ones, but that didn't trigger this method).
579 protected static void SetIssuerBindingContextIfRequired (
580 SecurityTokenParameters parameters,
581 BindingContext issuerBindingContext)
583 if (parameters is IssuedSecurityTokenParameters ||
584 parameters is SecureConversationSecurityTokenParameters ||
585 parameters is SslSecurityTokenParameters ||
586 parameters is SspiSecurityTokenParameters) {
587 parameters.IssuerBindingContext = issuerBindingContext;