1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 
5 namespace System.IdentityModel.Tokens
6 {
7     using System;
8     using System.Collections.Generic;
9     using System.Collections.ObjectModel;
10     using System.ComponentModel;
11     using System.IdentityModel.Claims;
12     using System.IdentityModel.Policy;
13     using System.IO;
14     using System.Runtime.InteropServices;
15     using System.Runtime.Serialization;
16     using System.Runtime.Serialization.Formatters.Binary;
17     using System.Security.Claims;
18     using System.Security.Cryptography;
19     using System.Security.Cryptography.X509Certificates;
20     using System.Security.Principal;
21     using System.Text;
22     using System.Xml;
23     using Claim = System.Security.Claims.Claim;
24     using ClaimTypes = System.Security.Claims.ClaimTypes;
25     using SysClaim = System.IdentityModel.Claims.Claim;
26     using SysClaimTypes = System.IdentityModel.Claims.ClaimTypes;
27     using SysUniqueId = System.Xml.UniqueId;
28 
29     /// <summary>
30     /// Defines a SessionSecurityToken that contains data associated with a session.
31     /// </summary>
32     [Serializable]
33     public class SessionSecurityToken : SecurityToken, ISerializable
34     {
35         const string SupportedVersion = "1";
36         const string tokenKey = "SessionToken";
37         const string WindowsSecurityTokenStubElementName = "WindowsSecurityTokenStub";
38 
39         static Dictionary<string, string> DomainNameMap = new Dictionary<string, string>(MaxDomainNameMapSize, StringComparer.OrdinalIgnoreCase);
40         const int MaxDomainNameMapSize = 50;
41         static Random rnd = new Random();
42 
43         string _context;
44         bool _isPersistent;
45 
46         ClaimsPrincipal _claimsPrincipal;
47         SctAuthorizationPolicy _sctAuthorizationPolicy;
48 
49         string _endpointId;
50         bool _isReferenceMode;
51         bool _isSecurityContextSecurityTokenWrapper;
52 
53         string _id;
54 
55         SysUniqueId _contextId;
56         SysUniqueId _keyGeneration;
57 
58         DateTime _keyEffectiveTime;
59         DateTime _keyExpirationTime;
60 
61         Uri _secureConversationVersion;
62 
63         DateTime _validFrom;
64         DateTime _validTo;
65 
66         ReadOnlyCollection<SecurityKey> _securityKeys;
67 
68         /// <summary>
69         /// Create session security token from a principal.
70         /// </summary>
71         /// <param name="claimsPrincipal">The <see cref="ClaimsPrincipal"/>.</param>
72         /// <returns></returns>
SessionSecurityToken(ClaimsPrincipal claimsPrincipal)73         public SessionSecurityToken(ClaimsPrincipal claimsPrincipal)
74             : this(claimsPrincipal, null)
75         { }
76 
77         /// <summary>
78         /// Create session security token from a principal.
79         /// </summary>
80         /// <param name="claimsPrincipal">The <see cref="ClaimsPrincipal"/>.</param>
81         /// <param name="lifetime">The Timespan the token is valid.</param>
SessionSecurityToken(ClaimsPrincipal claimsPrincipal, TimeSpan lifetime)82         public SessionSecurityToken(ClaimsPrincipal claimsPrincipal, TimeSpan lifetime)
83             : this(claimsPrincipal, null, DateTime.UtcNow, DateTimeUtil.AddNonNegative(DateTime.UtcNow, lifetime))
84         {
85         }
86 
87         /// <summary>
88         /// Create session security token from principal and bootstrap token.
89         /// </summary>
90         /// <param name="claimsPrincipal">The <see cref="ClaimsPrincipal"/> that generated from the bootstrap token.</param>
91         /// <param name="context">Session specific context string</param>
SessionSecurityToken(ClaimsPrincipal claimsPrincipal, string context)92         public SessionSecurityToken(ClaimsPrincipal claimsPrincipal, string context)
93             : this(claimsPrincipal, context, DateTime.UtcNow, DateTimeUtil.AddNonNegative(DateTime.UtcNow, SessionSecurityTokenHandler.DefaultTokenLifetime))
94         { }
95 
96         /// <summary>
97         /// Create session security token from principal and bootstrap token.
98         /// </summary>
99         /// <param name="claimsPrincipal">The <see cref="ClaimsPrincipal"/> that generated from the bootstrap token.</param>
100         /// <param name="context">Session specific context string</param>
101         /// <param name="validFrom">DateTime specifying the time the token becomes valid.</param>
102         /// <param name="validTo">DateTime specifying the time the token becomes invalid.</param>
SessionSecurityToken(ClaimsPrincipal claimsPrincipal, string context, DateTime? validFrom, DateTime? validTo)103         public SessionSecurityToken(ClaimsPrincipal claimsPrincipal, string context, DateTime? validFrom, DateTime? validTo)
104             : this(claimsPrincipal, new SysUniqueId(), context, String.Empty, validFrom, validTo, null)
105         { }
106 
107         /// <summary>
108         /// Create session security token from principal and bootstrap token.
109         /// </summary>
110         /// <param name="claimsPrincipal">The <see cref="ClaimsPrincipal"/> that generated from the bootstrap token.</param>
111         /// <param name="context">Session specific context string</param>
112         /// <param name="endpointId">The endpoint to which this token is bound. String.Empty would create a unscoped token.</param>
113         /// <param name="validFrom">DateTime specifying the time the token becomes valid.</param>
114         /// <param name="validTo">DateTime specifying the time the token becomes invalid.</param>
SessionSecurityToken(ClaimsPrincipal claimsPrincipal, string context, string endpointId, DateTime? validFrom, DateTime? validTo)115         public SessionSecurityToken(ClaimsPrincipal claimsPrincipal, string context, string endpointId, DateTime? validFrom, DateTime? validTo)
116             : this(claimsPrincipal, new SysUniqueId(), context, endpointId, validFrom, validTo, null)
117         { }
118 
119         /// <summary>
120         /// Initializes a new instance of the <see cref="SessionSecurityToken"/> class.
121         /// </summary>
122         /// <param name="claimsPrincipal"><see cref="ClaimsPrincipal"/> associated with this session.</param>
123         /// <param name="contextId">Optional context identifier associated with this token.  If null a new identifier will be generated.</param>
124         /// <param name="context">Optional context information associated with the session.</param>
125         /// <param name="endpointId">The endpoint to which this token is bound. String.Empty would create a unscoped token.</param>
126         /// <param name="lifetime">The lifetime of the session token.  ValidFrom will be set to DateTime.UtcNow, ValidTo will be set to ValidFrom + lifetime.</param>
127         /// <param name="key">Optional symmetric session key.</param>
128         /// <exception cref="InvalidOperationException">The value of lifetime &lt;= TimeSpan.Zero."</exception>
SessionSecurityToken(ClaimsPrincipal claimsPrincipal, SysUniqueId contextId, string context, string endpointId, TimeSpan lifetime, SymmetricSecurityKey key)129         public SessionSecurityToken(ClaimsPrincipal claimsPrincipal,
130                                      SysUniqueId contextId,
131                                      string context,
132                                      string endpointId,
133                                      TimeSpan lifetime,
134                                      SymmetricSecurityKey key)
135             : this(claimsPrincipal, contextId, context, endpointId, DateTime.UtcNow, lifetime, key)
136         {
137         }
138 
139         /// <summary>
140         /// Initializes a new instance of the <see cref="SessionSecurityToken"/> class.
141         /// </summary>
142         /// <param name="claimsPrincipal"><see cref="ClaimsPrincipal"/> associated with this session.</param>
143         /// <param name="contextId">Optional context identifier associated with this token.  If null a new identifier will be generated.</param>
144         /// <param name="context">Optional context information associated with the session.</param>
145         /// <param name="endpointId">The endpoint to which this token is bound. String.Empty would create a unscoped token.</param>
146         /// <param name="validFrom">DateTime specifying the time the token becomes valid.</param>
147         /// <param name="lifetime">The lifetime of the session token.  ValidTo will be set to ValidFrom + lifetime.</param>
148         /// <param name="key">Optional symmetric session key.</param>
149         /// <exception cref="InvalidOperationException">The value of lifetime &lt;= TimeSpan.Zero."</exception>
SessionSecurityToken(ClaimsPrincipal claimsPrincipal, SysUniqueId contextId, string context, string endpointId, DateTime validFrom, TimeSpan lifetime, SymmetricSecurityKey key)150         public SessionSecurityToken(ClaimsPrincipal claimsPrincipal,
151                                      SysUniqueId contextId,
152                                      string context,
153                                      string endpointId,
154                                      DateTime validFrom,
155                                      TimeSpan lifetime,
156                                      SymmetricSecurityKey key)
157             : this(claimsPrincipal, contextId, context, endpointId, validFrom, DateTimeUtil.AddNonNegative(validFrom, lifetime), key)
158         {
159         }
160 
161         /// <summary>
162         /// Initializes a new instance of the <see cref="SessionSecurityToken"/> class.
163         /// </summary>
164         /// <param name="claimsPrincipal"><see cref="ClaimsPrincipal"/> associated with this session.</param>
165         /// <param name="contextId">Context Identifier that identifies the session</param>
166         /// <param name="context">Optional context information associated with the session.</param>
167         /// <param name="endpointId">The endpoint to which this token is bound. String.Empty would create a unscoped token.</param>
168         /// <param name="validFrom">DateTime specifying the time the token becomes valid.</param>
169         /// <param name="validTo">DateTime specifying the time the token becomes invalid.</param>
170         /// <param name="key">Optional symmetric session key.</param>
171         /// <exception cref="ArgumentNullException">The input parameter 'claimsPrincipal' is null.</exception>
172         /// <exception cref="ArgumentNullException">The input parameter 'contextId' is null.</exception>
173         /// <exception cref="ArgumentOutOfRangeException">validFrom is greater than or equal to validTo.</exception>
174         /// <exception cref="ArgumentOutOfRangeException">validTo is less than current time.</exception>
175         /// <remarks>
176         /// If no key is supplied, a 128bit key is generated. KeyEffectiveTime is set to validFrom, KeyExpirationTime is set to validTo.
177         /// A key generation identifier is created.
178         /// </remarks>
SessionSecurityToken(ClaimsPrincipal claimsPrincipal, SysUniqueId contextId, string context, string endpointId, DateTime? validFrom, DateTime? validTo, SymmetricSecurityKey key)179         public SessionSecurityToken(ClaimsPrincipal claimsPrincipal,
180                                      SysUniqueId contextId,
181                                      string context,
182                                      string endpointId,
183                                      DateTime? validFrom,
184                                      DateTime? validTo,
185                                      SymmetricSecurityKey key)
186             : this(claimsPrincipal, contextId, System.IdentityModel.UniqueId.CreateUniqueId(), context, key == null ? null : key.GetSymmetricKey(), endpointId, validFrom, validTo, null, validFrom, validTo, null, null)
187         {
188         }
189 
190         /// <summary>
191         /// Core ctor with all parameters in their most primitive form.  This constructor is used in deserialization and
192         /// when generating a wrapper SessionSecurityToken from a SecurityContextSecurityToken.
193         /// </summary>
194         /// <param name="contextId">Context identifier</param>
195         /// <param name="id">Token identifier</param>
196         /// <param name="context">Session context data</param>
197         /// <param name="endpointId">The endpoint to which this token is bound. String.Empty would create a unscoped token.</param>
198         /// <param name="key">Key material</param>
199         /// <param name="validFrom">Start time</param>
200         /// <param name="validTo">End time</param>
201         /// <param name="keyGeneration">Key Generation identifier</param>
202         /// <param name="keyEffectiveTime">Key start time</param>
203         /// <param name="keyExpirationTime">Key end time</param>
204         /// <param name="authorizationPolicies">Authorization policies</param>
205         /// <param name="securityContextSecurityTokenWrapperSecureConversationVersion">The version of
206         /// WS-SecureConversation used to generate this SCT.  This should be null if the token is not an SCT wrapper.</param>
SessionSecurityToken(ClaimsPrincipal claimsPrincipal, SysUniqueId contextId, string id, string context, byte[] key, string endpointId, DateTime? validFrom, DateTime? validTo, SysUniqueId keyGeneration, DateTime? keyEffectiveTime, DateTime? keyExpirationTime, SctAuthorizationPolicy sctAuthorizationPolicy, Uri securityContextSecurityTokenWrapperSecureConversationVersion)207         internal SessionSecurityToken(ClaimsPrincipal claimsPrincipal,
208                                        SysUniqueId contextId,
209                                        string id,
210                                        string context,
211                                        byte[] key,
212                                        string endpointId,
213                                        DateTime? validFrom,
214                                        DateTime? validTo,
215                                        SysUniqueId keyGeneration,
216                                        DateTime? keyEffectiveTime,
217                                        DateTime? keyExpirationTime,
218                                        SctAuthorizationPolicy sctAuthorizationPolicy,
219                                        Uri securityContextSecurityTokenWrapperSecureConversationVersion)
220             : base()
221         {
222             if (claimsPrincipal == null || claimsPrincipal.Identities == null)
223             {
224                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("claimsPrincipal");
225             }
226 
227             if (contextId == null)
228             {
229                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contextId");
230             }
231 
232             //
233             // validFrom and validTo may not have values.
234             // need to set them to reasonable defaults before moving forward.
235             // SecurityContextSecurityToken will check the values, but I choose to check
236             // here to keep the exception in our stack.
237             //
238 
239             DateTime validFromEffective;
240             DateTime validToEffective;
241 
242             if (validFrom.HasValue)
243             {
244                 validFromEffective = DateTimeUtil.ToUniversalTime(validFrom.Value);
245             }
246             else
247             {
248                 validFromEffective = DateTime.UtcNow;
249             }
250 
251             if (validTo.HasValue)
252             {
253                 validToEffective = DateTimeUtil.ToUniversalTime(validTo.Value);
254             }
255             else
256             {
257                 validToEffective = DateTimeUtil.Add(validFromEffective, SessionSecurityTokenHandler.DefaultTokenLifetime);
258             }
259 
260             if (validFromEffective >= validToEffective)
261             {
262                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("validFrom"));
263             }
264 
265             if (validToEffective < DateTime.UtcNow)
266             {
267                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("validTo"));
268             }
269 
270             if (endpointId == null)
271             {
272                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpointId");
273             }
274 
275             if (!keyEffectiveTime.HasValue)
276             {
277                 keyEffectiveTime = (DateTime?)validFromEffective;
278             }
279 
280             if (!keyExpirationTime.HasValue)
281             {
282                 keyExpirationTime = (DateTime?)validToEffective;
283             }
284 
285             if (keyEffectiveTime.Value > keyExpirationTime.Value || keyEffectiveTime.Value < validFromEffective)
286             {
287                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("keyEffectiveTime"));
288             }
289 
290             if (keyExpirationTime.Value > validToEffective)
291             {
292                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("keyExpirationTime"));
293             }
294 
295             if (securityContextSecurityTokenWrapperSecureConversationVersion == null)
296             {
297                 // Not an SCT wrapper: use the default namespace.
298                 _secureConversationVersion = WSSecureConversation13Constants.NamespaceUri;
299             }
300             else
301             {
302                 // SCT wrapper: use the provided namespace.
303                 _isSecurityContextSecurityTokenWrapper = true;
304                 _secureConversationVersion = securityContextSecurityTokenWrapperSecureConversationVersion;
305             }
306 
307             if (key == null)
308             {
309                 // We have to create a dummy key here. We are not in WCF and we will
310                 // never use this key. But this is created only to satisfy WCF's
311                 // SecurityContextSecurityToken constructor.
312                 key = CryptoHelper.KeyGenerator.GenerateSymmetricKey(128);
313             }
314 
315             if (endpointId == null)
316             {
317                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpointId");
318             }
319 
320             _claimsPrincipal = claimsPrincipal;
321             _contextId = contextId;
322             _id = id;
323             _context = context;
324             _securityKeys = new ReadOnlyCollection<SecurityKey>(new SecurityKey[] { new InMemorySymmetricSecurityKey(key) });
325             _endpointId = endpointId;
326             _validFrom = validFrom.Value;
327             _validTo = validTo.Value;
328             _keyGeneration = keyGeneration;
329             _keyEffectiveTime = keyEffectiveTime.Value;
330             _keyExpirationTime = keyExpirationTime.Value;
331             _sctAuthorizationPolicy = sctAuthorizationPolicy;
332         }
333 
SessionSecurityToken(SerializationInfo info, StreamingContext context)334         protected SessionSecurityToken(SerializationInfo info, StreamingContext context)
335         {
336             if (info == null)
337                 return;
338 
339             byte[] cookie = (byte[])info.GetValue(tokenKey, typeof(byte[]));
340 
341             if (null == cookie || 0 == cookie.Length)
342             {
343                 throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4272));
344             }
345 
346             SessionDictionary dictionary = SessionDictionary.Instance;
347             //
348             // We are creating a reader over the decrypted form of the cookie that is in memory.
349             // Passing Max for the XmlDictionaryReaderQuotas is safe.
350             //
351             using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(cookie, 0, cookie.Length, dictionary, XmlDictionaryReaderQuotas.Max, null, null))
352             {
353                 //
354                 // Layout is strict, must be in following order:
355                 //
356                 // Version
357                 // SecureConversationVersion
358                 // ID
359                 // ContextID
360                 // Key
361                 // Generation {optional}
362                 // EffectiveTime
363                 // ExpiryTime
364                 // KeyEffectiveTime
365                 // KeyExpiryTime
366                 //
367                 // SessionSecurityToken data may follow, in the order:
368                 //
369                 bool isSecurityContextSecurityTokenWrapper = false;
370                 bool isPersistent = true;
371                 bool isReferenceMode = false;
372                 string cookieContext = String.Empty;
373 
374                 if (reader.IsStartElement(dictionary.SecurityContextToken, dictionary.EmptyString))
375                 {
376                     isSecurityContextSecurityTokenWrapper = true;
377                 }
378                 else if (reader.IsStartElement(dictionary.SessionToken, dictionary.EmptyString))
379                 {
380                     //@PersistentTrue
381                     if (reader.GetAttribute(dictionary.PersistentTrue, dictionary.EmptyString) == null)
382                     {
383                         isPersistent = false;
384                     }
385 
386                     if (reader.GetAttribute(dictionary.ReferenceModeTrue, dictionary.EmptyString) != null)
387                     {
388                         isReferenceMode = true;
389                     }
390 
391                     reader.ReadFullStartElement();
392                     reader.MoveToContent();
393 
394                     // <Context>
395                     if (reader.IsStartElement(dictionary.Context, dictionary.EmptyString))
396                     {
397                         cookieContext = reader.ReadElementContentAsString();
398                     }
399                 }
400                 else
401                 {
402                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4230, dictionary.SecurityContextToken.Value, reader.Name)));
403                 }
404 
405                 string version = reader.ReadElementString();
406                 if (version != SupportedVersion)
407                 {
408                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4232, version, SupportedVersion)));
409                 }
410 
411                 //
412                 // SecureConversation Version
413                 //
414                 string scNamespace = reader.ReadElementString();
415                 Uri scVersion;
416 
417                 if (scNamespace == WSSecureConversationFeb2005Constants.Namespace)
418                 {
419                     scVersion = WSSecureConversationFeb2005Constants.NamespaceUri;
420                 }
421                 else if (scNamespace == WSSecureConversation13Constants.Namespace)
422                 {
423                     scVersion = WSSecureConversation13Constants.NamespaceUri;
424                 }
425                 else
426                 {
427                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4232, version, SupportedVersion)));
428                 }
429 
430                 string instanceIdentifier = null;
431                 if (reader.IsStartElement(dictionary.Id, dictionary.EmptyString))
432                 {
433                     instanceIdentifier = reader.ReadElementString();
434                 }
435 
436                 if (string.IsNullOrEmpty(instanceIdentifier))
437                 {
438                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4239, dictionary.Id.Value)));
439                 }
440 
441                 if (!reader.IsStartElement(dictionary.ContextId, dictionary.EmptyString))
442                 {
443                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4230, dictionary.ContextId.Value, reader.Name)));
444                 }
445 
446                 SysUniqueId contextIdentifier = reader.ReadElementContentAsUniqueId();
447 
448                 if (!reader.IsStartElement(dictionary.Key, dictionary.EmptyString))
449                 {
450                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4230, dictionary.Key.Value, reader.Name)));
451                 }
452                 byte[] key = reader.ReadElementContentAsBase64();
453 
454                 // optional
455                 SysUniqueId generation = null;
456                 if (reader.IsStartElement(dictionary.KeyGeneration, dictionary.EmptyString))
457                 {
458                     generation = reader.ReadElementContentAsUniqueId();
459                 }
460 
461                 if (!reader.IsStartElement(dictionary.EffectiveTime, dictionary.EmptyString))
462                 {
463                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4230, dictionary.EffectiveTime.Value, reader.Name)));
464                 }
465                 DateTime effectiveTime = new DateTime(XmlUtil.ReadElementContentAsInt64(reader), DateTimeKind.Utc);
466 
467                 if (!reader.IsStartElement(dictionary.ExpiryTime, dictionary.EmptyString))
468                 {
469                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4230, dictionary.ExpiryTime.Value, reader.Name)));
470                 }
471                 DateTime expiryTime = new DateTime(XmlUtil.ReadElementContentAsInt64(reader), DateTimeKind.Utc);
472 
473                 if (!reader.IsStartElement(dictionary.KeyEffectiveTime, dictionary.EmptyString))
474                 {
475                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4230, dictionary.KeyEffectiveTime.Value, reader.Name)));
476                 }
477                 DateTime keyEffectiveTime = new DateTime(XmlUtil.ReadElementContentAsInt64(reader), DateTimeKind.Utc);
478 
479                 if (!reader.IsStartElement(dictionary.KeyExpiryTime, dictionary.EmptyString))
480                 {
481                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4230, dictionary.KeyExpiryTime.Value, reader.Name)));
482                 }
483                 DateTime keyExpiryTime = new DateTime(XmlUtil.ReadElementContentAsInt64(reader), DateTimeKind.Utc);
484 
485                 ClaimsPrincipal principal = null;
486 
487                 if (reader.IsStartElement(dictionary.ClaimsPrincipal, dictionary.EmptyString))
488                 {
489                     principal = ReadPrincipal(reader, dictionary);
490                 }
491 
492                 SctAuthorizationPolicy sctAuthorizationPolicy = null;
493                 if (reader.IsStartElement(dictionary.SctAuthorizationPolicy, dictionary.EmptyString))
494                 {
495                     reader.ReadStartElement(dictionary.SctAuthorizationPolicy, dictionary.EmptyString);
496                     SysClaim sysClaim = DeserializeSysClaim(reader);
497                     reader.ReadEndElement();
498                     sctAuthorizationPolicy = new SctAuthorizationPolicy(sysClaim);
499                 }
500 
501                 string endpointId = null;
502                 if (reader.IsStartElement(dictionary.EndpointId, dictionary.EmptyString))
503                 {
504                     endpointId = reader.ReadElementContentAsString();
505                 }
506 
507                 reader.ReadEndElement();
508 
509                 _claimsPrincipal = principal;
510                 _contextId = contextIdentifier;
511                 _id = instanceIdentifier;
512                 _context = cookieContext;
513                 _securityKeys = new ReadOnlyCollection<SecurityKey>(new SecurityKey[] { new InMemorySymmetricSecurityKey(key) });
514                 _endpointId = endpointId;
515                 _validFrom = effectiveTime;
516                 _validTo = expiryTime;
517                 _keyGeneration = generation;
518                 _keyEffectiveTime = keyEffectiveTime;
519                 _keyExpirationTime = keyExpiryTime;
520                 _isSecurityContextSecurityTokenWrapper = isSecurityContextSecurityTokenWrapper;
521                 _secureConversationVersion = scVersion;
522                 _sctAuthorizationPolicy = sctAuthorizationPolicy;
523                 _isPersistent = isPersistent;
524                 _isReferenceMode = isReferenceMode;
525 
526             }
527         }
528 
529         /// <summary>
530         /// The <see cref="ClaimsPrincipal"/> associated with the session.
531         /// </summary>
532         public ClaimsPrincipal ClaimsPrincipal
533         {
534             get
535             {
536                 return _claimsPrincipal;
537             }
538         }
539 
540         /// <summary>
541         /// Gets the user specified value.
542         /// </summary>
543         public string Context
544         {
545             get { return _context; }
546         }
547 
548         /// <summary>
549         /// The Session Context Identifier
550         /// </summary>
551         public SysUniqueId ContextId
552         {
553             get { return _contextId; }
554         }
555 
556         /// <summary>
557         /// Gets the Id of the endpoint to which this token is scoped.
558         /// </summary>
559         public string EndpointId
560         {
561             get { return _endpointId; }
562         }
563 
564         /// <summary>
565         /// Gets a value indicating whether this token is wrapping an SCT.
566         /// </summary>
567         internal bool IsSecurityContextSecurityTokenWrapper
568         {
569             get { return _isSecurityContextSecurityTokenWrapper; }
570         }
571 
572         /// <summary>
573         /// The effective date/time of the key in this token
574         /// </summary>
575         public DateTime KeyEffectiveTime
576         {
577             get { return _keyEffectiveTime; }
578         }
579 
580         /// <summary>
581         /// The expiration date/time of the key in this token
582         /// </summary>
583         public DateTime KeyExpirationTime
584         {
585             get { return _keyExpirationTime; }
586         }
587 
588         /// <summary>
589         /// The identifier for the key generation in this token
590         /// </summary>
591         public SysUniqueId KeyGeneration
592         {
593             get { return _keyGeneration; }
594         }
595 
596         /// <summary>
597         /// Gets the id of this token.
598         /// </summary>
599         public override string Id
600         {
601             get { return _id; }
602         }
603 
604         /// <summary>
605         /// If true, cookie is written as a persistent cookie.
606         /// </summary>
607         public bool IsPersistent
608         {
609             get { return _isPersistent; }
610             set { _isPersistent = value; }
611         }
612 
613         /// <summary>
614         /// If true, the SessionSecurityToken is operating in reference mode.
615         /// </summary>
616         /// <remarks>
617         /// In reference mode, a simple artifact is produced during serialization
618         /// and the real token is stored in the token cache associated with the
619         /// token handler. For Web Farm scenarios, the token cache must operate
620         /// across all nodes in teh farm.
621         /// </remarks>
622         public bool IsReferenceMode
623         {
624             get
625             {
626                 return _isReferenceMode;
627             }
628             set
629             {
630                 _isReferenceMode = value;
631             }
632         }
633 
634         /// <summary>
635         /// Gets the authorization policies associated with the session. Only has meaning if this is wrapping an SCT
636         /// token.
637         /// </summary>
638         internal SctAuthorizationPolicy SctAuthorizationPolicy
639         {
640             get { return _sctAuthorizationPolicy; }
641         }
642 
643         /// <summary>
644         /// Gets the SecureConversationVersion used for this token.
645         /// </summary>
646         public Uri SecureConversationVersion
647         {
648             get { return _secureConversationVersion; }
649         }
650 
651         /// <summary>
652         /// Gets the keys associated with this session, usually a single key
653         /// </summary>
654         public override ReadOnlyCollection<SecurityKey> SecurityKeys
655         {
656             get { return _securityKeys; }
657         }
658 
659         /// <summary>
660         /// Gets the begining DateTime before which token is invalid.
661         /// </summary>
662         public override DateTime ValidFrom
663         {
664             get { return _validFrom; }
665         }
666 
667         /// <summary>
668         /// Gets the ending DateTime after which the token is invalid.
669         /// </summary>
670         public override DateTime ValidTo
671         {
672             get { return _validTo; }
673         }
674 
675         #region ISerializable Members
676 
GetObjectData(SerializationInfo info, StreamingContext context)677         public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
678         {
679             MemoryStream stream = new MemoryStream();
680             SessionDictionary dictionary = SessionDictionary.Instance;
681 
682             //
683             // XmlDictionaryWriter.CreateBinaryWriter() defaults to ownsStream=true.
684             // So, the XmlWriter returned by the below code owns the memory stream, and will dispose it.
685             //
686             using (XmlDictionaryWriter dicWriter = XmlDictionaryWriter.CreateBinaryWriter(stream, dictionary))
687             {
688                 //<SecurityContextSecurityToken> or <SessionSecurityToken>
689                 if (this.IsSecurityContextSecurityTokenWrapper)
690                 {
691                     dicWriter.WriteStartElement(dictionary.SecurityContextToken, dictionary.EmptyString);
692                 }
693                 else
694                 {
695                     dicWriter.WriteStartElement(dictionary.SessionToken, dictionary.EmptyString);
696 
697                     // @PersistentTrue
698                     if (this.IsPersistent)
699                     {
700                         dicWriter.WriteAttributeString(dictionary.PersistentTrue, dictionary.EmptyString, "");
701                     }
702 
703                     // @ReferenceModeTrue
704                     if (this.IsReferenceMode)
705                     {
706                         dicWriter.WriteAttributeString(dictionary.ReferenceModeTrue, dictionary.EmptyString, "");
707                     }
708 
709                     // <Context>
710                     if (!string.IsNullOrEmpty(this.Context))
711                     {
712                         dicWriter.WriteElementString(dictionary.Context, dictionary.EmptyString, this.Context);
713                     }
714                 }
715 
716                 // Serialization Format Version
717                 // <Version>1</Version>
718                 dicWriter.WriteStartElement(dictionary.Version, dictionary.EmptyString);
719                 dicWriter.WriteValue(SupportedVersion);
720                 dicWriter.WriteEndElement();
721 
722                 //
723                 // SecureConversation Version
724                 //
725                 dicWriter.WriteElementString(dictionary.SecureConversationVersion, dictionary.EmptyString, this.SecureConversationVersion.AbsoluteUri);
726 
727                 //
728                 // ID and ContextId
729                 //
730                 dicWriter.WriteElementString(dictionary.Id, dictionary.EmptyString, this.Id);
731                 XmlUtil.WriteElementStringAsUniqueId(dicWriter, dictionary.ContextId, dictionary.EmptyString, this.ContextId.ToString());
732 
733                 //
734                 // Key material
735                 //
736                 byte[] key = ((SymmetricSecurityKey)this.SecurityKeys[0]).GetSymmetricKey();
737 
738                 dicWriter.WriteStartElement(dictionary.Key, dictionary.EmptyString);
739                 dicWriter.WriteBase64(key, 0, key.Length);
740                 dicWriter.WriteEndElement();
741 
742                 //
743                 // Key Generation
744                 //
745                 if (this.KeyGeneration != null)
746                 {
747                     XmlUtil.WriteElementStringAsUniqueId(dicWriter, dictionary.KeyGeneration, dictionary.EmptyString, this.KeyGeneration.ToString());
748                 }
749 
750                 //
751                 // Effective and Expiry dates
752                 //
753                 XmlUtil.WriteElementContentAsInt64(dicWriter, dictionary.EffectiveTime, dictionary.EmptyString, this.ValidFrom.ToUniversalTime().Ticks);
754                 XmlUtil.WriteElementContentAsInt64(dicWriter, dictionary.ExpiryTime, dictionary.EmptyString, this.ValidTo.ToUniversalTime().Ticks);
755                 XmlUtil.WriteElementContentAsInt64(dicWriter, dictionary.KeyEffectiveTime, dictionary.EmptyString, this.KeyEffectiveTime.ToUniversalTime().Ticks);
756                 XmlUtil.WriteElementContentAsInt64(dicWriter, dictionary.KeyExpiryTime, dictionary.EmptyString, this.KeyExpirationTime.ToUniversalTime().Ticks);
757 
758                 //
759                 // Claims Principal
760                 //
761                 WritePrincipal(dicWriter, dictionary, this.ClaimsPrincipal);
762 
763                 // The WCF SCT will have a SctAuthorizationPolicy that wraps the Primary Identity
764                 // of the bootstrap token. This is required for SCT renewal scenarios. Write the
765                 // SctAuthorizationPolicy if one is available.
766                 if (this.SctAuthorizationPolicy != null)
767                 {
768                     dicWriter.WriteStartElement(dictionary.SctAuthorizationPolicy, dictionary.EmptyString);
769                     SysClaim identityClaim = ((System.IdentityModel.Claims.DefaultClaimSet)((IAuthorizationPolicy)this.SctAuthorizationPolicy).Issuer)[0];
770                     SerializeSysClaim(identityClaim, dicWriter);
771                     dicWriter.WriteEndElement();
772                 }
773 
774                 dicWriter.WriteElementString(dictionary.EndpointId, dictionary.EmptyString, this.EndpointId);
775                 dicWriter.WriteEndElement();
776                 dicWriter.Flush();
777 
778                 info.AddValue(tokenKey, stream.ToArray());
779             }
780         }
781 
782         #endregion
783 
784         /// <summary>
785         /// Reads a ClaimsPrincipal from a XmlDictionaryReader.
786         /// </summary>
787         /// <param name="dictionaryReader">XmlDictionaryReader positioned at dictionary.ClaimsPrincipal.</param>
788         /// <param name="dictionary">SessionDictionary to provide dictionary strings.</param>
789         /// <exception cref="ArgumentNullException">The input argument 'dictionaryReader' or 'dictionary' is null.</exception>
790         /// <returns>ClaimsPrincipal</returns>
ReadPrincipal(XmlDictionaryReader dictionaryReader, SessionDictionary dictionary)791         ClaimsPrincipal ReadPrincipal(XmlDictionaryReader dictionaryReader, SessionDictionary dictionary)
792         {
793             if (dictionaryReader == null)
794             {
795                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryReader");
796             }
797 
798             if (dictionary == null)
799             {
800                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionary");
801             }
802 
803             ClaimsPrincipal principal = null;
804 
805             Collection<ClaimsIdentity> identities = new Collection<ClaimsIdentity>();
806 
807             dictionaryReader.MoveToContent();
808 
809             if (dictionaryReader.IsStartElement(dictionary.ClaimsPrincipal, dictionary.EmptyString))
810             {
811                 dictionaryReader.ReadFullStartElement();
812 
813                 ReadIdentities(dictionaryReader, dictionary, identities);
814 
815                 dictionaryReader.ReadEndElement();
816             }
817 
818             // If we find a WindowsIdentity in the identities we just read, we should be creating a WindowsPrincipal using it
819             WindowsIdentity wi = null;
820             foreach (ClaimsIdentity identity in identities)
821             {
822                 wi = identity as WindowsIdentity;
823                 if (wi != null)
824                 {
825                     principal = new WindowsPrincipal(wi);
826                     break;
827                 }
828             }
829 
830             // If we did create a WindowsPrincipal we can remove the associated WindowsIdentity from the identities collection
831             // so that we dont add it twice in the subsequent step
832             if (principal != null)
833             {
834                 identities.Remove(wi);
835             }
836             else if (identities.Count > 0)
837             {
838                 // If we did not create a WindowsPrincipal, default to a ClaimsPrincipal
839                 principal = new ClaimsPrincipal();
840             }
841 
842             if (principal != null)
843             {
844                 // Add the identities we just read to the principal
845                 principal.AddIdentities(identities);
846             }
847 
848             return principal;
849         }
850 
851         /// <summary>
852         /// Reads the ClaimsIdentites from a XmlDictionaryReader and adds them to a ClaimIdentityColleciton.
853         /// </summary>
854         /// <param name="dictionaryReader">XmlDictionaryReader positioned at dictionary.Identities</param>
855         /// <param name="dictionary">SessionDictionary to provide dictionary strings.</param>
856         /// <param name="identities">A collection of <see cref="ClaimsIdentity"/> to populate.</param>
857         /// <exception cref="ArgumentNullException">The input argument 'dictionaryReader', 'dictionary' or 'identities' is null.</exception>
858         /// <remarks>Reads 'n' identies and adds them to identies.</remarks>
ReadIdentities(XmlDictionaryReader dictionaryReader, SessionDictionary dictionary, Collection<ClaimsIdentity> identities)859         void ReadIdentities(XmlDictionaryReader dictionaryReader, SessionDictionary dictionary, Collection<ClaimsIdentity> identities)
860         {
861             if (dictionaryReader == null)
862             {
863                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryReader");
864             }
865 
866             if (dictionary == null)
867             {
868                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionary");
869             }
870 
871             if (identities == null)
872             {
873                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("identities");
874             }
875 
876             dictionaryReader.MoveToContent();
877 
878             if (dictionaryReader.IsStartElement(dictionary.Identities, dictionary.EmptyString))
879             {
880                 dictionaryReader.ReadFullStartElement();
881 
882                 while (dictionaryReader.IsStartElement(dictionary.Identity, dictionary.EmptyString))
883                 {
884                     identities.Add(ReadIdentity(dictionaryReader, dictionary));
885                 }
886 
887                 dictionaryReader.ReadEndElement();
888             }
889         }
890 
891         /// <summary>
892         /// Reads a single ClaimsIdentity from a XmlDictionaryReader.
893         /// </summary>
894         /// <param name="dictionaryReader">XmlDictionaryReader positioned at dictionary.Identity.</param>
895         /// <param name="dictionary">SessionDictionary to provide dictionary strings.</param>
896         /// <exception cref="ArgumentNullException">The input argument 'dictionaryReader' or 'dictionary' is null.</exception>
897         /// <exception cref="SecurityTokenException">The dictionaryReader is not positioned a SessionDictionary.Identity.</exception>
898         /// <returns>ClaimsIdentity</returns>
ReadIdentity(XmlDictionaryReader dictionaryReader, SessionDictionary dictionary)899         ClaimsIdentity ReadIdentity(XmlDictionaryReader dictionaryReader, SessionDictionary dictionary)
900         {
901             if (dictionaryReader == null)
902             {
903                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryReader");
904             }
905 
906             if (dictionary == null)
907             {
908                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionary");
909             }
910 
911             dictionaryReader.MoveToContent();
912 
913             ClaimsIdentity identity = null;
914 
915             if (!dictionaryReader.IsStartElement(dictionary.Identity, dictionary.EmptyString))
916             {
917                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID3007, dictionaryReader.LocalName, dictionaryReader.NamespaceURI)));
918             }
919 
920             // @NameClaimType
921             string nameClaimType = dictionaryReader.GetAttribute(dictionary.NameClaimType, dictionary.EmptyString);
922 
923             // @RoleClaimType
924             string roleClaimType = dictionaryReader.GetAttribute(dictionary.RoleClaimType, dictionary.EmptyString);
925 
926             // @WindowsLogonName (optional) => windows claims identity
927             string logonName = dictionaryReader.GetAttribute(dictionary.WindowsLogonName, dictionary.EmptyString);
928             string authenticationType = dictionaryReader.GetAttribute(dictionary.AuthenticationType, dictionary.EmptyString);
929 
930             if (string.IsNullOrEmpty(logonName))
931             {
932                 identity = new ClaimsIdentity(authenticationType, nameClaimType, roleClaimType);
933             }
934             else
935             {
936                 // The WindowsIdentity(string, string) c'tor does not set the Auth type. Hence we use that c'tor to get a intPtr and
937                 // call the other c'tor that actually sets the authType passed in.
938                 // DevDiv 279196 tracks the issue and in WindowsIdentity c'tor. Its too late to fix it in 4.5 cycle as we are in Beta and would not be
939                 // able to complete the analysis of the change for the current release. This should be investigated in 5.0
940                 WindowsIdentity winId = new WindowsIdentity(GetUpn(logonName));
941                 identity = new WindowsIdentity(winId.Token, authenticationType);
942             }
943 
944             // @Label
945             identity.Label = dictionaryReader.GetAttribute(dictionary.Label, dictionary.EmptyString);
946 
947 
948             dictionaryReader.ReadFullStartElement();
949 
950             // <ClaimCollection>
951             if (dictionaryReader.IsStartElement(dictionary.ClaimCollection, dictionary.EmptyString))
952             {
953                 dictionaryReader.ReadStartElement();
954 
955                 Collection<Claim> claims = new Collection<Claim>();
956                 ReadClaims(dictionaryReader, dictionary, claims);
957                 identity.AddClaims(claims);
958 
959                 dictionaryReader.ReadEndElement();
960             }
961 
962             // <Actor>
963             if (dictionaryReader.IsStartElement(dictionary.Actor, dictionary.EmptyString))
964             {
965                 dictionaryReader.ReadStartElement();
966 
967                 identity.Actor = ReadIdentity(dictionaryReader, dictionary);
968 
969                 dictionaryReader.ReadEndElement();
970             }
971 
972             if (dictionaryReader.IsStartElement(dictionary.BootstrapToken, dictionary.EmptyString))
973             {
974                 dictionaryReader.ReadStartElement();
975 
976                 byte[] bytes = dictionaryReader.ReadContentAsBase64();
977                 using (MemoryStream ms = new MemoryStream(bytes))
978                 {
979                     BinaryFormatter formatter = new BinaryFormatter();
980                     identity.BootstrapContext = (BootstrapContext)formatter.Deserialize(ms);
981                 }
982 
983                 dictionaryReader.ReadEndElement();
984             }
985 
986             dictionaryReader.ReadEndElement(); // Identity
987 
988             return identity;
989         }
990 
991         /// <summary>
992         /// Returns a User Principal Name from a windows logon name.
993         /// </summary>
994         /// <param name="windowsLogonName">Name to translate into the UPN</param>
995         /// <exception cref="ArgumentNullException">The input argument 'windowsLogonName' is null or empty.</exception>
996         /// <exception cref="InvalidOperationException">If 'windowsLogonName' is not of the form domain\\user or user@domain.</exception>
997         /// <returns>A User Principal Name of the form 'user@domain'</returns>
GetUpn(string windowsLogonName)998         string GetUpn(string windowsLogonName)
999         {
1000             if (string.IsNullOrEmpty(windowsLogonName))
1001             {
1002                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("windowsLogonName");
1003             }
1004             int delimiterPos = windowsLogonName.IndexOf('\\');
1005 
1006             if ((delimiterPos < 0) || (delimiterPos == 0) || (delimiterPos == windowsLogonName.Length - 1))
1007             {
1008                 if (IsPossibleUpn(windowsLogonName))
1009                 {
1010                     return windowsLogonName;
1011                 }
1012 
1013                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4248, windowsLogonName)));
1014             }
1015 
1016             string shortDomainName = windowsLogonName.Substring(0, delimiterPos + 1);
1017             string userName = windowsLogonName.Substring(delimiterPos + 1);
1018             string fullDomainName;
1019             bool found;
1020 
1021             // 1) Read from cache
1022             lock (DomainNameMap)
1023             {
1024                 found = DomainNameMap.TryGetValue(shortDomainName, out fullDomainName);
1025             }
1026 
1027             // 2) Not found, do expensive look up
1028             if (!found)
1029             {
1030                 uint capacity = 50;
1031                 StringBuilder fullyQualifiedDomainName = new StringBuilder((int)capacity);
1032                 if (!NativeMethods.TranslateName(shortDomainName, EXTENDED_NAME_FORMAT.NameSamCompatible, EXTENDED_NAME_FORMAT.NameCanonical,
1033                     fullyQualifiedDomainName, out capacity))
1034                 {
1035                     int errorCode = Marshal.GetLastWin32Error();
1036                     if (errorCode == (int)Win32Error.ERROR_INSUFFICIENT_BUFFER)
1037                     {
1038                         fullyQualifiedDomainName = new StringBuilder((int)capacity);
1039                         if (!NativeMethods.TranslateName(shortDomainName, EXTENDED_NAME_FORMAT.NameSamCompatible, EXTENDED_NAME_FORMAT.NameCanonical,
1040                             fullyQualifiedDomainName, out capacity))
1041                         {
1042                             errorCode = Marshal.GetLastWin32Error();
1043                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4248, windowsLogonName), new Win32Exception(errorCode)));
1044                         }
1045                     }
1046                     else
1047                     {
1048                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4248, windowsLogonName), new Win32Exception(errorCode)));
1049                     }
1050                 }
1051                 // trim the trailing / from fqdn
1052                 fullyQualifiedDomainName = fullyQualifiedDomainName.Remove(fullyQualifiedDomainName.Length - 1, 1);
1053                 fullDomainName = fullyQualifiedDomainName.ToString();
1054 
1055                 // 3) Save in cache (remove a random item if cache is full)
1056                 lock (DomainNameMap)
1057                 {
1058                     if (DomainNameMap.Count >= MaxDomainNameMapSize)
1059                     {
1060                         if (rnd == null)
1061                         {
1062                             rnd = new Random(unchecked((int)DateTime.Now.Ticks));
1063                         }
1064                         int victim = rnd.Next() % DomainNameMap.Count;
1065                         foreach (string key in DomainNameMap.Keys)
1066                         {
1067                             if (victim <= 0)
1068                             {
1069                                 DomainNameMap.Remove(key);
1070                                 break;
1071                             }
1072                             --victim;
1073                         }
1074                     }
1075                     DomainNameMap[shortDomainName] = fullDomainName;
1076                 }
1077             }
1078 
1079             return userName + "@" + fullDomainName;
1080         }
1081 
1082         /// <summary>
1083         /// Reads Claims from a XmlDictionaryReader and adds them to a ClaimCollection.
1084         /// </summary>
1085         /// <param name="dictionaryReader">XmlDictionaryReader positioned at dictionary.Claim.</param>
1086         /// <param name="dictionary">SessionDictionary to provide dictionary strings.</param>
1087         /// <param name="claims">ClaimCollection to add the claims to.</param>
1088         /// <exception cref="ArgumentNullException">The input argument 'dictionaryReader',  'dictionary' or 'claims' is null.</exception>
1089         /// <remarks>Reads 'n' claims and adds them to claims.</remarks>
ReadClaims(XmlDictionaryReader dictionaryReader, SessionDictionary dictionary, Collection<Claim> claims)1090         void ReadClaims(XmlDictionaryReader dictionaryReader, SessionDictionary dictionary, Collection<Claim> claims)
1091         {
1092             if (dictionaryReader == null)
1093             {
1094                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryReader");
1095             }
1096 
1097             if (dictionary == null)
1098             {
1099                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionary");
1100             }
1101 
1102             if (claims == null)
1103             {
1104                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("claims");
1105             }
1106 
1107             while (dictionaryReader.IsStartElement(dictionary.Claim, dictionary.EmptyString))
1108             {
1109                 // @Issuer (optional), @OriginalIssuer (optional), @Type, @Value, @ValueType
1110 
1111                 Claim claim = new Claim(dictionaryReader.GetAttribute(dictionary.Type, dictionary.EmptyString),
1112                                          dictionaryReader.GetAttribute(dictionary.Value, dictionary.EmptyString),
1113                                          dictionaryReader.GetAttribute(dictionary.ValueType, dictionary.EmptyString),
1114                                          dictionaryReader.GetAttribute(dictionary.Issuer, dictionary.EmptyString),
1115                                          dictionaryReader.GetAttribute(dictionary.OriginalIssuer, dictionary.EmptyString));
1116 
1117                 dictionaryReader.ReadFullStartElement();
1118 
1119                 // <Properties> (optional)
1120                 if (dictionaryReader.IsStartElement(dictionary.ClaimProperties, dictionary.EmptyString))
1121                 {
1122                     ReadClaimProperties(dictionaryReader, dictionary, claim.Properties);
1123                 }
1124 
1125                 dictionaryReader.ReadEndElement();
1126 
1127                 claims.Add(claim);
1128             }
1129         }
1130 
1131         /// <summary>
1132         /// Reads ClaimProperties from a XmlDictionaryReader and adds them to a Dictionary.
1133         /// </summary>
1134         /// <param name="dictionaryReader">XmlDictionaryReader positioned at the element dictionary.ClaimProperties </param>
1135         /// <param name="dictionary">SessionDictionary to provide dictionary strings.</param>
1136         /// <param name="properties">Dictionary to add properties to.</param>
1137         /// <exception cref="ArgumentNullException">The input argument 'dictionaryReader',  'dictionary' or 'properties' is null.</exception>
1138         /// <exception cref="SecurityTokenException">Is thrown if the 'name' of a property is null or an empty string.</exception>
1139         /// <exception cref="SecurityTokenException">Is thrown if the 'value' of a property is null.</exception>
1140         /// <remarks>Reads 'n' properties.</remarks>
ReadClaimProperties(XmlDictionaryReader dictionaryReader, SessionDictionary dictionary, IDictionary<string, string> properties)1141         void ReadClaimProperties(XmlDictionaryReader dictionaryReader, SessionDictionary dictionary, IDictionary<string, string> properties)
1142         {
1143             if (dictionaryReader == null)
1144             {
1145                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryReader");
1146             }
1147 
1148             if (dictionary == null)
1149             {
1150                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionary");
1151             }
1152 
1153             if (properties == null)
1154             {
1155                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("properties");
1156             }
1157 
1158             dictionaryReader.ReadStartElement();
1159 
1160             // <Property>
1161             while (dictionaryReader.IsStartElement(dictionary.ClaimProperty, dictionary.EmptyString))
1162             {
1163                 // @Name, @Value
1164 
1165                 string name = dictionaryReader.GetAttribute(dictionary.ClaimPropertyName, dictionary.EmptyString);
1166                 string value = dictionaryReader.GetAttribute(dictionary.ClaimPropertyValue, dictionary.EmptyString);
1167 
1168                 if (string.IsNullOrEmpty(name))
1169                 {
1170                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4249)));
1171                 }
1172 
1173                 if (string.IsNullOrEmpty(value))
1174                 {
1175                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4250)));
1176                 }
1177 
1178                 properties.Add(new KeyValuePair<string, string>(name, value));
1179 
1180                 dictionaryReader.ReadFullStartElement();
1181                 dictionaryReader.ReadEndElement();
1182             }
1183 
1184             dictionaryReader.ReadEndElement();
1185         }
1186 
1187         /// <summary>
1188         /// Writes out a ClaimsPrincipal using a XmlDictionaryWriter.
1189         /// </summary>
1190         /// <param name="dictionaryWriter">XmlDictionaryWriter to write to.</param>
1191         /// <param name="dictionary">SessionDictionary to provide dictionary strings.</param>
1192         /// <param name="principal">ClaimsPrincipal to write.</param>
1193         /// <exception cref="ArgumentNullException">The input argument 'dictionaryWriter', 'dictionary' or 'principal' is null.</exception>
WritePrincipal(XmlDictionaryWriter dictionaryWriter, SessionDictionary dictionary, ClaimsPrincipal principal)1194         void WritePrincipal(XmlDictionaryWriter dictionaryWriter, SessionDictionary dictionary, ClaimsPrincipal principal)
1195         {
1196             if (dictionaryWriter == null)
1197             {
1198                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryWriter");
1199             }
1200 
1201             if (dictionary == null)
1202             {
1203                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionary");
1204             }
1205 
1206             if (principal == null)
1207             {
1208                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("principal");
1209             }
1210 
1211             // <ClaimsPrincipal>
1212             dictionaryWriter.WriteStartElement(dictionary.ClaimsPrincipal, dictionary.EmptyString);
1213 
1214             if (principal.Identities != null)
1215             {
1216                 WriteIdentities(dictionaryWriter, dictionary, principal.Identities);
1217             }
1218 
1219             dictionaryWriter.WriteEndElement();
1220         }
1221 
1222         /// <summary>
1223         /// Writes a collection of ClaimsIdentity using a XmlDictionaryWriter.
1224         /// </summary>
1225         /// <param name="dictionaryWriter">XmlDictionaryWriter to write to.</param>
1226         /// <param name="dictionary">SessionDictionary to provide dictionary strings.</param>
1227         /// <param name="identities">The collection of ClaimsIdentity to write.</param>
1228         /// <exception cref="ArgumentNullException">The input argument 'dictionaryWriter', 'dictionary' or 'identities' is null.</exception>
WriteIdentities(XmlDictionaryWriter dictionaryWriter, SessionDictionary dictionary, IEnumerable<ClaimsIdentity> identities)1229         void WriteIdentities(XmlDictionaryWriter dictionaryWriter, SessionDictionary dictionary, IEnumerable<ClaimsIdentity> identities)
1230         {
1231             if (dictionaryWriter == null)
1232             {
1233                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryWriter");
1234             }
1235 
1236             if (dictionary == null)
1237             {
1238                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionary");
1239             }
1240 
1241             if (identities == null)
1242             {
1243                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("identities");
1244             }
1245 
1246             // <Identities>
1247             dictionaryWriter.WriteStartElement(dictionary.Identities, dictionary.EmptyString);
1248 
1249             foreach (ClaimsIdentity ci in identities)
1250             {
1251                 WriteIdentity(dictionaryWriter, dictionary, ci);
1252             }
1253 
1254             dictionaryWriter.WriteEndElement();
1255         }
1256 
1257         /// <summary>
1258         /// Writes a single ClaimsIdentity using a XmlDictionaryWriter.
1259         /// </summary>
1260         /// <param name="dictionaryWriter">XmlDictionaryWriter to write to.</param>
1261         /// <param name="dictionary">SessionDictionary to provide dictionary strings.</param>
1262         /// <param name="identity">ClaimsIdentiy to write.</param>
1263         /// <exception cref="ArgumentNullException">The input argument 'dictionaryWriter', 'dictionary' or 'identity' is null.</exception>
WriteIdentity(XmlDictionaryWriter dictionaryWriter, SessionDictionary dictionary, ClaimsIdentity identity)1264         void WriteIdentity(XmlDictionaryWriter dictionaryWriter, SessionDictionary dictionary, ClaimsIdentity identity)
1265         {
1266             if (dictionaryWriter == null)
1267             {
1268                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryWriter");
1269             }
1270 
1271             if (dictionary == null)
1272             {
1273                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionary");
1274             }
1275 
1276             if (identity == null)
1277             {
1278                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("identity");
1279             }
1280 
1281             //
1282             // WindowsIdentity needs special handling
1283             //
1284 
1285             // <Identity>
1286             dictionaryWriter.WriteStartElement(dictionary.Identity, dictionary.EmptyString);
1287 
1288             WindowsIdentity wci = identity as WindowsIdentity;
1289             if (wci != null)
1290             {
1291                 // @WindowsLogonName (optional)
1292                 dictionaryWriter.WriteAttributeString(dictionary.WindowsLogonName, dictionary.EmptyString, wci.Name);
1293             }
1294 
1295             // @AuthenticationType (optional)
1296             if (!String.IsNullOrEmpty(identity.AuthenticationType))
1297             {
1298                 dictionaryWriter.WriteAttributeString(dictionary.AuthenticationType, dictionary.EmptyString, identity.AuthenticationType);
1299             }
1300 
1301             // @LabelWrite (optional)
1302             if (!String.IsNullOrEmpty(identity.Label))
1303             {
1304                 dictionaryWriter.WriteAttributeString(dictionary.Label, dictionary.EmptyString, identity.Label);
1305             }
1306 
1307             // @NameClaimType (optional)
1308             if (identity.NameClaimType != null)
1309             {
1310                 dictionaryWriter.WriteAttributeString(dictionary.NameClaimType, dictionary.EmptyString, identity.NameClaimType);
1311             }
1312 
1313             // @RoleClaimType (optional)
1314             if (identity.RoleClaimType != null)
1315             {
1316                 dictionaryWriter.WriteAttributeString(dictionary.RoleClaimType, dictionary.EmptyString, identity.RoleClaimType);
1317             }
1318 
1319             // <ClaimCollection> (optional)
1320             if (identity.Claims != null)
1321             {
1322                 dictionaryWriter.WriteStartElement(dictionary.ClaimCollection, dictionary.EmptyString);
1323 
1324                 WriteClaims(dictionaryWriter, dictionary, identity.Claims, (wci == null) ?
1325                     (OutboundClaimsFilter)null
1326                     :
1327                     // do not serialize SID claims for WindowsIdentities as they will be created when the
1328                     // windows identity is recreated.
1329                     delegate(Claim c)
1330                     {
1331                         if (c.Type == ClaimTypes.GroupSid
1332                           || c.Type == ClaimTypes.PrimaryGroupSid
1333                           || c.Type == ClaimTypes.PrimarySid
1334                           || c.Type == ClaimTypes.DenyOnlyPrimaryGroupSid
1335                           || c.Type == ClaimTypes.DenyOnlyPrimarySid
1336                           || c.Type == ClaimTypes.Name && c.Issuer == ClaimsIdentity.DefaultIssuer && c.ValueType == ClaimValueTypes.String)
1337                         {
1338                             return true;
1339                         }
1340 
1341                         return false;
1342                     }
1343                 );
1344 
1345                 dictionaryWriter.WriteEndElement();
1346             }
1347 
1348             // <Actor> (optional)
1349             if (identity.Actor != null)
1350             {
1351                 dictionaryWriter.WriteStartElement(dictionary.Actor, dictionary.EmptyString);
1352 
1353                 WriteIdentity(dictionaryWriter, dictionary, identity.Actor);
1354 
1355                 dictionaryWriter.WriteEndElement();
1356             }
1357 
1358             if (identity.BootstrapContext != null)
1359             {
1360                 dictionaryWriter.WriteStartElement(dictionary.BootstrapToken, dictionary.EmptyString);
1361 
1362                 using (MemoryStream ms = new MemoryStream())
1363                 {
1364                     BinaryFormatter formatter = new BinaryFormatter();
1365                     formatter.Serialize(ms, identity.BootstrapContext);
1366                     byte[] bootstrapArray = ms.ToArray();
1367                     dictionaryWriter.WriteBase64(bootstrapArray, 0, bootstrapArray.Length);
1368                 }
1369 
1370                 dictionaryWriter.WriteEndElement(); // </BootstrapToken>
1371             }
1372 
1373             dictionaryWriter.WriteEndElement();
1374 
1375         }
1376 
1377         /// <summary>
1378         /// Actor that returns true if a claim should be filtered.
1379         /// </summary>
1380         /// <param name="claim">Claim to check.</param>
1381         /// <returns></returns>
OutboundClaimsFilter(Claim claim)1382         delegate bool OutboundClaimsFilter(Claim claim);
1383 
1384         /// <summary>
1385         /// Writes a collection of claims using a XmlDictionaryWriter.
1386         /// </summary>
1387         /// <param name="dictionaryWriter">XmlDictionaryWriter to write to.</param>
1388         /// <param name="dictionary">SessionDictionary to provide dictionary strings.</param>
1389         /// <param name="claims">ClaimCollection to write.</param>
1390         /// <param name="outboundClaimsFilter">Filter to apply when writing claims. If parameter is not null and filter returns true, claim will not be written.</param>
1391         /// <exception cref="ArgumentNullException">The input argument 'dictionaryWriter', 'dictionary' or 'claims' is null.</exception>
WriteClaims(XmlDictionaryWriter dictionaryWriter, SessionDictionary dictionary, IEnumerable<Claim> claims, OutboundClaimsFilter outboundClaimsFilter)1392         void WriteClaims(XmlDictionaryWriter dictionaryWriter, SessionDictionary dictionary, IEnumerable<Claim> claims, OutboundClaimsFilter outboundClaimsFilter)
1393         {
1394             if (dictionaryWriter == null)
1395             {
1396                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryWriter");
1397             }
1398 
1399             if (dictionary == null)
1400             {
1401                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionary");
1402             }
1403 
1404             if (claims == null)
1405             {
1406                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("claims");
1407             }
1408 
1409             foreach (Claim claim in claims)
1410             {
1411                 if (claim == null)
1412                 {
1413                     continue;
1414                 }
1415 
1416                 if (outboundClaimsFilter != null && outboundClaimsFilter(claim))
1417                 {
1418                     continue;
1419                 }
1420 
1421                 // <Claim>
1422                 dictionaryWriter.WriteStartElement(dictionary.Claim, dictionary.EmptyString);
1423 
1424                 // @Issuer
1425                 if (!String.IsNullOrEmpty(claim.Issuer))
1426                 {
1427                     dictionaryWriter.WriteAttributeString(dictionary.Issuer, dictionary.EmptyString, claim.Issuer);
1428                 }
1429 
1430                 // @OriginalIssuer
1431                 if (!String.IsNullOrEmpty(claim.OriginalIssuer))
1432                 {
1433                     dictionaryWriter.WriteAttributeString(dictionary.OriginalIssuer, dictionary.EmptyString, claim.OriginalIssuer);
1434                 }
1435 
1436                 // @Type
1437                 dictionaryWriter.WriteAttributeString(dictionary.Type, dictionary.EmptyString, claim.Type);
1438 
1439                 // @Value
1440                 dictionaryWriter.WriteAttributeString(dictionary.Value, dictionary.EmptyString, claim.Value);
1441 
1442                 // @ValueType
1443                 dictionaryWriter.WriteAttributeString(dictionary.ValueType, dictionary.EmptyString, claim.ValueType);
1444 
1445                 // <Properties>
1446                 if (claim.Properties != null && claim.Properties.Count > 0)
1447                 {
1448                     WriteClaimProperties(dictionaryWriter, dictionary, claim.Properties);
1449                 }
1450 
1451                 dictionaryWriter.WriteEndElement();
1452             }
1453         }
1454 
1455         /// <summary>
1456         /// Writes a collection of ClaimProperties using a XmlDictionaryWriter.
1457         /// </summary>
1458         /// <param name="dictionaryWriter">XmlDictionaryWriter to write to.</param>
1459         /// <param name="dictionary">SessionDictionary to provide dictionary strings.</param>
1460         /// <param name="properties">ClaimProperties to write.</param>
1461         /// <exception cref="ArgumentNullException">The input argument 'dictionaryWriter', 'dictionary' or 'properties' is null.</exception>
WriteClaimProperties(XmlDictionaryWriter dictionaryWriter, SessionDictionary dictionary, IDictionary<string, string> properties)1462         void WriteClaimProperties(XmlDictionaryWriter dictionaryWriter, SessionDictionary dictionary, IDictionary<string, string> properties)
1463         {
1464             if (dictionaryWriter == null)
1465             {
1466                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryWriter");
1467             }
1468 
1469             if (dictionary == null)
1470             {
1471                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionary");
1472             }
1473 
1474             if (properties == null)
1475             {
1476                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("properties");
1477             }
1478 
1479             if (properties.Count > 0)
1480             {
1481                 dictionaryWriter.WriteStartElement(dictionary.ClaimProperties, dictionary.EmptyString);
1482 
1483                 foreach (KeyValuePair<string, string> property in properties)
1484                 {
1485                     // <ClaimProperty>
1486                     if (!String.IsNullOrEmpty(property.Key) && !String.IsNullOrEmpty(property.Value))
1487                     {
1488                         dictionaryWriter.WriteStartElement(dictionary.ClaimProperty, dictionary.EmptyString);
1489                         // @Name
1490 
1491                         dictionaryWriter.WriteAttributeString(dictionary.ClaimPropertyName, dictionary.EmptyString, property.Key);
1492 
1493                         // @Value
1494                         dictionaryWriter.WriteAttributeString(dictionary.ClaimPropertyValue, dictionary.EmptyString, property.Value);
1495 
1496                         dictionaryWriter.WriteEndElement();
1497                     }
1498                 }
1499 
1500                 dictionaryWriter.WriteEndElement();
1501             }
1502         }
1503 
1504         /// <summary>
1505         /// Serializes the given <see cref="System.IdentityModel.Claims.Claim"/> to the given XmlDictionaryWriter.
1506         /// </summary>
1507         /// <param name="claim">The claim to be serialized.</param>
1508         /// <param name="writer">The XmlDictionaryWriter to which to serialize the claim.</param>
SerializeSysClaim(SysClaim claim, XmlDictionaryWriter writer)1509         private void SerializeSysClaim(SysClaim claim, XmlDictionaryWriter writer)
1510         {
1511             SessionDictionary dictionary = SessionDictionary.Instance;
1512 
1513             // the order in which known claim types are checked is optimized for use patterns
1514             if (claim == null)
1515             {
1516                 writer.WriteElementString(dictionary.NullValue, dictionary.EmptyString, string.Empty);
1517                 return;
1518             }
1519             else if (SysClaimTypes.Sid.Equals(claim.ClaimType))
1520             {
1521                 writer.WriteStartElement(dictionary.WindowsSidClaim, dictionary.EmptyString);
1522                 WriteRightAttribute(claim, dictionary, writer);
1523                 SerializeSid((SecurityIdentifier)claim.Resource, dictionary, writer);
1524                 writer.WriteEndElement();
1525                 return;
1526             }
1527             else if (SysClaimTypes.DenyOnlySid.Equals(claim.ClaimType))
1528             {
1529                 writer.WriteStartElement(dictionary.DenyOnlySidClaim, dictionary.EmptyString);
1530                 WriteRightAttribute(claim, dictionary, writer);
1531                 SerializeSid((SecurityIdentifier)claim.Resource, dictionary, writer);
1532                 writer.WriteEndElement();
1533                 return;
1534             }
1535             else if (SysClaimTypes.X500DistinguishedName.Equals(claim.ClaimType))
1536             {
1537                 writer.WriteStartElement(dictionary.X500DistinguishedNameClaim, dictionary.EmptyString);
1538                 WriteRightAttribute(claim, dictionary, writer);
1539                 byte[] rawData = ((X500DistinguishedName)claim.Resource).RawData;
1540                 writer.WriteBase64(rawData, 0, rawData.Length);
1541                 writer.WriteEndElement();
1542                 return;
1543             }
1544             else if (SysClaimTypes.Thumbprint.Equals(claim.ClaimType))
1545             {
1546                 writer.WriteStartElement(dictionary.X509ThumbprintClaim, dictionary.EmptyString);
1547                 WriteRightAttribute(claim, dictionary, writer);
1548                 byte[] thumbprint = (byte[])claim.Resource;
1549                 writer.WriteBase64(thumbprint, 0, thumbprint.Length);
1550                 writer.WriteEndElement();
1551                 return;
1552             }
1553             else if (SysClaimTypes.Name.Equals(claim.ClaimType))
1554             {
1555                 writer.WriteStartElement(dictionary.NameClaim, dictionary.EmptyString);
1556                 WriteRightAttribute(claim, dictionary, writer);
1557                 writer.WriteString((string)claim.Resource);
1558                 writer.WriteEndElement();
1559                 return;
1560             }
1561             else if (SysClaimTypes.Dns.Equals(claim.ClaimType))
1562             {
1563                 writer.WriteStartElement(dictionary.DnsClaim, dictionary.EmptyString);
1564                 WriteRightAttribute(claim, dictionary, writer);
1565                 writer.WriteString((string)claim.Resource);
1566                 writer.WriteEndElement();
1567                 return;
1568             }
1569             else if (SysClaimTypes.Rsa.Equals(claim.ClaimType))
1570             {
1571                 writer.WriteStartElement(dictionary.RsaClaim, dictionary.EmptyString);
1572                 WriteRightAttribute(claim, dictionary, writer);
1573                 writer.WriteString(((RSA)claim.Resource).ToXmlString(false));
1574                 writer.WriteEndElement();
1575                 return;
1576             }
1577             else if (SysClaimTypes.Email.Equals(claim.ClaimType))
1578             {
1579                 writer.WriteStartElement(dictionary.MailAddressClaim, dictionary.EmptyString);
1580                 WriteRightAttribute(claim, dictionary, writer);
1581                 writer.WriteString(((System.Net.Mail.MailAddress)claim.Resource).Address);
1582                 writer.WriteEndElement();
1583                 return;
1584             }
1585             else if (claim == SysClaim.System)
1586             {
1587                 writer.WriteElementString(dictionary.SystemClaim, dictionary.EmptyString, string.Empty);
1588                 return;
1589             }
1590             else if (SysClaimTypes.Hash.Equals(claim.ClaimType))
1591             {
1592                 writer.WriteStartElement(dictionary.HashClaim, dictionary.EmptyString);
1593                 WriteRightAttribute(claim, dictionary, writer);
1594                 byte[] hash = (byte[])claim.Resource;
1595                 writer.WriteBase64(hash, 0, hash.Length);
1596                 writer.WriteEndElement();
1597                 return;
1598             }
1599             else if (SysClaimTypes.Spn.Equals(claim.ClaimType))
1600             {
1601                 writer.WriteStartElement(dictionary.SpnClaim, dictionary.EmptyString);
1602                 WriteRightAttribute(claim, dictionary, writer);
1603                 writer.WriteString((string)claim.Resource);
1604                 writer.WriteEndElement();
1605                 return;
1606             }
1607             else if (SysClaimTypes.Upn.Equals(claim.ClaimType))
1608             {
1609                 writer.WriteStartElement(dictionary.UpnClaim, dictionary.EmptyString);
1610                 WriteRightAttribute(claim, dictionary, writer);
1611                 writer.WriteString((string)claim.Resource);
1612                 writer.WriteEndElement();
1613                 return;
1614             }
1615             else if (SysClaimTypes.Uri.Equals(claim.ClaimType))
1616             {
1617                 writer.WriteStartElement(dictionary.UrlClaim, dictionary.EmptyString);
1618                 WriteRightAttribute(claim, dictionary, writer);
1619                 writer.WriteString(((Uri)claim.Resource).AbsoluteUri);
1620                 writer.WriteEndElement();
1621                 return;
1622             }
1623             else
1624             {
1625                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4290, claim)));
1626             }
1627         }
1628 
1629         /// <summary>
1630         /// Deserializes a WCF claim.
1631         /// </summary>
1632         /// <param name="reader">XmlReader to the WCF Claim.</param>
1633         /// <returns>Instance of <see cref="System.IdentityModel.Claims.Claim"/></returns>
DeserializeSysClaim(XmlDictionaryReader reader)1634         private SysClaim DeserializeSysClaim(XmlDictionaryReader reader)
1635         {
1636             SessionDictionary dictionary = SessionDictionary.Instance;
1637 
1638             if (reader.IsStartElement(dictionary.NullValue, dictionary.EmptyString))
1639             {
1640                 reader.ReadElementString();
1641                 return null;
1642             }
1643             else if (reader.IsStartElement(dictionary.WindowsSidClaim, dictionary.EmptyString))
1644             {
1645                 string right = ReadRightAttribute(reader, dictionary);
1646                 reader.ReadStartElement();
1647                 byte[] sidBytes = reader.ReadContentAsBase64();
1648                 reader.ReadEndElement();
1649                 return new SysClaim(SysClaimTypes.Sid, new SecurityIdentifier(sidBytes, 0), right);
1650             }
1651             else if (reader.IsStartElement(dictionary.DenyOnlySidClaim, dictionary.EmptyString))
1652             {
1653                 string right = ReadRightAttribute(reader, dictionary);
1654                 reader.ReadStartElement();
1655                 byte[] sidBytes = reader.ReadContentAsBase64();
1656                 reader.ReadEndElement();
1657                 return new SysClaim(SysClaimTypes.DenyOnlySid, new SecurityIdentifier(sidBytes, 0), right);
1658             }
1659             else if (reader.IsStartElement(dictionary.X500DistinguishedNameClaim, dictionary.EmptyString))
1660             {
1661                 string right = ReadRightAttribute(reader, dictionary);
1662                 reader.ReadStartElement();
1663                 byte[] rawData = reader.ReadContentAsBase64();
1664                 reader.ReadEndElement();
1665                 return new SysClaim(SysClaimTypes.X500DistinguishedName, new X500DistinguishedName(rawData), right);
1666             }
1667             else if (reader.IsStartElement(dictionary.X509ThumbprintClaim, dictionary.EmptyString))
1668             {
1669                 string right = ReadRightAttribute(reader, dictionary);
1670                 reader.ReadStartElement();
1671                 byte[] thumbprint = reader.ReadContentAsBase64();
1672                 reader.ReadEndElement();
1673                 return new SysClaim(SysClaimTypes.Thumbprint, thumbprint, right);
1674             }
1675             else if (reader.IsStartElement(dictionary.NameClaim, dictionary.EmptyString))
1676             {
1677                 string right = ReadRightAttribute(reader, dictionary);
1678                 reader.ReadStartElement();
1679                 string name = reader.ReadString();
1680                 reader.ReadEndElement();
1681                 return new SysClaim(SysClaimTypes.Name, name, right);
1682             }
1683             else if (reader.IsStartElement(dictionary.DnsClaim, dictionary.EmptyString))
1684             {
1685                 string right = ReadRightAttribute(reader, dictionary);
1686                 reader.ReadStartElement();
1687                 string dns = reader.ReadString();
1688                 reader.ReadEndElement();
1689                 return new SysClaim(SysClaimTypes.Dns, dns, right);
1690             }
1691             else if (reader.IsStartElement(dictionary.RsaClaim, dictionary.EmptyString))
1692             {
1693                 string right = ReadRightAttribute(reader, dictionary);
1694                 reader.ReadStartElement();
1695                 string rsaXml = reader.ReadString();
1696                 reader.ReadEndElement();
1697 
1698                 System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
1699                 rsa.FromXmlString(rsaXml);
1700                 return new SysClaim(SysClaimTypes.Rsa, rsa, right);
1701             }
1702             else if (reader.IsStartElement(dictionary.MailAddressClaim, dictionary.EmptyString))
1703             {
1704                 string right = ReadRightAttribute(reader, dictionary);
1705                 reader.ReadStartElement();
1706                 string address = reader.ReadString();
1707                 reader.ReadEndElement();
1708                 return new SysClaim(SysClaimTypes.Email, new System.Net.Mail.MailAddress(address), right);
1709             }
1710             else if (reader.IsStartElement(dictionary.SystemClaim, dictionary.EmptyString))
1711             {
1712                 reader.ReadElementString();
1713                 return SysClaim.System;
1714             }
1715             else if (reader.IsStartElement(dictionary.HashClaim, dictionary.EmptyString))
1716             {
1717                 string right = ReadRightAttribute(reader, dictionary);
1718                 reader.ReadStartElement();
1719                 byte[] hash = reader.ReadContentAsBase64();
1720                 reader.ReadEndElement();
1721                 return new SysClaim(SysClaimTypes.Hash, hash, right);
1722             }
1723             else if (reader.IsStartElement(dictionary.SpnClaim, dictionary.EmptyString))
1724             {
1725                 string right = ReadRightAttribute(reader, dictionary);
1726                 reader.ReadStartElement();
1727                 string spn = reader.ReadString();
1728                 reader.ReadEndElement();
1729                 return new SysClaim(SysClaimTypes.Spn, spn, right);
1730             }
1731             else if (reader.IsStartElement(dictionary.UpnClaim, dictionary.EmptyString))
1732             {
1733                 string right = ReadRightAttribute(reader, dictionary);
1734                 reader.ReadStartElement();
1735                 string upn = reader.ReadString();
1736                 reader.ReadEndElement();
1737                 return new SysClaim(SysClaimTypes.Upn, upn, right);
1738             }
1739             else if (reader.IsStartElement(dictionary.UrlClaim, dictionary.EmptyString))
1740             {
1741                 string right = ReadRightAttribute(reader, dictionary);
1742                 reader.ReadStartElement();
1743                 string url = reader.ReadString();
1744                 reader.ReadEndElement();
1745                 return new SysClaim(SysClaimTypes.Uri, new Uri(url), right);
1746             }
1747             else
1748             {
1749                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.ID4289, reader.LocalName, reader.NamespaceURI)));
1750             }
1751         }
1752 
SerializeSid(SecurityIdentifier sid, SessionDictionary dictionary, XmlDictionaryWriter writer)1753         static void SerializeSid(SecurityIdentifier sid, SessionDictionary dictionary, XmlDictionaryWriter writer)
1754         {
1755             byte[] sidBytes = new byte[sid.BinaryLength];
1756             sid.GetBinaryForm(sidBytes, 0);
1757             writer.WriteBase64(sidBytes, 0, sidBytes.Length);
1758         }
1759 
ReadRightAttribute(XmlDictionaryReader reader, SessionDictionary dictionary)1760         static string ReadRightAttribute(XmlDictionaryReader reader, SessionDictionary dictionary)
1761         {
1762             string right = reader.GetAttribute(dictionary.Right, dictionary.EmptyString);
1763             return string.IsNullOrEmpty(right) ? System.IdentityModel.Claims.Rights.PossessProperty : right;
1764         }
1765 
WriteRightAttribute(SysClaim claim, SessionDictionary dictionary, XmlDictionaryWriter writer)1766         static void WriteRightAttribute(SysClaim claim, SessionDictionary dictionary, XmlDictionaryWriter writer)
1767         {
1768             if (System.IdentityModel.Claims.Rights.PossessProperty.Equals(claim.Right))
1769                 return;
1770             writer.WriteAttributeString(dictionary.Right, dictionary.EmptyString, claim.Right);
1771         }
1772 
1773         // As name says, certainly not a complete test, but it will allow us to move forward on
1774         // strings that are possible UPN's
1775         // a@b will succeed
1776         // @a, a@, @ will fail
IsPossibleUpn(string name)1777         static bool IsPossibleUpn(string name)
1778         {
1779             int delimiterPos = name.IndexOf('@');
1780 
1781             // if it is the first of last character
1782             if ((name.Length < 3) || (delimiterPos < 0) || (delimiterPos == 0) || (delimiterPos == name.Length - 1))
1783             {
1784                 return false;
1785             }
1786 
1787             return true;
1788         }
1789     }
1790 }
1791