File Coverage

blib/lib/Net/SAML2/SP.pm
Criterion Covered Total %
statement 53 63 84.1
branch 3 6 50.0
condition n/a
subroutine 16 19 84.2
pod 10 10 100.0
total 82 98 83.6


line stmt bran cond sub pod time code
1             package Net::SAML2::SP;
2 13     13   2721557 use Moose;
  13         5847298  
  13         119  
3 13     13   109790 use MooseX::Types::URI qw/ Uri /;
  13         1499012  
  13         96  
4              
5             our $VERSION = '0.41';
6              
7             # ABSTRACT: Net::SAML2::SP - SAML Service Provider object
8              
9              
10 13     13   34776 use Crypt::OpenSSL::X509;
  13         49669  
  13         1034  
11 13     13   9797 use XML::Generator;
  13         117073  
  13         69  
12              
13 13     13   8074 use Net::SAML2::Binding::POST;
  13         210827  
  13         736  
14 13     13   8678 use Net::SAML2::Binding::Redirect;
  13         5482  
  13         625  
15 13     13   8432 use Net::SAML2::Binding::SOAP;
  13         5550  
  13         597  
16 13     13   8334 use Net::SAML2::Protocol::AuthnRequest;
  13         6251  
  13         697  
17 13     13   8959 use Net::SAML2::Protocol::LogoutRequest;
  13         5794  
  13         14281  
