File Coverage

blib/lib/Plack/Middleware/GepokX/ModSSL.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Plack::Middleware::GepokX::ModSSL;
2              
3 1     1   22810 use 5.010;
  1         3  
  1         42  
4 1     1   5 use strict 0 qw(vars subs refs);
  1         18  
  1         43  
5              
6 1     1   5 use base 0 qw(Plack::Middleware);
  1         22  
  1         932877  
7 1     1   1916561 use Plack::Util::Accessor qw(vars);
  1         2  
  1         6  
8              
9 1     1   570 use Crypt::X509 0 qw(); # ridiculous exports
  0            
  0            
10             use DateTime 0 qw();
11             use MIME::Base64 0 qw(decode_base64);
12             use Net::SSLeay 0 qw();
13              
14             my $__use_these_too = q(
15             use Gepok 0.20 qw();
16             use Plack 0 qw();
17             );
18              
19             BEGIN {
20             $Plack::Middleware::GepokX::ModSSL::AUTHORITY = 'cpan:TOBYINK';
21             $Plack::Middleware::GepokX::ModSSL::VERSION = '0.002';
22             }
23              
24             my %PROTO = (
25             0x0002 => 'SSLv2',
26             0x0300 => 'SSLv3',
27             0x0301 => 'TLSv1',
28             0xFEFF => 'DTLSv1',
29             );
30              
31             our %KNOWN = (
32             SSL_CLIENT_VERIFY => sub {
33             my $r = Net::SSLeay::get_verify_result($_->_get_ssl_object);
34             $_->peer_certificate ? ($r==0?'SUCCESS':'FAILED') : 'NONE'
35             },
36             SSL_CLIENT_CERT => sub {
37             $_->peer_certificate ? Net::SSLeay::PEM_get_string_X509($_->peer_certificate) : ''
38             },
39             SSL_CLIENT_V_START => sub { DateTime->from_epoch(epoch => _CX(@_)->not_before)->strftime('%b %d %T %Y %Z') },
40             SSL_CLIENT_V_END => sub { DateTime->from_epoch(epoch => _CX(@_)->not_after)->strftime('%b %d %T %Y %Z') },
41             SSL_CLIENT_S_DN_CN => sub { _CX(@_)->subject_cn },
42             SSL_CLIENT_S_DN_Email => sub { _CX(@_)->subject_email },
43             SSL_CLIENT_S_DN_O => sub { _CX(@_)->subject_org },
44             SSL_CLIENT_S_DN_L => sub { _CX(@_)->subject_locality },
45             SSL_CLIENT_S_DN_ST => sub { _CX(@_)->subject_state },
46             SSL_CLIENT_S_DN_C => sub { _CX(@_)->subject_country },
47             SSL_CLIENT_I_DN_CN => sub { _CX(@_)->issuer_cn },
48             SSL_CLIENT_I_DN_Email => sub { _CX(@_)->issuer_email },
49             SSL_CLIENT_I_DN_O => sub { _CX(@_)->issuer_org },
50             SSL_CLIENT_I_DN_L => sub { _CX(@_)->issuer_locality },
51             SSL_CLIENT_I_DN_ST => sub { _CX(@_)->issuer_state },
52             SSL_CLIENT_I_DN_C => sub { _CX(@_)->issuer_country },
53             SSL_CLIENT_M_SERIAL => sub { _CX(@_)->serial },
54             SSL_CLIENT_M_VERSION => sub { _CX(@_)->version },
55             SSL_CIPHER => sub { $_->get_cipher },
56             SSL_CIPHER_USEKEYSIZE => sub { Net::SSLeay::get_cipher_bits($_->_get_ssl_object) },
57             SSL_PROTOCOL => sub { my $p = Net::SSLeay::version($_->_get_ssl_object); $PROTO{$p} // $p },
58             SSL_CLIENT_I_DN => sub {
59             my $cx = _CX(@_);
60             sprintf(
61             '/C=%s/ST=%s/L=%s/O=%s/CN=%s/emailAddress=%s',
62             $cx->issuer_country,
63             $cx->issuer_state,
64             $cx->issuer_locality,
65             $cx->issuer_org,
66             $cx->issuer_cn,
67             $cx->issuer_email,
68             );
69             },
70             SSL_CLIENT_S_DN => sub {
71             my $cx = _CX(@_);
72             sprintf(
73             '/C=%s/ST=%s/L=%s/O=%s/CN=%s/emailAddress=%s',
74             $cx->subject_country,
75             $cx->subject_state,
76             $cx->subject_locality,
77             $cx->subject_org,
78             $cx->subject_cn,
79             $cx->subject_email,
80             );
81             },
82             );
83              
84             sub all
85             {
86             return keys %KNOWN;
87             }
88              
89             sub _CX
90             {
91             my ($self, $env) = @_;
92             $env->{_CRYPTX509_} //=
93             Crypt::X509->new(
94             cert => decode_base64(do {
95             local $_ = $env->{'gepok.socket'};
96             my $pem = $KNOWN{SSL_CLIENT_CERT}->($self, $env);
97             $pem =~ s/-----([^-]+?)-----//g;
98             $pem;
99             })
100             );
101             return $env->{_CRYPTX509_};
102             }
103              
104             sub call
105             {
106             my ($self, $env) = @_;
107            
108             if ($env->{HTTPS} and exists $env->{'gepok.socket'})
109             {
110             for my $var (@{ $self->vars // [] })
111             {
112             die "unknown var: $var" unless $KNOWN{$var};
113             local $_ = $env->{'gepok.socket'};
114             $env->{$var} //= $KNOWN{$var}->($self, $env);
115             }
116             }
117            
118             delete $env->{_CRYPTX509_};
119             $self->app->($env);
120             }
121              
122             __PACKAGE__
123             __END__