1
.net下模拟不同身份登陆以获取不同权限
2
3
作者:佚名 时间:2004-04-16 09:14 出处:互连网 责编:chinaitpower
4
5
摘要:.net下模拟不同身份登陆以获取不同权限
6
7
8
不管是asp.net、web service还是window service,程序运行的时候只有本地计算机的部分权限,有时候需要更大的权限,比如读写某台服务器或域中的一台计算机上的文件等,这就需要更大的权限,比如域帐户权限。
9
10
通过获取不同身份的WindowsImpersonationContext对象,可以模拟不同用户登陆,请看我生成的NetworkSecurity类的
11
public static WindowsImpersonationContext ImpersonateUser(string strDomain,
12
string strLogin,
13
14
string strPwd,
15
16
LogonType logonType,
17
18
LogonProvider logonProvider);
19
20
附NetworkSecurity.cs源代码如下:
21
22
/*
23
* Author : TongWei
24
* Date : 2005-1-25
25
* Rights : China Netwave Inc.@2005
26
*/
27
28
using System;
29
using System.Runtime.InteropServices;
30
using System.Security.Principal;
31
using System.Security.Permissions;
32
33
namespace CNW.OMP.Common.Utility
34
{
35
public enum LogonType : int
36
{
37
/// <summary>
38
/// This logon type is intended for users who will be interactively using the computer, such as a user
39
/// being logged on by a terminal server, remote shell, or similar process. This logon type has the
40
/// additional expense of caching logon information for disconnected operation, and is therefore
41
/// inappropriate for some client/server applications, such as a mail server.
42
/// </summary>
43
LOGON32_LOGON_INTERACTIVE = 2,
44
45
/// <summary>
46
/// This logon type is intended for high performance servers to authenticate clear text passwords.
47
/// The LogonUser function does not cache credentials for this logon type.
48
/// </summary>
49
LOGON32_LOGON_NETWORK = 3,
50
51
/// <summary>
52
/// This logon type is intended for batch servers, where processes may be executing on behalf of a user
53
/// without their direct intervention; or for higher performance servers that process many clear-text
54
/// authentication attempts at a time, such as mail or web servers. The LogonUser function does not cache
55
/// credentials for this logon type.
56
/// </summary>
57
LOGON32_LOGON_BATCH = 4,
58
59
/// <summary>
60
/// Indicates a service-type logon. The account provided must have the service privilege enabled.
61
/// </summary>
62
LOGON32_LOGON_SERVICE = 5,
63
64
/// <summary>
65
/// This logon type is intended for GINA DLLs logging on users who will be interactively using the computer.
66
/// This logon type allows a unique audit record to be generated that shows when the workstation was unlocked.
67
/// </summary>
68
LOGON32_LOGON_UNLOCK = 7,
69
70
/// <summary>
71
/// Windows XP/2000: This logon type preserves the name and password in the authentication packages,
72
/// allowing the server to make connections to other network servers while impersonating the client.
73
/// This allows a server to accept clear text credentials from a client, call LogonUser, verify that
74
/// the user can access the system across the network, and still communicate with other servers.
75
/// </summary>
76
LOGON32_LOGON_NETWORK_CLEARTEXT = 8,
77
78
/// <summary>
79
/// Windows XP/2000: This logon type allows the caller to clone its current token and specify new credentials
80
/// for outbound connections. The new logon session has the same local identity, but uses different credentials
81
/// for other network connections.
82
/// This logon type is supported only by the LOGON32_PROVIDER_WINNT50 logon provider.
83
/// </summary>
84
LOGON32_LOGON_NEW_CREDENTIALS = 9
85
};
86
87
public enum LogonProvider : int
88
{
89
/// <summary>
90
/// Use the standard logon provider for the system. The default security provider is NTLM.
91
/// Windows XP: The default provider is negotiate, unless you pass NULL for the domain name and
92
/// the user name is not in UPN format. In this case the default provider is NTLM.
93
/// </summary>
94
LOGON32_PROVIDER_DEFAULT = 0,
95
96
/// <summary>
97
/// Use the Windows NT 3.5 logon provider.
98
/// </summary>
99
LOGON32_PROVIDER_WINNT35 = 1,
100
101
/// <summary>
102
/// Use the NTLM logon provider.
103
/// </summary>
104
LOGON32_PROVIDER_WINNT40 = 2,
105
106
/// <summary>
107
/// Windows XP/2000: Use the negotiate logon provider.
108
/// </summary>
109
LOGON32_PROVIDER_WINNT50 = 3
110
};
111
112
class SecuUtil32
113
{
114
[DllImport("advapi32.dll", SetLastError=true)]
115
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
116
int dwLogonType, int dwLogonProvider, ref IntPtr TokenHandle);
117
118
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
119
public extern static bool CloseHandle(IntPtr handle);
120
121
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
122
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
123
int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
124
}
125
126
public class NetworkSecurity
127
{
128
public NetworkSecurity()
129
{
130
//
131
// TODO: Add constructor logic here
132
//
133
}
134
135
/// <summary>
136
/// The ImpersonateUser function attempts to log a user on to the local computer.
137
/// The local computer is the computer from which ImpersonateUser was called.
138
/// You cannot use ImpersonateUser to log on to a remote computer.
139
/// You specify the user with a user name and domain, and authenticate the user with a clear-text password.
140
/// If the function succeeds, you receive a handle to a token that represents the logged-on user.
141
/// You can then use this token handle to impersonate the specified user, or in most cases,
142
/// to create a process running in the context of the specified user.
143
/// </summary>
144
/// <param name="strDomain">
145
/// specifies the name of the domain or server whose account database contains the strLogin account.
146
/// </param>
147
/// <param name="strLogin">specifies the name of the user.</param>
148
/// <param name="strPwd">specifies the clear-text password for the user account specified by strLogin.</param>
149
/// <param name="logonType">Specifies the type of logon operation to perform.</param>
150
/// <param name="logonProvider">Specifies the logon provider.</param>
151
/// <example>
152
/// //Add System.Security.dll
153
/// //using System.Security.Principal;
154
///
155
/// string strDomain=ConfigurationSettings.AppSettings["mSALoginDomainName"];
156
/// string strUser=ConfigurationSettings.AppSettings["mSALoginDomainUser"];
157
/// string strPassword=ConfigurationSettings.AppSettings["mSALoginDomainPassword"];
158
///
159
/// WindowsImpersonationContext impContext = null;
160
/// try
161
/// {
162
/// impContext = NetworkSecurity.ImpersonateUser(strDomain,strUser,strPassword,
163
/// LogonType.LOGON32_LOGON_SERVICE,
164
/// LogonProvider.LOGON32_PROVIDER_DEFAULT);
165
/// }
166
/// catch
167
/// {
168
///
169
/// }
170
///
171
/// //work under this logined user
172
///
173
/// impContext.Undo();
174
/// </example>
175
/// <returns>
176
/// </returns>
177
public static WindowsImpersonationContext ImpersonateUser(string strDomain,
178
string strLogin,
179
string strPwd,
180
LogonType logonType,
181
LogonProvider logonProvider)
182
{
183
// Initialize tokens
184
IntPtr tokenHandle = new IntPtr(0);
185
IntPtr dupeTokenHandle = new IntPtr(0);
186
tokenHandle = IntPtr.Zero;
187
dupeTokenHandle = IntPtr.Zero;
188
189
// If domain name was blank, assume local machine
190
if (strDomain == "")
191
strDomain = System.Environment.MachineName;
192
193
try
194
{
195
const int SecurityImpersonation = 2;
196
197
// Call LogonUser to obtain a handle to an access token.
198
bool returnValue = SecuUtil32.LogonUser(
199
strLogin,
200
strDomain,
201
strPwd,
202
(int)logonType,
203
(int)logonProvider,
204
ref tokenHandle);
205
206
// Did impersonation fail?
207
if (false == returnValue)
208
{
209
int ret = Marshal.GetLastWin32Error();
210
// Throw the exception show the reason why LogonUser failed
211
string strErr = String.Format("LogonUser failed with error code : {0}", ret);
212
throw new ApplicationException(strErr, null);
213
}
214
215
// Get identity before impersonation
216
bool retVal = SecuUtil32.DuplicateToken(tokenHandle, SecurityImpersonation, ref dupeTokenHandle);
217
218
// Did DuplicateToken fail?
219
if (false == retVal)
220
{
221
// Close existing handle
222
SecuUtil32.CloseHandle(tokenHandle);
223
// Throw the exception show the reason why DuplicateToken failed
224
throw new ApplicationException("Failed to duplicate token", null);
225
}
226
227
// Create new identity using new primary token
228
// The token that is passed to the following constructor must
229
// be a primary token in order to use it for impersonation.
230
WindowsIdentity newId = new WindowsIdentity(dupeTokenHandle);
231
WindowsImpersonationContext impersonatedUser = newId.Impersonate();
232
233
return impersonatedUser;
234
}
235
catch (Exception ex)
236
{
237
throw new ApplicationException(ex.Message, ex);
238
}
239
finally
240
{
241
// Close handle
242
if (tokenHandle != IntPtr.Zero)
243
SecuUtil32.CloseHandle(tokenHandle);
244
if (dupeTokenHandle != IntPtr.Zero)
245
SecuUtil32.CloseHandle(dupeTokenHandle);
246
}
247
}
248
}
249
}
250
251
252
.net下模拟不同身份登陆以获取不同权限 2
3
作者:佚名 时间:2004-04-16 09:14 出处:互连网 责编:chinaitpower 4
5
摘要:.net下模拟不同身份登陆以获取不同权限 6
7
8
不管是asp.net、web service还是window service,程序运行的时候只有本地计算机的部分权限,有时候需要更大的权限,比如读写某台服务器或域中的一台计算机上的文件等,这就需要更大的权限,比如域帐户权限。 9

10
通过获取不同身份的WindowsImpersonationContext对象,可以模拟不同用户登陆,请看我生成的NetworkSecurity类的 11
public static WindowsImpersonationContext ImpersonateUser(string strDomain, 12
string strLogin, 13

14
string strPwd, 15

16
LogonType logonType, 17

18
LogonProvider logonProvider); 19

20
附NetworkSecurity.cs源代码如下: 21

22
/* 23
* Author : TongWei 24
* Date : 2005-1-25 25
* Rights : China Netwave Inc.@2005 26
*/ 27

28
using System; 29
using System.Runtime.InteropServices; 30
using System.Security.Principal; 31
using System.Security.Permissions; 32

33
namespace CNW.OMP.Common.Utility 34
{ 35
public enum LogonType : int 36
{ 37
/// <summary> 38
/// This logon type is intended for users who will be interactively using the computer, such as a user 39
/// being logged on by a terminal server, remote shell, or similar process. This logon type has the 40
/// additional expense of caching logon information for disconnected operation, and is therefore 41
/// inappropriate for some client/server applications, such as a mail server. 42
/// </summary> 43
LOGON32_LOGON_INTERACTIVE = 2, 44

45
/// <summary> 46
/// This logon type is intended for high performance servers to authenticate clear text passwords. 47
/// The LogonUser function does not cache credentials for this logon type. 48
/// </summary> 49
LOGON32_LOGON_NETWORK = 3, 50

51
/// <summary> 52
/// This logon type is intended for batch servers, where processes may be executing on behalf of a user 53
/// without their direct intervention; or for higher performance servers that process many clear-text 54
/// authentication attempts at a time, such as mail or web servers. The LogonUser function does not cache 55
/// credentials for this logon type. 56
/// </summary> 57
LOGON32_LOGON_BATCH = 4, 58

59
/// <summary> 60
/// Indicates a service-type logon. The account provided must have the service privilege enabled. 61
/// </summary> 62
LOGON32_LOGON_SERVICE = 5, 63

64
/// <summary> 65
/// This logon type is intended for GINA DLLs logging on users who will be interactively using the computer. 66
/// This logon type allows a unique audit record to be generated that shows when the workstation was unlocked. 67
/// </summary> 68
LOGON32_LOGON_UNLOCK = 7, 69

70
/// <summary> 71
/// Windows XP/2000: This logon type preserves the name and password in the authentication packages, 72
/// allowing the server to make connections to other network servers while impersonating the client. 73
/// This allows a server to accept clear text credentials from a client, call LogonUser, verify that 74
/// the user can access the system across the network, and still communicate with other servers. 75
/// </summary> 76
LOGON32_LOGON_NETWORK_CLEARTEXT = 8, 77

78
/// <summary> 79
/// Windows XP/2000: This logon type allows the caller to clone its current token and specify new credentials 80
/// for outbound connections. The new logon session has the same local identity, but uses different credentials 81
/// for other network connections. 82
/// This logon type is supported only by the LOGON32_PROVIDER_WINNT50 logon provider. 83
/// </summary> 84
LOGON32_LOGON_NEW_CREDENTIALS = 9 85
}; 86

87
public enum LogonProvider : int 88
{ 89
/// <summary> 90
/// Use the standard logon provider for the system. The default security provider is NTLM. 91
/// Windows XP: The default provider is negotiate, unless you pass NULL for the domain name and 92
/// the user name is not in UPN format. In this case the default provider is NTLM. 93
/// </summary> 94
LOGON32_PROVIDER_DEFAULT = 0, 95

96
/// <summary> 97
/// Use the Windows NT 3.5 logon provider. 98
/// </summary> 99
LOGON32_PROVIDER_WINNT35 = 1, 100

101
/// <summary> 102
/// Use the NTLM logon provider. 103
/// </summary> 104
LOGON32_PROVIDER_WINNT40 = 2, 105

106
/// <summary> 107
/// Windows XP/2000: Use the negotiate logon provider. 108
/// </summary> 109
LOGON32_PROVIDER_WINNT50 = 3 110
}; 111

112
class SecuUtil32 113
{ 114
[DllImport("advapi32.dll", SetLastError=true)] 115
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, 116
int dwLogonType, int dwLogonProvider, ref IntPtr TokenHandle); 117

118
[DllImport("kernel32.dll", CharSet=CharSet.Auto)] 119
public extern static bool CloseHandle(IntPtr handle); 120

121
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 122
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, 123
int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle); 124
} 125

