3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>[....]</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 [....] 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 public static void RunImpersonated(SafeAccessTokenHandle safeAccessTokenHandle, Action action)
615 throw new ArgumentNullException("action");
617 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
619 WindowsIdentity wi = null;
620 if (!safeAccessTokenHandle.IsInvalid)
621 wi = new WindowsIdentity(safeAccessTokenHandle);
623 using (WindowsImpersonationContext wiContext = SafeImpersonate(safeAccessTokenHandle, wi, ref stackMark))
629 [SecuritySafeCritical]
630 public static T RunImpersonated<T>(SafeAccessTokenHandle safeAccessTokenHandle, Func<T> func)
633 throw new ArgumentNullException("func");
635 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
637 WindowsIdentity wi = null;
638 if (!safeAccessTokenHandle.IsInvalid)
639 wi = new WindowsIdentity(safeAccessTokenHandle);
641 T result = default(T);
642 using (WindowsImpersonationContext wiContext = SafeImpersonate(safeAccessTokenHandle, wi, ref stackMark))
650 [System.Security.SecuritySafeCritical] // auto-generated
651 [DynamicSecurityMethodAttribute()]
652 [ResourceExposure(ResourceScope.Process)] // Call from within a CER, or use a RunAsUser helper.
653 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
654 public virtual WindowsImpersonationContext Impersonate ()
656 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
657 return Impersonate(ref stackMark);
660 [System.Security.SecuritySafeCritical] // auto-generated
661 [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlPrincipal | SecurityPermissionFlag.UnmanagedCode)]
662 [DynamicSecurityMethodAttribute()]
663 [ResourceExposure(ResourceScope.Process)] // Call from within a CER, or use a RunAsUser helper.
664 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
665 public static WindowsImpersonationContext Impersonate (IntPtr userToken)
667 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
668 if (userToken == IntPtr.Zero)
669 return SafeRevertToSelf(ref stackMark);
671 WindowsIdentity wi = new WindowsIdentity(userToken, null, -1);
672 return wi.Impersonate(ref stackMark);
675 [System.Security.SecurityCritical] // auto-generated
676 internal WindowsImpersonationContext Impersonate (ref StackCrawlMark stackMark) {
677 if (m_safeTokenHandle.IsInvalid)
678 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AnonymousCannotImpersonate"));
680 return SafeImpersonate(m_safeTokenHandle, this, ref stackMark);
683 [System.Security.SecuritySafeCritical] // auto-generated
685 protected virtual void Dispose(bool disposing) {
687 if (m_safeTokenHandle != null && !m_safeTokenHandle.IsClosed)
688 m_safeTokenHandle.Dispose();
696 public void Dispose() {
700 public SafeAccessTokenHandle AccessToken {
701 [System.Security.SecurityCritical] // auto-generated
703 return m_safeTokenHandle;
711 [System.Security.SecurityCritical] // auto-generated
712 [ResourceExposure(ResourceScope.None)]
713 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
714 internal static WindowsImpersonationContext SafeRevertToSelf(ref StackCrawlMark stackMark)
716 return SafeImpersonate(s_invalidTokenHandle, null, ref stackMark);
719 [System.Security.SecurityCritical] // auto-generated
720 [ResourceExposure(ResourceScope.Process)]
721 [ResourceConsumption(ResourceScope.Process)]
722 internal static WindowsImpersonationContext SafeImpersonate (SafeAccessTokenHandle userToken, WindowsIdentity wi, ref StackCrawlMark stackMark)
724 bool isImpersonating;
726 SafeAccessTokenHandle safeTokenHandle = GetCurrentToken(TokenAccessLevels.MaximumAllowed, false, out isImpersonating, out hr);
727 if (safeTokenHandle == null || safeTokenHandle.IsInvalid)
728 throw new SecurityException(Win32Native.GetMessage(hr));
730 // Set the SafeAccessTokenHandle on the FSD:
731 FrameSecurityDescriptor secObj = SecurityRuntime.GetSecurityObjectForFrame(ref stackMark, true);
734 // Security: REQ_SQ flag is missing. Bad compiler ?
735 // This can happen when you create delegates over functions that need the REQ_SQ
736 throw new SecurityException(Environment.GetResourceString( "ExecutionEngine_MissingSecurityDescriptor" ) );
739 WindowsImpersonationContext context = new WindowsImpersonationContext(safeTokenHandle, GetCurrentThreadWI(), isImpersonating, secObj);
741 if (userToken.IsInvalid) { // impersonating a zero token means clear the token on the thread
742 hr = Win32.RevertToSelf();
744 Environment.FailFast(Win32Native.GetMessage(hr));
745 // update identity on the thread
747 secObj.SetTokenHandles(safeTokenHandle, (wi == null?null:wi.AccessToken));
749 hr = Win32.RevertToSelf();
751 Environment.FailFast(Win32Native.GetMessage(hr));
752 hr = Win32.ImpersonateLoggedOnUser(userToken);
755 throw new SecurityException(Environment.GetResourceString("Argument_ImpersonateUser"));
758 secObj.SetTokenHandles(safeTokenHandle, (wi == null?null:wi.AccessToken));
764 [System.Security.SecurityCritical] // auto-generated
765 internal static WindowsIdentity GetCurrentThreadWI()
767 return SecurityContext.GetCurrentWI(Thread.CurrentThread.GetExecutionContextReader());
771 internal static void UpdateThreadWI(WindowsIdentity wi)
773 // Set WI on Thread.CurrentThread.ExecutionContext.SecurityContext
774 Thread currentThread = Thread.CurrentThread;
775 if (currentThread.GetExecutionContextReader().SecurityContext.WindowsIdentity != wi)
777 ExecutionContext ec = currentThread.GetMutableExecutionContext();
778 SecurityContext sc = ec.SecurityContext;
779 if (wi != null && sc == null)
781 // create a new security context on the thread
782 sc = new SecurityContext();
783 ec.SecurityContext = sc;
786 if (sc != null) // null-check needed here since we will not create an sc if wi is null
788 sc.WindowsIdentity = wi;
794 [System.Security.SecurityCritical] // auto-generated
795 [ResourceExposure(ResourceScope.None)]
796 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
797 internal static WindowsIdentity GetCurrentInternal (TokenAccessLevels desiredAccess, bool threadOnly) {
799 bool isImpersonating;
800 SafeAccessTokenHandle safeTokenHandle = GetCurrentToken(desiredAccess, threadOnly, out isImpersonating, out hr);
801 if (safeTokenHandle == null || safeTokenHandle.IsInvalid) {
802 // either we wanted only ThreadToken - return null
803 if (threadOnly && !isImpersonating)
805 // or there was an error
806 throw new SecurityException(Win32Native.GetMessage(hr));
808 WindowsIdentity wi = new WindowsIdentity();
809 wi.m_safeTokenHandle.Dispose();
810 wi.m_safeTokenHandle = safeTokenHandle;
814 internal static RuntimeConstructorInfo GetSpecialSerializationCtor()
816 return s_specialSerializationCtor;
823 private static int GetHRForWin32Error (int dwLastError) {
824 if ((dwLastError & 0x80000000) == 0x80000000)
827 return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
830 [System.Security.SecurityCritical] // auto-generated
831 private static Exception GetExceptionFromNtStatus (int status) {
832 if ((uint) status == Win32Native.STATUS_ACCESS_DENIED)
833 return new UnauthorizedAccessException();
835 if ((uint) status == Win32Native.STATUS_INSUFFICIENT_RESOURCES || (uint) status == Win32Native.STATUS_NO_MEMORY)
836 return new OutOfMemoryException();
838 int win32ErrorCode = Win32Native.LsaNtStatusToWinError(status);
839 return new SecurityException(Win32Native.GetMessage(win32ErrorCode));
842 [System.Security.SecurityCritical] // auto-generated
843 [ResourceExposure(ResourceScope.Process)]
844 [ResourceConsumption(ResourceScope.Process)]
845 private static SafeAccessTokenHandle GetCurrentToken(TokenAccessLevels desiredAccess, bool threadOnly, out bool isImpersonating, out int hr) {
846 isImpersonating = true;
847 SafeAccessTokenHandle safeTokenHandle = GetCurrentThreadToken(desiredAccess, out hr);
848 if (safeTokenHandle == null && hr == GetHRForWin32Error(Win32Native.ERROR_NO_TOKEN)) {
850 isImpersonating = false;
852 safeTokenHandle = GetCurrentProcessToken(desiredAccess, out hr);
854 return safeTokenHandle;
857 [System.Security.SecurityCritical] // auto-generated
858 [ResourceExposure(ResourceScope.Process)]
859 [ResourceConsumption(ResourceScope.Process)]
860 private static SafeAccessTokenHandle GetCurrentProcessToken (TokenAccessLevels desiredAccess, out int hr) {
862 SafeAccessTokenHandle safeTokenHandle;
863 if (!Win32Native.OpenProcessToken(Win32Native.GetCurrentProcess(), desiredAccess, out safeTokenHandle))
864 hr = GetHRForWin32Error(Marshal.GetLastWin32Error());
865 return safeTokenHandle;
868 [System.Security.SecurityCritical] // auto-generated
869 [ResourceExposure(ResourceScope.Process)]
870 [ResourceConsumption(ResourceScope.Process)]
871 internal static SafeAccessTokenHandle GetCurrentThreadToken(TokenAccessLevels desiredAccess, out int hr) {
872 SafeAccessTokenHandle safeTokenHandle;
873 hr = Win32.OpenThreadToken(desiredAccess, WinSecurityContext.Both, out safeTokenHandle);
874 return safeTokenHandle;
878 /// Get a property from the current token
880 [System.Security.SecurityCritical] // auto-generated
881 private T GetTokenInformation<T>(TokenInformationClass tokenInformationClass) where T : struct{
882 Contract.Assert(!m_safeTokenHandle.IsInvalid && !m_safeTokenHandle.IsClosed, "!m_safeTokenHandle.IsInvalid && !m_safeTokenHandle.IsClosed");
884 using (SafeLocalAllocHandle information = GetTokenInformation(m_safeTokenHandle, tokenInformationClass)) {
885 Contract.Assert(information.ByteLength >= (ulong)Marshal.SizeOf(typeof(T)),
886 "information.ByteLength >= (ulong)Marshal.SizeOf(typeof(T))");
888 return information.Read<T>(0);
893 // QueryImpersonation used to test if the current thread is impersonated.
894 // This method doesn't return the thread token (WindowsIdentity).
895 // Although GetCurrentInternal can be used to perform the same test but
896 // QueryImpersonation is optimized for the perf.
898 [System.Security.SecurityCritical] // auto-generated
899 [ResourceExposure(ResourceScope.Process)]
900 [ResourceConsumption(ResourceScope.Process)]
901 internal static ImpersonationQueryResult QueryImpersonation() {
902 SafeAccessTokenHandle safeTokenHandle = null;
903 int hr = Win32.OpenThreadToken(TokenAccessLevels.Query, WinSecurityContext.Thread, out safeTokenHandle);
905 if (safeTokenHandle != null) {
906 Contract.Assert(hr == 0, "[WindowsIdentity..QueryImpersonation] - hr == 0");
907 safeTokenHandle.Close();
908 return ImpersonationQueryResult.Impersonated;
911 if (hr == GetHRForWin32Error(Win32Native.ERROR_ACCESS_DENIED)) {
912 // thread is impersonated because the thread was there (and we failed to open it).
913 return ImpersonationQueryResult.Impersonated;
916 if (hr == GetHRForWin32Error(Win32Native.ERROR_NO_TOKEN)) {
917 // definitely not impersonating
918 return ImpersonationQueryResult.NotImpersonated;
921 // Unexpected failure.
922 return ImpersonationQueryResult.Failed;
925 [System.Security.SecurityCritical] // auto-generated
926 private static Win32Native.LUID GetLogonAuthId (SafeAccessTokenHandle safeTokenHandle) {
927 using (SafeLocalAllocHandle pStatistics = GetTokenInformation(safeTokenHandle, TokenInformationClass.TokenStatistics)) {
928 Win32Native.TOKEN_STATISTICS statistics = pStatistics.Read<Win32Native.TOKEN_STATISTICS>(0);
929 return statistics.AuthenticationId;
933 [System.Security.SecurityCritical]
934 private static SafeLocalAllocHandle GetTokenInformation (SafeAccessTokenHandle tokenHandle, TokenInformationClass tokenInformationClass) {
935 SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
936 uint dwLength = (uint) Marshal.SizeOf(typeof(uint));
937 bool result = Win32Native.GetTokenInformation(tokenHandle,
938 (uint) tokenInformationClass,
939 safeLocalAllocHandle,
942 int dwErrorCode = Marshal.GetLastWin32Error();
943 switch (dwErrorCode) {
944 case Win32Native.ERROR_BAD_LENGTH:
945 // special case for TokenSessionId. Falling through
946 case Win32Native.ERROR_INSUFFICIENT_BUFFER:
947 // ptrLength is an [In] param to LocalAlloc
948 UIntPtr ptrLength = new UIntPtr(dwLength);
949 safeLocalAllocHandle.Dispose();
950 safeLocalAllocHandle = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength);
951 if (safeLocalAllocHandle == null || safeLocalAllocHandle.IsInvalid)
952 throw new OutOfMemoryException();
953 safeLocalAllocHandle.Initialize(dwLength);
955 result = Win32Native.GetTokenInformation(tokenHandle,
956 (uint) tokenInformationClass,
957 safeLocalAllocHandle,
961 throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
963 case Win32Native.ERROR_INVALID_HANDLE:
964 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidImpersonationToken"));
966 throw new SecurityException(Win32Native.GetMessage(dwErrorCode));
968 return safeLocalAllocHandle;
971 [System.Security.SecurityCritical] // auto-generated
972 #if FEATURE_CORRUPTING_EXCEPTIONS
973 [HandleProcessCorruptedStateExceptions] //
974 #endif // FEATURE_CORRUPTING_EXCEPTIONS
975 private unsafe static SafeAccessTokenHandle KerbS4ULogon (string upn, ref SafeAccessTokenHandle safeTokenHandle)
978 byte[] sourceName = new byte[] { (byte)'C', (byte)'L', (byte)'R' }; // we set the source name to "CLR".
980 // ptrLength is an [In] param to LocalAlloc
981 UIntPtr ptrLength = new UIntPtr((uint)(sourceName.Length + 1));
983 using (SafeLocalAllocHandle pSourceName = Win32Native.LocalAlloc(Win32Native.LPTR, ptrLength)) {
984 if (pSourceName == null || pSourceName.IsInvalid)
985 throw new OutOfMemoryException();
987 pSourceName.Initialize((ulong)sourceName.Length + 1);
988 pSourceName.WriteArray(0, sourceName, 0, sourceName.Length);
989 Win32Native.UNICODE_INTPTR_STRING Name = new Win32Native.UNICODE_INTPTR_STRING(sourceName.Length,
993 SafeLsaLogonProcessHandle logonHandle = SafeLsaLogonProcessHandle.InvalidHandle;
994 SafeLsaReturnBufferHandle profile = SafeLsaReturnBufferHandle.InvalidHandle;
996 Privilege privilege = null;
998 RuntimeHelpers.PrepareConstrainedRegions();
999 // Try to get an impersonation token.
1001 // Try to enable the TCB privilege if possible
1003 privilege = new Privilege("SeTcbPrivilege");
1006 catch (PrivilegeNotHeldException) { }
1008 IntPtr dummy = IntPtr.Zero;
1009 status = Win32Native.LsaRegisterLogonProcess(ref Name, ref logonHandle, ref dummy);
1010 if (Win32Native.ERROR_ACCESS_DENIED == Win32Native.LsaNtStatusToWinError(status)) {
1011 // We don't have the Tcb privilege. The best we can hope for is to get an Identification token.
1012 status = Win32Native.LsaConnectUntrusted(ref logonHandle);
1016 // protect against exception filter-based luring attacks
1017 if (privilege != null)
1022 if (privilege != null)
1025 if (status < 0) // non-negative numbers indicate success
1026 throw GetExceptionFromNtStatus(status);
1028 // package name ("Kerberos")
1029 byte[] arrayPackageName = new byte[Win32Native.MICROSOFT_KERBEROS_NAME.Length + 1];
1030 Encoding.ASCII.GetBytes(Win32Native.MICROSOFT_KERBEROS_NAME, 0, Win32Native.MICROSOFT_KERBEROS_NAME.Length, arrayPackageName, 0);
1032 // ptrLength is an [In] param to LocalAlloc
1033 ptrLength = new UIntPtr((uint)arrayPackageName.Length);
1034 using (SafeLocalAllocHandle pPackageName = Win32Native.LocalAlloc(Win32Native.LMEM_FIXED, ptrLength)) {
1035 if (pPackageName == null || pPackageName.IsInvalid)
1036 throw new OutOfMemoryException();
1037 pPackageName.Initialize((ulong)(uint)arrayPackageName.Length);
1039 pPackageName.WriteArray(0, arrayPackageName, 0, arrayPackageName.Length);
1040 Win32Native.UNICODE_INTPTR_STRING PackageName = new Win32Native.UNICODE_INTPTR_STRING(Win32Native.MICROSOFT_KERBEROS_NAME.Length,
1043 status = Win32Native.LsaLookupAuthenticationPackage(logonHandle, ref PackageName, ref packageId);
1044 if (status < 0) // non-negative numbers indicate success
1045 throw GetExceptionFromNtStatus(status);
1048 Win32Native.TOKEN_SOURCE sourceContext = new Win32Native.TOKEN_SOURCE();
1049 if (!Win32Native.AllocateLocallyUniqueId(ref sourceContext.SourceIdentifier))
1050 throw new SecurityException(Win32Native.GetMessage(Marshal.GetLastWin32Error()));
1051 sourceContext.Name = new char[8];
1052 sourceContext.Name[0] = 'C'; sourceContext.Name[1] = 'L'; sourceContext.Name[2] = 'R';
1054 uint profileSize = 0;
1055 Win32Native.LUID logonId = new Win32Native.LUID();
1056 Win32Native.QUOTA_LIMITS quotas = new Win32Native.QUOTA_LIMITS();
1060 // Build the KERB_S4U_LOGON structure. Note that the LSA expects this entire
1061 // structure to be contained within the same block of memory, so we need to allocate
1062 // enough room for both the structure itself and the UPN string in a single buffer
1063 // and do the marshalling into this buffer by hand.
1066 byte[] upnBytes = Encoding.Unicode.GetBytes(upn);
1068 Contract.Assert(Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON)) % IntPtr.Size == 0, "Potential allignment issue setting up S4U logon buffer");
1069 uint logonInfoSize = (uint) (Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON)) + upnBytes.Length);
1070 using (SafeLocalAllocHandle logonInfoBuffer = Win32Native.LocalAlloc(Win32Native.LPTR, new UIntPtr(logonInfoSize))) {
1071 if (logonInfoBuffer == null || logonInfoBuffer.IsInvalid) {
1072 throw new OutOfMemoryException();
1075 logonInfoBuffer.Initialize((ulong)logonInfoSize);
1077 // Write the UPN to the end of the serialized buffer
1078 ulong upnOffset = (ulong)Marshal.SizeOf(typeof(Win32Native.KERB_S4U_LOGON));
1079 logonInfoBuffer.WriteArray(upnOffset,
1085 byte* pLogonInfoBuffer = null;
1087 RuntimeHelpers.PrepareConstrainedRegions();
1089 logonInfoBuffer.AcquirePointer(ref pLogonInfoBuffer);
1091 // Setup the KERB_S4U_LOGON structure
1092 Win32Native.KERB_S4U_LOGON logonInfo = new Win32Native.KERB_S4U_LOGON();
1093 logonInfo.MessageType = (uint)KerbLogonSubmitType.KerbS4ULogon;
1094 logonInfo.Flags = 0;
1096 // Point the ClientUpn at the UPN written at the end of this buffer
1097 logonInfo.ClientUpn = new Win32Native.UNICODE_INTPTR_STRING(upnBytes.Length,
1098 new IntPtr(pLogonInfoBuffer + upnOffset));
1100 logonInfoBuffer.Write(0, logonInfo);
1103 status = Win32Native.LsaLogonUser(logonHandle,
1105 (uint)SecurityLogonType.Network,
1107 new IntPtr(pLogonInfoBuffer),
1108 (uint)logonInfoBuffer.ByteLength,
1114 ref safeTokenHandle,
1118 // If both status and substatus are < 0, substatus is preferred.
1119 if (status == Win32Native.STATUS_ACCOUNT_RESTRICTION && subStatus < 0)
1121 if (status < 0) // non-negative numbers indicate success
1122 throw GetExceptionFromNtStatus(status);
1123 if (subStatus < 0) // non-negative numbers indicate success
1124 throw GetExceptionFromNtStatus(subStatus);
1127 if (pLogonInfoBuffer != null) {
1128 logonInfoBuffer.ReleasePointer();
1134 return safeTokenHandle;
1138 if (!logonHandle.IsInvalid)
1139 logonHandle.Dispose();
1140 if (!profile.IsInvalid)
1146 #if !FEATURE_CORECLR
1148 [SecuritySafeCritical]
1149 protected WindowsIdentity (WindowsIdentity identity)
1150 : base( identity, null, identity.m_authType, null, null, false )
1152 if (identity == null)
1153 throw new ArgumentNullException("identity");
1155 Contract.EndContractBlock();
1157 bool mustDecrement = false;
1158 RuntimeHelpers.PrepareConstrainedRegions();
1161 if (!identity.m_safeTokenHandle.IsInvalid && identity.m_safeTokenHandle != SafeAccessTokenHandle.InvalidHandle && identity.m_safeTokenHandle.DangerousGetHandle() != IntPtr.Zero)
1163 identity.m_safeTokenHandle.DangerousAddRef(ref mustDecrement);
1165 if (!identity.m_safeTokenHandle.IsInvalid && identity.m_safeTokenHandle.DangerousGetHandle() != IntPtr.Zero)
1166 CreateFromToken(identity.m_safeTokenHandle.DangerousGetHandle());
1168 m_authType = identity.m_authType;
1169 m_isAuthenticated = identity.m_isAuthenticated;
1175 identity.m_safeTokenHandle.DangerousRelease();
1180 internal IntPtr GetTokenInternal()
1182 return m_safeTokenHandle.DangerousGetHandle();
1186 internal WindowsIdentity(ClaimsIdentity claimsIdentity, IntPtr userToken)
1187 : base(claimsIdentity)
1189 if (userToken != IntPtr.Zero && userToken.ToInt64() > 0)
1191 CreateFromToken(userToken);
1196 /// Returns a new instance of the base, used when serializing the WindowsIdentity.
1198 internal ClaimsIdentity CloneAsBase()
1200 return base.Clone();
1204 /// Returns a new instance of <see cref="WindowsIdentity"/> with values copied from this object.
1206 public override ClaimsIdentity Clone()
1208 return new WindowsIdentity(this);
1212 /// Gets the 'User Claims' from the NTToken that represents this identity
1214 public virtual IEnumerable<Claim> UserClaims
1220 return m_userClaims.AsReadOnly();
1225 /// Gets the 'Device Claims' from the NTToken that represents the device the identity is using
1227 public virtual IEnumerable<Claim> DeviceClaims
1233 return m_deviceClaims.AsReadOnly();
1238 /// Gets the claims as <see cref="IEnumerable{Claim}"/>, associated with this <see cref="WindowsIdentity"/>.
1239 /// Includes UserClaims and DeviceClaims.
1241 public override IEnumerable<Claim> Claims
1245 if (!m_claimsInitialized)
1250 foreach (Claim claim in base.Claims)
1253 foreach (Claim claim in m_userClaims)
1256 foreach (Claim claim in m_deviceClaims)
1262 /// Intenal method to initialize the claim collection.
1263 /// Lazy init is used so claims are not initialzed until needed
1265 [SecuritySafeCritical]
1266 void InitializeClaims()
1268 if (!m_claimsInitialized)
1270 lock (m_claimsIntiailizedLock)
1272 if (!m_claimsInitialized)
1274 m_userClaims = new List<Claim>();
1275 m_deviceClaims = new List<Claim>();
1277 if (!String.IsNullOrEmpty(Name))
1280 // Add the name claim only if the WindowsIdentity.Name is populated
1281 // WindowsIdentity.Name will be null when it is the fake anonymous user
1282 // with a token value of IntPtr.Zero
1284 m_userClaims.Add(new Claim(NameClaimType, Name, ClaimValueTypes.String, m_issuerName, m_issuerName, this));
1288 AddPrimarySidClaim(m_userClaims);
1291 AddGroupSidClaims(m_userClaims);
1293 // The following TokenInformationClass's were part of the Win8 release
1294 if (Environment.IsWindows8OrAbove)
1296 // Device group sids
1297 AddDeviceGroupSidClaims(m_deviceClaims, TokenInformationClass.TokenDeviceGroups);
1299 // User token claims
1300 AddTokenClaims(m_userClaims, TokenInformationClass.TokenUserClaimAttributes, ClaimTypes.WindowsUserClaim);
1302 // Device token claims
1303 AddTokenClaims(m_deviceClaims, TokenInformationClass.TokenDeviceClaimAttributes, ClaimTypes.WindowsDeviceClaim);
1306 m_claimsInitialized = true;
1313 /// Creates a collection of SID claims that represent the DeviceSidGroups.
1315 /// this is SafeCritical as it accesss the NT token.
1317 void AddDeviceGroupSidClaims(List<Claim> instanceClaims, TokenInformationClass tokenInformationClass)
1319 // special case the anonymous identity.
1320 if (m_safeTokenHandle.IsInvalid)
1323 SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1326 // Retrieve all group sids
1328 safeAllocHandle = GetTokenInformation(m_safeTokenHandle, tokenInformationClass);
1329 int count = Marshal.ReadInt32(safeAllocHandle.DangerousGetHandle());
1330 IntPtr pSidAndAttributes = new IntPtr((long)safeAllocHandle.DangerousGetHandle() + (long)Marshal.OffsetOf(typeof(Win32Native.TOKEN_GROUPS), "Groups"));
1331 string claimType = null;
1333 for (int i = 0; i < count; ++i)
1335 Win32Native.SID_AND_ATTRIBUTES group = (Win32Native.SID_AND_ATTRIBUTES)Marshal.PtrToStructure(pSidAndAttributes, typeof(Win32Native.SID_AND_ATTRIBUTES));
1336 uint mask = Win32Native.SE_GROUP_ENABLED | Win32Native.SE_GROUP_LOGON_ID | Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
1337 SecurityIdentifier groupSid = new SecurityIdentifier(group.Sid, true);
1338 if ((group.Attributes & mask) == Win32Native.SE_GROUP_ENABLED)
1340 claimType = ClaimTypes.WindowsDeviceGroup;
1341 Claim claim = new Claim(claimType, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture));
1342 claim.Properties.Add(claimType, "");
1343 instanceClaims.Add(claim);
1345 else if ((group.Attributes & mask) == Win32Native.SE_GROUP_USE_FOR_DENY_ONLY)
1347 claimType = ClaimTypes.DenyOnlyWindowsDeviceGroup;
1348 Claim claim = new Claim(claimType, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture));
1349 claim.Properties.Add(claimType, "");
1350 instanceClaims.Add(claim);
1353 pSidAndAttributes = new IntPtr((long)pSidAndAttributes + Win32Native.SID_AND_ATTRIBUTES.SizeOf);
1358 safeAllocHandle.Close();
1363 /// Creates a collection of SID claims that represent the users groups.
1365 /// this is SafeCritical as it accesss the NT token.
1367 void AddGroupSidClaims(List<Claim> instanceClaims)
1369 // special case the anonymous identity.
1370 if (m_safeTokenHandle.IsInvalid)
1373 SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1374 SafeLocalAllocHandle safeAllocHandlePrimaryGroup = SafeLocalAllocHandle.InvalidHandle;
1377 // Retrieve the primary group sid
1378 safeAllocHandlePrimaryGroup = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenPrimaryGroup);
1379 Win32Native.TOKEN_PRIMARY_GROUP primaryGroup = (Win32Native.TOKEN_PRIMARY_GROUP)Marshal.PtrToStructure(safeAllocHandlePrimaryGroup.DangerousGetHandle(), typeof(Win32Native.TOKEN_PRIMARY_GROUP));
1380 SecurityIdentifier primaryGroupSid = new SecurityIdentifier(primaryGroup.PrimaryGroup, true);
1382 // only add one primary group sid
1383 bool foundPrimaryGroupSid = false;
1385 // Retrieve all group sids, primary group sid is one of them
1386 safeAllocHandle = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenGroups);
1387 int count = Marshal.ReadInt32(safeAllocHandle.DangerousGetHandle());
1388 IntPtr pSidAndAttributes = new IntPtr((long)safeAllocHandle.DangerousGetHandle() + (long)Marshal.OffsetOf(typeof(Win32Native.TOKEN_GROUPS), "Groups"));
1389 for (int i = 0; i < count; ++i)
1391 Win32Native.SID_AND_ATTRIBUTES group = (Win32Native.SID_AND_ATTRIBUTES)Marshal.PtrToStructure(pSidAndAttributes, typeof(Win32Native.SID_AND_ATTRIBUTES));
1392 uint mask = Win32Native.SE_GROUP_ENABLED | Win32Native.SE_GROUP_LOGON_ID | Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
1393 SecurityIdentifier groupSid = new SecurityIdentifier(group.Sid, true);
1395 if ((group.Attributes & mask) == Win32Native.SE_GROUP_ENABLED)
1397 if (!foundPrimaryGroupSid && StringComparer.Ordinal.Equals( groupSid.Value, primaryGroupSid.Value))
1399 instanceClaims.Add(new Claim(ClaimTypes.PrimaryGroupSid, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1400 foundPrimaryGroupSid = true;
1402 //Primary group sid generates both regular groupsid claim and primary groupsid claim
1403 instanceClaims.Add(new Claim(ClaimTypes.GroupSid, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1406 else if ((group.Attributes & mask) == Win32Native.SE_GROUP_USE_FOR_DENY_ONLY)
1408 if (!foundPrimaryGroupSid && StringComparer.Ordinal.Equals( groupSid.Value, primaryGroupSid.Value))
1410 instanceClaims.Add(new Claim(ClaimTypes.DenyOnlyPrimaryGroupSid, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1411 foundPrimaryGroupSid = true;
1413 //Primary group sid generates both regular groupsid claim and primary groupsid claim
1414 instanceClaims.Add(new Claim(ClaimTypes.DenyOnlySid, groupSid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1416 pSidAndAttributes = new IntPtr((long)pSidAndAttributes + Win32Native.SID_AND_ATTRIBUTES.SizeOf);
1421 safeAllocHandle.Close();
1422 safeAllocHandlePrimaryGroup.Close();
1427 /// Creates a Windows SID Claim and adds to collection of claims.
1429 /// this is SafeCritical as it accesss the NT token.
1431 void AddPrimarySidClaim(List<Claim> instanceClaims)
1433 // special case the anonymous identity.
1434 if (m_safeTokenHandle.IsInvalid)
1437 SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1440 safeAllocHandle = GetTokenInformation(m_safeTokenHandle, TokenInformationClass.TokenUser);
1441 Win32Native.SID_AND_ATTRIBUTES user = (Win32Native.SID_AND_ATTRIBUTES)Marshal.PtrToStructure(safeAllocHandle.DangerousGetHandle(), typeof(Win32Native.SID_AND_ATTRIBUTES));
1442 uint mask = Win32Native.SE_GROUP_USE_FOR_DENY_ONLY;
1444 SecurityIdentifier sid = new SecurityIdentifier(user.Sid, true);
1446 if (user.Attributes == 0)
1448 instanceClaims.Add(new Claim(ClaimTypes.PrimarySid, sid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(sid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1450 else if ((user.Attributes & mask) == Win32Native.SE_GROUP_USE_FOR_DENY_ONLY)
1452 instanceClaims.Add(new Claim(ClaimTypes.DenyOnlyPrimarySid, sid.Value, ClaimValueTypes.String, m_issuerName, m_issuerName, this, ClaimTypes.WindowsSubAuthority, Convert.ToString(sid.IdentifierAuthority, CultureInfo.InvariantCulture)));
1457 safeAllocHandle.Close();
1462 void AddTokenClaims(List<Claim> instanceClaims, TokenInformationClass tokenInformationClass, string propertyValue)
1464 // special case the anonymous identity.
1465 if (m_safeTokenHandle.IsInvalid)
1468 SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1472 SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
1473 safeAllocHandle = GetTokenInformation(m_safeTokenHandle, tokenInformationClass);
1475 Win32Native.CLAIM_SECURITY_ATTRIBUTES_INFORMATION claimAttributes = (Win32Native.CLAIM_SECURITY_ATTRIBUTES_INFORMATION)Marshal.PtrToStructure(safeAllocHandle.DangerousGetHandle(), typeof(Win32Native.CLAIM_SECURITY_ATTRIBUTES_INFORMATION));
1476 // An attribute represents a collection of claims. Inside each attribute a claim can be multivalued, we create a claim for each value.
1477 // It is a ragged multi-dimentional array, where each cell can be of different lenghts.
1479 // index into array of claims.
1482 for (int attribute = 0; attribute < claimAttributes.AttributeCount; attribute++)
1484 IntPtr pAttribute = new IntPtr(claimAttributes.Attribute.pAttributeV1.ToInt64() + offset);
1485 Win32Native.CLAIM_SECURITY_ATTRIBUTE_V1 windowsClaim = (Win32Native.CLAIM_SECURITY_ATTRIBUTE_V1)Marshal.PtrToStructure(pAttribute, typeof(Win32Native.CLAIM_SECURITY_ATTRIBUTE_V1));
1487 // 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.
1488 switch (windowsClaim.ValueType)
1490 case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
1491 IntPtr[] stringPointers = new IntPtr[windowsClaim.ValueCount];
1492 Marshal.Copy(windowsClaim.Values.ppString, stringPointers, 0, (int)windowsClaim.ValueCount);
1494 for (int item = 0; item < windowsClaim.ValueCount; item++)
1496 instanceClaims.Add( new Claim(windowsClaim.Name, Marshal.PtrToStringAuto(stringPointers[item]), ClaimValueTypes.String, m_issuerName, m_issuerName, this, propertyValue, string.Empty));
1500 case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
1501 Int64[] intValues = new Int64[windowsClaim.ValueCount];
1502 Marshal.Copy(windowsClaim.Values.pInt64, intValues, 0, (int)windowsClaim.ValueCount);
1504 for (int item = 0; item < windowsClaim.ValueCount; item++)
1506 instanceClaims.Add(new Claim(windowsClaim.Name, Convert.ToString(intValues[item], CultureInfo.InvariantCulture), ClaimValueTypes.Integer64, m_issuerName, m_issuerName, this, propertyValue, string.Empty));
1511 case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
1512 Int64[] uintValues = new Int64[windowsClaim.ValueCount];
1513 Marshal.Copy(windowsClaim.Values.pUint64, uintValues, 0, (int)windowsClaim.ValueCount);
1515 for (int item = 0; item < windowsClaim.ValueCount; item++)
1517 instanceClaims.Add( new Claim(windowsClaim.Name, Convert.ToString((UInt64)uintValues[item], CultureInfo.InvariantCulture), ClaimValueTypes.UInteger64, m_issuerName, m_issuerName, this, propertyValue, string.Empty));
1521 case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
1522 Int64[] boolValues = new Int64[windowsClaim.ValueCount];
1523 Marshal.Copy(windowsClaim.Values.pUint64, boolValues, 0, (int)windowsClaim.ValueCount);
1525 for (int item = 0; item < windowsClaim.ValueCount; item++)
1527 instanceClaims.Add(new Claim(windowsClaim.Name,
1528 ((UInt64)boolValues[item] == 0 ? Convert.ToString(false, CultureInfo.InvariantCulture) : Convert.ToString(true, CultureInfo.InvariantCulture)),
1529 ClaimValueTypes.Boolean,
1539 // 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.
1541 //case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_FQBN:
1544 //case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
1547 //case Win32Native.CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
1552 offset += Marshal.SizeOf(windowsClaim);
1557 safeAllocHandle.Close();
1565 internal enum KerbLogonSubmitType : int {
1566 KerbInteractiveLogon = 2,
1567 KerbSmartCardLogon = 6,
1568 KerbWorkstationUnlockLogon = 7,
1569 KerbSmartCardUnlockLogon = 8,
1571 KerbTicketLogon = 10,
1572 KerbTicketUnlockLogon = 11,
1577 internal enum SecurityLogonType : int {
1587 internal enum TokenType : int {
1593 internal enum TokenInformationClass : int {
1602 TokenImpersonationLevel,
1604 TokenRestrictedSids,
1606 TokenGroupsAndPrivileges,
1607 TokenSessionReference,
1614 TokenHasRestrictions,
1615 TokenAccessInformation,
1616 TokenVirtualizationAllowed,
1617 TokenVirtualizationEnabled,
1618 TokenIntegrityLevel,
1620 TokenMandatoryPolicy,
1622 TokenIsAppContainer,
1624 TokenAppContainerSid,
1625 TokenAppContainerNumber,
1626 TokenUserClaimAttributes,
1627 TokenDeviceClaimAttributes,
1628 TokenRestrictedUserClaimAttributes,
1629 TokenRestrictedDeviceClaimAttributes,
1631 TokenRestrictedDeviceGroups,
1632 MaxTokenInfoClass // MaxTokenInfoClass should always be the last enum