我正在尝试为用 Perl(或者可能是 XS 模块)编写的 Web 服务器实现 NTLM 授权。我的理解是它应该以下列方式工作:
c -> s: GET
s -> c: 401, WWW-Authenticate: NTLM
c -> s: GET, Authorization: NTLM [Type1 Message]
s -> c: 401, WWW-Authenticate: NTLM [Type2 Message]
c -> s: GET, Authorization: NTLM [Type3 Message]
IF s.Check([Type3 Message]):
s -> c: 200
ELSE:
s -> c: 401
为了生成 Type3 消息,我同时使用了Authen::Perl::NTLM和Authen::NTLM::HTTP,它们似乎都可以很好地生成消息,但是,它们没有提供检查 Type3 消息的功能。
我的下一步是尝试使用Win32::IntAuth来验证 NTLM 令牌。这是我遇到麻烦的地方,开发人员和其他搜索到的信息片段说这个模块应该能够验证 NTLM 二进制令牌。
该模块包含一些 Win32 API 调用,即 AcquireCredentialsHandle、AcceptSecurityContext、CompleteAuthToken 和 ImpersonateSecurityContext。
不幸的是,我在 AcceptSecurityContext 上对 NTLM 令牌进行身份验证的所有尝试都失败了,因为SEC_E_INVALID_TOKEN或SEC_E_INSUFFICIENT_MEMORY导致我建议我的 NTLM 令牌不正确。下面是一些代码片段来帮助展示我的方法。
# other code
...
if (not defined $headers->header('Authorization')) {
initHandshake($response);
} else {
my $authHeader = $headers->header('Authorization');
if ($authHeader =~ m/^NTLM\s(.+)$/i) {
my $message = $1;
if (length($message) == 56) {
handleType1($response, $message);
} else {
handleType3($response, $message);
}
} else {
printf "ERROR - Unable to pull out an NTLM message.\n";
print $authHeader . "\n";
}
}
...
sub handleType3 {
my $response = shift();
my $message = shift();
print "handleType3 - ", $message, "\n";
my $auth = Win32::IntAuth->new(debug => 1);
my $token = $auth->get_token_upn(decode_base64($message)) or die
"Couldn'timpersonate user, ", $auth->last_err_txt();
print "Hurrargh. User ", $auth->get_username(), " authed!\n";
$response->status(200);
}
..
完整代码可以在这里查看:http: //codepad.org/cpMWnFru