1 
2 namespace System.IdentityModel.Diagnostics
3 {
4     using System;
5     using System.Collections.Generic;
6     using System.Linq;
7     using System.Text;
8     using System.IdentityModel.Diagnostics;
9     using System.Diagnostics;
10     using System.Runtime.Diagnostics;
11     using System.Security.Authentication.ExtendedProtection;
12     using System.IO;
13     using System.Runtime.Serialization.Formatters.Binary;
14     using System.ServiceModel.Diagnostics;
15     using System.Xml;
16     using System.IdentityModel.Tokens;
17     using System.Security.Cryptography;
18 
19     class SecurityTraceRecord : TraceRecord
20     {
21         String traceName;
SecurityTraceRecord(String traceName)22         internal SecurityTraceRecord(String traceName)
23         {
24             if (string.IsNullOrEmpty(traceName))
25                 this.traceName = "Empty";
26             else
27                 this.traceName = traceName;
28         }
29 
30         internal override string EventId { get { return BuildEventId(traceName); } }
31     }
32 
33     internal static class SecurityTraceRecordHelper
34     {
TraceServiceNameBindingOnServer(string serviceBindingNameSentByClient, string defaultServiceBindingNameOfServer, ServiceNameCollection serviceNameCollectionConfiguredOnServer)35         internal static void TraceServiceNameBindingOnServer(string serviceBindingNameSentByClient, string defaultServiceBindingNameOfServer, ServiceNameCollection serviceNameCollectionConfiguredOnServer)
36         {
37             TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.ServiceBindingCheck, SR.GetString(SR.TraceCodeServiceBindingCheck), new ServiceBindingNameTraceRecord(serviceBindingNameSentByClient, defaultServiceBindingNameOfServer, serviceNameCollectionConfiguredOnServer), null, null);
38         }
39 
TraceChannelBindingInformation(ExtendedProtectionPolicyHelper policyHelper, bool isServer, ChannelBinding channelBinding)40         internal static void TraceChannelBindingInformation(ExtendedProtectionPolicyHelper policyHelper, bool isServer, ChannelBinding channelBinding)
41         {
42             TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.ChannelBindingCheck, SR.GetString(SR.TraceCodeChannelBindingCheck), new ChannelBindingNameTraceRecord(policyHelper, isServer, channelBinding), null, null);
43         }
44 
45         class ServiceBindingNameTraceRecord : SecurityTraceRecord
46         {
47             string serviceBindingNameSentByClient;
48             string defaultServiceBindingNameOfServer;
49             ServiceNameCollection serviceNameCollectionConfiguredOnServer;
50 
ServiceBindingNameTraceRecord(string serviceBindingNameSentByClient, string defaultServiceBindingNameOfServer, ServiceNameCollection serviceNameCollectionConfiguredOnServer)51             public ServiceBindingNameTraceRecord(string serviceBindingNameSentByClient, string defaultServiceBindingNameOfServer, ServiceNameCollection serviceNameCollectionConfiguredOnServer)
52                 : base("ServiceBindingCheckAfterSpNego")
53             {
54                 this.serviceBindingNameSentByClient = serviceBindingNameSentByClient;
55                 this.defaultServiceBindingNameOfServer = defaultServiceBindingNameOfServer;
56                 this.serviceNameCollectionConfiguredOnServer = serviceNameCollectionConfiguredOnServer;
57             }
58 
WriteTo(XmlWriter xml)59             internal override void WriteTo(XmlWriter xml)
60             {
61                 if (xml == null)
62                     return;
63 
64                 xml.WriteComment(SR.GetString(SR.ServiceNameFromClient));
65                 xml.WriteElementString("ServiceName", this.serviceBindingNameSentByClient);
66 
67                 xml.WriteComment(SR.GetString(SR.ServiceNameOnService));
68                 xml.WriteStartElement("ServiceNameCollection");
69                 if (this.serviceNameCollectionConfiguredOnServer == null || this.serviceNameCollectionConfiguredOnServer.Count < 1)
70                 {
71                     xml.WriteElementString("ServiceName", this.defaultServiceBindingNameOfServer);
72                 }
73                 else
74                 {
75                     foreach (string serviceName in this.serviceNameCollectionConfiguredOnServer)
76                     {
77                         xml.WriteElementString("ServiceName", serviceName);
78                     }
79                 }
80 
81                 xml.WriteFullEndElement();
82 
83             }
84         }
85 
86         class ChannelBindingNameTraceRecord : SecurityTraceRecord
87         {
88             ExtendedProtectionPolicyHelper policyHelper;
89             bool isServer;
90             bool channelBindingUsed;
91             ChannelBinding channelBinding;
92 
ChannelBindingNameTraceRecord(ExtendedProtectionPolicyHelper policyHelper, bool isServer, ChannelBinding channelBinding)93             public ChannelBindingNameTraceRecord(ExtendedProtectionPolicyHelper policyHelper, bool isServer, ChannelBinding channelBinding)
94                 : base("SpNegoChannelBindingInformation")
95             {
96                 this.policyHelper = policyHelper;
97                 this.isServer = isServer;
98                 this.channelBindingUsed = false;
99                 this.channelBinding = channelBinding;
100             }
101 
WriteTo(XmlWriter xml)102             internal override void WriteTo(XmlWriter xml)
103             {
104                 if (xml == null)
105                     return;
106                 if (this.policyHelper != null)
107                 {
108                     xml.WriteElementString("PolicyEnforcement", this.policyHelper.PolicyEnforcement.ToString());
109                     xml.WriteElementString("ProtectionScenario", this.policyHelper.ProtectionScenario.ToString());
110 
111                     xml.WriteStartElement("ServiceNameCollection");
112 
113                     if (this.policyHelper.ServiceNameCollection != null && this.policyHelper.ServiceNameCollection.Count > 0)
114                     {
115                         foreach (string serviceName in this.policyHelper.ServiceNameCollection)
116                         {
117                             xml.WriteElementString("ServiceName", serviceName);
118                         }
119                     }
120 
121                     xml.WriteFullEndElement();
122 
123                     if (this.isServer)
124                     {
125                         this.channelBindingUsed = this.policyHelper.ShouldAddChannelBindingToASC();
126                     }
127                     else
128                     {
129                         this.channelBindingUsed = this.policyHelper.ChannelBinding != null;
130                     }
131 
132                     xml.WriteElementString("ChannelBindingUsed", this.channelBindingUsed.ToString());
133 
134                     if (this.channelBinding != null && this.policyHelper.PolicyEnforcement != PolicyEnforcement.Never && this.channelBindingUsed == true)
135                     {
136                         ExtendedProtectionPolicy extendedProtection = new ExtendedProtectionPolicy(policyHelper.PolicyEnforcement, channelBinding);
137                         xml.WriteElementString("ChannelBindingData", GetBase64EncodedChannelBindingData(extendedProtection));
138                     }
139                 }
140                 else
141                 {
142                     // This is the case for KerberosRequestorSecurityToken where policyHelper is null.
143                     if (this.channelBinding != null)
144                     {
145                         xml.WriteElementString("ChannelBindingUsed", "true");
146 
147                         // We do not know the PolicyEnforcement value here on the client side and we can not pass Never
148                         //as ExtendedProtectionPolicy constructor would throw on PolicyEnforcement.Never
149                         ExtendedProtectionPolicy extendedProtection = new ExtendedProtectionPolicy(PolicyEnforcement.WhenSupported, channelBinding);
150                         xml.WriteElementString("ChannelBindingData", GetBase64EncodedChannelBindingData(extendedProtection));
151                     }
152                     else
153                     {
154                         xml.WriteElementString("ChannelBindingUsed", "false");
155                         xml.WriteElementString("ChannelBindingData", null);
156                     }
157                 }
158 
159             }
160 
GetBase64EncodedChannelBindingData(ExtendedProtectionPolicy extendedProtectionPolicy)161             internal string GetBase64EncodedChannelBindingData(ExtendedProtectionPolicy extendedProtectionPolicy)
162             {
163                 MemoryStream ms = new MemoryStream();
164                 BinaryFormatter formatter = new BinaryFormatter();
165                 formatter.Serialize(ms, extendedProtectionPolicy);
166                 byte[] channelBindingData = ms.GetBuffer();
167                 return Convert.ToBase64String(channelBindingData, Base64FormattingOptions.None);
168             }
169         }
170 
171         /// <summary>
172         /// Used to serialize a token to the trace.  Used in multiple places.
173         /// </summary>
174         internal class TokenTraceRecord : SecurityTraceRecord
175         {
176             const string ElementName = "TokenTraceRecord";
177 
178             SecurityToken _securityToken;
179 
TokenTraceRecord(SecurityToken securityToken)180             public TokenTraceRecord(SecurityToken securityToken)
181                 : base(ElementName)
182             {
183                 _securityToken = securityToken;
184             }
185 
WriteSessionToken(XmlWriter writer, SessionSecurityToken sessionToken)186             void WriteSessionToken(XmlWriter writer, SessionSecurityToken sessionToken)
187             {
188                 SessionSecurityTokenHandler ssth = GetOrCreateSessionSecurityTokenHandler();
189 
190                 XmlDictionaryWriter dictionaryWriter = XmlDictionaryWriter.CreateDictionaryWriter(writer);
191                 ssth.WriteToken(dictionaryWriter, sessionToken);
192             }
193 
GetOrCreateSessionSecurityTokenHandler()194             private static SessionSecurityTokenHandler GetOrCreateSessionSecurityTokenHandler()
195             {
196                 SecurityTokenHandlerCollection defaultHandlers = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
197                 SessionSecurityTokenHandler ssth = defaultHandlers[typeof(SessionSecurityToken)] as SessionSecurityTokenHandler;
198 
199                 if (ssth == null)
200                 {
201                     ssth = new SessionSecurityTokenHandler();
202                     defaultHandlers.AddOrReplace(ssth);
203                 }
204 
205                 return ssth;
206             }
207 
WriteTo(XmlWriter writer)208             internal override void WriteTo(XmlWriter writer)
209             {
210                 writer.WriteStartElement(ElementName);
211                 writer.WriteAttributeString(DiagnosticStrings.NamespaceTag, EventId);
212 
213                 writer.WriteStartElement("SecurityToken");
214                 writer.WriteAttributeString("Type", _securityToken.GetType().ToString());
215 
216                 if (_securityToken is SessionSecurityToken)
217                 {
218                     WriteSessionToken(writer, _securityToken as SessionSecurityToken);
219                 }
220                 else
221                 {
222                     SecurityTokenHandlerCollection sthc = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
223                     if (sthc.CanWriteToken(_securityToken))
224                     {
225                         {
226                             sthc.WriteToken(writer, _securityToken);
227                         }
228                     }
229                     else
230                     {
231                         writer.WriteElementString("Warning", SR.GetString(SR.TraceUnableToWriteToken, _securityToken.GetType().ToString()));
232                     }
233                 }
234 
235                 writer.WriteEndElement();
236             }
237         }
238     }
239 }
240