1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4 
5 using System.ServiceModel.Diagnostics;
6 using System.ServiceModel.Dispatcher;
7 using System.ServiceModel.Description;
8 using System.ServiceModel.Security;
9 using System.ServiceModel.Configuration;
10 using System.Collections.ObjectModel;
11 using System.Net.Security;
12 
13 namespace System.ServiceModel.Channels
14 {
15     using System.Xml;
16     using System.ServiceModel.Security.Tokens;
17     using System.ServiceModel.Security;
18     using System.ServiceModel;
19     using System.IO;
20     using System.Collections.ObjectModel;
21     using System.Collections.Generic;
22     using System.Runtime.InteropServices;
23 
24     public class SecurityBindingElementImporter : IPolicyImportExtension
25     {
26         internal const string MaxPolicyRedirectionsKey = "MaxPolicyRedirections";
27         internal const string SecureConversationBootstrapEncryptionRequirements = "SecureConversationBootstrapEncryptionRequirements";
28         internal const string SecureConversationBootstrapSignatureRequirements = "SecureConversationBootstrapSignatureRequirements";
29         internal const string InSecureConversationBootstrapBindingImportMode = "InSecureConversationBootstrapBindingImportMode";
30         internal const string ContractProtectionLevelKey = "ContractProtectionLevelKey";
31 
32         int maxPolicyRedirections;
33 
SecurityBindingElementImporter()34         public SecurityBindingElementImporter()
35         {
36             this.maxPolicyRedirections = 10;
37         }
38 
39         public int MaxPolicyRedirections
40         {
41             get
42             {
43                 return this.maxPolicyRedirections;
44             }
45         }
46 
ImportOperationScopeSupportingTokensPolicy(MetadataImporter importer, PolicyConversionContext policyContext, SecurityBindingElement binding)47         void ImportOperationScopeSupportingTokensPolicy(MetadataImporter importer, PolicyConversionContext policyContext, SecurityBindingElement binding)
48         {
49             foreach (OperationDescription operation in policyContext.Contract.Operations)
50             {
51                 string requestAction = null;
52                 foreach (MessageDescription message in operation.Messages)
53                 {
54                     if (message.Direction == MessageDirection.Input)
55                     {
56                         requestAction = message.Action;
57                         break;
58                     }
59                 }
60 
61                 SupportingTokenParameters requirements = new SupportingTokenParameters();
62                 SupportingTokenParameters optionalRequirements = new SupportingTokenParameters();
63                 ICollection<XmlElement> operationBindingAssertions = policyContext.GetOperationBindingAssertions(operation);
64                 this.ImportSupportingTokenAssertions(importer, policyContext, operationBindingAssertions, requirements, optionalRequirements);
65                 if (requirements.Endorsing.Count > 0
66                     || requirements.Signed.Count > 0
67                     || requirements.SignedEncrypted.Count > 0
68                     || requirements.SignedEndorsing.Count > 0)
69                 {
70                     if (requestAction != null)
71                     {
72                         binding.OperationSupportingTokenParameters[requestAction] = requirements;
73                     }
74                     else
75                     {
76                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CannotImportSupportingTokensForOperationWithoutRequestAction)));
77                     }
78                 }
79                 if (optionalRequirements.Endorsing.Count > 0
80                     || optionalRequirements.Signed.Count > 0
81                     || optionalRequirements.SignedEncrypted.Count > 0
82                     || optionalRequirements.SignedEndorsing.Count > 0)
83                 {
84                     if (requestAction != null)
85                     {
86                         binding.OptionalOperationSupportingTokenParameters[requestAction] = optionalRequirements;
87                     }
88                     else
89                     {
90                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CannotImportSupportingTokensForOperationWithoutRequestAction)));
91                     }
92                 }
93             }
94         }
95 
ImportProtectionAssertions(ICollection<XmlElement> assertions, out MessagePartSpecification signedParts, out MessagePartSpecification encryptedParts)96         void ImportProtectionAssertions(ICollection<XmlElement> assertions, out MessagePartSpecification signedParts, out MessagePartSpecification encryptedParts)
97         {
98             XmlElement assertion;
99 
100             signedParts = null;
101             encryptedParts = null;
102 
103             WSSecurityPolicy securityPolicy;
104             if (WSSecurityPolicy.TryGetSecurityPolicyDriver(assertions, out securityPolicy))
105             {
106                 if (!securityPolicy.TryImportWsspEncryptedPartsAssertion(assertions, out encryptedParts, out assertion)
107                     && assertion != null)
108                 {
109                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnsupportedSecurityPolicyAssertion, assertion.OuterXml)));
110                 }
111 
112                 if (!securityPolicy.TryImportWsspSignedPartsAssertion(assertions, out signedParts, out assertion)
113                     && assertion != null)
114                 {
115                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnsupportedSecurityPolicyAssertion, assertion.OuterXml)));
116                 }
117             }
118 
119             if (encryptedParts == null)
120             {
121                 encryptedParts = MessagePartSpecification.NoParts;
122             }
123             if (signedParts == null)
124             {
125                 signedParts = MessagePartSpecification.NoParts;
126             }
127         }
128 
ValidateExistingOrSetNewProtectionLevel(MessagePartDescription part, MessageDescription message, OperationDescription operation, ContractDescription contract, ProtectionLevel newProtectionLevel)129         void ValidateExistingOrSetNewProtectionLevel(MessagePartDescription part, MessageDescription message, OperationDescription operation, ContractDescription contract, ProtectionLevel newProtectionLevel)
130         {
131             ProtectionLevel existingProtectionLevel;
132 
133             if (part != null && part.HasProtectionLevel)
134             {
135                 existingProtectionLevel = part.ProtectionLevel;
136             }
137             else if (message.HasProtectionLevel)
138             {
139                 existingProtectionLevel = message.ProtectionLevel;
140             }
141             else if (operation.HasProtectionLevel)
142             {
143                 existingProtectionLevel = operation.ProtectionLevel;
144             }
145             else
146             {
147                 if (part != null)
148                 {
149                     part.ProtectionLevel = newProtectionLevel;
150                 }
151                 else
152                 {
153                     message.ProtectionLevel = newProtectionLevel;
154                 }
155                 existingProtectionLevel = newProtectionLevel;
156             }
157 
158             if (existingProtectionLevel != newProtectionLevel)
159             {
160                 if (part != null && !part.HasProtectionLevel)
161                 {
162                     part.ProtectionLevel = newProtectionLevel;
163                 }
164                 else if (part == null && !message.HasProtectionLevel)
165                 {
166                     message.ProtectionLevel = newProtectionLevel;
167                 }
168                 else
169                 {
170                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.CannotImportProtectionLevelForContract, contract.Name, contract.Namespace)));
171                 }
172             }
173         }
174 
AddParts(ref MessagePartSpecification parts1, MessagePartSpecification parts2)175         void AddParts(ref MessagePartSpecification parts1, MessagePartSpecification parts2)
176         {
177             if (parts1 == null)
178                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("parts1"));
179             if (parts2 == null)
180                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("parts2"));
181 
182             if (!parts2.IsEmpty())
183             {
184                 if (parts1.IsReadOnly)
185                 {
186                     MessagePartSpecification p = new MessagePartSpecification();
187                     p.Union(parts1);
188                     p.Union(parts2);
189                     parts1 = p;
190                 }
191                 else
192                 {
193                     parts1.Union(parts2);
194                 }
195             }
196         }
197 
198         class ContractProtectionLevel
199         {
200             bool hasProtectionRequirements;
201             bool hasUniformProtectionLevel;
202             ProtectionLevel uniformProtectionLevel;
203 
ContractProtectionLevel(bool hasProtectionRequirements, bool hasUniformProtectionLevel, ProtectionLevel uniformProtectionLevel)204             public ContractProtectionLevel(bool hasProtectionRequirements, bool hasUniformProtectionLevel, ProtectionLevel uniformProtectionLevel)
205             {
206                 this.hasProtectionRequirements = hasProtectionRequirements;
207                 this.hasUniformProtectionLevel = hasUniformProtectionLevel;
208                 this.uniformProtectionLevel = uniformProtectionLevel;
209             }
210 
211             public bool HasProtectionRequirements { get { return this.hasProtectionRequirements; } }
212             public bool HasUniformProtectionLevel { get { return this.hasUniformProtectionLevel; } }
213             public ProtectionLevel UniformProtectionLevel { get { return this.uniformProtectionLevel; } }
214         }
215 
ImportMessageScopeProtectionPolicy(MetadataImporter importer, PolicyConversionContext policyContext)216         void ImportMessageScopeProtectionPolicy(MetadataImporter importer, PolicyConversionContext policyContext)
217         {
218             MessagePartSpecification endpointSignedParts;
219             MessagePartSpecification endpointEncryptedParts;
220             bool isContractAssociatedWithAtLeastOneOtherBinding;
221             ContractProtectionLevel otherBindingProtectionLevel = null;
222             bool hasContractProtectionLevel = false;
223             bool isContractProtectionLevelUniform = true;
224             ProtectionLevel contractProtectionLevel = ProtectionLevel.None;
225 
226             string contractAssociationName = String.Format("{0}:{1}:{2}", ContractProtectionLevelKey, policyContext.Contract.Name, policyContext.Contract.Namespace);
227             if (importer.State.ContainsKey(contractAssociationName))
228             {
229                 isContractAssociatedWithAtLeastOneOtherBinding = true;
230                 otherBindingProtectionLevel = (ContractProtectionLevel)importer.State[contractAssociationName];
231             }
232             else
233             {
234                 isContractAssociatedWithAtLeastOneOtherBinding = false;
235             }
236 
237             ICollection<XmlElement> endpointBindingAssertions = policyContext.GetBindingAssertions();
238             this.ImportProtectionAssertions(endpointBindingAssertions, out endpointSignedParts, out endpointEncryptedParts);
239 
240             if (importer.State.ContainsKey(InSecureConversationBootstrapBindingImportMode))
241             {
242                 // when importing secure conversation boostrap binding, add the endpoint scope protection requirements
243                 // to the importer state to be consumed in SecurityPolicy11.TryImportWsspBootrstapPolicyAssertion
244                 if (endpointEncryptedParts != null)
245                     importer.State[SecureConversationBootstrapEncryptionRequirements] = endpointEncryptedParts;
246                 if (endpointSignedParts != null)
247                     importer.State[SecureConversationBootstrapSignatureRequirements] = endpointSignedParts;
248             }
249 
250             foreach (OperationDescription operation in policyContext.Contract.Operations)
251             {
252                 MessagePartSpecification operationSignedParts;
253                 MessagePartSpecification operationEncryptedParts;
254 
255                 ICollection<XmlElement> operationBindingAssertions = policyContext.GetOperationBindingAssertions(operation);
256                 this.ImportProtectionAssertions(operationBindingAssertions, out operationSignedParts, out operationEncryptedParts);
257                 this.AddParts(ref operationSignedParts, endpointSignedParts);
258                 this.AddParts(ref operationEncryptedParts, endpointEncryptedParts);
259 
260                 MessagePartSpecification messageSignedParts;
261                 MessagePartSpecification messageEncryptedParts;
262                 bool hasProtectionLevel = false;
263                 bool isProtectionLevelUniform = true;
264                 ProtectionLevel protectionLevel = ProtectionLevel.None;
265 
266                 // import application message protection requirements
267                 foreach (MessageDescription message in operation.Messages)
268                 {
269                     ICollection<XmlElement> messageBindingAssertions = policyContext.GetMessageBindingAssertions(message);
270                     this.ImportProtectionAssertions(messageBindingAssertions, out messageSignedParts, out messageEncryptedParts);
271                     this.AddParts(ref messageSignedParts, operationSignedParts);
272                     this.AddParts(ref messageEncryptedParts, operationEncryptedParts);
273 
274                     // validate or set body protection level
275                     ProtectionLevel newProtectionLevel = GetProtectionLevel(messageSignedParts.IsBodyIncluded, messageEncryptedParts.IsBodyIncluded, message.Action);
276                     if (OperationFormatter.IsValidReturnValue(message.Body.ReturnValue))
277                     {
278                         ValidateExistingOrSetNewProtectionLevel(message.Body.ReturnValue, message, operation, policyContext.Contract, newProtectionLevel);
279                     }
280                     foreach (MessagePartDescription body in message.Body.Parts)
281                     {
282                         ValidateExistingOrSetNewProtectionLevel(body, message, operation, policyContext.Contract, newProtectionLevel);
283                     }
284                     if (!OperationFormatter.IsValidReturnValue(message.Body.ReturnValue) || message.Body.Parts.Count == 0)
285                     {
286                         ValidateExistingOrSetNewProtectionLevel(null, message, operation, policyContext.Contract, newProtectionLevel);
287                     }
288 
289                     if (hasProtectionLevel)
290                     {
291                         if (protectionLevel != newProtectionLevel)
292                         {
293                             isProtectionLevelUniform = false;
294                         }
295                     }
296                     else
297                     {
298                         protectionLevel = newProtectionLevel;
299                         hasProtectionLevel = true;
300                     }
301                     if (hasContractProtectionLevel)
302                     {
303                         if (contractProtectionLevel != newProtectionLevel)
304                         {
305                             isContractProtectionLevelUniform = false;
306                         }
307                     }
308                     else
309                     {
310                         contractProtectionLevel = newProtectionLevel;
311                         hasContractProtectionLevel = true;
312                     }
313 
314                     // validate o set header protection level
315                     foreach (MessageHeaderDescription header in message.Headers)
316                     {
317                         bool signed = messageSignedParts.IsHeaderIncluded(header.Name, header.Namespace);
318                         bool encrypted = messageEncryptedParts.IsHeaderIncluded(header.Name, header.Namespace);
319                         newProtectionLevel = GetProtectionLevel(signed, encrypted, message.Action);
320                         ValidateExistingOrSetNewProtectionLevel(header, message, operation, policyContext.Contract, newProtectionLevel);
321 
322                         if (hasProtectionLevel)
323                         {
324                             if (protectionLevel != newProtectionLevel)
325                             {
326                                 isProtectionLevelUniform = false;
327                             }
328                         }
329                         else
330                         {
331                             protectionLevel = newProtectionLevel;
332                             hasProtectionLevel = true;
333                         }
334                         if (hasContractProtectionLevel)
335                         {
336                             if (contractProtectionLevel != newProtectionLevel)
337                             {
338                                 isContractProtectionLevelUniform = false;
339                             }
340                         }
341                         else
342                         {
343                             contractProtectionLevel = newProtectionLevel;
344                             hasContractProtectionLevel = true;
345                         }
346                     }
347                 }
348 
349                 // normalize protection level settings at the operation scope if possible to help avoid typed message generation
350                 if (hasProtectionLevel && isProtectionLevelUniform)
351                 {
352                     // (Microsoft) remove the foreach message here
353                     //  foreach (MessageDescription message in operation.Messages)
354 
355                     this.ResetProtectionLevelForMessages(operation);
356 
357                     operation.ProtectionLevel = protectionLevel;
358                 }
359 
360                 // import fault protection requirements
361                 foreach (FaultDescription fault in operation.Faults)
362                 {
363                     ICollection<XmlElement> faultBindingAssertions = policyContext.GetFaultBindingAssertions(fault);
364                     this.ImportProtectionAssertions(faultBindingAssertions, out messageSignedParts, out messageEncryptedParts);
365                     this.AddParts(ref messageSignedParts, operationSignedParts);
366                     this.AddParts(ref messageEncryptedParts, operationEncryptedParts);
367 
368                     // validate or set fault protection level
369                     ProtectionLevel newProtectionLevel = GetProtectionLevel(messageSignedParts.IsBodyIncluded, messageEncryptedParts.IsBodyIncluded, fault.Action);
370                     if (fault.HasProtectionLevel)
371                     {
372                         if (fault.ProtectionLevel != newProtectionLevel)
373                         {
374                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.CannotImportProtectionLevelForContract, policyContext.Contract.Name, policyContext.Contract.Namespace)));
375                         }
376                     }
377                     else
378                     {
379                         fault.ProtectionLevel = newProtectionLevel;
380                     }
381                     if (hasContractProtectionLevel)
382                     {
383                         if (contractProtectionLevel != newProtectionLevel)
384                         {
385                             isContractProtectionLevelUniform = false;
386                         }
387                     }
388                     else
389                     {
390                         contractProtectionLevel = newProtectionLevel;
391                         hasContractProtectionLevel = true;
392                     }
393                 }
394             }
395 
396             if (isContractAssociatedWithAtLeastOneOtherBinding)
397             {
398                 if (hasContractProtectionLevel != otherBindingProtectionLevel.HasProtectionRequirements
399                     || isContractProtectionLevelUniform != otherBindingProtectionLevel.HasUniformProtectionLevel
400                     || contractProtectionLevel != otherBindingProtectionLevel.UniformProtectionLevel)
401                 {
402                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.CannotImportProtectionLevelForContract, policyContext.Contract.Name, policyContext.Contract.Namespace)));
403                 }
404             }
405             else
406             {
407                 if (hasContractProtectionLevel && isContractProtectionLevelUniform && contractProtectionLevel == ProtectionLevel.EncryptAndSign)
408                 {
409                     // remove all explicitly set protection levels on the contract description, since they are uniform across the contract
410                     // and match our binding's default of EncryptAndSign
411                     foreach (OperationDescription operation in policyContext.Contract.Operations)
412                     {
413                         this.ResetProtectionLevelForMessages(operation);
414                         foreach (FaultDescription fault in operation.Faults)
415                         {
416                             fault.ResetProtectionLevel();
417                         }
418                         operation.ResetProtectionLevel();
419                     }
420                 }
421                 importer.State[contractAssociationName] = new ContractProtectionLevel(hasContractProtectionLevel, isContractProtectionLevelUniform, contractProtectionLevel);
422             }
423         }
424 
ResetProtectionLevelForMessages(OperationDescription operation)425         void ResetProtectionLevelForMessages(OperationDescription operation)
426         {
427             foreach (MessageDescription message in operation.Messages)
428             {
429                 if (OperationFormatter.IsValidReturnValue(message.Body.ReturnValue))
430                 {
431                     message.Body.ReturnValue.ResetProtectionLevel();
432                 }
433                 foreach (MessagePartDescription body in message.Body.Parts)
434                 {
435                     body.ResetProtectionLevel();
436                 }
437                 foreach (MessageHeaderDescription header in message.Headers)
438                 {
439                     header.ResetProtectionLevel();
440                 }
441                 message.ResetProtectionLevel();
442             }
443         }
444 
GetProtectionLevel(bool signed, bool encrypted, string action)445         static ProtectionLevel GetProtectionLevel(bool signed, bool encrypted, string action)
446         {
447             ProtectionLevel result;
448 
449             if (encrypted)
450             {
451                 if (signed)
452                 {
453                     result = ProtectionLevel.EncryptAndSign;
454                 }
455                 else
456                 {
457                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidChannelBindingException(SR.GetString(SR.PolicyRequiresConfidentialityWithoutIntegrity, action)));
458                 }
459             }
460             else if (signed)
461             {
462                 result = ProtectionLevel.Sign;
463             }
464             else
465             {
466                 result = ProtectionLevel.None;
467             }
468 
469             return result;
470         }
471 
ImportSupportingTokenAssertions(MetadataImporter importer, PolicyConversionContext policyContext, ICollection<XmlElement> assertions, SupportingTokenParameters requirements, SupportingTokenParameters optionalRequirements)472         void ImportSupportingTokenAssertions(MetadataImporter importer, PolicyConversionContext policyContext, ICollection<XmlElement> assertions, SupportingTokenParameters requirements, SupportingTokenParameters optionalRequirements)
473         {
474             WSSecurityPolicy securityPolicy;
475             if (WSSecurityPolicy.TryGetSecurityPolicyDriver(assertions, out securityPolicy))
476             {
477                 securityPolicy.TryImportWsspSupportingTokensAssertion(
478                 importer,
479                 policyContext,
480                 assertions,
481                 requirements.Signed,
482                 requirements.SignedEncrypted,
483                 requirements.Endorsing,
484                 requirements.SignedEndorsing,
485                 optionalRequirements.Signed,
486                 optionalRequirements.SignedEncrypted,
487                 optionalRequirements.Endorsing,
488                 optionalRequirements.SignedEndorsing);
489             }
490         }
491 
ImportEndpointScopeMessageBindingAssertions(MetadataImporter importer, PolicyConversionContext policyContext, SecurityBindingElement binding)492         void ImportEndpointScopeMessageBindingAssertions(MetadataImporter importer, PolicyConversionContext policyContext, SecurityBindingElement binding)
493         {
494             XmlElement assertion = null;
495 
496             this.ImportSupportingTokenAssertions(importer, policyContext, policyContext.GetBindingAssertions(), binding.EndpointSupportingTokenParameters, binding.OptionalEndpointSupportingTokenParameters);
497 
498             WSSecurityPolicy securityPolicy;
499             if (WSSecurityPolicy.TryGetSecurityPolicyDriver(policyContext.GetBindingAssertions(), out securityPolicy))
500             {
501                 if (!securityPolicy.TryImportWsspWssAssertion(importer, policyContext.GetBindingAssertions(), binding, out assertion)
502                     && assertion != null)
503                 {
504                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnsupportedSecurityPolicyAssertion, assertion.OuterXml)));
505                 }
506 
507                 if (!securityPolicy.TryImportWsspTrustAssertion(importer, policyContext.GetBindingAssertions(), binding, out assertion)
508                     && assertion != null)
509                 {
510                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnsupportedSecurityPolicyAssertion, assertion.OuterXml)));
511                 }
512             }
513 
514             //
515             // We don't have WSTrust assertion => it is possible we are a BasicHttpBinding
516             // Set the flag here so that later when we tried to compare binding element with basic http binding
517             // we can have an exact match.
518             //
519             if (assertion == null)
520                 binding.DoNotEmitTrust = true;
521         }
522 
523 
TryImportSymmetricSecurityBindingElement(MetadataImporter importer, PolicyConversionContext policyContext, out SecurityBindingElement sbe)524         bool TryImportSymmetricSecurityBindingElement(MetadataImporter importer, PolicyConversionContext policyContext, out SecurityBindingElement sbe)
525         {
526             SymmetricSecurityBindingElement binding = null;
527             XmlElement assertion;
528             WSSecurityPolicy securityPolicy;
529             if (WSSecurityPolicy.TryGetSecurityPolicyDriver(policyContext.GetBindingAssertions(), out securityPolicy))
530             {
531                 if (securityPolicy.TryImportWsspSymmetricBindingAssertion(importer, policyContext, policyContext.GetBindingAssertions(), out binding, out assertion))
532                 {
533                     this.ImportEndpointScopeMessageBindingAssertions(importer, policyContext, binding);
534                     this.ImportOperationScopeSupportingTokensPolicy(importer, policyContext, binding);
535                     this.ImportMessageScopeProtectionPolicy(importer, policyContext);
536                     policyContext.BindingElements.Add(binding);
537                 }
538                 else if (assertion != null)
539                 {
540                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnsupportedSecurityPolicyAssertion, assertion.OuterXml)));
541                 }
542             }
543 
544             sbe = binding;
545             return binding != null;
546         }
547 
TryImportAsymmetricSecurityBindingElement(MetadataImporter importer, PolicyConversionContext policyContext, out SecurityBindingElement sbe)548         bool TryImportAsymmetricSecurityBindingElement(MetadataImporter importer, PolicyConversionContext policyContext, out SecurityBindingElement sbe)
549         {
550             AsymmetricSecurityBindingElement binding = null;
551             XmlElement assertion;
552             WSSecurityPolicy securityPolicy;
553             if (WSSecurityPolicy.TryGetSecurityPolicyDriver(policyContext.GetBindingAssertions(), out securityPolicy))
554             {
555                 if (securityPolicy.TryImportWsspAsymmetricBindingAssertion(importer, policyContext, policyContext.GetBindingAssertions(), out binding, out assertion))
556                 {
557                     this.ImportEndpointScopeMessageBindingAssertions(importer, policyContext, binding);
558                     this.ImportOperationScopeSupportingTokensPolicy(importer, policyContext, binding);
559                     this.ImportMessageScopeProtectionPolicy(importer, policyContext);
560                     policyContext.BindingElements.Add(binding);
561                 }
562                 else if (assertion != null)
563                 {
564                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnsupportedSecurityPolicyAssertion, assertion.OuterXml)));
565                 }
566             }
567 
568             sbe = binding;
569             return binding != null;
570         }
571 
572         // isDualSecurityModeOnly is true if the binding has both message security and https security enabled.
TryImportTransportSecurityBindingElement(MetadataImporter importer, PolicyConversionContext policyContext, out SecurityBindingElement sbe, bool isDualSecurityModeOnly)573         bool TryImportTransportSecurityBindingElement(MetadataImporter importer, PolicyConversionContext policyContext, out SecurityBindingElement sbe, bool isDualSecurityModeOnly)
574         {
575             TransportSecurityBindingElement binding = null;
576             XmlElement assertion;
577             sbe = null;
578 
579             WSSecurityPolicy securityPolicy;
580             if (WSSecurityPolicy.TryGetSecurityPolicyDriver(policyContext.GetBindingAssertions(), out securityPolicy))
581             {
582                 if (securityPolicy.TryImportWsspTransportBindingAssertion(importer, policyContext.GetBindingAssertions(), out binding, out assertion))
583                 {
584                     this.ImportEndpointScopeMessageBindingAssertions(importer, policyContext, binding);
585 
586                     // If it is not DualSecurityMode then it is Mixed mode. So we need to look for supporting tokens in the binding.
587                     if (!isDualSecurityModeOnly)
588                     {
589                         this.ImportOperationScopeSupportingTokensPolicy(importer, policyContext, binding);
590                         if (importer.State.ContainsKey(InSecureConversationBootstrapBindingImportMode))
591                         {
592                             this.ImportMessageScopeProtectionPolicy(importer, policyContext);
593                         }
594 
595                         if (HasSupportingTokens(binding) || binding.IncludeTimestamp)
596                         {
597                             sbe = binding;
598                             policyContext.BindingElements.Add(binding);
599                         }
600                     }
601                 }
602                 else if (assertion != null)
603                 {
604                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnsupportedSecurityPolicyAssertion, assertion.OuterXml)));
605                 }
606             }
607 
608             return binding != null;
609         }
610 
611 
HasSupportingTokens(SecurityBindingElement binding)612         static bool HasSupportingTokens(SecurityBindingElement binding)
613         {
614             if (binding.EndpointSupportingTokenParameters.Endorsing.Count > 0
615                     || binding.EndpointSupportingTokenParameters.SignedEndorsing.Count > 0
616                     || binding.EndpointSupportingTokenParameters.SignedEncrypted.Count > 0
617                     || binding.EndpointSupportingTokenParameters.Signed.Count > 0)
618             {
619                 return true;
620             }
621 
622             foreach (SupportingTokenParameters r in binding.OperationSupportingTokenParameters.Values)
623             {
624                 if (r.Endorsing.Count > 0
625                         || r.SignedEndorsing.Count > 0
626                         || r.SignedEncrypted.Count > 0
627                         || r.Signed.Count > 0)
628                 {
629                     return true;
630                 }
631             }
632 
633             return false;
634         }
635 
IPolicyImportExtension.ImportPolicy(MetadataImporter importer, PolicyConversionContext policyContext)636         void IPolicyImportExtension.ImportPolicy(MetadataImporter importer, PolicyConversionContext policyContext)
637         {
638             if (importer == null)
639             {
640                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("importer");
641             }
642             if (policyContext == null)
643             {
644                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("policyContext");
645             }
646             WSSecurityPolicy securityPolicy;
647             if (WSSecurityPolicy.TryGetSecurityPolicyDriver(policyContext.GetBindingAssertions(), out securityPolicy))
648             {
649                 if ((importer.State != null) && (!importer.State.ContainsKey(MaxPolicyRedirectionsKey)))
650                 {
651                     importer.State.Add(MaxPolicyRedirectionsKey, this.MaxPolicyRedirections);
652                 }
653 
654                 SecurityBindingElement sbe = null;
655                 bool success = this.TryImportSymmetricSecurityBindingElement(importer, policyContext, out sbe);
656                 if (!success)
657                 {
658                     success = this.TryImportAsymmetricSecurityBindingElement(importer, policyContext, out sbe);
659                 }
660                 if (!success)
661                 {
662                     success = this.TryImportTransportSecurityBindingElement(importer, policyContext, out sbe, false);
663                 }
664                 else
665                 {
666                     // We already have found and imported the message security binding element above. Hence this could be the dual mode security.
667                     // Now let us see if there is HttpsTransportBinding assertion also below it .This is to avoid the
668                     // warning messages while importing wsdl representing the message security over Https transport security scenario. See Bug:136416.
669 
670                     SecurityBindingElement tbe = null;
671                     this.TryImportTransportSecurityBindingElement(importer, policyContext, out tbe, true);
672                 }
673 
674                 if (sbe != null)
675                 {
676                     SecurityElement config = new SecurityElement();
677                     config.InitializeFrom(sbe, false);
678                     if (config.HasImportFailed)
679                     {
680 #pragma warning suppress 56506
681                         importer.Errors.Add(new MetadataConversionError(SR.GetString(SR.SecurityBindingElementCannotBeExpressedInConfig), true));
682                     }
683                 }
684             }
685         }
686     }
687 }
688