File Coverage

lib/Mojolicious/Plugin/SPNEGO.pm
Criterion Covered Total %
statement 12 68 17.6
branch 0 42 0.0
condition 0 25 0.0
subroutine 4 6 66.6
pod 1 1 100.0
total 17 142 11.9


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::SPNEGO;
2 1     1   1008 use Mojo::Base 'Mojolicious::Plugin';
  1         164125  
  1         7  
3 1     1   1294 use Net::LDAP::SPNEGO;
  1         153786  
  1         10  
4 1     1   479 use IO::Socket::Timeout;
  1         3672  
  1         6  
5 1     1   28 use Mojo::Util qw(b64_decode);
  1         3  
  1         950  
6             our $VERSION = '0.5.2';
7              
8             my %cCache;
9              
10             sub register {
11 0     0 1   my $self = shift;
12 0           my $app = shift;
13 0           my $plugin_cfg = shift;
14              
15             $app->helper(
16             ntlm_auth => sub {
17 0     0     my $c = shift;
18 0 0         my $helper_cfg = ref ${_}[0] eq 'HASH' ? ${_}[0] : { @_ };
19 0           my $cfg = { %$plugin_cfg, %$helper_cfg };
20 0           my $cId = $c->tx->connection;
21              
22 0 0 0       my $authorization = $c->req->headers->header(($cfg->{web_proxy_mode} ? 'Proxy-' : '' ) .'Authorization') // '';
23 0           my ($AuthBase64) = ($authorization =~ /^NTLM\s(.+)$/);
24             # $c->app->log->debug("AuthBase64: $AuthBase64") if $AuthBase64;
25              
26 0 0 0       my $cCache = $cCache{$cId} //= {
27             status => $AuthBase64 ? 'expectType1' : 'init'
28             };
29 0 0         return 1 if $cCache->{status} eq 'authenticated';
30              
31 0           my ($status) = ($cCache->{status} =~ /^expect(Type[13])/);
32             # $c->app->log->debug("status: $status") if $status;
33              
34 0 0 0       if ($AuthBase64 and $status){
35 0           for ($status){
36 0   0       my $timeout = $cfg->{timeout} // 10;
37             my $ldap = $cCache->{ldapObj} //= Net::LDAP::SPNEGO->new(
38             $cfg->{ad_server},
39             debug=>($cfg->{ldap_debug}//$ENV{SPNEGO_LDAP_DEBUG}//0),
40 0           onerror=> sub { my $msg = shift;
41 0           $c->log->error("LDAP ERROR: " . $msg->error);
42 0           return $msg
43             },
44             timeout=>$timeout,
45 0 0 0       verify => $cfg->{verify} // 'none'
      0        
      0        
      0        
46             ) or return 0;
47 0 0         if ($ldap->uri !~ m{^ldaps://}){
48 0           my $msg;
49 0 0         if ($cfg->{verify}){
    0          
50 0           $msg = $ldap->start_tls(verify => $cfg->{verify});
51             }
52             elsif ($cfg->{start_tls}){
53 0           $msg = $ldap->start_tls($cfg->{start_tls});
54             }
55 0 0 0       if ($msg and $msg->is_error()){
56 0           $c->log->error($msg->error);
57 0           return 0;
58             }
59             }
60             # Read/Write timeouts via setsockopt
61 0           my $socket = $ldap->socket(sasl_layer=>0);
62 0           IO::Socket::Timeout->enable_timeouts_on($socket);
63 0           $socket->read_timeout($timeout);
64 0           $socket->write_timeout($timeout);
65 0 0         /^Type1/ && do {
66 0           $c->app->log->debug("Bind Type1 ...");
67 0           my $mesg = $ldap->bind_type1($AuthBase64);
68 0 0         if ($mesg->{ntlm_type2_base64}){
69 0 0         $c->res->headers->header( ($cfg->{web_proxy_mode} ? 'Proxy' : 'WWW' ) . '-Authenticate' => 'NTLM '.$mesg->{ntlm_type2_base64});
70 0 0         $c->render( text => 'Waiting for Type3 NTLM Token', status => $cfg->{web_proxy_mode} ? 407 : 401);
71 0           $cCache->{status} = 'expectType3';
72 0           return 0;
73             }
74             # lets try with a new connection
75 0           $ldap->unbind;
76 0           delete $cCache->{ldapObj};
77             };
78 0 0         /^Type3/ && do {
79 0           $c->app->log->debug("Bind Type3 as user '".$ldap->_get_user_from_ntlm_type3(b64_decode($AuthBase64))."'");
80 0           my $mesg = $ldap->bind_type3($AuthBase64);
81 0 0         if (my $user = $mesg->{ldap_user_entry}){
82 0 0         if (my $cb = $cfg->{auth_success_cb}){
83 0 0 0       if (not $cb or $cb->($c,$user,$ldap)){
84 0           $cCache->{status} = 'authenticated';
85             }
86             }
87             }
88 0           $ldap->unbind;
89 0           delete $cCache->{ldapObj};
90 0 0         return 1 if $cCache->{status} eq 'authenticated';
91             };
92             }
93             }
94 0 0         $c->res->headers->header( ($cfg->{web_proxy_mode} ? 'Proxy' : 'WWW') . '-Authenticate' => 'NTLM' );
95 0 0         $c->render( text => 'Waiting for Type 1 NTLM Token', status => $cfg->{web_proxy_mode} ? 407 : 401 );
96 0           $cCache->{status} = 'expectType1';
97 0           return 0;
98             }
99 0           );
100             }
101              
102             1;
103              
104             __END__