3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>Microsoft</OWNER>
13 namespace System
.Security
.Claims
15 using System
.Collections
.Generic
;
16 using System
.Collections
.ObjectModel
;
17 using System
.Diagnostics
.Contracts
;
19 using System
.Runtime
.CompilerServices
;
20 using System
.Runtime
.InteropServices
;
21 using System
.Runtime
.Serialization
;
22 using System
.Runtime
.Serialization
.Formatters
.Binary
;
23 using System
.Security
.Permissions
;
24 using System
.Security
.Principal
;
27 /// An Identity that is represented by a set of claims.
31 public class ClaimsIdentity
: IIdentity
33 private enum SerializationMask
36 AuthenticationType
= 1,
47 private byte[] m_userSerializationData
;
50 const string PreFix
= "System.Security.ClaimsIdentity.";
52 const string ActorKey
= PreFix
+ "actor";
54 const string AuthenticationTypeKey
= PreFix
+ "authenticationType";
56 const string BootstrapContextKey
= PreFix
+ "bootstrapContext";
58 const string ClaimsKey
= PreFix
+ "claims";
60 const string LabelKey
= PreFix
+ "label";
62 const string NameClaimTypeKey
= PreFix
+ "nameClaimType";
64 const string RoleClaimTypeKey
= PreFix
+ "roleClaimType";
66 const string VersionKey
= PreFix
+ "version";
68 public const string DefaultIssuer
= @"LOCAL AUTHORITY";
70 public const string DefaultNameClaimType
= ClaimTypes
.Name
;
72 public const string DefaultRoleClaimType
= ClaimTypes
.Role
;
75 // adding claims to this list will affect the Authorization for this Identity
76 // originally marked this as SecurityCritical, however because enumerators access it
77 // we would need to extend SecuritySafeCritical to the enumerator methods AND the constructors.
78 // In the end, this requires additional [SecuritySafeCritical] attributes. So if any additional access
79 // is added to 'm_instanceClaims' then this must be carefully monitored. This is equivalent to adding sids to the
80 // NTToken and will be used up the stack to make Authorization decisions.
83 // these are claims that are added by using the AddClaim, AddClaims methods or passed in the constructor.
85 List
<Claim
> m_instanceClaims
= new List
<Claim
>();
87 // These are claims that are external to the identity. .Net runtime attaches roles owned by principals GenericPrincpal and RolePrincipal here.
88 // They are not serialized OR remembered when cloned. Access through public method: ClaimProviders.
90 Collection
<IEnumerable
<Claim
>> m_externalClaims
= new Collection
<IEnumerable
<Claim
>>();
93 string m_nameType
= DefaultNameClaimType
;
96 string m_roleType
= DefaultRoleClaimType
;
98 [OptionalField(VersionAdded
=2)]
99 string m_version
= "1.0";
101 [OptionalField(VersionAdded
= 2)]
102 ClaimsIdentity m_actor
;
104 [OptionalField(VersionAdded
= 2)]
105 string m_authenticationType
;
107 [OptionalField(VersionAdded
= 2)]
108 object m_bootstrapContext
;
110 [OptionalField(VersionAdded
= 2)]
113 [OptionalField(VersionAdded
= 2)]
114 string m_serializedNameType
;
116 [OptionalField(VersionAdded
= 2)]
117 string m_serializedRoleType
;
119 [OptionalField(VersionAdded
= 2)]
120 string m_serializedClaims
;
122 #region ClaimsIdentity Constructors
125 /// Initializes an instance of <see cref="ClaimsIdentity"/> with an empty claims collection.
128 /// <see cref="Identity.AuthenticationType"/> is set to null.
130 public ClaimsIdentity()
131 : this((Claim
[])null)
136 /// Initializes an instance of <see cref="ClaimsIdentity"/> using the name and authentication type from
137 /// an <see cref="IIdentity"/> instance.
139 /// <param name="identity"><see cref="IIdentity"/> to draw the name and authentication type from.</param>
140 /// <exception cref="ArgumentNullException"> if <paramref name="identity"/> is null.</exception>
141 public ClaimsIdentity(IIdentity identity
)
142 : this(identity
, (IEnumerable
<Claim
>)null)
147 /// Initializes an instance of <see cref="Identity"/> using an enumerated collection of
148 /// <see cref="Claim"/> objects.
150 /// <param name="claims">
151 /// The collection of <see cref="Claim"/> objects to populate <see cref="Identity.Claims"/> with.
154 /// <see cref="Identity.AuthenticationType"/> is set to null.
156 public ClaimsIdentity(IEnumerable
<Claim
> claims
)
157 : this((IIdentity
) null, claims
, null, null, null)
162 /// Initializes an instance of <see cref="Identity"/> with an empty <see cref="Claim"/> collection
163 /// and the specified authentication type.
165 /// <param name="authenticationType">The type of authentication used.</param>
166 public ClaimsIdentity(string authenticationType
)
167 : this((IIdentity
) null, (IEnumerable
<Claim
>)null, authenticationType
, (string)null, (string)null)
172 /// Initializes an instance of <see cref="Identity"/> using an enumerated collection of
173 /// <see cref="Claim"/> objects.
175 /// <param name="claims">
176 /// The collection of <see cref="Claim"/> objects to populate <see cref="Identity.Claims"/> with.
178 /// <param name="authenticationType">The type of authentication used.</param>
180 /// <see cref="Identity.AuthenticationType"/> is set to null.
182 public ClaimsIdentity(IEnumerable
<Claim
> claims
, string authenticationType
)
183 : this((IIdentity
)null, claims
, authenticationType
, null, null)
188 /// Initializes an instance of <see cref="ClaimsIdentity"/> using the name and authentication type from
189 /// an <see cref="IIdentity"/> instance.
191 /// <param name="identity"><see cref="IIdentity"/> to draw the name and authentication type from.</param>
192 /// <exception cref="ArgumentNullException"> if <paramref name="identity"/> is null.</exception>
193 public ClaimsIdentity(IIdentity identity
, IEnumerable
<Claim
> claims
)
194 : this(identity
, claims
, (string)null, (string)null, (string)null)
199 /// Initializes an instance of <see cref="Identity"/> with an empty <see cref="Claim"/> collection,
200 /// the specified authentication type, name claim type, and role claim type.
202 /// <param name="authenticationType">The type of authentication used.</param>
203 /// <param name="nameType">The claim type to use for <see cref="Identity.Name"/>.</param>
204 /// <param name="roleType">The claim type to use for IClaimsPrincipal.IsInRole(string).</param>
205 public ClaimsIdentity(string authenticationType
, string nameType
, string roleType
)
206 : this((IIdentity
) null, (IEnumerable
<Claim
>)null, authenticationType
, nameType
, roleType
)
211 /// Initializes an instance of <see cref="ClaimsIdentity"/> using an enumeration of type
212 /// <see cref="Claim"/>, authentication type, name claim type, role claim type, and bootstrapContext.
214 /// <param name="claims">An enumeration of type <see cref="Claim"/> to initialize this identity</param>
215 /// <param name="authenticationType">The type of authentication used.</param>
216 /// <param name="nameType">The claim type to identify NameClaims.</param>
217 /// <param name="roleType">The claim type to identify RoleClaims.</param>
218 public ClaimsIdentity(IEnumerable
<Claim
> claims
, string authenticationType
, string nameType
, string roleType
)
219 : this((IIdentity
)null, claims
, authenticationType
, nameType
, roleType
)
224 /// Initializes an instance of <see cref="ClaimsIdentity"/> using an enumeration of type
225 /// <see cref="Claim"/>, authentication type, name claim type, role claim type, and bootstrapContext.
227 /// <param name="identity">The initial identity to base this identity from.</param>
228 /// <param name="claims">An enumeration of type <see cref="Claim"/> to initialize this identity.</param>
229 /// <param name="authenticationType">The type of authentication used.</param>
230 /// <param name="nameType">The claim type to identify NameClaims.</param>
231 /// <param name="roleType">The claim type to identify RoleClaims.</param>
232 public ClaimsIdentity(IIdentity identity
, IEnumerable
<Claim
> claims
, string authenticationType
, string nameType
, string roleType
)
233 : this(identity
, claims
, authenticationType
, nameType
, roleType
, true)
239 /// This constructor was added so that the WindowsIdentity could control if the authenticationType should be checked. For WindowsIdentities this
240 /// leads to a priviledged call and will fail where the caller has low priviledge.
242 /// <param name="identity">The initial identity to base this identity from.</param>
243 /// <param name="claims">An enumeration of type <see cref="Claim"/> to initialize this identity.</param>
244 /// <param name="authenticationType">The type of authentication used.</param>
245 /// <param name="nameType">The claim type to identify NameClaims.</param>
246 /// <param name="roleType">The claim type to identify RoleClaims.</param>
247 /// <param name="checkAuthType">This boolean flag controls if we blindly set the authenticationType, since call WindowsIdentity.AuthenticationType is a priviledged call.</param>
248 internal ClaimsIdentity(IIdentity identity
, IEnumerable
<Claim
> claims
, string authenticationType
, string nameType
, string roleType
, bool checkAuthType
)
250 bool nameTypeSet
= false;
251 bool roleTypeSet
= false;
253 // move the authtype, nameType and roleType over from the identity ONLY if they weren't specifically set.
254 if(checkAuthType
&& null != identity
&& string.IsNullOrEmpty(authenticationType
))
256 // can safely ignore UnauthorizedAccessException from WindowsIdentity,
257 // LSA didn't allow the call and WindowsIdentity throws if property is never accessed, no reason to fail.
258 if (identity
is WindowsIdentity
)
262 m_authenticationType
= identity
.AuthenticationType
;
264 catch (UnauthorizedAccessException
)
266 m_authenticationType
= null;
271 m_authenticationType
= identity
.AuthenticationType
;
276 m_authenticationType
= authenticationType
;
279 if(!string.IsNullOrEmpty(nameType
))
281 m_nameType
= nameType
;
285 if(!string.IsNullOrEmpty(roleType
))
287 m_roleType
= roleType
;
291 ClaimsIdentity claimsIdentity
= identity
as ClaimsIdentity
;
293 if (claimsIdentity
!= null)
295 m_label
= claimsIdentity
.m_label
;
297 // give preference to parameters
300 m_nameType
= claimsIdentity
.m_nameType
;
305 m_roleType
= claimsIdentity
.m_roleType
;
308 m_bootstrapContext
= claimsIdentity
.m_bootstrapContext
;
310 if (claimsIdentity
.Actor
!= null)
313 // Check if the Actor is circular before copying. That check is done while setting
314 // the Actor property and so not really needed here. But checking just for sanity sake
316 if(!IsCircular(claimsIdentity
.Actor
))
318 if (!AppContextSwitches
.SetActorAsReferenceWhenCopyingClaimsIdentity
)
320 m_actor
= claimsIdentity
.Actor
.Clone();
324 m_actor
= claimsIdentity
.Actor
;
329 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperationException_ActorGraphCircular"));
333 // We can only copy over the claims we own, it is up to the derived
334 // to copy over claims they own.
335 // BUT we need to special case WindowsIdentity as it keeps its own claims.
336 // In the case where we are not a windowsIdentity and the claimsIdentity is
337 // we need to copy the claims
339 if ((claimsIdentity
is WindowsIdentity
) && (!(this is WindowsIdentity
)))
340 SafeAddClaims(claimsIdentity
.Claims
);
342 SafeAddClaims(claimsIdentity
.m_instanceClaims
);
344 if (claimsIdentity
.m_userSerializationData
!= null)
346 m_userSerializationData
= claimsIdentity
.m_userSerializationData
.Clone() as byte[];
351 if (identity
!= null && !string.IsNullOrEmpty(identity
.Name
))
353 SafeAddClaim(new Claim(m_nameType
, identity
.Name
, ClaimValueTypes
.String
, DefaultIssuer
, DefaultIssuer
, this));
359 SafeAddClaims(claims
);
363 /// Initializes an instance of <see cref="ClaimsIdentity"/> using a <see cref="BinaryReader"/>.
364 /// Normally the reader is constructed from the bytes returned from <see cref="WriteTo"/>
366 /// <param name="reader">a <see cref="BinaryReader"/> pointing to a <see cref="ClaimsIdentity"/>.</param>
367 /// <exception cref="ArgumentNullException">if 'reader' is null.</exception>
368 public ClaimsIdentity(BinaryReader reader
)
371 throw new ArgumentNullException("reader");
377 /// Copy constructor.
379 /// <param name="other"><see cref="ClaimsIdentity"/> to copy.</param>
380 /// <exception cref="ArgumentNullException">if 'other' is null.</exception>
381 protected ClaimsIdentity(ClaimsIdentity other
)
385 throw new ArgumentNullException("other");
388 if (other
.m_actor
!= null)
390 m_actor
= other
.m_actor
.Clone();
393 m_authenticationType
= other
.m_authenticationType
;
394 m_bootstrapContext
= other
.m_bootstrapContext
;
395 m_label
= other
.m_label
;
396 m_nameType
= other
.m_nameType
;
397 m_roleType
= other
.m_roleType
;
398 if (other
.m_userSerializationData
!= null)
400 m_userSerializationData
= other
.m_userSerializationData
.Clone() as byte[];
403 SafeAddClaims(other
.m_instanceClaims
);
407 /// Initializes an instance of <see cref="Identity"/> from a serialized stream created via
408 /// <see cref="ISerializable"/>.
410 /// <param name="info">
411 /// The <see cref="SerializationInfo"/> to read from.
413 /// <param name="context">The <see cref="StreamingContext"/> for serialization. Can be null.</param>
414 /// <exception cref="ArgumentNullException">Thrown is the <paramref name="info"/> is null.</exception>
416 protected ClaimsIdentity(SerializationInfo info
, StreamingContext context
)
420 throw new ArgumentNullException("info");
423 Deserialize(info
, context
, true);
427 /// Initializes an instance of <see cref="Identity"/> from a serialized stream created via
428 /// <see cref="ISerializable"/>.
430 /// <param name="info">
431 /// The <see cref="SerializationInfo"/> to read from.
433 /// <exception cref="ArgumentNullException">Thrown is the <paramref name="info"/> is null.</exception>
435 protected ClaimsIdentity(SerializationInfo info
)
439 throw new ArgumentNullException("info");
442 StreamingContext sc
= new StreamingContext();
443 Deserialize(info
, sc
, false);
449 /// Gets the authentication type.
451 public virtual string AuthenticationType
453 get { return m_authenticationType; }
457 /// Gets a value that indicates whether the user has been authenticated.
459 public virtual bool IsAuthenticated
461 get { return !string.IsNullOrEmpty(m_authenticationType); }
465 /// Gets or sets a <see cref="ClaimsIdentity"/> that was granted delegation rights.
467 public ClaimsIdentity Actor
469 get { return m_actor; }
474 if(IsCircular(value))
476 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperationException_ActorGraphCircular"));
484 /// Gets or sets a context that was used to create this <see cref="ClaimsIdentity"/>.
486 public object BootstrapContext
488 get { return m_bootstrapContext; }
491 set { m_bootstrapContext = value; }
495 /// Gets the claims as <see cref="IEnumerable{Claim}"/>, associated with this <see cref="ClaimsIdentity"/>.
497 /// <remarks>May contain nulls.</remarks>
498 public virtual IEnumerable
<Claim
> Claims
502 for (int i
= 0; i
< m_instanceClaims
.Count
; i
++)
504 yield return m_instanceClaims
[i
];
507 if (m_externalClaims
!= null)
509 for (int j
= 0; j
< m_externalClaims
.Count
; j
++)
511 if (m_externalClaims
[j
] != null)
513 foreach (Claim claim
in m_externalClaims
[j
])
524 /// Contains any additional data provided by a derived type, typically set when calling <see cref="WriteTo(BinaryWriter, byte[])"/>.</param>
526 protected virtual byte[] CustomSerializationData
530 return m_userSerializationData
;
535 /// Allow the association of claims with this instance of <see cref="ClaimsIdentity"/>.
536 /// The claims will not be serialized or added in Clone(). They will be included in searches, finds and returned from the call to Claims.
537 /// It is recommended the creator of the claims ensures the subject of the claims reflects this <see cref="ClaimsIdentity"/>.
539 internal Collection
<IEnumerable
<Claim
>> ExternalClaims
541 [FriendAccessAllowed
]
542 get { return m_externalClaims; }
546 /// Gets or sets the label for this <see cref="Identity"/>
550 get { return m_label; }
551 set { m_label = value; }
555 /// Gets the value of the first claim that has a type of NameClaimType. If no claim is found, null is returned.
557 public virtual string Name
559 // just an accessor for getting the name claim
562 Claim claim
= FindFirst(m_nameType
);
573 /// Gets the claim type used to distinguish claims that refer to the name.
575 public string NameClaimType
577 get { return m_nameType; }
581 /// Gets the claim type used to distinguish claims that refer to Roles.
583 public string RoleClaimType
585 get { return m_roleType; }
589 /// Returns a new instance of <see cref="ClaimsIdentity"/> with values copied from this object.
591 /// <returns>A new <see cref="Identity"/> object copied from this object</returns>
592 public virtual ClaimsIdentity
Clone()
594 ClaimsIdentity newIdentity
= new ClaimsIdentity(m_instanceClaims
);
596 newIdentity
.m_authenticationType
= this.m_authenticationType
;
597 newIdentity
.m_bootstrapContext
= this.m_bootstrapContext
;
598 newIdentity
.m_label
= this.m_label
;
599 newIdentity
.m_nameType
= this.m_nameType
;
600 newIdentity
.m_roleType
= this.m_roleType
;
602 if(this.Actor
!= null)
604 // Check if the Actor is circular before copying. That check is done while setting
605 // the Actor property and so not really needed here. But checking just for sanity sake
606 if(!IsCircular(this.Actor
))
608 if (!AppContextSwitches
.SetActorAsReferenceWhenCopyingClaimsIdentity
)
610 newIdentity
.Actor
= this.Actor
.Clone();
614 newIdentity
.Actor
= this.Actor
;
619 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperationException_ActorGraphCircular"));
627 /// Adds a single claim to this ClaimsIdentity. The claim is examined and if the subject != this, then a new claim is
628 /// created by calling claim.Clone(this). This creates a new claim, with the correct subject.
630 /// <param name="claims">Enumeration of claims to add.</param>
631 /// This is SecurityCritical as we need to control who can add claims to the Identity. Futher down the pipe
632 /// Authorization decisions will be made based on the claims found in this collection.
634 public virtual void AddClaim(Claim claim
)
638 throw new ArgumentNullException("claim");
641 Contract
.EndContractBlock();
643 if(object.ReferenceEquals(claim
.Subject
, this))
645 m_instanceClaims
.Add(claim
);
649 m_instanceClaims
.Add(claim
.Clone(this));
654 /// Adds a list of claims to this Claims Identity. Each claim is examined and if the subject != this, then a new claim is
655 /// created by calling claim.Clone(this). This creates a new claim, with the correct subject.
657 /// <param name="claims">Enumeration of claims to add.</param>
658 /// This is SecurityCritical as we need to control who can add claims to the Identity. Futher down the pipe
659 /// Authorization decisions will be made based on the claims found in this collection.
661 public virtual void AddClaims(IEnumerable
<Claim
> claims
)
665 throw new ArgumentNullException("claims");
668 Contract
.EndContractBlock();
670 foreach (Claim claim
in claims
)
682 /// Attempts to remove a claim from the identity. It is possible that the claim cannot be removed since it is not owned
683 /// by the identity. This would be the case for role claims that are owned by the Principal.
684 /// Matches by object reference.
687 public virtual bool TryRemoveClaim(Claim claim
)
689 bool removed
= false;
691 for (int i
= 0; i
< m_instanceClaims
.Count
; i
++)
693 if (object.ReferenceEquals(m_instanceClaims
[i
], claim
))
695 m_instanceClaims
.RemoveAt(i
);
704 public virtual void RemoveClaim(Claim claim
)
706 if (!TryRemoveClaim(claim
))
708 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_ClaimCannotBeRemoved", claim
));
713 /// Called from constructor, isolated for easy review
714 /// This is called from the constructor, this implies that the base class has
715 /// ownership of holding onto the claims. We can't call AddClaim as that is a virtual and the
716 /// Derived class may not be constructed yet.
718 /// <param name="claims"></param>
719 [SecuritySafeCritical
]
720 void SafeAddClaims(IEnumerable
<Claim
> claims
)
722 foreach (Claim claim
in claims
)
724 if (object.ReferenceEquals(claim
.Subject
, this))
726 m_instanceClaims
.Add(claim
);
730 m_instanceClaims
.Add(claim
.Clone(this));
736 /// Called from constructor, isolated for easy review.
737 /// This is called from the constructor, this implies that the base class has
738 /// ownership of holding onto the claims. We can't call AddClaim as that is a virtual and the
739 /// Derived class may not be constructed yet.
741 /// <param name="claim"></param>
742 [SecuritySafeCritical
]
743 void SafeAddClaim(Claim claim
)
745 if (object.ReferenceEquals(claim
.Subject
, this))
747 m_instanceClaims
.Add(claim
);
751 m_instanceClaims
.Add(claim
.Clone(this));
756 /// Retrieves a <see cref="IEnumerable{Claim}"/> where each claim is matched by <param name="match"/>.
758 /// <param name="match">The function that performs the matching logic.</param>
759 /// <returns>A <see cref="IEnumerable{Claim}"/> of matched claims.</returns>
760 public virtual IEnumerable
<Claim
> FindAll(Predicate
<Claim
> match
)
764 throw new ArgumentNullException("match");
767 Contract
.EndContractBlock();
769 List
<Claim
> claims
= new List
<Claim
>();
771 foreach (Claim claim
in Claims
)
779 return claims
.AsReadOnly();
783 /// Retrieves a <see cref="IEnumerable{Claim}"/> where each Claim.Type equals <paramref name="type"/>.
785 /// <param name="type">The type of the claim to match.</param>
786 /// <returns>A <see cref="IEnumerable{Claim}"/> of matched claims.</returns>
787 /// <remarks>Comparison is made using Ordinal case in-sensitive on type.<</remarks>
788 public virtual IEnumerable
<Claim
> FindAll(string type
)
792 throw new ArgumentNullException("type");
795 Contract
.EndContractBlock();
797 List
<Claim
> claims
= new List
<Claim
>();
799 foreach (Claim claim
in Claims
)
803 if (string.Equals(claim
.Type
, type
, StringComparison
.OrdinalIgnoreCase
))
810 return claims
.AsReadOnly();
814 /// Determines if a claim is contained within this ClaimsIdentity.
816 /// <param name="match">The function that performs the matching logic.</param>
817 /// <returns>true if a claim is found, false otherwise.</returns>
818 public virtual bool HasClaim(Predicate
<Claim
> match
)
822 throw new ArgumentNullException("match");
825 Contract
.EndContractBlock();
827 foreach (Claim claim
in Claims
)
839 /// Determines if a claim with type AND value is contained in the claims within this ClaimsIdentity.
841 /// <param name="type"> the type of the claim to match.</param>
842 /// <param name="value"> the value of the claim to match.</param>
843 /// <returns>true if a claim is matched, false otherwise.</returns>
844 /// <remarks>Does not check Issuer or OriginalIssuer. Comparison is made using Ordinal, case sensitive on value, case in-sensitive on type.</remarks>
845 public virtual bool HasClaim(string type
, string value)
849 throw new ArgumentNullException("type");
854 throw new ArgumentNullException("value");
857 Contract
.EndContractBlock();
859 foreach (Claim claim
in Claims
)
864 && string.Equals(claim
.Type
, type
, StringComparison
.OrdinalIgnoreCase
)
865 && string.Equals(claim
.Value
, value, StringComparison
.Ordinal
))
876 /// Retrieves the first <see cref="Claim"/> that is matched by <param name="match"/>.
878 /// <param name="match">The function that performs the matching logic.</param>
879 /// <returns>A <see cref="Claim"/>, null if nothing matches.</returns>
880 /// <remarks>Comparison is made using Ordinal, case in-sensitive.</remarks>
881 public virtual Claim
FindFirst(Predicate
<Claim
> match
)
885 throw new ArgumentNullException("match");
888 Contract
.EndContractBlock();
890 foreach (Claim claim
in Claims
)
902 /// Retrieves the first <see cref="Claim"/> where Claim.Type equals <paramref name="type"/>.
904 /// <param name="type">The type of the claim to match.</param>
905 /// <returns>A <see cref="Claim"/>, null if nothing matches.</returns>
906 /// <remarks>Comparison is made using Ordinal, case in-sensitive.</remarks>
907 public virtual Claim
FindFirst(string type
)
911 throw new ArgumentNullException("type");
914 Contract
.EndContractBlock();
916 foreach (Claim claim
in Claims
)
920 if (string.Equals(claim
.Type
, type
, StringComparison
.OrdinalIgnoreCase
))
932 private void OnSerializingMethod(StreamingContext context
)
934 if (this is ISerializable
)
937 m_serializedClaims
= SerializeClaims();
938 m_serializedNameType
= m_nameType
;
939 m_serializedRoleType
= m_roleType
;
944 private void OnDeserializedMethod(StreamingContext context
)
946 if (this is ISerializable
)
949 if (!String
.IsNullOrEmpty(m_serializedClaims
))
951 DeserializeClaims(m_serializedClaims
);
952 m_serializedClaims
= null;
955 m_nameType
= string.IsNullOrEmpty(m_serializedNameType
) ? DefaultNameClaimType
: m_serializedNameType
;
956 m_roleType
= string.IsNullOrEmpty(m_serializedRoleType
) ? DefaultRoleClaimType
: m_serializedRoleType
;
960 private void OnDeserializingMethod(StreamingContext context
)
962 if (this is ISerializable
)
965 m_instanceClaims
= new List
<Claim
>();
967 m_externalClaims
= new Collection
<IEnumerable
<Claim
>>();
971 /// Populates the specified <see cref="SerializationInfo"/> with the serialization data for the ClaimsIdentity
973 /// <param name="info">The serialization information stream to write to. Satisfies ISerializable contract.</param>
974 /// <param name="context">Context for serialization. Can be null.</param>
975 /// <exception cref="ArgumentNullException">Thrown if the info parameter is null.</exception>
977 [SecurityPermission(SecurityAction
.Assert
, SerializationFormatter
= true)]
978 protected virtual void GetObjectData(SerializationInfo info
, StreamingContext context
)
982 throw new ArgumentNullException("info");
984 Contract
.EndContractBlock();
986 BinaryFormatter formatter
= new BinaryFormatter();
988 info
.AddValue(VersionKey
, m_version
);
989 if (!string.IsNullOrEmpty(m_authenticationType
))
991 info
.AddValue(AuthenticationTypeKey
, m_authenticationType
);
994 info
.AddValue(NameClaimTypeKey
, m_nameType
);
995 info
.AddValue(RoleClaimTypeKey
, m_roleType
);
997 if (!string.IsNullOrEmpty(m_label
))
999 info
.AddValue(LabelKey
, m_label
);
1005 if (m_actor
!= null)
1007 using (MemoryStream ms
= new MemoryStream())
1009 formatter
.Serialize(ms
, m_actor
, null, false);
1010 info
.AddValue(ActorKey
, Convert
.ToBase64String(ms
.GetBuffer(), 0, (int)ms
.Length
));
1017 info
.AddValue(ClaimsKey
, SerializeClaims());
1022 if (m_bootstrapContext
!= null)
1024 using (MemoryStream ms
= new MemoryStream())
1026 formatter
.Serialize(ms
, m_bootstrapContext
, null, false);
1027 info
.AddValue(BootstrapContextKey
, Convert
.ToBase64String(ms
.GetBuffer(), 0, (int)ms
.Length
));
1033 private void DeserializeClaims(string serializedClaims
)
1035 if (!string.IsNullOrEmpty(serializedClaims
))
1037 using (MemoryStream stream
= new MemoryStream(Convert
.FromBase64String(serializedClaims
)))
1039 m_instanceClaims
= (List
<Claim
>)(new BinaryFormatter()).Deserialize(stream
, null, false);
1040 for (int i
= 0; i
< m_instanceClaims
.Count
; i
++)
1042 m_instanceClaims
[i
].Subject
= this;
1047 if (m_instanceClaims
== null)
1049 m_instanceClaims
= new List
<Claim
>();
1054 private string SerializeClaims()
1056 using (MemoryStream ms
= new MemoryStream())
1058 (new BinaryFormatter()).Serialize(ms
, m_instanceClaims
, null, false);
1059 return Convert
.ToBase64String(ms
.GetBuffer(), 0, (int)ms
.Length
);
1064 /// Checks if a circular reference exists to 'this'
1066 /// <param name="subject"></param>
1067 /// <returns></returns>
1068 bool IsCircular(ClaimsIdentity subject
)
1070 if(ReferenceEquals(this, subject
))
1075 ClaimsIdentity currSubject
= subject
;
1077 while(currSubject
.Actor
!= null)
1079 if(ReferenceEquals(this, currSubject
.Actor
))
1084 currSubject
= currSubject
.Actor
;
1091 /// Initializes from a <see cref="BinaryReader"/>. Normally the reader is initialized in the same as the one passed to <see cref="Serialize(BinaryWriter)"/>
1093 /// <param name="reader">a <see cref="BinaryReader"/> pointing to a <see cref="ClaimsIdentity"/>.</param>
1094 /// <exception cref="ArgumentNullException">if 'reader' is null.</exception>
1095 private void Initialize(BinaryReader reader
)
1099 throw new ArgumentNullException("reader");
1103 SerializationMask mask
= (SerializationMask
)reader
.ReadInt32();
1105 if ((mask
& SerializationMask
.AuthenticationType
) == SerializationMask
.AuthenticationType
)
1107 m_authenticationType
= reader
.ReadString();
1110 if ((mask
& SerializationMask
.BootstrapConext
) == SerializationMask
.BootstrapConext
)
1112 m_bootstrapContext
= reader
.ReadString();
1115 if ((mask
& SerializationMask
.NameClaimType
) == SerializationMask
.NameClaimType
)
1117 m_nameType
= reader
.ReadString();
1121 m_nameType
= ClaimsIdentity
.DefaultNameClaimType
;
1124 if ((mask
& SerializationMask
.RoleClaimType
) == SerializationMask
.RoleClaimType
)
1126 m_roleType
= reader
.ReadString();
1130 m_roleType
= ClaimsIdentity
.DefaultRoleClaimType
;
1133 if ((mask
& SerializationMask
.HasClaims
) == SerializationMask
.HasClaims
)
1136 int numberOfClaims
= reader
.ReadInt32();
1137 for (int index
= 0; index
< numberOfClaims
; ++index
)
1139 Claim claim
= new Claim(reader
, this);
1140 m_instanceClaims
.Add(claim
);
1146 /// Provides and extensibility point for derived types to create a custom <see cref="Claim"/>.
1148 /// <param name="reader">the <see cref="BinaryReader"/>that points at the claim.</param>
1149 /// <returns>a new <see cref="Claim"/>.</returns>
1150 protected virtual Claim
CreateClaim(BinaryReader reader
)
1154 throw new ArgumentNullException("reader");
1157 return new Claim(reader
, this);
1161 /// Serializes using a <see cref="BinaryWriter"/>
1163 /// <param name="writer">the <see cref="BinaryWriter"/> to use for data storage.</param>
1164 /// <exception cref="ArgumentNullException">if 'writer' is null.</exception>
1165 public virtual void WriteTo(BinaryWriter writer
)
1167 WriteTo(writer
, null);
1171 /// Serializes using a <see cref="BinaryWriter"/>
1173 /// <param name="writer">the <see cref="BinaryWriter"/> to use for data storage.</param>
1174 /// <param name="userData">additional data provided by derived type.</param>
1175 /// <exception cref="ArgumentNullException">if 'writer' is null.</exception>
1176 protected virtual void WriteTo(BinaryWriter writer
, byte[] userData
)
1180 throw new ArgumentNullException("writer");
1183 int numberOfPropertiesWritten
= 0;
1184 var mask
= SerializationMask
.None
;
1185 if (m_authenticationType
!= null)
1187 mask
|= SerializationMask
.AuthenticationType
;
1188 numberOfPropertiesWritten
++;
1191 if (m_bootstrapContext
!= null)
1193 string rawData
= m_bootstrapContext
as string;
1194 if (rawData
!= null)
1196 mask
|= SerializationMask
.BootstrapConext
;
1197 numberOfPropertiesWritten
++;
1201 if (!string.Equals(m_nameType
, ClaimsIdentity
.DefaultNameClaimType
, StringComparison
.Ordinal
))
1203 mask
|= SerializationMask
.NameClaimType
;
1204 numberOfPropertiesWritten
++;
1207 if (!string.Equals(m_roleType
, ClaimsIdentity
.DefaultRoleClaimType
, StringComparison
.Ordinal
))
1209 mask
|= SerializationMask
.RoleClaimType
;
1210 numberOfPropertiesWritten
++;
1213 if (!string.IsNullOrWhiteSpace(m_label
))
1215 mask
|= SerializationMask
.HasLabel
;
1216 numberOfPropertiesWritten
++;
1219 if (m_instanceClaims
.Count
> 0)
1221 mask
|= SerializationMask
.HasClaims
;
1222 numberOfPropertiesWritten
++;
1225 if (m_actor
!= null)
1227 mask
|= SerializationMask
.Actor
;
1228 numberOfPropertiesWritten
++;
1231 if (userData
!= null && userData
.Length
> 0)
1233 numberOfPropertiesWritten
++;
1234 mask
|= SerializationMask
.UserData
;
1237 writer
.Write((Int32
)mask
);
1238 writer
.Write((Int32
)numberOfPropertiesWritten
);
1239 if ((mask
& SerializationMask
.AuthenticationType
) == SerializationMask
.AuthenticationType
)
1241 writer
.Write(m_authenticationType
);
1244 if ((mask
& SerializationMask
.BootstrapConext
) == SerializationMask
.BootstrapConext
)
1246 writer
.Write(m_bootstrapContext
as string);
1249 if ((mask
& SerializationMask
.NameClaimType
) == SerializationMask
.NameClaimType
)
1251 writer
.Write(m_nameType
);
1254 if ((mask
& SerializationMask
.RoleClaimType
) == SerializationMask
.RoleClaimType
)
1256 writer
.Write(m_roleType
);
1259 if ((mask
& SerializationMask
.HasLabel
) == SerializationMask
.HasLabel
)
1261 writer
.Write(m_label
);
1264 if ((mask
& SerializationMask
.HasClaims
) == SerializationMask
.HasClaims
)
1266 writer
.Write((Int32
)m_instanceClaims
.Count
);
1267 foreach (var claim
in m_instanceClaims
)
1269 claim
.WriteTo(writer
);
1273 if ((mask
& SerializationMask
.Actor
) == SerializationMask
.Actor
)
1275 m_actor
.WriteTo(writer
);
1278 if ((mask
& SerializationMask
.UserData
) == SerializationMask
.UserData
)
1280 writer
.Write((Int32
)userData
.Length
);
1281 writer
.Write(userData
);
1287 // <param name="useContext"></param> The reason for this param is due to WindowsIdentity deciding to have an
1288 // api that doesn't pass the context to its internal constructor.
1290 [SecurityPermission(SecurityAction
.Assert
, SerializationFormatter
= true)]
1291 private void Deserialize(SerializationInfo info
, StreamingContext context
, bool useContext
)
1296 throw new ArgumentNullException("info");
1302 bf
= new BinaryFormatter(null, context
);
1304 bf
= new BinaryFormatter();
1307 SerializationInfoEnumerator enumerator
= info
.GetEnumerator();
1308 while (enumerator
.MoveNext())
1310 switch (enumerator
.Name
)
1313 info
.GetString(VersionKey
);
1316 case AuthenticationTypeKey
:
1317 m_authenticationType
= info
.GetString(AuthenticationTypeKey
);
1320 case NameClaimTypeKey
:
1321 m_nameType
= info
.GetString(NameClaimTypeKey
);
1324 case RoleClaimTypeKey
:
1325 m_roleType
= info
.GetString(RoleClaimTypeKey
);
1329 m_label
= info
.GetString(LabelKey
);
1333 using (MemoryStream stream
= new MemoryStream(Convert
.FromBase64String(info
.GetString(ActorKey
))))
1335 m_actor
= (ClaimsIdentity
)bf
.Deserialize(stream
, null, false);
1340 DeserializeClaims(info
.GetString(ClaimsKey
));
1343 case BootstrapContextKey
:
1344 using (MemoryStream ms
= new MemoryStream(Convert
.FromBase64String(info
.GetString(BootstrapContextKey
))))
1346 m_bootstrapContext
= bf
.Deserialize(ms
, null, false);
1351 // Ignore other fields for forward compatability.