Skip to content

Instantly share code, notes, and snippets.

@tadegenban
Created March 12, 2016 14:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tadegenban/25a89fe9576e8e0741f3 to your computer and use it in GitHub Desktop.
Save tadegenban/25a89fe9576e8e0741f3 to your computer and use it in GitHub Desktop.
---- Mojo::UserAgent::NTLMAuth
package Mojo::UserAgent::NTLMAuth;
use Mojo::Base 'Exporter';
use Mojo::UserAgent;
use Authen::NTLM;
use XXX -with => 'Data::Dumper';
use constant DEBUG => $ENV{MOJO_USERAGENT_NTLM_AUTH_DEBUG} || 0;
our $VERSION = '0.01';
our @EXPORT = qw( $_request_with_digest_auth );
my $NC = 0;
our $_request_with_digest_auth = sub {
my $cb = ref $_[-1] eq 'CODE' ? pop : undef;
my $ua = shift;
my @args = @_;
my $tx = $ua->build_tx(@args);
my $auth = {};
@$auth{qw(username password)} = split ':', $tx->req->url->userinfo || '';
$tx->req->url($tx->req->url->clone)->url->userinfo(undef);
warn "[NTLMAuth] url=@{[$tx->req->url]}\n" if DEBUG;
my $build_next = sub {
my $tx = shift;
my $code = $tx->res->code || '';
warn "[NTLMAuth] code=$code\n" if DEBUG;
return $tx
unless 3 == grep { defined $_ } @$auth{qw(username password)}, $tx->res->headers->header('WWW-Authenticate');
return $tx unless $tx->res->headers->header('WWW-Authenticate') eq 'NTLM';
warn "[NTLMAuth] NTLM authorization ... first phase, send handshake\n" if DEBUG;
ntlm_user($auth->{username});
ntlm_password($auth->{password});
ntlm_domain('');
my $next_tx = ($ua->build_tx(@args));
$next_tx->req->headers->authorization(sprintf 'NTLM %s', ntlm());
$next_tx->req->headers->accept('*/*');
#WWW $ua->{connections};
$ua->start($next_tx);
#WWW $ua->{connections};
my $challenge = $next_tx->res->headers->header('WWW-Authenticate');
$challenge =~ s/NTLM //;
warn "[NTLMAuth] NTLM authorization ... second phase, challenge\n" if DEBUG;
$next_tx->req->headers->authorization(sprintf 'NTLM %s', ntlm($challenge));
$next_tx->req->headers->accept('*/*');
$next_tx;
};
# non-blocking
if ($cb) {
Mojo::IOLoop->delay(
sub { $ua->start($tx, shift->begin) },
sub {
my ($delay, $tx) = @_;
my $next_tx = $build_next->($tx);
return $ua->$cb($tx) if $next_tx eq $tx;
return $ua->start($next_tx, $delay->begin);
},
sub { $ua->$cb($_[1]) },
);
return $ua;
}
# blocking
my $next_tx = $build_next->($ua->start($tx));
return $tx if $next_tx eq $tx;
return $ua->start($next_tx);
};
--- app code
use strict; use warnings;use 5.020;
use Mojo::UserAgent::NTLMAuth;
use Mojo::UserAgent;
use Data::Dumper;
my $ua = Mojo::UserAgent->new;
my $tx = $ua->$_request_with_digest_auth(get => 'http://username:password@internal-site', {Connection => 'keep-alive'} );
---- log
[NTLMAuth] url=http://internal-site
-- Blocking request (http://internal-site)
-- Connect 31f25d0d84394242a58fdb78d66f5429 (http://internal-site:80)
-- Client >>> Server (http://internal-site)
GET / HTTP/1.1
User-Agent: Mojolicious (Perl)
Connection: keep-alive
Content-Length: 0
Accept-Encoding: gzip
Host: internal-site
-- Client <<< Server (http://internal-site)
HTTP/1.1 401 Unauthorized
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/8.5
SPRequestGuid: 0dd6679d-4465-b088-15c1-8d9f6f445f24
request-id: 0dd6679d-4465-b088-15c1-8d9f6f445f24
X-FRAME-OPTIONS: SAMEORIGIN
SPRequestDuration: 3
SPIisLatency: 0
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 15.0.0.4687
X-Content-Type-Options: nosniff
X-MS-InvokeApp: 1; RequireReadOnly
Date: Sat, 12 Mar 2016 14:21:22 GMT
Content-Length: 16
X-RBT-Optimized-By: cn42-riverbed (RiOS 8.6.2d) GR
401 UNAUTHORIZED
[NTLMAuth] code=401
[NTLMAuth] NTLM authorization ... first phase, send handshake
-- Blocking request (http://username:password@internal-site)
-- Connect 593617e297fcf86a03e9a457f36cf843 (http://internal-site:80)
-- Client >>> Server (http://username:password@internal-site)
GET / HTTP/1.1
Accept-Encoding: gzip
Host: internal-site
Content-Length: 0
Connection: keep-alive
Accept: */*
User-Agent: Mojolicious (Perl)
Authorization: NTLM TlRMTVNTUAABAAAAB6IAAAcABwAgAAAAAAAAAAcAAAB5YW5jaGVu
-- Client <<< Server (http://username:password@internal-site)
HTTP/1.1 401 Unauthorized
Server: Microsoft-IIS/8.5
WWW-Authenticate: NTLM TlRMTVNTUAACAAAAEAAQADgAAAAFgoEC80nEY8n0+iUAAAAAAAAAAOIA4gBIAAAABgOAJQAAAA9TAFkATgBPAFAAUwBZAFMAAgAQAFMAWQBOAE8AUABTAFkAUwABABoAVQBTADAAMgBWAFcAUwBQADEAMwBGAEUAMgAEACoAaQBuAHQAZQByAG4AYQBsAC4AcwB5AG4AbwBwAHMAeQBzAC4AYwBvAG0AAwBGAHUAcwAwADIAdgB3AHMAcAAxADMAZgBlADIALgBpAG4AdABlAHIAbgBhAGwALgBzAHkAbgBvAHAAcwB5AHMALgBjAG8AbQAFACQAcwB5AG4AbwBwAHMAeQBzAGYAbwByAGUAcwB0AC4AYwBvAG0ABwAIAISqYIpqfNEBAAAAAA==
SPRequestGuid: 16d6679d-a476-b088-15c1-82cfdbaf6372
request-id: 16d6679d-a476-b088-15c1-82cfdbaf6372
X-FRAME-OPTIONS: SAMEORIGIN
SPRequestDuration: 1
SPIisLatency: 0
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 15.0.0.4687
X-Content-Type-Options: nosniff
X-MS-InvokeApp: 1; RequireReadOnly
Date: Sat, 12 Mar 2016 14:21:59 GMT
Content-Length: 0
[NTLMAuth] NTLM authorization ... second phase, challenge
-- Blocking request (http://username:password@internal-site)
-- Reusing connection 593617e297fcf86a03e9a457f36cf843 (http://internal-site:80)
Can't call method "stream" on an undefined value at /remote/cn42home1/jasanj/perl5/perlbrew/perls/perl-5.20.3/lib/site_perl/5.20.3/Mojo/UserAgent.pm line 156.
Use of uninitialized value $loop in hash element at /remote/cn42home1/jasanj/perl5/perlbrew/perls/perl-5.20.3/lib/site_perl/5.20.3/Mojo/UserAgent.pm line 198.
(in cleanup) Can't call method "remove" on an undefined value at /remote/cn42home1/jasanj/perl5/perlbrew/perls/perl-5.20.3/lib/site_perl/5.20.3/Mojo/UserAgent.pm line 271.
@mavit
Copy link

mavit commented Aug 11, 2016

I came here from http://irclog.perlgeek.de/mojo/2016-03-12#i_12173382. Did you get this working, in the end? Do you have any plans to release Mojo::UserAgent::NTLMAuth in any form? Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment