首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Perl中的NTLM授权

Perl中的NTLM授权
EN

Stack Overflow用户
提问于 2014-03-06 12:45:28
回答 1查看 695关注 0票数 6

我正在尝试为用Perl编写的web服务器(或者可能是XS模块)实现NTLM授权。我的理解是,它应以下列方式运作:

代码语言:javascript
复制
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::NTLMAuthen::NTLM::HTTP,这两种方法似乎都能很好地生成消息,但是,它们没有提供检查Type3消息的功能。

下一步是尝试使用Win32 32::IntAuth对NTLM令牌进行身份验证。这个是我遇到麻烦的地方,开发人员和其他搜索到的信息片段说,这个模块应该能够对NTLM二进制令牌进行身份验证。

该模块包含一些Win32 API调用,即AcquireCredntialsHandle、AcceptSecurityContext、CompleteAuthToken和ImpersonateSecurityContext。

不幸的是,我对NTLM令牌进行身份验证的所有尝试在SEC_E_INVALID_TOKENSEC_E_INSUFFICIENT_MEMORY上都失败了,这导致我认为NTLM令牌是不正确的。下面是一些帮助展示我的方法的代码片段。

代码语言:javascript
复制
# 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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-05-08 17:25:22

我设法通过对Win32 32::IntAuth(我认为它中有一个bug )进行私用来实现这个功能。本质上,我没有保存在创建Type 2令牌期间创建的部分上下文,这和Win32 32::IntAuth中有一个错误的事实:

代码语言:javascript
复制
my $buf_size     = 4096;
my $sec_inbuf    = pack("L L P$buf_size", $buf_size, SECBUFFER_TOKEN, $token);

这导致令牌错误,因为它不是令牌的正确长度,因此:

代码语言:javascript
复制
my $sec_inbuf    = pack("L L P" . length($token), length($token), SECBUFFER_TOKEN, $token);

得出了正确的结果。

以前的代码更改为:

代码语言:javascript
复制
...
sub handleType1 {
    my $response = shift();
    my $message = shift();                               
    print "handleType1 - |", ${$message}, "|\n";
    my $challenge = acceptSecurityContext(${$message});
    ${$response}->status(401);
    ${$response}->header("WWW-Authenticate" => "NTLM " . $challenge);
}
...
sub handleType3 {
    my $response = shift();               
    my $message = shift();
    print "handleType3 - ", ${$message}, "\n";
    if (acceptSecurityContext(${$message})) {
        ${$response}->status(200);
    } else {
        ${$response}->status(401);
    }
}
...

acceptSecurityContext是一个函数,它遵循这个伪代码:

代码语言:javascript
复制
credentials = Win32->AcquireCredentialsHandle(...)
challenge = Win32->AcceptSecurityContext(credentials, token, globalCtx ? globalCtx : 0, ...)

希望这能帮助那些可能在类似船上的人。请随时联系我的完整演示。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22224975

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档