3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>Microsoft</OWNER>
12 // Representation of a process/thread token.
15 namespace System.Security.Principal
17 using System.Diagnostics.Contracts;
18 using System.Reflection;
19 using System.Runtime.CompilerServices;
20 #if FEATURE_CORRUPTING_EXCEPTIONS
21 using System.Runtime.ExceptionServices;
22 #endif // FEATURE_CORRUPTING_EXCEPTIONS
23 using System.Runtime.InteropServices;
24 using System.Runtime.Serialization;
25 using System.Runtime.Versioning;
26 using System.Security.AccessControl;
27 using System.Security.Permissions;
29 using System.Threading;
30 using Microsoft.Win32;
31 using Microsoft.Win32.SafeHandles;
34 using System.Security.Claims;
35 using System.Collections.ObjectModel;
36 using System.Collections.Generic;
37 using System.Globalization;
41 [System.Runtime.InteropServices.ComVisible(true)]
42 public enum WindowsAccountType {
49 // Keep in sync with vm\comprincipal.h
50 internal enum WinSecurityContext {
51 Thread = 1, // OpenAsSelf = false
52 Process = 2, // OpenAsSelf = true
53 Both = 3 // OpenAsSelf = true, then OpenAsSelf = false
56 internal enum ImpersonationQueryResult {
57 Impersonated = 0, // current thread is impersonated
58 NotImpersonated = 1, // current thread is not impersonated
59 Failed = 2 // failed to query
63 [System.Runtime.InteropServices.ComVisible(true)]
65 public class WindowsIdentity : ClaimsIdentity, ISerializable, IDeserializationCallback, IDisposable {
67 public class WindowsIdentity : IIdentity, ISerializable, IDeserializationCallback, IDisposable {
69 [System.Security.SecurityCritical] // auto-generated
70 static SafeAccessTokenHandle s_invalidTokenHandle = SafeAccessTokenHandle.InvalidHandle;
71 private string m_name = null;
72 private SecurityIdentifier m_owner = null;
73 private SecurityIdentifier m_user = null;
74 private object m_groups = null;
75 [System.Security.SecurityCritical] // auto-generated
76 private SafeAccessTokenHandle m_safeTokenHandle = SafeAccessTokenHandle.InvalidHandle;
77 private string m_authType = null;
78 private int m_isAuthenticated = -1;
79 private volatile TokenImpersonationLevel m_impersonationLevel;
80 private volatile bool m_impersonationLevelInitialized;
81 private static RuntimeConstructorInfo s_specialSerializationCtor;
86 public new const string DefaultIssuer = @"AD AUTHORITY";
89 string m_issuerName = DefaultIssuer;
92 private object m_claimsIntiailizedLock = new object();
95 volatile bool m_claimsInitialized;
98 List<Claim> m_deviceClaims;
101 List<Claim> m_userClaims;
109 [System.Security.SecuritySafeCritical] // auto-generated
110 static WindowsIdentity()
112 s_specialSerializationCtor = typeof(WindowsIdentity).GetConstructor(
113 BindingFlags.Instance | BindingFlags.NonPublic,
115 new Type[] { typeof(SerializationInfo) },
116 null) as RuntimeConstructorInfo;
119 [System.Security.SecurityCritical] // auto-generated
121 private WindowsIdentity ()
122 : base( null, null, null, ClaimTypes.Name, ClaimTypes.GroupSid ) {}
124 private WindowsIdentity () {}
127 [System.Security.SecurityCritical] // auto-generated
128 internal WindowsIdentity (SafeAccessTokenHandle safeTokenHandle) : this (safeTokenHandle.DangerousGetHandle(), null, -1) {
129 GC.KeepAlive(safeTokenHandle);
132 [System.Security.SecuritySafeCritical] // auto-generated
133 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
134 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
135 public WindowsIdentity (IntPtr userToken) : this (userToken, null, -1) {}
137 [System.Security.SecuritySafeCritical] // auto-generated
138 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
139 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
140 public WindowsIdentity (IntPtr userToken, string type) : this (userToken, type, -1) {}
142 [System.Security.SecuritySafeCritical] // auto-generated
143 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
144 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
145 public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType) : this (userToken, type, -1) {}
147 [System.Security.SecuritySafeCritical] // auto-generated
148 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
149 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
150 public WindowsIdentity (IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated)
151 : this (userToken, type, isAuthenticated ? 1 : 0) {}
153 [System.Security.SecurityCritical] // auto-generated
156 private WindowsIdentity (IntPtr userToken, string authType, int isAuthenticated )
158 : base(null, null, null, ClaimTypes.Name, ClaimTypes.GroupSid)
161 CreateFromToken(userToken);
162 m_authType = authType;
163 m_isAuthenticated = isAuthenticated;
166 [System.Security.SecurityCritical] // auto-generated
167 [ResourceExposure(ResourceScope.None)]
168 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
169 private void CreateFromToken (IntPtr userToken) {
170 if (userToken == IntPtr.Zero)
171 throw new ArgumentException(Environment.GetResourceString("Argument_TokenZero"));
172 Contract.EndContractBlock();
174 // Find out if the specified token is a valid.
175 uint dwLength = (uint) Marshal.SizeOf(typeof(uint));
176 bool result = Win32Native.GetTokenInformation(userToken, (uint) TokenInformationClass.TokenType,
177 SafeLocalAllocHandle.InvalidHandle, 0, out dwLength);
178 if (Marshal.GetLastWin32Error() == Win32Native.ERROR_INVALID_HANDLE)
179 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidImpersonationToken"));
181 if (!Win32Native.DuplicateHandle(Win32Native.GetCurrentProcess(),
183 Win32Native.GetCurrentProcess(),
184 ref m_safeTokenHandle,
187 Win32Native.DUPLICATE_SAME_ACCESS))
188 throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
191 [System.Security.SecuritySafeCritical] // auto-generated
192 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
193 public WindowsIdentity (string sUserPrincipalName) : this (sUserPrincipalName, null) {}
195 [System.Security.SecuritySafeCritical] // auto-generated
196 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
199 public WindowsIdentity (string sUserPrincipalName, string type )
201 : base( null, null, null, ClaimTypes.Name, ClaimTypes.GroupSid )
204 KerbS4ULogon(sUserPrincipalName, ref m_safeTokenHandle);
208 // We cannot make sure the token will stay alive
209 // until it is being deserialized in another AppDomain. We do not have a way to capture
210 // the state of a token (just a pointer to kernel memory) and re-construct it later
211 // and even if we did (via calling NtQueryInformationToken and relying on the token undocumented
212 // format), constructing a token requires TCB privilege. We need to address the "serializable"
213 // nature of WindowsIdentity since it is not obvious that can be achieved at all.
216 [System.Security.SecuritySafeCritical] // auto-generated
217 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
218 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.SerializationFormatter )]
219 public WindowsIdentity (SerializationInfo info, StreamingContext context) : this(info)
223 // This is a copy of the serialization constructor above but without the
224 // security demand that's slow and breaks partial trust scenarios
225 // without an expensive assert in place in the remoting code. Instead we
226 // special case this class and call the private constructor directly
227 // (changing the demand above is considered a breaking change, even
228 // though nobody else should have been using a serialization constructor
230 [System.Security.SecurityCritical] // auto-generated
231 private WindowsIdentity(SerializationInfo info)
238 m_claimsInitialized = false;
241 IntPtr userToken = (IntPtr) info.GetValue("m_userToken", typeof(IntPtr));
242 if (userToken != IntPtr.Zero)
243 CreateFromToken(userToken);
247 [System.Security.SecurityCritical] // auto-generated_required
248 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) {
250 base.GetObjectData(info, context);
252 info.AddValue("m_userToken", m_safeTokenHandle.DangerousGetHandle());
256 void IDeserializationCallback.OnDeserialization (Object sender) {}
263 [System.Security.SecuritySafeCritical] // auto-generated
264 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
265 public static WindowsIdentity GetCurrent () {
266 return GetCurrentInternal(TokenAccessLevels.MaximumAllowed, false);
269 [System.Security.SecuritySafeCritical] // auto-generated
270 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
271 public static WindowsIdentity GetCurrent (bool ifImpersonating) {
272 return GetCurrentInternal(TokenAccessLevels.MaximumAllowed, ifImpersonating);
275 [System.Security.SecuritySafeCritical] // auto-generated
276 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
277 public static WindowsIdentity GetCurrent (TokenAccessLevels desiredAccess) {
278 return GetCurrentInternal(desiredAccess, false);
281 // GetAnonymous() is used heavily in ASP.NET requests as a dummy identity to indicate
282 // the request is anonymous. It does not represent a real process or thread token so
283 // it cannot impersonate or do anything useful. Note this identity does not represent the
284 // usual concept of an anonymous token, and the name is simply misleading but we cannot change it now.
286 [System.Security.SecuritySafeCritical] // auto-generated
287 public static WindowsIdentity GetAnonymous () {
288 return new WindowsIdentity();
294 // this is defined 'override sealed' for back compat. Il generated is 'virtual final' and this needs to be the same.
296 public override sealed string AuthenticationType {
298 public string AuthenticationType {
300 [System.Security.SecuritySafeCritical] // auto-generated
302 // If this is an anonymous identity, return an empty string
303 if (m_safeTokenHandle.IsInvalid)
306 if (m_authType == null) {
307 Win32Native.LUID authId = GetLogonAuthId(m_safeTokenHandle);
308 if (authId.LowPart == Win32Native.ANONYMOUS_LOGON_LUID)
309 return String.Empty; // no authentication, just return an empty string
311 SafeLsaReturnBufferHandle pLogonSessionData = SafeLsaReturnBufferHandle.InvalidHandle;
313 int status = Win32Native.LsaGetLogonSessionData(ref authId, ref pLogonSessionData);
314 if (status < 0) // non-negative numbers indicate success
315 throw GetExceptionFromNtStatus(status);
317 pLogonSessionData.Initialize((uint)Marshal.SizeOf(typeof(Win32Native.SECURITY_LOGON_SESSION_DATA)));
319 Win32Native.SECURITY_LOGON_SESSION_DATA logonSessionData = pLogonSessionData.Read<Win32Native.SECURITY_LOGON_SESSION_DATA>(0);
320 return Marshal.PtrToStringUni(logonSessionData.AuthenticationPackage.Buffer);
323 if (!pLogonSessionData.IsInvalid)
324 pLogonSessionData.Dispose();
334 public TokenImpersonationLevel ImpersonationLevel {
335 [System.Security.SecuritySafeCritical] // auto-generated
337 // If two threads ---- here, they'll both set m_impersonationLevel to the same value,
339 if (!m_impersonationLevelInitialized) {
340 TokenImpersonationLevel impersonationLevel = TokenImpersonationLevel.None;
341 // If this is an anonymous identity
342 if (m_safeTokenHandle.IsInvalid) {
343 impersonationLevel = TokenImpersonationLevel.Anonymous;
346 TokenType tokenType = (TokenType)GetTokenInformation<int>(TokenInformationClass.TokenType);
347 if (tokenType == TokenType.TokenPrimary) {
348 impersonationLevel = TokenImpersonationLevel.None; // primary token;
351 /// This is an impersonation token, get the impersonation level
352 int level = GetTokenInformation<int>(TokenInformationClass.TokenImpersonationLevel);
353 impersonationLevel = (TokenImpersonationLevel)level + 1;
357 m_impersonationLevel = impersonationLevel;
358 m_impersonationLevelInitialized = true;
361 return m_impersonationLevel;
366 public override bool IsAuthenticated {
368 public virtual bool IsAuthenticated {
372 if (m_isAuthenticated == -1) {
373 // There is a known bug where this approach will not work correctly for domain guests (will return false
374 // instead of true). But this is a corner-case that is not very interesting.
376 m_isAuthenticated = CheckNtTokenForSid(new SecurityIdentifier(IdentifierAuthority.NTAuthority,
377 new int[] { Win32Native.SECURITY_AUTHENTICATED_USER_RID })) ? 1 : 0;
379 WindowsPrincipal wp = new WindowsPrincipal(this);
380 SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
381 new int[] {Win32Native.SECURITY_AUTHENTICATED_USER_RID});
382 m_isAuthenticated = wp.IsInRole(sid) ? 1 : 0;
387 return m_isAuthenticated == 1;
392 [System.Security.SecuritySafeCritical]
394 bool CheckNtTokenForSid (SecurityIdentifier sid) {
396 Contract.EndContractBlock();
398 // special case the anonymous identity.
399 if (m_safeTokenHandle.IsInvalid)
402 // CheckTokenMembership expects an impersonation token
403 SafeAccessTokenHandle token = SafeAccessTokenHandle.InvalidHandle;
404 TokenImpersonationLevel til = ImpersonationLevel;
405 bool isMember = false;
408 if (til == TokenImpersonationLevel.None) {
409 if (!Win32Native.DuplicateTokenEx(m_safeTokenHandle,
410 (uint) TokenAccessLevels.Query,
412 (uint) TokenImpersonationLevel.Identification,
413 (uint) TokenType.TokenImpersonation,
415 throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
419 // CheckTokenMembership will check if the SID is both present and enabled in the access token.
420 if (!Win32Native.CheckTokenMembership((til != TokenImpersonationLevel.None ? m_safeTokenHandle : token),
423 throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
426 if (token != SafeAccessTokenHandle.InvalidHandle) {
436 // IsGuest, IsSystem and IsAnonymous are maintained for compatibility reasons. It is always
437 // possible to extract this same information from the User SID property and the new
438 // (and more general) methods defined in the SID class (IsWellKnown, etc...).
441 public virtual bool IsGuest {
442 [System.Security.SecuritySafeCritical] // auto-generated
444 // special case the anonymous identity.
445 if (m_safeTokenHandle.IsInvalid)
449 return CheckNtTokenForSid(new SecurityIdentifier(IdentifierAuthority.NTAuthority,
450 new int[] { Win32Native.SECURITY_BUILTIN_DOMAIN_RID, (int)WindowsBuiltInRole.Guest }));
452 WindowsPrincipal principal = new WindowsPrincipal(this);
453 return principal.IsInRole(WindowsBuiltInRole.Guest);
459 public virtual bool IsSystem {
460 [System.Security.SecuritySafeCritical] // auto-generated
462 // special case the anonymous identity.
463 if (m_safeTokenHandle.IsInvalid)
465 SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
466 new int[] {Win32Native.SECURITY_LOCAL_SYSTEM_RID});
467 return (this.User == sid);
471 public virtual bool IsAnonymous {
472 [System.Security.SecuritySafeCritical] // auto-generated
474 // special case the anonymous identity.
475 if (m_safeTokenHandle.IsInvalid)
477 SecurityIdentifier sid = new SecurityIdentifier(IdentifierAuthority.NTAuthority,
478 new int[] {Win32Native.SECURITY_ANONYMOUS_LOGON_RID});
479 return (this.User == sid);
484 public override string Name {
486 public virtual string Name {
488 [System.Security.SecuritySafeCritical] // auto-generated
494 [System.Security.SecurityCritical] // auto-generated
495 [DynamicSecurityMethodAttribute()]
496 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
497 internal String GetName()
499 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
500 // special case the anonymous identity.
501 if (m_safeTokenHandle.IsInvalid)
506 // revert thread impersonation for the duration of the call to get the name.
507 using (SafeRevertToSelf(ref stackMark))
509 NTAccount ntAccount = this.User.Translate(typeof(NTAccount)) as NTAccount;
510 m_name = ntAccount.ToString();
518 public SecurityIdentifier Owner {
519 [System.Security.SecuritySafeCritical] // auto-generated
521 // special case the anonymous identity.
522 if (m_safeTokenHandle.IsInvalid)
525 if (m_owner == null) {
526 using (SafeLocalAllocHandle tokenOwner = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenOwner)) {
527 m_owner = new SecurityIdentifier(tokenOwner.Read<IntPtr>(0), true);
536 public SecurityIdentifier User {
537 [System.Security.SecuritySafeCritical] // auto-generated
539 // special case the anonymous identity.
540 if (m_safeTokenHandle.IsInvalid)
543 if (m_user == null) {
544 using (SafeLocalAllocHandle tokenUser = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenUser)) {
545 m_user = new SecurityIdentifier(tokenUser.Read<IntPtr>(0), true);
553 public IdentityReferenceCollection Groups {
554 [System.Security.SecuritySafeCritical] // auto-generated
556 // special case the anonymous identity.
557 if (m_safeTokenHandle.IsInvalid)
560 if (m_groups == null) {
561 IdentityReferenceCollection groups = new IdentityReferenceCollection();
562 using (SafeLocalAllocHandle pGroups = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenGroups)) {
564 uint groupCount = pGroups.Read<uint>(0);
565 // Work-around bug on WS03 that only populates the GroupCount field of TOKEN_GROUPS if the count is 0
566 // In that situation, attempting to read the entire TOKEN_GROUPS structure will lead to InsufficientBuffer exception
567 // since the field is only 4 bytes long (uint only, for GroupCount), but we try to read more (including the pointer to GroupDetails).
571 Win32Native.TOKEN_GROUPS tokenGroups = pGroups.Read<Win32Native.TOKEN_GROUPS>(0);
572 Win32Native.SID_AND_ATTRIBUTES[] groupDetails = new Win32Native.SID_AND_ATTRIBUTES[tokenGroups.GroupCount];
574 pGroups.ReadArray((uint)Marshal.OffsetOf(typeof(Win32Native.TOKEN_GROUPS), "Groups").ToInt32(),
577 groupDetails.Length);
579 foreach (Win32Native.SID_AND_ATTRIBUTES group in groupDetails)
581 // Ignore disabled, logon ID, and deny-only groups.
582 uint mask = Win32Native.SE_GROUP_ENABLED | Win32Native.SE_GROUP_LOGON_ID | Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
583 if ((group.Attributes & mask) == Win32Native.SE_GROUP_ENABLED) {
584 groups.Add(new SecurityIdentifier(group.Sid, true ));
589 Interlocked.CompareExchange(ref m_groups, groups, null);
592 return m_groups as IdentityReferenceCollection;
597 // Note this property does not duplicate the token. This is also the same as V1/Everett behaviour.
600 public virtual IntPtr Token {
601 [System.Security.SecuritySafeCritical] // auto-generated
602 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
604 return m_safeTokenHandle.DangerousGetHandle();
611 [SecuritySafeCritical]
612 [DynamicSecurityMethodAttribute()]
613 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
614 public static void RunImpersonated(SafeAccessTokenHandle safeAccessTokenHandle, Action action)
617 throw new ArgumentNullException("action");
619 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
621 WindowsIdentity wi = null;
622 if (!safeAccessTokenHandle.IsInvalid)
623 wi = new WindowsIdentity(safeAccessTokenHandle);
625 using (WindowsImpersonationContext wiContext = SafeImpersonate(safeAccessTokenHandle, wi, ref stackMark))
631 [SecuritySafeCritical]
632 [DynamicSecurityMethodAttribute()]
633 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
634 public static T RunImpersonated<T>(SafeAccessTokenHandle safeAccessTokenHandle, Func<T> func)
637 throw new ArgumentNullException("func");
639 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
641 WindowsIdentity wi = null;
642 if (!safeAccessTokenHandle.IsInvalid)
643 wi = new WindowsIdentity(safeAccessTokenHandle);
645 T result = default(T);
646 using (WindowsImpersonationContext wiContext = SafeImpersonate(safeAccessTokenHandle, wi, ref stackMark))
654 [System.Security.SecuritySafeCritical] // auto-generated
655 [DynamicSecurityMethodAttribute()]
656 [ResourceExposure(ResourceScope.Process)] // Call from within a CER, or use a RunAsUser helper.
657 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
658 public virtual WindowsImpersonationContext Impersonate ()
660 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
661 return Impersonate(ref stackMark);
664 [System.Security.SecuritySafeCritical] // auto-generated
665 [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlPrincipal | SecurityPermissionFlag.UnmanagedCode)]
666 [DynamicSecurityMethodAttribute()]
667 [ResourceExposure(ResourceScope.Process)] // Call from within a CER, or use a RunAsUser helper.
668 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
669 public static WindowsImpersonationContext Impersonate (IntPtr userToken)
671 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
672 if (userToken == IntPtr.Zero)
673 return SafeRevertToSelf(ref stackMark);
675 WindowsIdentity wi = new WindowsIdentity(userToken, null, -1);
676 return wi.Impersonate(ref stackMark);
679 [System.Security.SecurityCritical] // auto-generated
680 internal WindowsImpersonationContext Impersonate (ref StackCrawlMark stackMark) {
681 if (m_safeTokenHandle.IsInvalid)
682 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AnonymousCannotImpersonate"));
684 return SafeImpersonate(m_safeTokenHandle, this, ref stackMark);
687 [System.Security.SecuritySafeCritical] // auto-generated
689 protected virtual void Dispose(bool disposing) {
691 if (m_safeTokenHandle != null && !m_safeTokenHandle.IsClosed)
692 m_safeTokenHandle.Dispose();
700 public void Dispose() {
704 public SafeAccessTokenHandle AccessToken {
705 [System.Security.SecurityCritical] // auto-generated
707 return m_safeTokenHandle;
715 [System.Security.SecurityCritical] // auto-generated
716 [ResourceExposure(ResourceScope.None)]
717 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
718 internal static WindowsImpersonationContext SafeRevertToSelf(ref StackCrawlMark stackMark)
720 return SafeImpersonate(s_invalidTokenHandle, null, ref stackMark);
723 [System.Security.SecurityCritical] // auto-generated
724 [ResourceExposure(ResourceScope.Process)]
725 [ResourceConsumption(ResourceScope.Process)]
726 internal static WindowsImpersonationContext SafeImpersonate (SafeAccessTokenHandle userToken, WindowsIdentity wi, ref StackCrawlMark stackMark)
728 bool isImpersonating;
730 SafeAccessTokenHandle safeTokenHandle = GetCurrentToken(TokenAccessLevels.MaximumAllowed, false, out isImpersonating, out hr);
731 if (safeTokenHandle == null || safeTokenHandle.IsInvalid)
732 throw new SecurityException(Win32Native.GetMessage(hr));
734 // Set the SafeAccessTokenHandle on the FSD:
735 FrameSecurityDescriptor secObj = SecurityRuntime.GetSecurityObjectForFrame(ref stackMark, true);
738 // Security: REQ_SQ flag is missing. Bad compiler ?
739 // This can happen when you create delegates over functions that need the REQ_SQ
740 throw new SecurityException(Environment.GetResourceString( "ExecutionEngine_MissingSecurityDescriptor" ) );
743 WindowsImpersonationContext context = new WindowsImpersonationContext(safeTokenHandle, GetCurrentThreadWI(), isImpersonating, secObj);
745 if (userToken.IsInvalid) { // impersonating a zero token means clear the token on the thread
746 hr = Win32.RevertToSelf();
748 Environment.FailFast(Win32Native.GetMessage(hr));
749 // update identity on the thread
751 secObj.SetTokenHandles(safeTokenHandle, (wi == null?null:wi.AccessToken));
753 hr = Win32.RevertToSelf();
755 Environment.FailFast(Win32Native.GetMessage(hr));
756 hr = Win32.ImpersonateLoggedOnUser(userToken);
759 throw new SecurityException(Environment.GetResourceString("Argument_ImpersonateUser"));
762 secObj.SetTokenHandles(safeTokenHandle, (wi == null?null:wi.AccessToken));
768 [System.Security.SecurityCritical] // auto-generated
769 internal static WindowsIdentity GetCurrentThreadWI()
771 return SecurityContext.GetCurrentWI(Thread.CurrentThread.GetExecutionContextReader());
775 internal static void UpdateThreadWI(WindowsIdentity wi)
777 // Set WI on Thread.CurrentThread.ExecutionContext.SecurityContext
778 Thread currentThread = Thread.CurrentThread;
779 if (currentThread.GetExecutionContextReader().SecurityContext.WindowsIdentity != wi)
781 ExecutionContext ec = currentThread.GetMutableExecutionContext();
782 SecurityContext sc = ec.SecurityContext;
783 if (wi != null && sc == null)
785 // create a new security context on the thread
786 sc = new SecurityContext();
787 ec.SecurityContext = sc;
790 if (sc != null) // null-check needed here since we will not create an sc if wi is null
792 sc.WindowsIdentity = wi;
798 [System.Security.SecurityCritical] // auto-generated
799 [ResourceExposure(ResourceScope.None)]
800 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
801 internal static WindowsIdentity GetCurrentInternal (TokenAccessLevels desiredAccess, bool threadOnly) {
803 bool isImpersonating;
804 SafeAccessTokenHandle safeTokenHandle = GetCurrentToken(desiredAccess, threadOnly, out isImpersonating, out hr);
805 if (safeTokenHandle == null || safeTokenHandle.IsInvalid) {
806 // either we wanted only ThreadToken - return null
807 if (threadOnly && !isImpersonating)
809 // or there was an error
810 throw new SecurityException(Win32Native.GetMessage(hr));
812 WindowsIdentity wi = new WindowsIdentity();
813 wi.m_safeTokenHandle.Dispose();
814 wi.m_safeTokenHandle = safeTokenHandle;
818 internal static RuntimeConstructorInfo GetSpecialSerializationCtor()
820 return s_specialSerializationCtor;
827 private static int GetHRForWin32Error (int dwLastError) {
828 if ((dwLastError & 0x80000000) == 0x80000000)
831 return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
834 [System.Security.SecurityCritical] // auto-generated
835 private static Exception GetExceptionFromNtStatus (int status) {
836 if ((uint) status == Win32Native.STATUS_ACCESS_DENIED)
837 return new UnauthorizedAccessException();
839 if ((uint) status == Win32Native.STATUS_INSUFFICIENT_RESOURCES || (uint) status == Win32Native.STATUS_NO_MEMORY)
840 return new OutOfMemoryException();
842 int win32ErrorCode = Win32Native.LsaNtStatusToWinError(status);
843 return new SecurityException(Win32Native.GetMessage(win32ErrorCode));
846 [System.Security.SecurityCritical] // auto-generated
847 [ResourceExposure(ResourceScope.Process)]
848 [ResourceConsumption(ResourceScope.Process)]
849 private static SafeAccessTokenHandle GetCurrentToken(TokenAccessLevels desiredAccess, bool threadOnly, out bool isImpersonating, out int hr) {
850 isImpersonating = true;
851 SafeAccessTokenHandle safeTokenHandle = GetCurrentThreadToken(desiredAccess, out hr);
852 if (safeTokenHandle == null && hr == GetHRForWin32Error(Win32Native.ERROR_NO_TOKEN)) {
854 isImpersonating = false;
856 safeTokenHandle = GetCurrentProcessToken(desiredAccess, out hr);
858 return safeTokenHandle;
861 [System.Security.SecurityCritical] // auto-generated
862 [ResourceExposure(ResourceScope.Process)]
863 [ResourceConsumption(ResourceScope.Process)]
864 private static SafeAccessTokenHandle GetCurrentProcessToken (TokenAccessLevels desiredAccess, out int hr) {
866 SafeAccessTokenHandle safeTokenHandle;
867 if (!Win32Native.OpenProcessToken(Win32Native.GetCurrentProcess(), desiredAccess, out safeTokenHandle))
868 hr = GetHRForWin32Error(Marshal.GetLastWin32Error());
869 return safeTokenHandle;
872 [System.Security.SecurityCritical] // auto-generated
873 [ResourceExposure(ResourceScope.Process)]
874 [ResourceConsumption(ResourceScope.Process)]
875 internal static SafeAccessTokenHandle GetCurrentThreadToken(TokenAccessLevels desiredAccess, out int hr) {
876 SafeAccessTokenHandle safeTokenHandle;
877 hr = Win32.OpenThreadToken(desiredAccess, WinSecurityContext.Both, out safeTokenHandle);
878 return safeTokenHandle;
882 /// Get a property from the current token
884 [System.Security.SecurityCritical] // auto-generated
885 private T GetTokenInformation<T>(TokenInformationClass tokenInformationClass) where T : struct{
886 Contract.Assert(!m_safeTokenHandle.IsInvalid && !m_safeTokenHandle.IsClosed, "!m_safeTokenHandle.IsInvalid && !m_safeTokenHandle.IsClosed");
888 using (SafeLocalAllocHandle information = GetTokenInformation(m_safeTokenHandle, tokenInformationClass)) {
889 Contract.Assert(information.ByteLength >= (ulong)Marshal.SizeOf(typeof(T)),
890 "information.ByteLength >= (ulong)Marshal.SizeOf(typeof(T))");
892 return information.Read<T>(0);
897 // QueryImpersonation used to test if the current thread is impersonated.
898 // This method doesn't return the thread token (WindowsIdentity).
899 // Although GetCurrentInternal can be used to perform the same test but
900 // QueryImpersonation is optimized for the perf.
902 [System.Security.SecurityCritical] // auto-generated
903 [ResourceExposure(ResourceScope.Process)]
904 [ResourceConsumption(ResourceScope.Process)]
905 internal static ImpersonationQueryResult QueryImpersonation() {
906 SafeAccessTokenHandle safeTokenHandle = null;
907 int hr = Win32.OpenThreadToken(TokenAccessLevels.Query, WinSecurityContext.Thread, out safeTokenHandle);
909 if (safeTokenHandle != null) {
910 Contract.Assert(hr == 0, "[WindowsIdentity..QueryImpersonation] - hr == 0");
911 safeTokenHandle.Close();
912 return ImpersonationQueryResult.Impersonated;
915 if (hr == GetHRForWin32Error(Win32Native.ERROR_ACCESS_DENIED)) {
916 // thread is impersonated because the thread was there (and we failed to open it).
917 return ImpersonationQueryResult.Impersonated;
920 if (hr == GetHRForWin32Error(Win32Native.ERROR_NO_TOKEN)) {
921 // definitely not impersonating
922 return ImpersonationQueryResult.NotImpersonated;
925 // Unexpected failure.
926 return ImpersonationQueryResult.Failed;
929 [System.Security.SecurityCritical] // auto-generated
930 private static Win32Native.LUID GetLogonAuthId (SafeAccessTokenHandle safeTokenHandle) {
931 using (SafeLocalAllocHandle pStatistics = GetTokenInformation(safeTokenHandle, TokenInformationClass.TokenStatistics)) {
932 Win32Native.TOKEN_STATISTICS statistics = pStatistics.Read<Win32Native.TOKEN_STATISTICS>(0);
933 return statistics.AuthenticationId;
937 [System.Security.SecurityCritical]
938 private static SafeLocalAllocHandle GetTokenInformation (SafeAccessTokenHandle tokenHandle, TokenInformationClass tokenInformationClass) {
939 SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
940 uint dwLength = (uint) Marshal.SizeOf(typeof(uint));
941 bool result = Win32Native.GetTokenInformation(tokenHandle,
942 (uint) tokenInformationClass,
943 safeLocalAllocHandle,
946 int dwErrorCode = Marshal.GetLastWin32Error();
947 switch (dwErrorCode) {
948 case Win32Native.ERROR_BAD_LENGTH:
949 // special case for TokenSessionId. Falling through
950 case Win32Native.ERROR_INSUFFICIENT_BUFFER:
951 // ptrLength is an [In] param to LocalAlloc
952 UIntPtr ptrLength = new UIntPtr(dwLength);
953 safeLocalAllocHandle.Dispose();
954 safeLocalAllocHandle = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength);
955 if (safeLocalAllocHandle == null || safeLocalAllocHandle.IsInvalid)
956 throw new OutOfMemoryException();
957 safeLocalAllocHandle.Initialize(dwLength);
959 result = Win32Native.GetTokenInformation(tokenHandle,
960 (uint) tokenInformationClass,
961 safeLocalAllocHandle,
965 throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
967 case Win32Native.ERROR_INVALID_HANDLE:
968 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidImpersonationToken"));
970 throw new SecurityException(Win32Native.GetMessage(dwErrorCode));
972 return safeLocalAllocHandle;
975 [System.Security.SecurityCritical] // auto-generated
976 #if FEATURE_CORRUPTING_EXCEPTIONS
977 [HandleProcessCorruptedStateExceptions] //
978 #endif // FEATURE_CORRUPTING_EXCEPTIONS
979 private unsafe static SafeAccessTokenHandle KerbS4ULogon (string upn, ref SafeAccessTokenHandle safeTokenHandle)
982 byte[] sourceName = new byte[] { (byte)'C', (byte)'L', (byte)'R' }; // we set the source name to "CLR".
984 // ptrLength is an [In] param to LocalAlloc
985 UIntPtr ptrLength = new UIntPtr((uint)(sourceName.Length + 1));
987 using (SafeLocalAllocHandle pSourceName = Win32Native.LocalAlloc(Win32Native.LPTR, ptrLength)) {
988 if (pSourceName == null || pSourceName.IsInvalid)
989 throw new OutOfMemoryException();
991 pSourceName.Initialize((ulong)sourceName.Length + 1);
992 pSourceName.WriteArray(0, sourceName, 0, sourceName.Length);
993 Win32Native.UNICODE_INTPTR_STRING Name = new Win32Native.UNICODE_INTPTR_STRING(sourceName.Length,
997 SafeLsaLogonProcessHandle logonHandle = SafeLsaLogonProcessHandle.InvalidHandle;
998 SafeLsaReturnBufferHandle profile = SafeLsaReturnBufferHandle.InvalidHandle;
1000 Privilege privilege = null;
1002 RuntimeHelpers.PrepareConstrainedRegions();
1003 // Try to get an impersonation token.
1005 // Try to enable the TCB privilege if possible
1007 privilege = new Privilege("SeTcbPrivilege");
1010 catch (PrivilegeNotHeldException) { }
1012 IntPtr dummy = IntPtr.Zero;
1013 status = Win32Native.LsaRegisterLogonProcess(ref Name, ref logonHandle, ref dummy);
1014 if (Win32Native.ERROR_ACCESS_DENIED == Win32Native.LsaNtStatusToWinError(status)) {
1015 // We don't have the Tcb privilege. The best we can hope for is to get an Identification token.
1016 status = Win32Native.LsaConnectUntrusted(ref logonHandle);
1020 // protect against exception filter-based luring attacks
1021 if (privilege != null)
1026 if (privilege != null)
1029 if (status < 0) // non-negative numbers indicate success
1030 throw GetExceptionFromNtStatus(status);
1032 // package name ("Kerberos")
1033 byte[] arrayPackageName = new byte[Win32Native.MICROSOFT_KERBEROS_NAME.Length + 1];
1034 Encoding.ASCII.GetBytes(Win32Native.MICROSOFT_KERBEROS_NAME, 0, Win32Native.MICROSOFT_KERBEROS_NAME.Length, arrayPackageName, 0);
1036 // ptrLength is an [In] param to LocalAlloc
1037 ptrLength = new UIntPtr((uint)arrayPackageName.Length);
1038 using (SafeLocalAllocHandle pPackageName = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength)) {
1039 if (pPackageName == null || pPackageName.IsInvalid)
1040 throw new OutOfMemoryException();
1041 pPackageName.Initialize((ulong)(uint)arrayPackageName.Length);
1043 pPackageName.WriteArray(0, arrayPackageName, 0, arrayPackageName.Length);
1044 Win32Native.UNICODE_INTPTR_STRING PackageName = new Win32Native.UNICODE_INTPTR_STRING(Win32Native.MICROSOFT_KERBEROS_NAME.Length,
1047 status = Win32Native.LsaLookupAuthenticationPackage(logonHandle, ref PackageName, ref packageId);
1048 if (status < 0) // non-negative numbers indicate success
1049 throw GetExceptionFromNtStatus(status);
1052 Win32Native.TOKEN_SOURCE sourceContext = new Win32Native.TOKEN_SOURCE();
1053 if (!Win32Native.AllocateLocallyUniqueId(ref sourceContext.SourceIdentifier))
1054 throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
1055 sourceContext.Name = new char[8];
1056 sourceContext.Name[0] = 'C'; sourceContext.Name[1] = 'L'; sourceContext.Name[2] = 'R';
1058 uint profileSize = 0;
1059 Win32Native.LUID logonId = new Win32Native.LUID();
1060 Win32Native.QUOTA_LIMITS quotas = new Win32Native.QUOTA_LIMITS();
1064 // Build the KERB_S4U_LOGON structure. Note that the LSA expects this entire
1065 // structure to be contained within the same block of memory, so we need to allocate
1066 // enough room for both the structure itself and the UPN string in a single buffer
1067 // and do the marshalling into this buffer by hand.
1070 byte[] upnBytes = Encoding.Unicode.GetBytes(upn);
1072 Contract.Assert(Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON)) % IntPtr.Size == 0, "Potential allignment issue setting up S4U logon buffer");
1073 uint logonInfoSize = (uint) (Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON)) + upnBytes.Length);
1074 using (SafeLocalAllocHandle logonInfoBuffer = Win32Native.LocalAlloc(Win32Native.LPTR, new UIntPtr(logonInfoSize))) {
1075 if (logonInfoBuffer == null || logonInfoBuffer.IsInvalid) {
1076 throw new OutOfMemoryException();
1079 logonInfoBuffer.Initialize((ulong)logonInfoSize);
1081 // Write the UPN to the end of the serialized buffer
1082 ulong upnOffset = (ulong)Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON));
1083 logonInfoBuffer.WriteArray(upnOffset,
1089 byte* pLogonInfoBuffer = null;
1091 RuntimeHelpers.PrepareConstrainedRegions();
1093 logonInfoBuffer.AcquirePointer(ref pLogonInfoBuffer);
1095 // Setup the KERB_S4U_LOGON structure
1096 Win32Native.KERB_S4U_LOGON logonInfo = new Win32Native.KERB_S4U_LOGON();
1097 logonInfo.MessageType = (uint)KerbLogonSubmitType.KerbS4ULogon;
1098 logonInfo.Flags = 0;
1100 // Point the ClientUpn at the UPN written at the end of this buffer
1101 logonInfo.ClientUpn = new Win32Native.UNICODE_INTPTR_STRING(upnBytes.Length,
1102 new IntPtr(pLogonInfoBuffer + upnOffset));
1104 logonInfoBuffer.Write(0, logonInfo);
1107 status = Win32Native.LsaLogonUser(logonHandle,
1109 (uint)SecurityLogonType.Network,
1111 new IntPtr(pLogonInfoBuffer),
1112 (uint)logonInfoBuffer.ByteLength,
1118 ref safeTokenHandle,
1122 // If both status and substatus are < 0, substatus is preferred.
1123 if (status == Win32Native.STATUS_ACCOUNT_RESTRICTION && subStatus < 0)
1125 if (status < 0) // non-negative numbers indicate success
1126 throw GetExceptionFromNtStatus(status);
1127 if (subStatus < 0) // non-negative numbers indicate success
1128 throw GetExceptionFromNtStatus(subStatus);
1131 if (pLogonInfoBuffer != null) {
1132 logonInfoBuffer.ReleasePointer();
1138 return safeTokenHandle;
1142 if (!logonHandle.IsInvalid)
1143 logonHandle.Dispose();
1144 if (!profile.IsInvalid)
1150 #if !FEATURE_CORECLR
1152 [SecuritySafeCritical]
1153 protected WindowsIdentity (WindowsIdentity identity)
1154 : base( identity, null, identity.m_authType, null, null, false )
1156 if (identity == null)
1157 throw new ArgumentNullException("identity");
1159 Contract.EndContractBlock();
1161 bool mustDecrement = false;
1162 RuntimeHelpers.PrepareConstrainedRegions();
1165 if (!identity.m_safeTokenHandle.IsInvalid && identity.m_safeTokenHandle != SafeAccessTokenHandle.InvalidHandle && identity.m_safeTokenHandle.DangerousGetHandle() != IntPtr.Zero)
1167 identity.m_safeTokenHandle.DangerousAddRef(ref mustDecrement);
1169 if (!identity.m_safeTokenHandle.IsInvalid && identity.m_safeTokenHandle.DangerousGetHandle() != IntPtr.Zero)
1170 CreateFromToken(identity.m_safeTokenHandle.DangerousGetHandle());
1172 m_authType = identity.m_authType;
1173 m_isAuthenticated = identity.m_isAuthenticated;
1179 identity.m_safeTokenHandle.DangerousRelease();
1184 internal IntPtr GetTokenInternal()
1186 return m_safeTokenHandle.DangerousGetHandle();
1190 internal WindowsIdentity(ClaimsIdentity claimsIdentity, IntPtr userToken)
1191 : base(claimsIdentity)
1193 if (userToken != IntPtr.Zero && userToken.ToInt64() > 0)
1195 CreateFromToken(userToken);
1200 /// Returns a new instance of the base, used when serializing the WindowsIdentity.
1202 internal ClaimsIdentity CloneAsBase()
1204 return base.Clone();
1208 /// Returns a new instance of <see cref="WindowsIdentity"/> with values copied from this object.
1210 public override ClaimsIdentity Clone()
1212 return new WindowsIdentity(this);
1216 /// Gets the 'User Claims' from the NTToken that represents this identity
1218 public virtual IEnumerable<Claim> UserClaims
1224 return m_userClaims.AsReadOnly();
1229 /// Gets the 'Device Claims' from the NTToken that represents the device the identity is using
1231 public virtual IEnumerable<Claim> DeviceClaims
1237 return m_deviceClaims.AsReadOnly();
1242 /// Gets the claims as <see cref="IEnumerable{Claim}"/>, associated with this <see cref="WindowsIdentity"/>.
1243 /// Includes UserClaims and DeviceClaims.
1245 public override IEnumerable<Claim> Claims
1249 if (!m_claimsInitialized)
1254 foreach (Claim claim in base.Claims)
1257 foreach (Claim claim in m_userClaims)
1260 foreach (Claim claim in m_deviceClaims)
1266 /// Intenal method to initialize the claim collection.
1267 /// Lazy init is used so claims are not initialzed until needed
1269 [SecuritySafeCritical]
1270 void InitializeClaims()
1272 if (!m_claimsInitialized)
1274 lock (m_claimsIntiailizedLock)
1276 if (!m_claimsInitialized)
1278 m_userClaims = new List<Claim>();
1279 m_deviceClaims = new List<Claim>();
1281 if (!String.IsNullOrEmpty(Name))
1284 // Add the name claim only if the WindowsIdentity.Name is populated
1285 // WindowsIdentity.Name will be null when it is the fake anonymous user
1286 // with a token value of IntPtr.Zero
1288 m_userClaims.Add(new Claim(NameClaimType, Name, ClaimValueTypes.String, m_issuerName, m_issuerName, this));
1292 AddPrimarySidClaim(m_userClaims);
1295 AddGroupSidClaims(m_userClaims);
1297 // The following TokenInformationClass's were part of the Win8 release
1298 if (Environment.IsWindows8OrAbove)
1300 // Device group sids
1301 AddDeviceGroupSidClaims(m_deviceClaims, TokenInformationClass.TokenDeviceGroups);
1303 // User token claims
1304 AddTokenClaims(m_userClaims, TokenInformationClass.TokenUserClaimAttributes, ClaimTypes.WindowsUserClaim);
1306 // Device token claims
1307 AddTokenClaims(m_deviceClaims, TokenInformationClass.TokenDeviceClaimAttributes, ClaimTypes.WindowsDeviceClaim);
1310 m_claimsInitialized = true;
1317 /// Creates a collection of SID claims that represent the DeviceSidGroups.
1319 /// this is SafeCritical as it accesss the NT token.
1321 void AddDeviceGroupSidClaims(List<Claim> instanceClaims, TokenInformationClass tokenInformationClass)
1323 // special case the anonymous identity.
1324 if (m_safeTokenHandle.IsInvalid)
1327 SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1330 // Retrieve all group sids
1332 safeAllocHandle = GetTokenInformation(m_safeTokenHandle, tokenInformationClass);
1333 int count = Marshal.ReadInt32(safeAllocHandle.DangerousGetHandle());
1334 IntPtr pSidAndAttributes = new IntPtr((long)safeAllocHandle.DangerousGetHandle() + (long)Marshal.OffsetOf(typeof(Win32Native.TOKEN_GROUPS), "Groups"));
1335 string claimType = null;
1337 for (int i = 0; i < count; ++i)
1339 Win32Native.SID_AND_ATTRIBUTES group = (Win32Native.SID_AND_ATTRIBUTES)Marshal.PtrToStructure(pSidAndAttributes, typeof(Win32Native.SID_AND_ATTRIBUTES));
1340 uint mask = Win32Native.SE_GROUP_ENABLED | Win32Native.SE_GROUP_LOGON_ID | Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
1341 SecurityIdentifier groupSid = new SecurityIdentifier(group.Sid, true);
1342 if ((group.Attributes & mask) == Win32Native.SE_GROUP_ENABLED)
1344 claimType = ClaimTypes.WindowsDeviceGroup;
1345 Claim claim = new Claim(claimType, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture));
1346 claim.Properties.Add(claimType, "");
1347 instanceClaims.Add(claim);
1349 else if ((group.Attributes & mask) == Win32Native.SE_GROUP_USE_FOR_DENY_ONLY)
1351 claimType = ClaimTypes.DenyOnlyWindowsDeviceGroup;
1352 Claim claim = new Claim(claimType, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture));
1353 claim.Properties.Add(claimType, "");
1354 instanceClaims.Add(claim);
1357 pSidAndAttributes = new IntPtr((long)pSidAndAttributes + Win32Native.SID_AND_ATTRIBUTES.SizeOf);
1362 safeAllocHandle.Close();
1367 /// Creates a collection of SID claims that represent the users groups.
1369 /// this is SafeCritical as it accesss the NT token.
1371 void AddGroupSidClaims(List<Claim> instanceClaims)
1373 // special case the anonymous identity.
1374 if (m_safeTokenHandle.IsInvalid)
1377 SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1378 SafeLocalAllocHandle safeAllocHandlePrimaryGroup = SafeLocalAllocHandle.InvalidHandle;
1381 // Retrieve the primary group sid
1382 safeAllocHandlePrimaryGroup = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenPrimaryGroup);
1383 Win32Native.TOKEN_PRIMARY_GROUP primaryGroup = (Win32Native.TOKEN_PRIMARY_GROUP)Marshal.PtrToStructure(safeAllocHandlePrimaryGroup.DangerousGetHandle(), typeof(Win32Native.TOKEN_PRIMARY_GROUP));
1384 SecurityIdentifier primaryGroupSid = new SecurityIdentifier(primaryGroup.PrimaryGroup, true);
1386 // only add one primary group sid
1387 bool foundPrimaryGroupSid = false;
1389 // Retrieve all group sids, primary group sid is one of them
1390 safeAllocHandle = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenGroups);
1391 int count = Marshal.ReadInt32(safeAllocHandle.DangerousGetHandle());
1392 IntPtr pSidAndAttributes = new IntPtr((long)safeAllocHandle.DangerousGetHandle() + (long)Marshal.OffsetOf(typeof(Win32Native.TOKEN_GROUPS), "Groups"));
1393 for (int i = 0; i < count; ++i)
1395 Win32Native.SID_AND_ATTRIBUTES group = (Win32Native.SID_AND_ATTRIBUTES)Marshal.PtrToStructure(pSidAndAttributes, typeof(Win32Native.SID_AND_ATTRIBUTES));
1396 uint mask = Win32Native.SE_GROUP_ENABLED | Win32Native.SE_GROUP_LOGON_ID | Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
1397 SecurityIdentifier groupSid = new SecurityIdentifier(group.Sid, true);
1399 if ((group.Attributes & mask) == Win32Native.SE_GROUP_ENABLED)
1401 if (!foundPrimaryGroupSid && StringComparer.Ordinal.Equals( groupSid.Value, primaryGroupSid.Value))
1403 instanceClaims.Add(new Claim(ClaimTypes.PrimaryGroupSid, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1404 foundPrimaryGroupSid = true;
1406 //Primary group sid generates both regular groupsid claim and primary groupsid claim
1407 instanceClaims.Add(new Claim(ClaimTypes.GroupSid, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1410 else if ((group.Attributes & mask) == Win32Native.SE_GROUP_USE_FOR_DENY_ONLY)
1412 if (!foundPrimaryGroupSid && StringComparer.Ordinal.Equals( groupSid.Value, primaryGroupSid.Value))
1414 instanceClaims.Add(new Claim(ClaimTypes.DenyOnlyPrimaryGroupSid, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1415 foundPrimaryGroupSid = true;
1417 //Primary group sid generates both regular groupsid claim and primary groupsid claim
1418 instanceClaims.Add(new Claim(ClaimTypes.DenyOnlySid, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1420 pSidAndAttributes = new IntPtr((long)pSidAndAttributes + Win32Native.SID_AND_ATTRIBUTES.SizeOf);
1425 safeAllocHandle.Close();
1426 safeAllocHandlePrimaryGroup.Close();
1431 /// Creates a Windows SID Claim and adds to collection of claims.
1433 /// this is SafeCritical as it accesss the NT token.
1435 void AddPrimarySidClaim(List<Claim> instanceClaims)
1437 // special case the anonymous identity.
1438 if (m_safeTokenHandle.IsInvalid)
1441 SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1444 safeAllocHandle = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenUser);
1445 Win32Native.SID_AND_ATTRIBUTES user = (Win32Native.SID_AND_ATTRIBUTES)Marshal.PtrToStructure(safeAllocHandle.DangerousGetHandle(), typeof(Win32Native.SID_AND_ATTRIBUTES));
1446 uint mask = Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
1448 SecurityIdentifier sid = new SecurityIdentifier(user.Sid, true);
1450 if (user.Attributes == 0)
1452 instanceClaims.Add(new Claim(ClaimTypes.PrimarySid, sid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(sid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1454 else if ((user.Attributes & mask) == Win32Native.SE_GROUP_USE_FOR_DENY_ONLY)
1456 instanceClaims.Add(new Claim(ClaimTypes.DenyOnlyPrimarySid, sid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(sid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1461 safeAllocHandle.Close();
1466 void AddTokenClaims(List<Claim> instanceClaims, TokenInformationClass tokenInformationClass, string propertyValue)
1468 // special case the anonymous identity.
1469 if (m_safeTokenHandle.IsInvalid)
1472 SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1476 SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1477 safeAllocHandle = GetTokenInformation(m_safeTokenHandle, tokenInformationClass);
1479 Win32Native.CLAIM_SECURITY_ATTRIBUTES_INFORMATION claimAttributes = (Win32Native.CLAIM_SECURITY_ATTRIBUTES_INFORMATION)Marshal.PtrToStructure(safeAllocHandle.DangerousGetHandle(), typeof(Win32Native.CLAIM_SECURITY_ATTRIBUTES_INFORMATION));
1480 // An attribute represents a collection of claims. Inside each attribute a claim can be multivalued, we create a claim for each value.
1481 // It is a ragged multi-dimentional array, where each cell can be of different lenghts.
1483 // index into array of claims.
1486 for (int attribute = 0; attribute < claimAttributes.AttributeCount; attribute++)
1488 IntPtr pAttribute = new IntPtr(claimAttributes.Attribute.pAttributeV1.ToInt64() + offset);
1489 Win32Native.CLAIM_SECURITY_ATTRIBUTE_V1 windowsClaim = (Win32Native.CLAIM_SECURITY_ATTRIBUTE_V1)Marshal.PtrToStructure(pAttribute, typeof(Win32Native.CLAIM_SECURITY_ATTRIBUTE_V1));
1491 // the switch was written this way, which appears to have multiple for loops, because each item in the ValueCount is of the same ValueType. This saves the type check each item.
1492 switch (windowsClaim.ValueType)
1494 case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
1495 IntPtr[] stringPointers = new IntPtr[windowsClaim.ValueCount];
1496 Marshal.Copy(windowsClaim.Values.ppString, stringPointers, 0, (int)windowsClaim.ValueCount);
1498 for (int item = 0; item < windowsClaim.ValueCount; item++)
1500 instanceClaims.Add( new Claim(windowsClaim.Name, Marshal.PtrToStringAuto(stringPointers[item]), ClaimValueTypes.String, m_issuerName, m_issuerName, this, propertyValue, string.Empty));
1504 case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
1505 Int64[] intValues = new Int64[windowsClaim.ValueCount];
1506 Marshal.Copy(windowsClaim.Values.pInt64, intValues, 0, (int)windowsClaim.ValueCount);
1508 for (int item = 0; item < windowsClaim.ValueCount; item++)
1510 instanceClaims.Add(new Claim(windowsClaim.Name, Convert.ToString(intValues[item], CultureInfo.InvariantCulture), ClaimValueTypes.Integer64, m_issuerName, m_issuerName, this, propertyValue, string.Empty));
1515 case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
1516 Int64[] uintValues = new Int64[windowsClaim.ValueCount];
1517 Marshal.Copy(windowsClaim.Values.pUint64, uintValues, 0, (int)windowsClaim.ValueCount);
1519 for (int item = 0; item < windowsClaim.ValueCount; item++)
1521 instanceClaims.Add( new Claim(windowsClaim.Name, Convert.ToString((UInt64)uintValues[item], CultureInfo.InvariantCulture), ClaimValueTypes.UInteger64, m_issuerName, m_issuerName, this, propertyValue, string.Empty));
1525 case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
1526 Int64[] boolValues = new Int64[windowsClaim.ValueCount];
1527 Marshal.Copy(windowsClaim.Values.pUint64, boolValues, 0, (int)windowsClaim.ValueCount);
1529 for (int item = 0; item < windowsClaim.ValueCount; item++)
1531 instanceClaims.Add(new Claim(windowsClaim.Name,
1532 ((UInt64)boolValues[item] == 0 ? Convert.ToString(false, CultureInfo.InvariantCulture) : Convert.ToString(true, CultureInfo.InvariantCulture)),
1533 ClaimValueTypes.Boolean,
1543 // These claim types are defined in the structure found in winnt.h, but I haven't received confirmation (may 2011) that they are supported and are not enabled.
1545 //case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_FQBN:
1548 //case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
1551 //case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
1556 offset += Marshal.SizeOf(windowsClaim);
1561 safeAllocHandle.Close();
1569 internal enum KerbLogonSubmitType : int {
1570 KerbInteractiveLogon = 2,
1571 KerbSmartCardLogon = 6,
1572 KerbWorkstationUnlockLogon = 7,
1573 KerbSmartCardUnlockLogon = 8,
1575 KerbTicketLogon = 10,
1576 KerbTicketUnlockLogon = 11,
1581 internal enum SecurityLogonType : int {
1591 internal enum TokenType : int {
1597 internal enum TokenInformationClass : int {
1606 TokenImpersonationLevel,
1608 TokenRestrictedSids,
1610 TokenGroupsAndPrivileges,
1611 TokenSessionReference,
1618 TokenHasRestrictions,
1619 TokenAccessInformation,
1620 TokenVirtualizationAllowed,
1621 TokenVirtualizationEnabled,
1622 TokenIntegrityLevel,
1624 TokenMandatoryPolicy,
1626 TokenIsAppContainer,
1628 TokenAppContainerSid,
1629 TokenAppContainerNumber,
1630 TokenUserClaimAttributes,
1631 TokenDeviceClaimAttributes,
1632 TokenRestrictedUserClaimAttributes,
1633 TokenRestrictedDeviceClaimAttributes,
1635 TokenRestrictedDeviceGroups,
1636 MaxTokenInfoClass // MaxTokenInfoClass should always be the last enum