我正在尝试使用C#为WMS 2009创建自定义身份验证插件。
我设法实现某些因某些原因阻止所有请求的东西......
[ComVisible(true)]
[Guid("C0A0B38C-C4FE-43B5-BE9E-C100A83BBCEE")]
public class AuthenticationPlugin : IWMSBasicPlugin, IWMSAuthenticationPlugin, IWMSAuthenticationContext
private const string SubKey = "SOFTWARE\\Microsoft\\Windows Media\\Server\\RegisteredPlugins\\Authentication\\{C0A0B38C-C4FE-43B5-BE9E-C100A83BBCEE}";
[ComRegisterFunction]
public static void RegisterFunction(Type t)
{
try
{
RegistryKey regHKLM = Registry.LocalMachine;
regHKLM = regHKLM.CreateSubKey(SubKey);
regHKLM.SetValue(null, "UC WMS Authentication plugin");
RegistryKey regHKCR = Registry.ClassesRoot;
regHKCR = regHKCR.CreateSubKey("CLSID\\{C0A0B38C-C4FE-43B5-BE9E-C100A83BBCEE}\\Properties");
regHKCR.SetValue("Name", CustomC WMS Authentication plugin");
regHKCR.SetValue("Author", "Me");
regHKCR.SetValue("CopyRight", "Copyright 2009. All rights reserved");
regHKCR.SetValue("Description", "Enables custom WMS authentication");
}
catch (Exception error)
{
Console.WriteLine(error.Message, "Inside RegisterFunction(). Cannot Register.");
}
}
[ComUnregisterFunction]
public static void UnRegisterFunction(Type t)
{
try
{
RegistryKey regHKLM = Registry.LocalMachine;
regHKLM.DeleteSubKey(SubKey);
RegistryKey regHKCR = Registry.ClassesRoot;
regHKCR.DeleteSubKeyTree("CLSID\\{C0A0B38C-C4FE-43B5-BE9E-C100A83BBCEE}");
regHKCR.DeleteSubKeyTree("CSEventTest.CSEventPlugin");
}
catch (Exception error)
{
Console.WriteLine(error.Message, "Cannot delete a subkey.");
}
}
#region IWMSBasicPlugin Members
public void InitializePlugin(IWMSContext serverContext, WMSNamedValues namedValues, IWMSClassObject classFactory)
{
}
public void ShutdownPlugin()
{
}
public void EnablePlugin(ref int flags, ref int heartbeatPeriod)
{
}
public void DisablePlugin()
{
}
public object GetCustomAdminInterface()
{
return null;
}
public void OnHeartbeat()
{
}
#endregion
#region IWMSAuthenticationPlugin Members
public IWMSAuthenticationContext CreateAuthenticationContext()
{
return (IWMSAuthenticationContext)this;
}
public int GetFlags()
{
return Convert.ToInt32(WMS_AUTHENTICATION_FLAGS.WMS_AUTHENTICATION_ANONYMOUS, CultureInfo.InvariantCulture);
}
public string GetPackageName()
{
return "Custom WMS Authentication";
}
public string GetProtocolName()
{
return "Basic";
}
#endregion
#region IWMSAuthenticationContext Members
public void Authenticate(object responseBlob, IWMSContext userContext, IWMSContext presentationContext, IWMSCommandContext commandContext, IWMSAuthenticationCallback callBack, object context)
{
callBack.OnAuthenticateComplete(WMS_AUTHENTICATION_RESULT.WMS_AUTHENTICATION_SUCCESS, null, context);
}
public IWMSAuthenticationPlugin GetAuthenticationPlugin()
{
return (IWMSAuthenticationPlugin)this;
}
public string GetImpersonationAccountName()
{
return String.Empty;
}
public int GetImpersonationToken()
{
return 0;
}
public string GetLogicalUserID()
{
return this.GetImpersonationAccountName();
}
#endregion
}
有谁能发现为什么会这样?
另外,有什么方法可以查看已安装在服务器上的标准匿名身份验证插件的代码吗?它是在某个地方组装吗?
感谢。
答案 0 :(得分:0)
我遇到了同样的问题。仅从Authenticate方法返回成功状态是不够的。
您实现的方法必须检索有效Windows登录的句柄。在网上搜索如何调用此方法的C#示例:http://msdn.microsoft.com/en-us/library/aa378184%28VS.85%29.aspx
bool result = LogonAPI.LogonUser("username", "domain", "password", LogonAPI.LOGON32_LOGON_NETWORK, LogonAPI.LOGON32_PROVIDER_DEFAULT, ref _userToken);
存储从LogonUser调用中返回的IntPtr并实现GetImpersonationToken方法,如下所示:
public int GetImpersonationToken()
{
return _userToken.ToInt32();
}
不知何故,该插件能够将该整数值绑定回真正的Windows帐户。我在Power Users组中的服务器上创建了一个本地帐户,并在LogonUser方法中使用其用户名和密码,服务器是域。一旦能够这样做,媒体就应该流式传输。
我的整个IWMSAuthenticationPlugin如下(它使用基本身份验证):
public class AuthenticationContext : IWMSAuthenticationContext
{
#region IWMSAuthenticationContext Members
private WMS_AUTHENTICATION_RESULT _result;
private readonly IWMSAuthenticationPlugin _plugin;
private Credentials _credentials;
private IntPtr _userToken;
public AuthenticationContext(IWMSAuthenticationPlugin plugin)
{
_plugin = plugin;
}
public void Authenticate(object responseBlob, IWMSContext pUserCtx, IWMSContext pPresentationCtx, IWMSCommandContext pCommandContext, IWMSAuthenticationCallback pCallback, object context)
{
// must be Unicode. If it isn't, the
// challenge isn't sent correctly
Encoding enc = Encoding.Unicode;
byte[] response;
byte[] challenge = enc.GetBytes("");
try
{
response = (byte[])responseBlob;
if (response.Length == 0)
{
// The client requested authentication; prepare the
// challenge response to send to the client. In order to
// do Basic authentication, be sure to return "Basic" from
// your implementation of IWMSAuthenticationPlugin.GetProtocolName()
string challengeTxt = "WWW-Authenticate: Basic realm=\"Domain\"";
challenge = enc.GetBytes(challengeTxt);
_result = WMS_AUTHENTICATION_RESULT.WMS_AUTHENTICATION_CONTINUE;
}
else
{
// parses Base64 encoded response and gets passed in credentials
SetCredentials(enc.GetString(response));
LdapConnection ldc = new LdapConnection("Domain");
NetworkCredential nc = new NetworkCredential(_credentials.Username, _credentials.Password, "Domain");
ldc.Credential = nc;
ldc.AuthType = AuthType.Negotiate;
ldc.Bind(nc); // user has authenticated at this point, as the credentials were used to login to the dc.
// must log in with a local windows account and get a handle for the account.
// even if success is returned, the plugin still needs a valid windows account
// to stream the file.
bool result = LogonAPI.LogonUser("local username", "local domain", "local password", LogonAPI.LOGON32_LOGON_NETWORK, LogonAPI.LOGON32_PROVIDER_DEFAULT, ref _userToken);
_result = WMS_AUTHENTICATION_RESULT.WMS_AUTHENTICATION_SUCCESS;
}
}
catch (LdapException e)
{
_result = WMS_AUTHENTICATION_RESULT.WMS_AUTHENTICATION_DENIED;
}
catch (Exception e)
{
_result = WMS_AUTHENTICATION_RESULT.WMS_AUTHENTICATION_ERROR;
}
finally
{
pCallback.OnAuthenticateComplete(_result, challenge, context);
}
}
public IWMSAuthenticationPlugin GetAuthenticationPlugin()
{
return _plugin;
}
public string GetImpersonationAccountName()
{
return "Domain\\" + _credentials.Username;
}
public int GetImpersonationToken()
{
// somehow the plugin knows how this integer ties to a windows account.
return _userToken.ToInt32();
}
public string GetLogicalUserID()
{
return GetImpersonationAccountName();
}
public void SetCredentials(string responseStr)
{
// for whatever reason, the responseStr has an extra character
// tacked on the end that blows up the conversion. When converting
// from the Base64 string, remove that last character.
string decoded = new UTF8Encoding().GetString(Convert.FromBase64String(responseStr.Substring(0, responseStr.Length - 1)));
// now that the string has been decoded and is now in the format
// username:password, parse it further into a Username and Password
// struct.
_credentials = new Credentials(decoded);
}
#endregion
}