【发布时间】:2014-02-19 14:11:30
【问题描述】:
我创建了使用 IWA 的 asp.net (vb.net) 网站。完全没有问题。
但是现在我的用户不一定是我公司域的一部分,但登录到我的网络以访问公共信息。
我在我的 AD 上创建了一个公共帐户。我想做的是,当外部用户登录时,能够传递公共帐户凭据,以便他们可以访问公共信息。
这可能吗?
【问题讨论】:
我创建了使用 IWA 的 asp.net (vb.net) 网站。完全没有问题。
但是现在我的用户不一定是我公司域的一部分,但登录到我的网络以访问公共信息。
我在我的 AD 上创建了一个公共帐户。我想做的是,当外部用户登录时,能够传递公共帐户凭据,以便他们可以访问公共信息。
这可能吗?
【问题讨论】:
您可以使用 web.config 中的身份模拟设置来设置凭据:
<system.web>
<authentication mode="Windows"/>
<identity impersonate="true" userName="foo" password="bar"/>
</system.web>
您还应该加密 web.config,这样密码就不会以明文形式存储。 http://msdn.microsoft.com/en-us/library/89211k9b.aspx
另一种选择是让您的用户能够在代码中冒充您的服务帐户。请注意,这段代码是用 C# 编写的,但我写它是为了即时模拟 Windows。它可以编译为 DLL 并在 VB.NET 中引用:
/// <summary>
/// Facilitates impersonation of a Windows User.
/// </summary>
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class Impersonation : IDisposable
{
public string Environment { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string DomainName { get; set; }
public enum LogonType
{
Interactive = 2,
Network = 3,
Batch = 4,
Service = 5,
Unlock = 7,
NetworkClearText = 8,
NewCredentials = 9
}
public enum LogonProvider
{
Default = 0,
WinNT35 = 1,
WinNT40 = 2,
WinNT50 = 3
}
/// <summary>
/// Windows Token.
/// </summary>
private readonly SafeTokenHandle _handle;
/// <summary>
/// The impersonated User.
/// </summary>
private WindowsImpersonationContext impersonatedUser;
public Impersonation()
{
}
/// <summary>
/// Initializes a new instance of the Impersonation class. Provides domain, user name, and password for impersonation.
/// </summary>
/// <param name="domainName">Domain name of the impersonated user.</param>
/// <param name="userName">Name of the impersonated user.</param>
/// <param name="password">Password of the impersonated user.</param>
/// <remarks>
/// Uses the unmanaged LogonUser function to get the user token for
/// the specified user, domain, and password.
/// </remarks>
public Impersonation(AccountCredentials credentials)
{
string[] splitName = WindowsIdentity.GetCurrent().Name.Split('\\');
string name = (splitName.Length > 0) ? splitName[0] : null;
LogonType logonType = LogonType.Interactive;
LogonProvider logonProvider = LogonProvider.Default;
if (name != credentials.Domain)
{
logonType = LogonType.NewCredentials;
logonProvider = LogonProvider.WinNT50;
}
// Call LogonUser to obtain a handle to an access token.
bool returnValue = LogonUser(
credentials.UserName,
credentials.Domain,
credentials.Password,
(int)logonType,
(int)logonProvider,
out this._handle);
if (!returnValue)
{
// Something went wrong.
int ret = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(ret);
}
this.impersonatedUser = WindowsIdentity.Impersonate(this._handle.DangerousGetHandle());
}
/// <summary>
/// Initializes a new instance of the Impersonation class. Provide domain, user name, and password for impersonation.
/// </summary>
/// <param name="domainName">Domain name of the impersonated user.</param>
/// <param name="userName">Name of the impersonated user.</param>
/// <param name="password">Password of the impersonated user.</param>
/// <remarks>
/// Uses the unmanaged LogonUser function to get the user token for
/// the specified user, domain, and password.
/// </remarks>
public Impersonation(string domainName, string userName, string password)
{
string[] splitName = WindowsIdentity.GetCurrent().Name.Split('\\');
string name = (splitName.Length > 0) ? splitName[0] : null;
LogonType logonType = LogonType.Interactive;
LogonProvider logonProvider = LogonProvider.Default;
if (name != domainName)
{
logonType = LogonType.NewCredentials;
logonProvider = LogonProvider.WinNT50;
}
// Call LogonUser to obtain a handle to an access token.
bool returnValue = LogonUser(
userName,
domainName,
password,
(int)logonType,
(int)logonProvider,
out this._handle);
if (!returnValue)
{
// Something went wrong.
int ret = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(ret);
}
this.impersonatedUser = WindowsIdentity.Impersonate(this._handle.DangerousGetHandle());
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(
string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
out SafeTokenHandle phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(IntPtr handle);
public void Dispose()
{
this.impersonatedUser.Dispose();
this._handle.Dispose();
}
private static string[] GetAccountInfo(string accountInfo)
{
return accountInfo.Split(' ');
}
}
public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTokenHandle()
: base(true) { }
[DllImport("kernel32.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);
protected override bool ReleaseHandle()
{
return CloseHandle(handle);
}
}
public class AccountCredentials
{
public string UserName { get; set; }
public string Password { get; set; }
public string Domain { get; set; }
}
然后您将在 using 块中执行您的模拟操作:
using(new Impersonation(new AccountCredentials("user", "password", "domain"))
{
// do impersonated actions
}
你需要在你的类中有这些 using 指令:
using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Security.Principal;
using Microsoft.Win32.SafeHandles;
using System.Runtime.ConstrainedExecution;
using System.Security;
using System.Configuration;
【讨论】:
您可以临时冒充用户:
在 c# 中,但您可以轻松将其转换为 vb
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
if (LogonUser("TempUser", Environment.MachineName,
"password", LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, SecurityImpersonation, ref tokenDuplicate) != 0)
{
m_ImpersonatedUser = new WindowsIdentity(tokenDuplicate);
m_ImpersonationContext = m_ImpersonatedUser.Impersonate();
try
{
// impersonated code here
}
catch { throw; }
finally
{
m_ImpersonationContext.Undo();
}
}
}
}
【讨论】:
感谢大家提供的信息丰富的答案......抱歉这么晚才回来......所以我现在所做的是......
导入 System.Web.Security
导入 System.Security.Principal
导入 System.Security.Permissions
导入 System.Runtime.InteropServices
导入 System.Environment
公共类重定向 继承 System.Web.UI.Page
Dim LOGON32_LOGON_INTERACTIVE As Integer = 2
Dim LOGON32_PROVIDER_DEFAULT As Integer = 0
Dim impersonationContext As WindowsImpersonationContext
Declare Function LogonUserA Lib "advapi32.dll" (ByVal lpszUsername As String, _
ByVal lpszDomain As String, _
ByVal lpszPassword As String, _
ByVal dwLogonType As Integer, _
ByVal dwLogonProvider As Integer, _
ByRef phToken As IntPtr) As Integer
Declare Auto Function DuplicateToken Lib "advapi32.dll" ( _
ByVal ExistingTokenHandle As IntPtr, _
ByVal ImpersonationLevel As Integer, _
ByRef DuplicateTokenHandle As IntPtr) As Integer
Declare Auto Function RevertToSelf Lib "advapi32.dll" () As Long
Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Long
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim redirstr As Integer
redirstr = Request.QueryString("id")
If impersonateValidUser("*username*", "*Domain*", "*Password*") Then
'Insert your code that runs under the security context of a specific user here.
Try
'Integrated Windows Authentication Site
Response.Redirect("http://<<servername>>/<app>/<<file>")
Catch ex As Exception
End Try
undoImpersonation()
Else
'Your impersonation failed. Therefore, include a fail-safe mechanism here.
'Not Integrated Windows Authentication Site
Response.Redirect("http://<<servername>>:81/<app>/<<file>?user=<<username>>&pass=<<password>>)
End If
End Sub
Private Function impersonateValidUser(ByVal userName As String, _
ByVal domain As String, ByVal password As String) As Boolean
Dim tempWindowsIdentity As WindowsIdentity
Dim token As IntPtr = IntPtr.Zero
Dim tokenDuplicate As IntPtr = IntPtr.Zero
impersonateValidUser = False
If RevertToSelf() Then
If LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, token) <> 0 Then
If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
impersonationContext = tempWindowsIdentity.Impersonate()
If Not impersonationContext Is Nothing Then
impersonateValidUser = True
End If
End If
End If
End If
If Not tokenDuplicate.Equals(IntPtr.Zero) Then
CloseHandle(tokenDuplicate)
End If
If Not token.Equals(IntPtr.Zero) Then
CloseHandle(token)
End If
End Function
Private Sub undoImpersonation()
impersonationContext.Undo()
End Sub
结束类
因此,在这种情况下,如果我的身份验证通过,理想情况下它应该将操作传递给 IWA 站点。它确实如此,但是一旦我进入 IWA 站点,它就会使用我的 Windows 凭据,而不是我试图模仿的那个。我如何做到这一点......使用我的模拟 Windows 用户凭据可以去哪里访问该站点?
【讨论】: