1
- use strict;
2
- use warnings;
3
1
package Net::SAML2::Protocol::AuthnRequest ;
4
- # VERSION
5
-
6
2
use Moose;
7
- use MooseX::Types::URI qw/ Uri / ;
3
+
4
+ # VERSION
5
+ use MooseX::Types::URI qw/ Uri / ;
8
6
use MooseX::Types::Common::String qw/ NonEmptySimpleStr / ;
9
- use XML::Writer 0.625;
10
- use List::Util qw( any) ;
7
+ use XML::Generator;
8
+ use List::Util qw( any) ;
9
+ use URN::OASIS::SAML2 qw( :urn BINDING_HTTP_POST) ;
11
10
12
11
with ' Net::SAML2::Role::ProtocolMessage' ;
13
12
@@ -54,7 +53,7 @@ Net::SAML2::Protocol::AuthnRequest - SAML2 AuthnRequest object
54
53
Constructor. Creates an instance of the AuthnRequest object.
55
54
56
55
Important Note: Best practice is to always do this first. While it is possible
57
- to call as_xml() first you do not have to set the id as it will be set for you
56
+ to call C< as_xml() > first you do not have to set the id as it will be set for you
58
57
automatically.
59
58
60
59
However tracking the id is important for security to ensure that the response
@@ -64,19 +63,25 @@ Arguments:
64
63
65
64
=over
66
65
67
- =item B< nameidpolicy_format >
66
+ =item nameidpolicy_format
68
67
69
68
Format attribute for NameIDPolicy
70
69
71
- =item B<AuthnContextClassRef > , B<AuthnContextDeclRef >
70
+ =item AuthnContextClassRef, <AuthnContextDeclRef
71
+
72
+ Each one is an arrayref containing values for AuthnContextClassRef and
73
+ AuthnContextDeclRef. If any is populated, the RequestedAuthnContext will be
74
+ included in the request.
72
75
73
- Each one is an arrayref containing values for AuthnContextClassRef and AuthnContextDeclRef.
74
- If any is populated, the RequestedAuthnContext will be included in the request.
76
+ =item RequestedAuthnContext_Comparison
75
77
76
- =item B<RequestedAuthnContext_Comparison >
78
+ Value for the I<Comparison > attribute in case I<RequestedAuthnContext > is
79
+ included (see above). Default value is I<exact > .
77
80
78
- Value for the I<Comparison > attribute in case I<RequestedAuthnContext > is included
79
- (see above). Default value is I<exact > .
81
+ =item identity_providers
82
+
83
+ An arrayref of Identity providers, if used the Scoping element is added to the
84
+ XML
80
85
81
86
=back
82
87
@@ -102,46 +107,46 @@ has 'nameid_allow_create' => (
102
107
);
103
108
104
109
has ' assertion_url' => (
105
- isa => Uri,
106
- is => ' rw' ,
107
- coerce => 1,
110
+ isa => Uri,
111
+ is => ' rw' ,
112
+ coerce => 1,
108
113
predicate => ' has_assertion_url' ,
109
114
);
110
115
111
116
has ' assertion_index' => (
112
- isa => ' Int' ,
113
- is => ' rw' ,
117
+ isa => ' Int' ,
118
+ is => ' rw' ,
114
119
predicate => ' has_assertion_index' ,
115
120
);
116
121
117
122
has ' attribute_index' => (
118
- isa => ' Int' ,
119
- is => ' rw' ,
123
+ isa => ' Int' ,
124
+ is => ' rw' ,
120
125
predicate => ' has_attribute_index' ,
121
126
);
122
127
123
128
has ' protocol_binding' => (
124
- isa => Uri,
125
- is => ' rw' ,
126
- coerce => 1,
129
+ isa => Uri,
130
+ is => ' rw' ,
131
+ coerce => 1,
127
132
predicate => ' has_protocol_binding' ,
128
133
);
129
134
has ' provider_name' => (
130
- isa => ' Str' ,
131
- is => ' rw' ,
135
+ isa => ' Str' ,
136
+ is => ' rw' ,
132
137
predicate => ' has_provider_name' ,
133
138
);
134
139
135
140
has ' AuthnContextClassRef' => (
136
- isa => ' ArrayRef[Str]' ,
137
- is => ' rw' ,
138
- default => sub {[] }
141
+ isa => ' ArrayRef[Str]' ,
142
+ is => ' rw' ,
143
+ default => sub { [] }
139
144
);
140
145
141
146
has ' AuthnContextDeclRef' => (
142
- isa => ' ArrayRef[Str]' ,
143
- is => ' rw' ,
144
- default => sub {[] }
147
+ isa => ' ArrayRef[Str]' ,
148
+ is => ' rw' ,
149
+ default => sub { [] }
145
150
);
146
151
147
152
has ' RequestedAuthnContext_Comparison' => (
@@ -151,17 +156,23 @@ has 'RequestedAuthnContext_Comparison' => (
151
156
);
152
157
153
158
has ' force_authn' => (
154
- isa => ' Bool' ,
155
- is => ' ro' ,
159
+ isa => ' Bool' ,
160
+ is => ' ro' ,
156
161
predicate => ' has_force_authn' ,
157
162
);
158
163
159
164
has ' is_passive' => (
160
- isa => ' Bool' ,
161
- is => ' ro' ,
165
+ isa => ' Bool' ,
166
+ is => ' ro' ,
162
167
predicate => ' has_is_passive' ,
163
168
);
164
169
170
+ has identity_providers => (
171
+ isa => ' ArrayRef[Str]' ,
172
+ is => ' ro' ,
173
+ predicate => ' has_identity_providers' ,
174
+ );
175
+
165
176
around BUILDARGS => sub {
166
177
my $orig = shift ;
167
178
my $self = shift ;
@@ -180,20 +191,13 @@ Returns the AuthnRequest as XML.
180
191
181
192
=cut
182
193
183
- my $saml = ' urn:oasis:names:tc:SAML:2.0:assertion ' ;
184
- my $samlp = ' urn:oasis:names:tc:SAML:2.0:protocol ' ;
194
+ my $samlp = [ ' samlp ' => URN_PROTOCOL] ;
195
+ my $saml = [ ' samlp ' => URN_ASSERTION] ;
185
196
186
197
sub as_xml {
187
198
my ($self ) = @_ ;
188
- my $x = XML::Writer-> new(
189
- OUTPUT => ' self' ,
190
- NAMESPACES => 1,
191
- FORCED_NS_DECLS => [$saml , $samlp ],
192
- PREFIX_MAP => {
193
- $saml => ' saml2' ,
194
- $samlp => ' saml2p'
195
- }
196
- );
199
+
200
+ my $x = XML::Generator-> new(' :std' );
197
201
198
202
my %req_atts = (
199
203
ID => $self -> id,
@@ -203,9 +207,8 @@ sub as_xml {
203
207
204
208
my %issuer_attrs = ();
205
209
206
- my %protocol_bindings = (
207
- ' HTTP-POST' => ' urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
208
- );
210
+ my %protocol_bindings
211
+ = (' HTTP-POST' => BINDING_HTTP_POST);
209
212
210
213
my %att_map = (
211
214
' assertion_url' => ' AssertionConsumerServiceURL' ,
@@ -235,7 +238,7 @@ sub as_xml {
235
238
$req_atts { $att_map {$opt } } = $protocol_bindings {$val };
236
239
}
237
240
elsif (any { $opt eq $_ } qw( force_authn is_passive) ) {
238
- $req_atts { $att_map {$opt } } = ( $val ? ' true' : ' false' );
241
+ $req_atts { $att_map {$opt } } = ($val ? ' true' : ' false' );
239
242
}
240
243
else {
241
244
$req_atts { $att_map {$opt } } = $val ;
@@ -250,59 +253,68 @@ sub as_xml {
250
253
$issuer_attrs { $att_map {$opt } } = $val ;
251
254
}
252
255
253
- $x -> startTag([$samlp , ' AuthnRequest' ], %req_atts );
254
- $x -> dataElement([$saml , ' Issuer' ], $self -> issuer, %issuer_attrs );
256
+ return $x -> AuthnRequest($samlp ,
257
+ \%req_atts ,
258
+ $x -> Issuer($saml , \%issuer_attrs , $self -> issuer),
259
+ $self -> _set_name_id($x ),
260
+ $self -> _set_name_policy_format($x ),
261
+ $self -> _set_requested_authn_context($x ),
262
+ $self -> _set_scoping($x ),
263
+ );
264
+
265
+ }
255
266
256
- $self -> _set_name_id($x );
257
- $self -> _set_name_policy_format($x );
258
- $self -> _set_requested_authn_context($x );
267
+ sub _set_scoping {
268
+ my $self = shift ;
269
+ return unless $self -> has_identity_providers;
270
+ my $x = shift ;
259
271
260
- $x -> endTag();
261
- $x -> end();
272
+ my @providers = map { $x -> IDPEntry($samlp , { ProviderID => $_ }) }
273
+ @{ $self -> identity_providers };
274
+ return $x -> Scoping($samlp , $x -> IDPList($samlp , @providers ));
262
275
}
263
276
264
277
sub _set_name_id {
265
- my ($self , $x ) = @_ ;
266
- return if !$self -> has_nameid;
267
- $x -> startTag([$saml , ' Subject' ]);
268
- $x -> dataElement([$saml , ' NameID' ], undef , NameQualifier => $self -> nameid);
269
- $x -> endTag();
270
- return ;
278
+ my $self = shift ;
279
+ return unless $self -> has_nameid;
280
+ my $x = shift ;
281
+ return $x -> Subject($saml , $x -> NameID($saml , {NameQualifier => $self -> nameid}));
271
282
}
272
283
273
284
sub _set_name_policy_format {
274
- my ($self , $x ) = @_ ;
275
- return if !$self -> has_nameidpolicy_format;
276
-
277
- $x -> dataElement([$samlp , ' NameIDPolicy' ],
278
- undef ,
279
- Format => $self -> nameidpolicy_format,
280
- $self -> has_nameid_allow_create
285
+ my $self = shift ;
286
+ return unless $self -> has_nameidpolicy_format;
287
+ my $x = shift ;
288
+ return $x -> NameIDPolicy(
289
+ $samlp ,
290
+ {
291
+ Format => $self -> nameidpolicy_format,
292
+ $self -> has_nameid_allow_create
281
293
? (AllowCreate => $self -> nameid_allow_create)
282
294
: (),
295
+ }
283
296
);
284
- return ;
297
+
285
298
}
286
299
287
300
sub _set_requested_authn_context {
288
- my ($self , $x ) = @_ ;
301
+ my ($self , $x ) = @_ ;
289
302
290
- if (!@{ $self -> AuthnContextClassRef } && !@{ $self -> AuthnContextDeclRef })
291
- {
292
- return ;
293
- }
303
+ return
304
+ if !@{ $self -> AuthnContextClassRef }
305
+ && !@{ $self -> AuthnContextDeclRef };
294
306
295
- $x -> startTag([ $samlp , ' RequestedAuthnContext ' ],
296
- Comparison => $self -> RequestedAuthnContext_Comparison) ;
307
+ my @class = map { $x -> AuthnContextClassRef( $saml , undef , $_ ) }
308
+ @{ $self -> AuthnContextClassRef } ;
297
309
298
- foreach my $ref (@{ $self -> AuthnContextClassRef }) {
299
- $x -> dataElement([$saml , ' AuthnContextClassRef' ], $ref );
300
- }
301
- foreach my $ref (@{ $self -> AuthnContextDeclRef }) {
302
- $x -> dataElement([$saml , ' AuthnContextDeclRef' ], $ref );
303
- }
310
+ my @decl = map { $x -> AuthnContextDeclRef($saml , undef , $_ ) }
311
+ @{ $self -> AuthnContextDeclRef };
304
312
305
- $x -> endTag();
313
+ return $x -> RequestedAuthnContext(
314
+ $samlp ,
315
+ { Comparison => $self -> RequestedAuthnContext_Comparison },
316
+ @class , @decl
317
+ );
306
318
}
307
319
308
320
__PACKAGE__ -> meta-> make_immutable;
0 commit comments