@@ -10,41 +10,41 @@ namespace BLAZAM.Common.Data
1010 public class WindowsImpersonation
1111 {
1212 private SafeAccessTokenHandle safeAccessTokenHandle ;
13- private WindowsImpersonationUser impersonationUser ;
13+ private WindowsImpersonationUser ? impersonationUser ;
1414 private readonly WindowsIdentity ApplicationIdentity ;
1515
16- private SafeAccessTokenHandle ImpersonatedToken
16+ private SafeAccessTokenHandle GetImpersonatedToken ( )
1717 {
18- get
18+ if ( impersonationUser == null )
1919 {
20- //Use interactive logon
21- var domain = impersonationUser . FQDN ?? "" ;
22- var username = impersonationUser . Username ;
23- var phPassword = Marshal . SecureStringToGlobalAllocUnicode ( impersonationUser . Password ) ;
24- bool returnValue = LogonUser ( username ,
25- domain ,
26- phPassword ,
27- LOGON32_LOGON_BATCH ,
28- LOGON32_PROVIDER_DEFAULT ,
29- out safeAccessTokenHandle ) ;
20+ throw new AppException ( "Attempted to impersonate without an impersonation user" ) ;
21+ }
22+ //Use interactive logon
23+ var domain = impersonationUser . FQDN ?? "" ;
24+ var username = impersonationUser . Username ;
25+ var phPassword = Marshal . SecureStringToGlobalAllocUnicode ( impersonationUser . Password ) ;
26+ bool returnValue = LogonUser ( username ,
27+ domain ,
28+ phPassword ,
29+ LOGON32_LOGON_NETWORK ,
30+ LOGON32_PROVIDER_DEFAULT ,
31+ out safeAccessTokenHandle ) ;
3032
3133
3234
33- Marshal . ZeroFreeGlobalAllocUnicode ( phPassword ) ;
34- if ( false == returnValue )
35- {
36- int ret = Marshal . GetLastWin32Error ( ) ;
37- Loggers . ActiveDirectoryLogger . Warning ( "LogonUser failed with error code : {0}" , ret ) ;
38- var exception = new System . ComponentModel . Win32Exception ( ret ) ;
39- if ( exception . NativeErrorCode == 1326 )
40- {
41-
42- throw new AuthenticationException ( exception . Message ) ;
43- }
44- }
45- return safeAccessTokenHandle ;
35+ Marshal . ZeroFreeGlobalAllocUnicode ( phPassword ) ;
36+ if ( ! returnValue )
37+ {
38+ int ret = Marshal . GetLastWin32Error ( ) ;
39+ Loggers . ActiveDirectoryLogger . Warning ( "LogonUser failed with error code : {0}" , ret ) ;
40+ var exception = new System . ComponentModel . Win32Exception ( ret ) ;
41+
42+
43+ throw new AuthenticationException ( exception . Message ) ;
4644
4745 }
46+ return safeAccessTokenHandle ;
47+
4848 }
4949
5050 private const int LOGON32_LOGON_INTERACTIVE = 2 ;
@@ -70,7 +70,7 @@ private static extern bool LogonUser(string lpszUsername, string lpszDomain, Int
7070 /// Creates a new impersonation context under the provided <see cref="WindowsImpersonationUser"/>
7171 /// </summary>
7272 /// <param name="user"></param>
73- public WindowsImpersonation ( WindowsImpersonationUser user )
73+ public WindowsImpersonation ( WindowsImpersonationUser ? user )
7474 {
7575 impersonationUser = user ;
7676 ApplicationIdentity = WindowsIdentity . GetCurrent ( ) ;
@@ -81,36 +81,52 @@ public WindowsImpersonation(WindowsImpersonationUser user)
8181 /// <typeparam name="T"></typeparam>
8282 /// <param name="task"></param>
8383 /// <returns></returns>
84- public async Task < T ? > RunAsync < T > ( Func < T > task ) => await Task . Run ( ( ) => Run < T > ( task ) ) ;
84+ public async Task < T ? > RunAsync < T > ( Func < T > task ) => await Task . Run ( ( ) => Run ( task ) ) ;
85+
8586 /// <summary>
86- /// Runs the provided action synchronously as the <see cref="WindowsImpersonationUser"/>
87+ /// Runs the provided async action as the <see cref="WindowsImpersonationUser"/>
8788 /// </summary>
8889 /// <typeparam name="T"></typeparam>
8990 /// <param name="task"></param>
9091 /// <returns></returns>
91- /// <exception cref="AppException"></exception>
92- public T ? Run < T > ( Func < T > task )
93- {
92+ public async Task < T ? > RunAsync < T > ( Func < Task < T > > task ) =>
93+ await Task . Run ( ( ) => RunImpersonated ( ( ) => task ( ) . GetAwaiter ( ) . GetResult ( ) ) ) ;
9494
95+ /// <summary>
96+ /// Runs the provided action synchronously as the <see cref="WindowsImpersonationUser"/> or as the application identity if no user was provided
97+ /// </summary>
98+ /// <typeparam name="T"></typeparam>
99+ /// <param name="task"></param>
100+ /// <returns></returns>
101+ public T ? Run < T > ( Func < T > task ) => RunImpersonated ( ( ) => task ( ) ) ;
102+
103+ /// <summary>
104+ /// Core impersonation logic shared by all Run methods
105+ /// </summary>
106+ private T ? RunImpersonated < T > ( Func < T > executeTask )
107+ {
108+ // If no impersonation user provided, run as application identity
109+ if ( impersonationUser == null )
110+ {
111+ Loggers . ActiveDirectoryLogger . Information ( "Running as application identity: {@Identity}" , WindowsIdentity . GetCurrent ( ) . Name ) ;
112+ return executeTask ( ) ;
113+ }
95114
96115 T ? result = default ;
97116 try
98117 {
99- var impersonatedToken = ImpersonatedToken ;
100-
118+ var impersonatedToken = GetImpersonatedToken ( ) ;
101119
102120 if ( impersonatedToken == null )
103121 {
104122 throw new AppException ( "The impersonation user is invalid. Check settings." ) ;
105123 }
106124
107-
108125 // Check the identity.
109- Loggers . ActiveDirectoryLogger . Debug ( "Before impersonation: " + WindowsIdentity . GetCurrent ( ) . Name ) ;
126+ Loggers . ActiveDirectoryLogger . Information ( "Before impersonation: {@PreIdentity}" , WindowsIdentity . GetCurrent ( ) . Name ) ;
110127
111128 try
112129 {
113-
114130 WindowsIdentity . RunImpersonated (
115131 impersonatedToken ,
116132 ( ) =>
@@ -122,13 +138,11 @@ public WindowsImpersonation(WindowsImpersonationUser user)
122138 var exception = new AppException ( "Impersonation running as application identity" ) ;
123139 ExceptionDispatchInfo . SetCurrentStackTrace ( exception ) ;
124140 Loggers . ActiveDirectoryLogger . Information ( exception , "Impersonation running as application identity" ) ;
125-
126141 }
127- Loggers . ActiveDirectoryLogger . Debug ( "During impersonation: " + WindowsIdentity . GetCurrent ( ) . Name ) ;
128- result = task . Invoke ( ) ;
142+ Loggers . ActiveDirectoryLogger . Information ( "During impersonation: {@PostIdentity}" , WindowsIdentity . GetCurrent ( ) . Name ) ;
143+ result = executeTask ( ) ;
129144 }
130145 ) ;
131-
132146 }
133147 catch ( IdentityNotMappedException ex )
134148 {
@@ -140,7 +154,7 @@ public WindowsImpersonation(WindowsImpersonationUser user)
140154 }
141155 finally
142156 {
143- impersonatedToken ? . Close ( ) ;
157+ impersonatedToken . Close ( ) ;
144158 }
145159 }
146160 catch ( AuthenticationException ex )
0 commit comments