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 <= 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 <= 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