18              
19              
20             has 'url' => (isa => Uri, is => 'ro', required => 1, coerce => 1);
21             has 'id' => (isa => 'Str', is => 'ro', required => 1);
22             has 'cert' => (isa => 'Str', is => 'ro', required => 1);
23             has 'key' => (isa => 'Str', is => 'ro', required => 1);
24             has 'cacert' => (isa => 'Maybe[Str]', is => 'ro', required => 1);
25              
26             has 'org_name' => (isa => 'Str', is => 'ro', required => 1);
27             has 'org_display_name' => (isa => 'Str', is => 'ro', required => 1);
28             has 'org_contact' => (isa => 'Str', is => 'ro', required => 1);
29             has 'org_url' => (isa => 'Str', is => 'ro', required => 0);
30              
31             has '_cert_text' => (isa => 'Str', is => 'rw', required => 0);
32              
33             has 'authnreq_signed' => (isa => 'Bool', is => 'ro', required => 0);
34             has 'want_assertions_signed' => (isa => 'Bool', is => 'ro', required => 0);
35              
36              
37             sub BUILD {
38 4     4 1 18 my ($self) = @_;
39              
40 4         141 my $cert = Crypt::OpenSSL::X509->new_from_file($self->cert);
41 4         135 my $text = $cert->as_string;
42 4         61 $text =~ s/-----[^-]*-----//gm;
43 4         163 $self->_cert_text($text);
44              
45 4         173 return $self;
46             }
47              
48              
49             sub authn_request {
50 1     1 1 4 my ($self, $destination, $nameid_format) = @_;
51              
52 1         14 my $authnreq = Net::SAML2::Protocol::AuthnRequest->new(
53             issueinstant => DateTime->now,
54             issuer => $self->id,
55             destination => $destination,
56             nameid_format => $nameid_format,
57             );
58              
59 1         17 return $authnreq;
60             }
61              
62              
63             sub logout_request {
64 1     1 1 6 my ($self, $destination, $nameid, $nameid_format, $session) = @_;
65              
66 1         30 my $logout_req = Net::SAML2::Protocol::LogoutRequest->new(
67             issuer => $self->id,
68             destination => $destination,
69             nameid => $nameid,
70             nameid_format => $nameid_format,
71             session => $session,
72             );
73              
74 1         6 return $logout_req;
75             }
76              
77              
78             sub logout_response {
79 0     0 1 0 my ($self, $destination, $status, $response_to) = @_;
80              
81 0         0 my $status_uri = Net::SAML2::Protocol::LogoutResponse->status_uri($status);
82 0         0 my $logout_req = Net::SAML2::Protocol::LogoutResponse->new(
83             issuer => $self->id,
84             destination => $destination,
85             status => $status_uri,
86             response_to => $response_to,
87             );
88              
89 0         0 return $logout_req;
90             }
91              
92              
93             sub artifact_request {
94 0     0 1 0 my ($self, $destination, $artifact) = @_;
95              
96 0         0 my $artifact_request = Net::SAML2::Protocol::ArtifactResolve->new(
97             issuer => $self->id,
98             destination => $destination,
99             artifact => $artifact,
100             issueinstant => DateTime->now,
101             );
102              
103 0         0 return $artifact_request;
104             }
105              
106              
107             sub sso_redirect_binding {
108 1     1 1 390 my ($self, $idp, $param) = @_;
109              
110 1         6 my $redirect = Net::SAML2::Binding::Redirect->new(
111             url => $idp->sso_url('urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'),
112             cert => $idp->cert('signing'),
113             key => $self->key,
114             param => $param,
115             );
116              
117 1         4 return $redirect;
118             }
119              
120              
121             sub slo_redirect_binding {
122 0     0 1 0 my ($self, $idp, $param) = @_;
123              
124 0         0 my $redirect = Net::SAML2::Binding::Redirect->new(
125             url => $idp->slo_url('urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'),
126             cert => $idp->cert('signing'),
127             key => $self->key,
128             param => $param,
129             );
130              
131 0         0 return $redirect;
132             }
133              
134              
135             sub soap_binding {
136 1     1 1 6052 my ($self, $ua, $idp_url, $idp_cert) = @_;
137              
138 1         60 my $soap = Net::SAML2::Binding::SOAP->new(
139             ua => $ua,
140             key => $self->key,
141             cert => $self->cert,
142             url => $idp_url,
143             idp_cert => $idp_cert,
144             cacert => $self->cacert,
145             );
146              
147 1         5 return $soap;
148             }
149              
150              
151             sub post_binding {
152 1     1 1 8 my ($self) = @_;
153              
154 1         29 my $post = Net::SAML2::Binding::POST->new(
155             cacert => $self->cacert,
156             );
157              
158 1         4 return $post;
159             }
160              
161              
162             sub metadata {
163 1     1 1 6 my ($self) = @_;
164              
165 1         12 my $x = XML::Generator->new(':pretty', conformance => 'loose');
166 1         147 my $md = ['md' => 'urn:oasis:names:tc:SAML:2.0:metadata'];
167 1         3 my $ds = ['ds' => 'http://www.w3.org/2000/09/xmldsig#'];
168              
169 1 50       32 $x->EntityDescriptor(
    50          
    50          
170             $md,
171             {
172             entityID => $self->id },
173             $x->SPSSODescriptor(
174             $md,
175             { AuthnRequestsSigned => defined($self->authnreq_signed) ? $self->authnreq_signed : '1',
176             WantAssertionsSigned => defined($self->want_assertions_signed) ? $self->want_assertions_signed : '1',
177             errorURL => $self->url . '/saml/error',
178             protocolSupportEnumeration => 'urn:oasis:names:tc:SAML:2.0:protocol' },
179             $x->KeyDescriptor(
180             $md,
181             {
182             use => 'signing' },
183             $x->KeyInfo(
184             $ds,
185             $x->X509Data(
186             $ds,
187             $x->X509Certificate(
188             $ds,
189             $self->_cert_text,
190             )
191             )
192             )
193             ),
194             $x->SingleLogoutService(
195             $md,
196             { Binding => 'urn:oasis:names:tc:SAML:2.0:bindings:SOAP',
197             Location => $self->url . '/saml/slo-soap' },
198             ),
199             $x->SingleLogoutService(
200             $md,
201             { Binding => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
202             Location => $self->url . '/saml/sls-redirect-response' },
203             ),
204             $x->SingleLogoutService(
205             $md,
206             { Binding => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
207             Location => $self->url . '/saml/sls-post-response' },
208             ),
209             $x->AssertionConsumerService(
210             $md,
211             { Binding => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
212             Location => $self->url . '/saml/consumer-post',
213             index => '1',
214             isDefault => 'true' },
215             ),
216             $x->AssertionConsumerService(
217             $md,
218             { Binding => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact',
219             Location => $self->url . '/saml/consumer-artifact',
220             index => '2',
221             isDefault => 'false' },
222             ),
223             ),
224             $x->Organization(
225             $md,
226             $x->OrganizationName(
227             $md,
228             {
229             'xml:lang' => 'en' },
230             $self->org_name,
231             ),
232             $x->OrganizationDisplayName(
233             $md,
234             {
235             'xml:lang' => 'en' },
236             $self->org_display_name,
237             ),
238             $x->OrganizationURL(
239             $md,
240             {
241             'xml:lang' => 'en' },
242             defined($self->org_url) ? $self->org_url :$self->url
243             )
244             ),
245             $x->ContactPerson(
246             $md,
247             {
248             contactType => 'other' },
249             $x->Company(
250             $md,
251             $self->org_display_name,
252             ),
253             $x->EmailAddress(
254             $md,
255             $self->org_contact,
256             ),
257             )
258             );
259             }
260              
261             __PACKAGE__->meta->make_immutable;
262              
263             __END__
264              
265             =pod
266              
267             =encoding UTF-8
268              
269             =head1 NAME
270              
271             Net::SAML2::SP - Net::SAML2::SP - SAML Service Provider object
272              
273             =head1 VERSION
274              
275             version 0.41
276              
277             =head1 SYNOPSIS
278              
279             my $sp = Net::SAML2::SP->new(
280             id => 'http://localhost:3000',
281             url => 'http://localhost:3000',
282             cert => 'sign-nopw-cert.pem',
283             key => 'sign-nopw-key.pem',
284             );
285              
286             =head1 NAME
287              
288             Net::SAML2::SP - SAML Service Provider object
289              
290             =head1 METHODS
291              
292             =head2 new( ... )
293              
294             Constructor. Create an SP object.
295              
296             Arguments:
297              
298             =over
299              
300             =item B<url>
301              
302             base for all SP service URLs
303              
304             =item B<id>
305              
306             SP's identity URI.
307              
308             =item B<cert>
309              
310             path to the signing certificate
311              
312             =item B<key>
313              
314             path to the private key for the signing certificate
315              
316             =item B<cacert>
317              
318             path to the CA certificate for verification
319              
320             =item B<org_name>
321              
322             SP organisation name
323              
324             =item B<org_display_name>
325              
326             SP organisation display name
327              
328             =item B<org_contact>
329              
330             SP contact email address
331              
332             =item B<org_url>
333              
334             SP organization url. This is optional and url will be used as in
335             previous versions if this is not provided.
336              
337             =item B<authnreq_signed>
338              
339             Specifies in the metadata whether the SP signs the AuthnRequest
340             Optional (0 or 1) defaults to 1 (TRUE) if not specified.
341              
342             =item B<want_assertions_signed>
343              
344             Specifies in the metadata whether the SP wants the Assertion from
345             the IdP to be signed
346             Optional (0 or 1) defaults to 1 (TRUE) if not specified.
347              
348             =back
349              
350             =head2 BUILD ( hashref of the parameters passed to the constructor )
351              
352             Called after the object is created to load the cert from a file
353              
354             =head2 authn_request( $destination, $nameid_format )
355              
356             Returns an AuthnRequest object created by this SP, intended for the
357             given destination, which should be the identity URI of the IdP.
358              
359             =head2 logout_request( $destination, $nameid, $nameid_format, $session )
360              
361             Returns a LogoutRequest object created by this SP, intended for the
362             given destination, which should be the identity URI of the IdP.
363              
364             Also requires the nameid (+format) and session to be logged out.
365              
366             =head2 logout_response( $destination, $status, $response_to )
367              
368             Returns a LogoutResponse object created by this SP, intended for the
369             given destination, which should be the identity URI of the IdP.
370              
371             Also requires the status and the ID of the corresponding
372             LogoutRequest.
373              
374             =head2 artifact_request( $destination, $artifact )
375              
376             Returns an ArtifactResolve request object created by this SP, intended
377             for the given destination, which should be the identity URI of the
378             IdP.
379              
380             =head2 sso_redirect_binding( $idp, $param )
381              
382             Returns a Redirect binding object for this SP, configured against the
383             given IDP for Single Sign On. $param specifies the name of the query
384             parameter involved - typically C<SAMLRequest>.
385              
386             =head2 slo_redirect_binding( $idp, $param )
387              
388             Returns a Redirect binding object for this SP, configured against the
389             given IDP for Single Log Out. $param specifies the name of the query
390             parameter involved - typically C<SAMLRequest> or C<SAMLResponse>.
391              
392             =head2 soap_binding( $ua, $idp_url, $idp_cert )
393              
394             Returns a SOAP binding object for this SP, with a destination of the
395             given URL and signing certificate.
396              
397             XXX UA
398              
399             =head2 post_binding( )
400              
401             Returns a POST binding object for this SP.
402              
403             =head2 metadata( )
404              
405             Returns the metadata XML document for this SP.
406              
407             =head1 AUTHOR
408              
409             Chris Andrews <chrisa@cpan.org>
410              
411             =head1 COPYRIGHT AND LICENSE
412              
413             This software is copyright (c) 2021 by Chris Andrews and Others, see the git log.
414              
415             This is free software; you can redistribute it and/or modify it under
416             the same terms as the Perl 5 programming language system itself.
417              
418             =cut