这是我设法从需要 NTLM 身份验证的 Microsoft 代理后面工作的唯一片段。此代码改编自Cosine Security,Authen::NTLM
由 Lee Man Chan使用。
#!/usr/bin/perl -w
use strict;
use LWP::UserAgent;
use Authen::NTLM;
use Authen::NTLM::HTTP;
my $url = 'http://www.google.com';
my $proxy = 'http://proxy.foobar.com:8080'; # Required
my $user = 'username'; # Required
my $pass = 'passw0rd'; # Required
my $nt_domain = 'DOMAIN'; # Optional can be blank ''
my $host_domain = 'foobar.com'; # NOT blank. At least 1 char 'x'
my $machine = 'hostname'; # Optional can be blank ''
# Creates the LWP User Agent, tells it to use the supplied proxy, and sends the
# initial HTTP GET request for the supplied URL and takes in a response
my $ua = new LWP::UserAgent(keep_alive=>1);
$ua->proxy('http', $proxy);
my $req = HTTP::Request->new(GET => $url);
# 1) code:'407', message='Proxy Authentication Required
# (Forefront TMG requires authorization to fulfill the request. Access to the
# Web Proxy filter is denied.)'
my $res = $ua->request($req);
print "1) " , $res->is_success? "It worked!->" : "It didn't work!->";
print "code:'". $res->code ."', message='". $res->message . "'\n";
# Once the initial request has been sent out, the proxy will send back an NTLM
# negotiate message
# We set up the NTLM authentication client response by passing ntlm hashes of
# the username, password, domain, and workstation hostname
my $client = new_client Authen::NTLM::HTTP(
Authen::NTLM::lm_hash($pass),
Authen::NTLM::nt_hash($pass),
Authen::NTLM::HTTP::NTLMSSP_HTTP_PROXY,
$user,
$nt_domain,
$host_domain,
$machine);
# Here we set the NTLM protocol flags that we wish to be accepted
my $negotiate_flags =
Authen::NTLM::NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
Authen::NTLM::NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED |
Authen::NTLM::NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED |
Authen::NTLM::NTLMSSP_NEGOTIATE_NTLM |
Authen::NTLM::NTLMSSP_NEGOTIATE_OEM;
# We then take the client data, and the flags and jam them into a header, and add
# it back to the original request, and resend it.
my $negotiate_msg = "Proxy-" . $client->http_negotiate($negotiate_flags);
my @pa = split(/:/,$negotiate_msg);
$req->header($pa[0] => $pa[1]);
# The proxy then sends back an NTLM challenge response, which we strip from the
# message and parse using the NTLM methods provided by the module
# 2) code:'407', message='Proxy Authentication Required ( Access is denied. )'
$res = $ua->request($req);
print "2) " , $res->is_success? "It worked!->" : "It didn't work!->";
print "code:'". $res->code ."', message='". $res->message . "'\n";
my $challenge_msg = "Proxy-Authenticate: " . $res->header("Proxy-Authenticate");
my ($domain, $flags, $nonce, $ctx_upper, $ctx_lower)
= $client->http_parse_challenge($challenge_msg);
# We set the next round of flags, take the Nonce which we gained from parsing the
# challenge message, and send back a final authentication message. Once the proxy
# recieves this, it processes the original GET request
my $auth_flags =
Authen::NTLM::NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
Authen::NTLM::NTLMSSP_NEGOTIATE_NTLM |
Authen::NTLM::NTLMSSP_REQUEST_TARGET;
my $auth_msg = $client->http_auth($nonce, $auth_flags);
@pa = split(/:/,$auth_msg);
#print STDERR "pa[0] = '$pa[0]', pa[1] = '$pa[1]'\n";
$req->header($pa[0] => $pa[1]);
# 3) code:'200', message='OK'
$res = $ua->request($req);
print "3) " , $res->is_success? "It worked!->" : "It didn't work!->";
print "code:'". $res->code ."', message='". $res->message . "'\n";
if ($res->is_success) {
print "##################################\n";
print "Success: " . $res->status_line . "\n";
print $res->headers()->as_string(), "\n";
print "##################################\n";
print $res->content;
} else {
print "Error: " . $res->status_line . "\n";
print $res->headers()->as_string(), "\n";
}
-hq