126
public class NetworkSecurity 127
{ 128
public NetworkSecurity() 129
{ 130
// 131
// TODO: Add constructor logic here 132
// 133
} 134

135
/// <summary> 136
/// The ImpersonateUser function attempts to log a user on to the local computer. 137
/// The local computer is the computer from which ImpersonateUser was called. 138
/// You cannot use ImpersonateUser to log on to a remote computer. 139
/// You specify the user with a user name and domain, and authenticate the user with a clear-text password. 140
/// If the function succeeds, you receive a handle to a token that represents the logged-on user. 141
/// You can then use this token handle to impersonate the specified user, or in most cases, 142
/// to create a process running in the context of the specified user. 143
/// </summary> 144
/// <param name="strDomain"> 145
/// specifies the name of the domain or server whose account database contains the strLogin account. 146
/// </param> 147
/// <param name="strLogin">specifies the name of the user.</param> 148
/// <param name="strPwd">specifies the clear-text password for the user account specified by strLogin.</param> 149
/// <param name="logonType">Specifies the type of logon operation to perform.</param> 150
/// <param name="logonProvider">Specifies the logon provider.</param> 151
/// <example> 152
/// //Add System.Security.dll 153
/// //using System.Security.Principal; 154
/// 155
/// string strDomain=ConfigurationSettings.AppSettings["mSALoginDomainName"]; 156
/// string strUser=ConfigurationSettings.AppSettings["mSALoginDomainUser"]; 157
/// string strPassword=ConfigurationSettings.AppSettings["mSALoginDomainPassword"]; 158
/// 159
/// WindowsImpersonationContext impContext = null; 160
/// try 161
/// { 162
/// impContext = NetworkSecurity.ImpersonateUser(strDomain,strUser,strPassword, 163
/// LogonType.LOGON32_LOGON_SERVICE, 164
/// LogonProvider.LOGON32_PROVIDER_DEFAULT); 165
/// } 166
/// catch 167
/// { 168
/// 169
/// } 170
/// 171
/// //work under this logined user 172
/// 173
/// impContext.Undo(); 174
/// </example> 175
/// <returns> 176
/// </returns> 177
public static WindowsImpersonationContext ImpersonateUser(string strDomain, 178
string strLogin, 179
string strPwd, 180
LogonType logonType, 181
LogonProvider logonProvider) 182
{ 183
// Initialize tokens 184
IntPtr tokenHandle = new IntPtr(0); 185
IntPtr dupeTokenHandle = new IntPtr(0); 186
tokenHandle = IntPtr.Zero; 187
dupeTokenHandle = IntPtr.Zero; 188

189
// If domain name was blank, assume local machine 190
if (strDomain == "") 191
strDomain = System.Environment.MachineName; 192

193
try 194
{ 195
const int SecurityImpersonation = 2; 196

197
// Call LogonUser to obtain a handle to an access token. 198
bool returnValue = SecuUtil32.LogonUser( 199
strLogin, 200
strDomain, 201
strPwd, 202
(int)logonType, 203
(int)logonProvider, 204
ref tokenHandle); 205

206
// Did impersonation fail? 207
if (false == returnValue) 208
{ 209
int ret = Marshal.GetLastWin32Error(); 210
// Throw the exception show the reason why LogonUser failed 211
string strErr = String.Format("LogonUser failed with error code : {0}", ret); 212
throw new ApplicationException(strErr, null); 213
} 214

215
// Get identity before impersonation 216
bool retVal = SecuUtil32.DuplicateToken(tokenHandle, SecurityImpersonation, ref dupeTokenHandle); 217

218
// Did DuplicateToken fail? 219
if (false == retVal) 220
{ 221
// Close existing handle 222
SecuUtil32.CloseHandle(tokenHandle); 223
// Throw the exception show the reason why DuplicateToken failed 224
throw new ApplicationException("Failed to duplicate token", null); 225
} 226

227
// Create new identity using new primary token 228
// The token that is passed to the following constructor must 229
// be a primary token in order to use it for impersonation. 230
WindowsIdentity newId = new WindowsIdentity(dupeTokenHandle); 231
WindowsImpersonationContext impersonatedUser = newId.Impersonate(); 232

233
return impersonatedUser; 234
} 235
catch (Exception ex) 236
{ 237
throw new ApplicationException(ex.Message, ex); 238
} 239
finally 240
{ 241
// Close handle 242
if (tokenHandle != IntPtr.Zero) 243
SecuUtil32.CloseHandle(tokenHandle); 244
if (dupeTokenHandle != IntPtr.Zero) 245
SecuUtil32.CloseHandle(dupeTokenHandle); 246
} 247
} 248
} 249
} 250
251
252

<%@ Page Language="C#"%>
<%@ Import Namespace = "System.Web" %>
<%@ Import Namespace = "System.Web.Security" %>
<%@ Import Namespace = "System.Security.Principal" %>
<%@ Import Namespace = "System.Runtime.InteropServices" %>
<script runat=server>
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext impersonationContext;
[DllImport("advapi32.dll")]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
public void Page_Load(Object s, EventArgs e)
{
if(impersonateValidUser("username", "domain", "password"))
{
//Insert your code that runs under the security context of a specific user here.
undoImpersonation();
}
else
{
//Your impersonation failed. Therefore, include a fail-safe mechanism here.
}
}
private bool impersonateValidUser(String userName, String domain, String password)
{
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if(RevertToSelf())
{
if(LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if(DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if(token!= IntPtr.Zero)
CloseHandle(token);
if(tokenDuplicate!=IntPtr.Zero)
CloseHandle(tokenDuplicate);
return false;
}
private void undoImpersonation()
{
impersonationContext.Undo();
}
</script>

