File Coverage

blib/lib/Connector/Role/SSLUserAgent.pm
Criterion Covered Total %
statement 26 59 44.0
branch 10 42 23.8
condition 0 3 0.0
subroutine 4 5 80.0
pod n/a
total 40 109 36.7


line stmt bran cond sub pod time code
1             package Connector::Role::SSLUserAgent;
2 1     1   1442 use Moose::Role;
  1         5772  
  1         5  
3 1     1   5931 use Data::Dumper;
  1         8  
  1         67  
4 1     1   881 use LWP::UserAgent;
  1         51081  
  1         792  
5              
6             has timeout => (
7             is => 'rw',
8             isa => 'Int',
9             required => 0,
10             default => 10,
11             );
12              
13             has proxy => (
14             is => 'rw',
15             isa => 'Str',
16             required => 0,
17             );
18              
19             has agent => (
20             is => 'rw',
21             isa => 'Object',
22             lazy => 1,
23             builder => '_init_agent',
24             );
25            
26             has use_net_ssl => (
27             is => 'rw',
28             isa => 'Bool',
29             default => 0,
30             );
31              
32             has ssl_ignore_hostname => (
33             is => 'rw',
34             isa => 'Bool',
35             default => 0,
36             );
37              
38             has ssl_ignore_mode => (
39             is => 'rw',
40             isa => 'Bool',
41             default => 0,
42             );
43              
44             has certificate_file => (
45             is => 'rw',
46             isa => 'Str',
47             );
48              
49             has certificate_key_file => (
50             is => 'rw',
51             isa => 'Str',
52             );
53              
54             has certificate_p12_file => (
55             is => 'rw',
56             isa => 'Str',
57             );
58              
59             has certificate_key_password => (
60             is => 'rw',
61             isa => 'Str',
62             );
63              
64             has ca_certificate_path => (
65             is => 'rw',
66             isa => 'Str',
67             );
68              
69             has ca_certificate_file => (
70             is => 'rw',
71             isa => 'Str',
72             );
73              
74             sub _init_agent {
75              
76 1     1   3 my $self = shift;
77              
78 1         30 my %ENV_BACKUP = %ENV;
79              
80 1         22 my $ua = LWP::UserAgent->new;
81 1         3262 $ua->timeout( $self->timeout() );
82 1 50       51 if ($self->proxy()) {
83 0         0 $ua->proxy(['http', 'https'], $self->proxy());
84             }
85              
86             # Force usage of net::ssl
87 1 50       31 if ($self->use_net_ssl()) {
    50          
88 0         0 require Net::SSL;
89 0         0 $ENV{PERL_NET_HTTPS_SSL_SOCKET_CLASS} = "Net::SSL";
90              
91 0 0       0 if ($self->certificate_p12_file) {
92 0         0 $ENV{HTTPS_PKCS12_FILE} = $self->certificate_p12_file;
93              
94 0 0 0     0 if ($self->certificate_key_file || $self->certificate_file) {
95 0         0 die "Options certificate_file/certificate_key_file and certificate_p12_file are mutually exclusive";
96             }
97              
98 0 0       0 if ($self->certificate_key_password) {
99 0         0 $ENV{HTTPS_PKCS12_PASSWORD} = $self->certificate_key_password;
100             }
101             }
102              
103 0 0       0 if ($self->certificate_key_file) {
    0          
104 0 0       0 if ($self->certificate_key_password) {
105 0         0 die "Net::SSL does not support password protected keys - use certificate_p12_file instead";
106             }
107              
108 0 0       0 if (!$self->certificate_file) {
109 0         0 die "You need to pass certificate AND key file, use certificate_p12_file to pass a PKCS12";
110             }
111              
112 0         0 $ENV{HTTPS_KEY_FILE} = $self->certificate_key_file;
113 0         0 $ENV{HTTPS_CERT_FILE} = $self->certificate_file;
114              
115             } elsif ($self->certificate_file) {
116 0         0 die "You need to pass certificate AND key file, use certificate_p12_file to pass a PKCS12";
117             }
118              
119 0 0       0 if ($self->ca_certificate_path) {
120 0         0 $ENV{HTTPS_CA_DIR} = $self->ca_certificate_path;
121             }
122              
123 0 0       0 if ($self->ca_certificate_file) {
124 0         0 $ENV{HTTPS_CA_FILE} = $self->ca_certificate_file;
125             }
126              
127 0         0 $self->log()->trace('Using Net::SSL, EVN is' . Dumper $ENV);
128              
129             } # end of Net:SSL, IO::Socket::SSL
130             elsif( $self->LOCATION() =~ /^https:/i ) {
131              
132 1         929 require IO::Socket::SSL;
133 1         69328 $ENV{PERL_NET_HTTPS_SSL_SOCKET_CLASS} = "IO::Socket::SSL";
134              
135 1 50       54 my $ssl_opts = {
    50          
136             verify_hostname => ($self->ssl_ignore_hostname ? 0 : 1),
137             SSL_verify_mode => ($self->ssl_ignore_mode ? 0 : 1)
138             };
139 1 50       111 if ($self->certificate_p12_file) {
140 0         0 die "Using pkcs12 containers is not supported by IO::Socket::SSL"
141             }
142              
143 1 50       46 if ($self->certificate_key_file) {
    50          
144 0 0       0 if (!$self->certificate_file) {
145 0         0 die "You need to pass certificate AND key file";
146             }
147 0         0 $ssl_opts->{SSL_key_file} = $self->certificate_key_file;
148 0         0 $ssl_opts->{SSL_cert_file} = $self->certificate_file;
149              
150 0 0       0 if ( $self->certificate_key_password ) {
151 0     0   0 $ssl_opts->{SSL_passwd_cb} = sub { return $self->certificate_key_password; };
  0         0  
152             }
153              
154             } elsif ($self->certificate_file) {
155 0         0 die "You need to pass certificate AND key file";
156             }
157              
158 1 50       34 if ($self->ca_certificate_path) {
159 0         0 $ssl_opts->{SSL_ca_path} = $self->ca_certificate_path;
160             }
161              
162 1 50       32 if ($self->ca_certificate_file) {
163 0         0 $ssl_opts->{SSL_ca_file} = $self->ca_certificate_file;
164             }
165              
166 1         3 $ua->ssl_opts( %{$ssl_opts} );
  1         58  
167              
168 1         93 $self->log()->trace('Using IO::Socket::SSL with options ' . Dumper $ssl_opts);
169             } else {
170             # No ssl
171             }
172              
173 1         176 return $ua;
174             }
175              
176             1;
177              
178             __END__;
179              
180             =head1 Connector::Role::SSLUserAgent
181              
182             Setup the HTTP UserAgent object with connection and SSL parameters.
183              
184             =head2 LWP options
185              
186             =over
187              
188             =item timeout
189              
190             Timeout for the connection in seconds, default is 10.
191              
192             =item proxy
193              
194             URL of a proxy to use, must include protocol and port,
195             e.g. https://proxy.intranet.company.com:8080/
196              
197             =back
198              
199             =head2 SSL support
200              
201             This connector supports client authentication using certificates.
202              
203             =over
204              
205             =item use_net_ssl
206              
207             Set this to a true value to use Net::SSL as backend library (otherwise
208             IO::Socket::SSL is used). Be aware the Net::SSL does not check the hostname
209             of the server certificate so Man-in-the-Middle-Attacks might be possible.
210             You should use this only with a really good reason or if you need support
211             for PKCS12 containers.
212              
213             =item ssl_ignore_hostname
214              
215             Do not validate the hostname of the server certificate (only useful with
216             IO::Socket::SSL as Net::SSL does not check the hostname at all).
217              
218             =item certificate_file
219              
220             Path to a PEM encoded certificate file.
221              
222             =item certificate_key_file
223              
224             Path to a PEM encoded key file.
225              
226             =item certificate_p12_file
227              
228             Path to a PKCS12 container file. This is only supported by Net:SSL and can
229             not be used together with certificate_file/certificate_key_file.
230              
231             =item certificate_key_password
232              
233             The plain password of your encrypted key or PKCS12 container. Note that
234             Net::SSL does not support password protected keys. You need to use a PKCS12
235             container instead! Leave this empty if your key is not protected by a password.
236              
237             =item ca_certificate_path
238              
239             Path to a directory with trusted certificates (with openssl hashed names).
240             Also used to validate the server certificate even if no client authentication
241             is used.
242              
243             =item ca_certificate_file
244              
245             Same as ca_certificate_path pointing to a single file.
246              
247             =item ssl_ignore_mode
248              
249             Boolean, turn of validation of ssl peer certificate (IO::Socket only).
250              
251             =back