File Coverage

blib/lib/Plack/Middleware/ClientCert.pm
Criterion Covered Total %
statement 33 35 94.2
branch 5 6 83.3
condition 3 7 42.8
subroutine 5 5 100.0
pod 1 2 50.0
total 47 55 85.4


line stmt bran cond sub pod time code
1             package Plack::Middleware::ClientCert;
2 3     3   1369 use strict;
  3         13  
  3         69  
3 3     3   14 use warnings;
  3         3  
  3         70  
4              
5 3     3   1045 use parent qw(Plack::Middleware);
  3         705  
  3         13  
6              
7             our $VERSION = '0.100';
8              
9             sub client_cert
10             {
11 3     3 0 5 my ($env) = @_;
12 3         8 my %cert = ();
13 3         5 my $prefix = 'client_';
14              
15 3         5 my $ssl_env = "SSL_CLIENT_S_DN";
16              
17 3   50     14 my $dn = $env->{ CERT_SUBJECT } || $env->{ $ssl_env } || '';
18              
19             #
20             # If headers are passed in by a proxy, they are prefixed by HTTP_
21             #
22 3 50 33     11 if (!$dn && $env->{ "HTTP_$ssl_env" }) {
23 0         0 $ssl_env = "HTTP_$ssl_env";
24 0         0 $dn = $env->{ $ssl_env };
25             }
26              
27             #
28             # Apache on Linux does the parsing for us. The parts to the DN are
29             # all in SSL_CLIENT_S_DN_xx
30             #
31 3         5 my @keys = grep s/^${ssl_env}_(.*)/$1/, (keys %{ $env });
  3         64  
32 3 100       17 if (@keys) {
    100          
33 1         3 for my $key (@keys) {
34 4         13 $env->{ $prefix . lc( $key ) } = $env->{ "${ssl_env}_${key}" };
35             }
36             }
37             #
38             # The DN can be delimited by commas or slashes (/). Assume commas unless
39             # the very first character is a slash.
40             #
41             elsif ($dn =~ /^\//) {
42             # Iterate through the DN while there are still 'field=value' pairs
43 1         5 while ($dn =~ /=/) {
44             #
45             # Match the leading slash, then the field name, equals sign,
46             # and value. Finally, match the next slash seperator or the
47             # end of the line.
48             #
49 4         20 $dn =~ s/^\/(.*?)=(.*?)(\/|$)/$3/;
50 4         18 $env->{ $prefix . lc( $1 ) } = $2;
51             }
52             }
53             else {
54             # Iterate through the DN while there are still 'field=value' pairs
55 1         5 while ($dn =~ /=/) {
56             #
57             # The first match is the field. Then match 0 or 1 quotation mark(s).
58             # The third match is the value. Match the closed quote (or nothing).
59             # Finally, match the comma seperator and blank space, or the end
60             #
61 4         22 $dn =~ s/^(.*?)=(\"*)(.*?)\2(,\s*|$)//;
62 4         17 $env->{ $prefix . lc( $1 ) } = $3;
63             }
64             }
65              
66             # Add serial number if appropriate
67 3         6 my $serial_key = $ssl_env;
68 3         11 $serial_key =~ s/S_DN/M_SERIAL/;
69              
70 3   50     19 $env->{ "${prefix}serial" } = $env->{ $serial_key } || '';
71              
72 3         6 return;
73              
74             } # End of client_cert()
75              
76             sub call {
77 3     3 1 1988 my($self, $env) = @_;
78              
79 3         11 client_cert( $env );
80              
81 3         18 return $self->app->($env);
82             }
83              
84             1;
85              
86             __END__