1
1
package Net::SAML2::Protocol::AuthnRequest ;
2
+
2
3
use Moose;
3
- use MooseX::Types::Moose qw / Str Int/ ;
4
4
use MooseX::Types::URI qw/ Uri / ;
5
5
use MooseX::Types::Common::String qw/ NonEmptySimpleStr / ;
6
6
use XML::Writer;
7
+ use List::Util qw( any) ;
7
8
8
9
with ' Net::SAML2::Role::ProtocolMessage' ;
9
10
10
- =head1 NAME
11
-
12
- Net::SAML2::Protocol::AuthnRequest - SAML2 AuthnRequest object
11
+ # ABSTRACT: SAML2 AuthnRequest object
13
12
14
13
=head1 SYNOPSIS
15
14
@@ -72,9 +71,17 @@ Value for the I<Comparison> attribute in case I<RequestedAuthnContext> is includ
72
71
73
72
=cut
74
73
75
- has ' nameid' => (isa => NonEmptySimpleStr, is => ' rw' , required => 0);
74
+ has ' nameid' => (
75
+ isa => NonEmptySimpleStr,
76
+ is => ' rw' ,
77
+ predicate => ' has_nameid'
78
+ );
76
79
77
- has ' nameidpolicy_format' => (isa => Str, is => ' rw' , required => 0);
80
+ has ' nameidpolicy_format' => (
81
+ isa => ' Str' ,
82
+ is => ' rw' ,
83
+ predicate => ' has_nameidpolicy_format'
84
+ );
78
85
79
86
has ' nameid_allow_create' => (
80
87
isa => ' Bool' ,
@@ -83,16 +90,55 @@ has 'nameid_allow_create' => (
83
90
predicate => ' has_nameid_allow_create'
84
91
);
85
92
86
- has ' assertion_url' => (isa => Uri, is => ' rw' , required => 0, coerce => 1);
87
- has ' assertion_index' => (isa => Int, is => ' rw' , required => 0);
88
- has ' attribute_index' => (isa => Int, is => ' rw' , required => 0);
89
- has ' protocol_binding' => (isa => Uri, is => ' rw' , required => 0, coerce => 1);
90
- has ' provider_name' => (isa => Str, is => ' rw' , required => 0);
93
+ has ' assertion_url' => (
94
+ isa => Uri,
95
+ is => ' rw' ,
96
+ coerce => 1,
97
+ predicate => ' has_assertion_url' ,
98
+ );
99
+
100
+ has ' assertion_index' => (
101
+ isa => ' Int' ,
102
+ is => ' rw' ,
103
+ predicate => ' has_assertion_index' ,
104
+ );
105
+
106
+ has ' attribute_index' => (
107
+ isa => ' Int' ,
108
+ is => ' rw' ,
109
+ predicate => ' has_attribute_index' ,
110
+ );
111
+
112
+ has ' protocol_binding' => (
113
+ isa => Uri,
114
+ is => ' rw' ,
115
+ coerce => 1,
116
+ predicate => ' has_protocol_binding' ,
117
+ );
118
+ has ' provider_name' => (
119
+ isa => ' Str' ,
120
+ is => ' rw' ,
121
+ predicate => ' has_provider_name' ,
122
+ );
91
123
92
124
# RequestedAuthnContext:
93
- has ' AuthnContextClassRef' => (isa => ' ArrayRef[Str]' , is => ' rw' , required => 0, default => sub {[]});
94
- has ' AuthnContextDeclRef' => (isa => ' ArrayRef[Str]' , is => ' rw' , required => 0, default => sub {[]});
95
- has ' RequestedAuthnContext_Comparison' => (isa => Str, is => ' rw' , required => 0, default => ' exact' );
125
+ has ' AuthnContextClassRef' => (
126
+ isa => ' ArrayRef[Str]' ,
127
+ is => ' rw' ,
128
+ default => sub {[]}
129
+ );
130
+
131
+ has ' AuthnContextDeclRef' => (
132
+ isa => ' ArrayRef[Str]' ,
133
+ is => ' rw' ,
134
+ default => sub {[]}
135
+ );
136
+
137
+ has ' RequestedAuthnContext_Comparison' => (
138
+ isa => ' Str' ,
139
+ is => ' rw' ,
140
+ default => ' exact'
141
+ );
96
142
97
143
around BUILDARGS => sub {
98
144
my $orig = shift ;
@@ -114,10 +160,11 @@ Returns the AuthnRequest as XML.
114
160
115
161
=cut
116
162
163
+ my $saml = ' urn:oasis:names:tc:SAML:2.0:assertion' ;
164
+ my $samlp = ' urn:oasis:names:tc:SAML:2.0:protocol' ;
165
+
117
166
sub as_xml {
118
167
my ($self ) = @_ ;
119
- my $saml = ' urn:oasis:names:tc:SAML:2.0:assertion' ;
120
- my $samlp = ' urn:oasis:names:tc:SAML:2.0:protocol' ;
121
168
my $x = XML::Writer-> new(
122
169
OUTPUT => ' self' ,
123
170
NAMESPACES => 1,
@@ -128,71 +175,104 @@ sub as_xml {
128
175
}
129
176
);
130
177
131
- my $req_atts = {
132
- ID => $self -> id,
133
- IssueInstant => $self -> issue_instant,
134
- Version => ' 2.0' ,
135
- };
136
-
137
- my $issuer_attrs = {};
138
-
139
- my $protocol_bindings = {
140
- ' HTTP-POST' => ' urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
141
- };
142
-
143
- my $att_map = {
144
- ' assertion_url' => ' AssertionConsumerServiceURL' ,
145
- ' assertion_index' => ' AssertionConsumerServiceIndex' ,
146
- ' attribute_index' => ' AttributeConsumingServiceIndex' ,
147
- ' protocol_binding' => ' ProtocolBinding' ,
148
- ' provider_name' => ' ProviderName' ,
149
- ' destination' => ' Destination' ,
150
- ' issuer_namequalifier' => ' NameQualifier' ,
151
- ' issuer_format' => ' Format' ,
152
- };
153
-
154
- foreach my $opt ( qw( assertion_url assertion_index protocol_binding
155
- attribute_index provider_name destination
156
- issuer_namequalifier issuer_format) ) {
157
- if (defined (my $val = $self -> $opt ())) {
158
- if ( $opt eq ' protocol_binding' ) {
159
- $req_atts -> { $att_map -> {$opt } } = $protocol_bindings -> {$val };
160
- } elsif ($opt eq ' issuer_namequalifier' || $opt eq ' issuer_format' ) {
161
- $issuer_attrs -> { $att_map -> {$opt } } = $val ;
162
- } else {
163
- $req_atts -> { $att_map -> {$opt } } = $val ;
164
- }
165
- }
166
- }
178
+ my %req_atts = (
179
+ ID => $self -> id,
180
+ IssueInstant => $self -> issue_instant,
181
+ Version => ' 2.0' ,
182
+ );
167
183
168
- $x -> startTag([$samlp , ' AuthnRequest' ], %$req_atts );
169
- $x -> dataElement([$saml , ' Issuer' ], $self -> issuer, %$issuer_attrs );
170
- if ($self -> nameid) {
171
- $x -> startTag([$saml , ' Subject' ]);
172
- $x -> dataElement([$saml , ' NameID' ], undef , NameQualifier => $self -> nameid);
173
- $x -> endTag(); # Subject
174
- }
175
- if ($self -> nameidpolicy_format) {
176
- $x -> dataElement([$samlp , ' NameIDPolicy' ],
177
- undef ,
178
- Format => $self -> nameidpolicy_format,
179
- $self -> has_nameid_allow_create
180
- ? (AllowCreate => $self -> nameid_allow_create)
181
- : (),
182
- );
183
- }
184
- if (@{$self -> AuthnContextClassRef} || @{$self -> AuthnContextDeclRef}) {
185
- $x -> startTag([$samlp , ' RequestedAuthnContext' ], Comparison => $self -> RequestedAuthnContext_Comparison);
186
- foreach my $ref (@{$self -> AuthnContextClassRef}) {
187
- $x -> dataElement([$saml , ' AuthnContextClassRef' ], $ref );
184
+ my %issuer_attrs = ();
185
+
186
+ my %protocol_bindings = (
187
+ ' HTTP-POST' => ' urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
188
+ );
189
+
190
+ my %att_map = (
191
+ ' assertion_url' => ' AssertionConsumerServiceURL' ,
192
+ ' assertion_index' => ' AssertionConsumerServiceIndex' ,
193
+ ' attribute_index' => ' AttributeConsumingServiceIndex' ,
194
+ ' protocol_binding' => ' ProtocolBinding' ,
195
+ ' provider_name' => ' ProviderName' ,
196
+ ' destination' => ' Destination' ,
197
+ ' issuer_namequalifier' => ' NameQualifier' ,
198
+ ' issuer_format' => ' Format' ,
199
+ );
200
+
201
+ my @opts = qw(
202
+ assertion_url assertion_index protocol_binding
203
+ attribute_index provider_name destination
204
+ issuer_namequalifier issuer_format
205
+ ) ;
206
+
207
+ foreach my $opt (@opts ) {
208
+ my $predicate = ' has_' . $opt ;
209
+ next unless $self -> $predicate ;
210
+
211
+ my $val = $self -> $opt ;
212
+ if ($opt eq ' protocol_binding' ) {
213
+ $req_atts { $att_map {$opt } } = $protocol_bindings {$val };
214
+ }
215
+ elsif (any { $opt eq $_ } qw( issuer_namequalifier issuer_format) ) {
216
+ $issuer_attrs { $att_map {$opt } } = $val ;
188
217
}
189
- foreach my $ref (@{ $self -> AuthnContextDeclRef}) {
190
- $x -> dataElement([ $saml , ' AuthnContextDeclRef ' ], $ref ) ;
218
+ else {
219
+ $req_atts { $att_map { $opt } } = $val ;
191
220
}
192
- $x -> endTag(); # RequestedAuthnContext
193
221
}
194
- $x -> endTag(); # AuthnRequest
222
+
223
+ $x -> startTag([$samlp , ' AuthnRequest' ], %req_atts );
224
+ $x -> dataElement([$saml , ' Issuer' ], $self -> issuer, %issuer_attrs );
225
+
226
+ $self -> _set_name_id($x );
227
+ $self -> _set_name_policy_format($x );
228
+ $self -> _set_requested_authn_context($x );
229
+
230
+ $x -> endTag();
195
231
$x -> end();
196
232
}
197
233
234
+ sub _set_name_id {
235
+ my ($self , $x ) = @_ ;
236
+ return if !$self -> has_nameid;
237
+ $x -> startTag([$saml , ' Subject' ]);
238
+ $x -> dataElement([$saml , ' NameID' ], undef , NameQualifier => $self -> nameid);
239
+ $x -> endTag();
240
+ return ;
241
+ }
242
+
243
+ sub _set_name_policy_format {
244
+ my ($self , $x ) = @_ ;
245
+ return if !$self -> has_nameidpolicy_format;
246
+
247
+ $x -> dataElement([$samlp , ' NameIDPolicy' ],
248
+ undef ,
249
+ Format => $self -> nameidpolicy_format,
250
+ $self -> has_nameid_allow_create
251
+ ? (AllowCreate => $self -> nameid_allow_create)
252
+ : (),
253
+ );
254
+ return ;
255
+ }
256
+
257
+ sub _set_requested_authn_context {
258
+ my ($self , $x ) = @_ ;
259
+
260
+ if (!@{ $self -> AuthnContextClassRef } && !@{ $self -> AuthnContextDeclRef })
261
+ {
262
+ return ;
263
+ }
264
+
265
+ $x -> startTag([$samlp , ' RequestedAuthnContext' ],
266
+ Comparison => $self -> RequestedAuthnContext_Comparison);
267
+
268
+ foreach my $ref (@{ $self -> AuthnContextClassRef }) {
269
+ $x -> dataElement([$saml , ' AuthnContextClassRef' ], $ref );
270
+ }
271
+ foreach my $ref (@{ $self -> AuthnContextDeclRef }) {
272
+ $x -> dataElement([$saml , ' AuthnContextDeclRef' ], $ref );
273
+ }
274
+
275
+ $x -> endTag();
276
+ }
277
+
198
278
__PACKAGE__ -> meta-> make_immutable;
0 commit comments