saml-sp 3.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,177 @@
1
+ require File.join(File.dirname(__FILE__), '../spec_helper')
2
+
3
+ describe Saml2::Assertion do
4
+ describe "w/ 2 attributes" do
5
+ before do
6
+ @assertion = Saml2::Assertion.new('http://idp.invalid', 'abcd', 'this' => 'that', 'foo' => 'bar')
7
+ end
8
+
9
+ it "should provide read access for issuer" do
10
+ @assertion.issuer.should == 'http://idp.invalid'
11
+ end
12
+
13
+ it "should provide read access to subject name id" do
14
+ @assertion.subject_name_id.should == 'abcd'
15
+ end
16
+
17
+ it "should provide read access to attributes ('this')" do
18
+ @assertion['this'].should == 'that'
19
+ end
20
+
21
+ it "should provide read access to attributes (:this)" do
22
+ @assertion[:this].should == 'that'
23
+ end
24
+
25
+ it "should provide read access to attributes ('foo')" do
26
+ @assertion['foo'].should == 'bar'
27
+ end
28
+
29
+ it "should provide read access to attributes (:foo)" do
30
+ @assertion[:foo].should == 'bar'
31
+ end
32
+ end
33
+
34
+ describe "instantiation" do
35
+ it 'should be creatable from artifact string' do
36
+ mock_artifact = mock('artifact', :resolve => :assertion_marker)
37
+ Saml2::Type4Artifact.should_receive(:new_from_string).with('artifact_marker').and_return(mock_artifact)
38
+
39
+ Saml2::Assertion.new_from_artifact("artifact_marker").should == :assertion_marker
40
+ end
41
+
42
+ it 'should be creatable from a type 4 artifact' do
43
+ artifact = Saml2::Type4Artifact.new(0, 'a-source-id', 'http://idp.invalid/')
44
+ artifact.should_receive(:resolve).and_return(:assertion_marker)
45
+
46
+ Saml2::Assertion.new_from_artifact(artifact).should == :assertion_marker
47
+ end
48
+ end
49
+
50
+ describe "parsing" do
51
+ before do
52
+ @assertion_xml = <<-XML
53
+ <SOAP-ENV:Envelope
54
+ xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
55
+ <SOAP-ENV:Body>
56
+ <ArtifactResponse
57
+ ID="_423adb988f2673de74553f9f26ff27eda8af"
58
+ InResponseTo="_gIPoW.YXQpZj17m.EpboPCp9cT"
59
+ IssueInstant="2006-11-28T23:07:43.738+00:00"
60
+ Version="2.0"
61
+ xmlns="urn:oasis:names:tc:SAML:2.0:protocol">
62
+ <ns1:Issuer xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion">
63
+ https://idp.invalid
64
+ </ns1:Issuer>
65
+
66
+ <Status>
67
+ <StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
68
+ </Status>
69
+
70
+ <Response
71
+ Destination="https://service_provider/SAMLConsumer"
72
+ ID="_dcfacebe4f2fca1cbdae749c5f5738995e0"
73
+ IssueInstant="2006-11-28T23:04:32Z"
74
+ Version="2.0">
75
+ <ns2:Issuer
76
+ Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
77
+ xmlns:ns2="urn:oasis:names:tc:SAML:2.0:assertion">
78
+ https://idp.invalid
79
+ </ns2:Issuer>
80
+
81
+ <Status>
82
+ <StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
83
+ </Status>
84
+
85
+ <ns3:Assertion
86
+ ID="_1ebc0cd2f88ade6396bccb22fc20a42792c4"
87
+ IssueInstant="2006-11-28T23:04:32Z"
88
+ Version="2.0"
89
+ xmlns:ns3="urn:oasis:names:tc:SAML:2.0:assertion">
90
+ <ns3:Issuer
91
+ Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">
92
+ https://idp.invalid
93
+ </ns3:Issuer>
94
+
95
+ <ns3:Subject>
96
+ <ns3:NameID
97
+ Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">
98
+ 12345678
99
+ </ns3:NameID>
100
+
101
+ <ns3:SubjectConfirmation
102
+ Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
103
+ <ns3:SubjectConfirmationData
104
+ NotOnOrAfter="2006-11-28T23:24:32Z"
105
+ Recipient="https://sp.invalid/SAMLConsumer"/>
106
+ </ns3:SubjectConfirmation>
107
+ </ns3:Subject>
108
+
109
+ <ns3:Conditions
110
+ NotBefore="2006-11-28T22:54:32Z"
111
+ NotOnOrAfter="2006-11-28T23:24:32Z">
112
+ <ns3:AudienceRestriction>
113
+ <ns3:Audience>https://sp.invalid</ns3:Audience>
114
+ </ns3:AudienceRestriction>
115
+ </ns3:Conditions>
116
+
117
+ <ns3:AuthnStatement
118
+ AuthnInstant="2006-11-28T23:03:14Z"
119
+ SessionIndex="MQSnyIps57sm2wRDKP+f9PsY+2A=nFfVrw=="
120
+ SessionNotOnOrAfter="2006-11-28T23:24:32Z">
121
+ <ns3:AuthnContext>
122
+ <ns3:AuthnContextClassRef>
123
+ urn:oasis:names:tc:SAML:2.0:ac:classes:Password
124
+ </ns3:AuthnContextClassRef>
125
+ </ns3:AuthnContext>
126
+ </ns3:AuthnStatement>
127
+
128
+ <ns3:AttributeStatement>
129
+ <ns3:Attribute
130
+ Name="cn"
131
+ NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
132
+ <ns3:AttributeValue>Smith, James</ns3:AttributeValue>
133
+ </ns3:Attribute>
134
+
135
+ <ns3:Attribute
136
+ Name="email"
137
+ NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
138
+ <ns3:AttributeValue>james.smith@idp.invalid</ns3:AttributeValue>
139
+ </ns3:Attribute>
140
+
141
+ </ns3:AttributeStatement>
142
+
143
+ </ns3:Assertion>
144
+ </Response>
145
+ </ArtifactResponse>
146
+ </SOAP-ENV:Body>
147
+ </SOAP-ENV:Envelope>
148
+ XML
149
+ end
150
+
151
+ def self.it_should_extract(prop, expected_value)
152
+ eval(<<-EXAMPLE)
153
+ it "should extract #{prop}" do
154
+ Saml2::Assertion.new_from_xml(@assertion_xml).#{prop}.should == #{expected_value.inspect}
155
+ end
156
+ EXAMPLE
157
+ end
158
+
159
+ it_should_extract :issuer, 'https://idp.invalid'
160
+ it_should_extract :subject_name_id, '12345678'
161
+
162
+ it "should extract attributes (cn)" do
163
+ Saml2::Assertion.new_from_xml(@assertion_xml)['cn'].should == 'Smith, James'
164
+ end
165
+
166
+ it "should extract attributes (email)" do
167
+ Saml2::Assertion.new_from_xml(@assertion_xml)['email'].should == 'james.smith@idp.invalid'
168
+ end
169
+ end
170
+
171
+ end
172
+
173
+
174
+ # Copyright (c) 2010 OpenLogic
175
+ #
176
+ # Licensed under MIT license. See LICENSE.txt
177
+
@@ -0,0 +1,66 @@
1
+ require File.join(File.dirname(__FILE__), '../spec_helper')
2
+
3
+ describe Saml2::Type4Artifact do
4
+ describe "parsing wrong type" do
5
+ it "should raise error" do
6
+ lambda {
7
+ # unencoded artifact: "\000\052\000\030test"
8
+ Saml2::Type4Artifact.new_from_string "ACoAGHRlc3Q="
9
+ }.should raise_error UnexpectedTypeCodeError
10
+ end
11
+
12
+ it "should have meaningful message" do
13
+ lambda {
14
+ # unencoded artifact: "\000\052\000\030test"
15
+ Saml2::Type4Artifact.new_from_string "ACoAGHRlc3Q="
16
+ }.should raise_error(/incorrect artifact type.*expected.*4.*found.*42/i)
17
+ end
18
+
19
+ end
20
+
21
+ describe "parsing type 4" do
22
+ before do
23
+ # unencoded artifact: "\000\004\000\00001234567890123456789abcdefghijklmnopqrst"
24
+ @artifact = Saml2::Type4Artifact.new_from_string "AAQAADAxMjM0NTY3ODkwMTIzNDU2Nzg5YWJjZGVmZ2hpamtsbW5vcHFyc3Q="
25
+ end
26
+
27
+ it "should know its type code" do
28
+ @artifact.type_code.should == 4
29
+ end
30
+
31
+ it "should know its endpoint index" do
32
+ @artifact.endpoint_index.should == 0
33
+ end
34
+
35
+ it "should know the source id" do
36
+ @artifact.source_id.should == '01234567890123456789'
37
+ end
38
+
39
+ it "should know the message handle" do
40
+ @artifact.message_handle.should == 'abcdefghijklmnopqrst'
41
+ end
42
+ end
43
+
44
+ describe "simple artifact" do
45
+ before do
46
+ @resolver = Saml2::ArtifactResolver.new('01234567890123456789', 'http://idp.invalid/artifact-resolver', 'http://idp.invalid/', 'http://sp.invalid/')
47
+
48
+ @artifact = Saml2::Type4Artifact.new(0, '01234567890123456789', 'abcdefghijklmnopqrst')
49
+ end
50
+
51
+ it "should be able to render itself to a string" do
52
+ @artifact.to_s.should == "AAQAADAxMjM0NTY3ODkwMTIzNDU2Nzg5YWJjZGVmZ2hpamtsbW5vcHFyc3Q="
53
+ end
54
+
55
+ it "should be able to resolve itself" do
56
+ @resolver.should_receive(:resolve).with(@artifact).and_return(:assertion_marker)
57
+ @artifact.resolve.should == :assertion_marker
58
+ end
59
+ end
60
+ end
61
+
62
+
63
+ # Copyright (c) 2010 OpenLogic
64
+ #
65
+ # Licensed under MIT license. See LICENSE.txt
66
+
@@ -0,0 +1,299 @@
1
+ require File.join(File.dirname(__FILE__), '../spec_helper')
2
+ require 'tempfile'
3
+
4
+ describe SamlSp::Config do
5
+ before do
6
+ @dsl = SamlSp::Config.new
7
+ end
8
+
9
+ describe "loading from file" do
10
+ before do
11
+ @source_id = Time.now.xmlschema(10)
12
+
13
+ @tmpfile = Tempfile.open('saml-sp-config')
14
+ @tmpfile << <<-CONFIG
15
+ artifact_resolution_service {
16
+ source_id "#{@source_id}"
17
+ uri "http://idp.invalid/resolve-artifacts"
18
+ identity_provider "http://idp.invalid/"
19
+ service_provider "http://sp.invalid/"
20
+ }
21
+ CONFIG
22
+ @tmpfile.flush
23
+ end
24
+
25
+ after do
26
+ @tmpfile.close!
27
+ end
28
+
29
+ it "should build resolver" do
30
+ SamlSp::Config.load_file(@tmpfile.path)
31
+
32
+ Saml2::ArtifactResolver(@source_id).should be_kind_of(Saml2::ArtifactResolver)
33
+ end
34
+ end
35
+
36
+ describe "global log configuration" do
37
+ before do
38
+ @orig_logger = SamlSp.logger
39
+ @dsl = SamlSp::Config.new
40
+ @resolver = @dsl.interpret(<<-CONFIG)
41
+ logger :MARKER
42
+ CONFIG
43
+ end
44
+
45
+ it "should set SamlSp.logger correctly" do
46
+ SamlSp.logger.should == :MARKER
47
+ end
48
+
49
+ after do
50
+ SamlSp.logger = @orig_logger
51
+ end
52
+ end
53
+
54
+ describe "valid basic auth'd service description" do
55
+ before do
56
+ @dsl = SamlSp::Config.new
57
+ @resolver = @dsl.interpret(<<-CONFIG)
58
+ artifact_resolution_service {
59
+ source_id "01234567890123456789"
60
+ uri "http://idp.invalid/resolve-artifacts"
61
+ identity_provider "http://idp.invalid/"
62
+ service_provider "http://sp.invalid/"
63
+
64
+ http_basic_auth {
65
+ realm "myssorealm"
66
+ user_id "myuserid"
67
+ password "mypassword"
68
+ }
69
+ }
70
+ CONFIG
71
+ end
72
+
73
+ it "should build a resolver" do
74
+ @resolver.should be_kind_of(Saml2::ArtifactResolver)
75
+ end
76
+
77
+ it "should build a resolver with correct source id" do
78
+ @resolver.source_id.should == '01234567890123456789'
79
+ end
80
+
81
+ it "should build a resolver with correct service uri" do
82
+ @resolver.resolution_service_uri.to_s.should == "http://idp.invalid/resolve-artifacts"
83
+ end
84
+
85
+ it "should build a resolver with correct identity provider id" do
86
+ @resolver.idp_id.should == "http://idp.invalid/"
87
+ end
88
+
89
+ it "should build a resolver with correct service provider id" do
90
+ @resolver.sp_id.should == "http://sp.invalid/"
91
+ end
92
+
93
+ it "should build a resolver with correct realm" do
94
+ @resolver.basic_auth_realm.should == 'myssorealm'
95
+ end
96
+
97
+ it "should build a resolver with correct user id" do
98
+ @resolver.basic_auth_user_id.should == 'myuserid'
99
+ end
100
+
101
+ it "should build a resolver with correct password" do
102
+ @resolver.basic_auth_password.should == 'mypassword'
103
+ end
104
+ end
105
+
106
+ describe "valid basic promiscuous auth'd service description" do
107
+ before do
108
+ @dsl = SamlSp::Config.new
109
+ @resolver = @dsl.interpret(<<-CONFIG)
110
+ artifact_resolution_service {
111
+ source_id "01234567890123456789"
112
+ uri "http://idp.invalid/resolve-artifacts"
113
+ identity_provider "http://idp.invalid/"
114
+ service_provider "http://sp.invalid/"
115
+
116
+ http_basic_auth {
117
+ promiscuous
118
+ user_id "myuserid"
119
+ password "mypassword"
120
+ }
121
+ }
122
+ CONFIG
123
+ end
124
+
125
+ it "should build a resolver" do
126
+ @resolver.should be_kind_of(Saml2::ArtifactResolver)
127
+ end
128
+
129
+ it "should build a resolver with correct source id" do
130
+ @resolver.source_id.should == '01234567890123456789'
131
+ end
132
+
133
+ it "should build a resolver with correct service uri" do
134
+ @resolver.resolution_service_uri.to_s.should == "http://idp.invalid/resolve-artifacts"
135
+ end
136
+
137
+ it "should build a resolver with correct identity provider id" do
138
+ @resolver.idp_id.should == "http://idp.invalid/"
139
+ end
140
+
141
+ it "should build a resolver with correct service provider id" do
142
+ @resolver.sp_id.should == "http://sp.invalid/"
143
+ end
144
+
145
+ it "should build a resolver with correct realm" do
146
+ @resolver.basic_auth_realm.should be_nil
147
+ end
148
+
149
+ it "should build a resolver with correct user id" do
150
+ @resolver.basic_auth_user_id.should == 'myuserid'
151
+ end
152
+
153
+ it "should build a resolver with correct password" do
154
+ @resolver.basic_auth_password.should == 'mypassword'
155
+ end
156
+ end
157
+
158
+ describe "valid non-auth service description" do
159
+ before do
160
+ @dsl = SamlSp::Config.new
161
+ @resolver = @dsl.interpret(<<-CONFIG)
162
+ artifact_resolution_service {
163
+ source_id "01234567890123456789"
164
+ uri "http://idp.invalid/resolve-artifacts"
165
+ identity_provider "http://idp.invalid/"
166
+ service_provider "http://sp.invalid/"
167
+ }
168
+ CONFIG
169
+ end
170
+
171
+ it "should build a resolver" do
172
+ @resolver.should be_kind_of(Saml2::ArtifactResolver)
173
+ end
174
+
175
+ it "should build a resolver with correct source id" do
176
+ @resolver.source_id.should == '01234567890123456789'
177
+ end
178
+
179
+ it "should build a resolver with correct service uri" do
180
+ @resolver.resolution_service_uri.to_s.should == "http://idp.invalid/resolve-artifacts"
181
+ end
182
+
183
+ it "should build a resolver with correct identity provider id" do
184
+ @resolver.idp_id.should == "http://idp.invalid/"
185
+ end
186
+
187
+ it "should build a resolver with correct service provider id" do
188
+ @resolver.sp_id.should == "http://sp.invalid/"
189
+ end
190
+
191
+ it "should build a resolver with correct realm" do
192
+ @resolver.basic_auth_realm.should == nil
193
+ end
194
+
195
+ it "should build a resolver with correct user id" do
196
+ @resolver.basic_auth_user_id.should == nil
197
+ end
198
+
199
+ it "should build a resolver with correct password" do
200
+ @resolver.basic_auth_password.should == nil
201
+ end
202
+ end
203
+
204
+ it "should raise error on missing source_id" do
205
+ lambda {
206
+ @dsl.interpret(<<-CONFIG)
207
+ artifact_resolution_service {
208
+ uri "http://idp.invalid/resolve-artifacts"
209
+ identity_provider "http://idp.invalid/"
210
+ service_provider "http://sp.invalid/"
211
+ }
212
+ CONFIG
213
+ }.should raise_error SamlSp::ConfigurationError
214
+ end
215
+
216
+ it "should raise error on missing uri" do
217
+ lambda {
218
+ @dsl.interpret(<<-CONFIG)
219
+ artifact_resolution_service {
220
+ source_id "01234567890123456789"
221
+ identity_provider "http://idp.invalid/"
222
+ service_provider "http://sp.invalid/"
223
+ }
224
+ CONFIG
225
+ }.should raise_error SamlSp::ConfigurationError
226
+ end
227
+
228
+ it "should raise error on missing issuer" do
229
+ lambda {
230
+ @dsl.interpret(<<-CONFIG)
231
+ artifact_resolution_service {
232
+ source_id "01234567890123456789"
233
+ uri "http://idp.invalid/resolve-artifacts"
234
+ }
235
+ CONFIG
236
+ }.should raise_error SamlSp::ConfigurationError
237
+ end
238
+
239
+ it "should raise error on missing basic auth realm" do
240
+ lambda {
241
+ @dsl.interpret(<<-CONFIG)
242
+ artifact_resolution_service {
243
+ source_id "01234567890123456789"
244
+ uri "http://idp.invalid/resolve-artifacts"
245
+ identity_provider "http://idp.invalid/"
246
+ service_provider "http://sp.invalid/"
247
+
248
+ http_basic_auth {
249
+ user_id "myuserid"
250
+ password "mypassword"
251
+ }
252
+ }
253
+ CONFIG
254
+ }.should raise_error SamlSp::ConfigurationError
255
+ end
256
+
257
+ it "should raise error on missing basic auth user id" do
258
+ lambda {
259
+ @dsl.interpret(<<-CONFIG)
260
+ artifact_resolution_service {
261
+ source_id "01234567890123456789"
262
+ uri "http://idp.invalid/resolve-artifacts"
263
+ identity_provider "http://idp.invalid/"
264
+ service_provider "http://sp.invalid/"
265
+
266
+ http_basic_auth {
267
+ realm "myssorealm"
268
+ password "mypassword"
269
+ }
270
+ }
271
+ CONFIG
272
+ }.should raise_error SamlSp::ConfigurationError
273
+ end
274
+
275
+ it "should raise error on missing basic auth password" do
276
+ lambda {
277
+ @dsl.interpret(<<-CONFIG)
278
+ artifact_resolution_service {
279
+ source_id "01234567890123456789"
280
+ uri "http://idp.invalid/resolve-artifacts"
281
+ identity_provider "http://idp.invalid/"
282
+ service_provider "http://sp.invalid/"
283
+
284
+ http_basic_auth {
285
+ realm "myssorealm"
286
+ user_id "myuserid"
287
+ }
288
+ }
289
+ CONFIG
290
+ }.should raise_error SamlSp::ConfigurationError
291
+ end
292
+
293
+ end
294
+
295
+
296
+ # Copyright (c) 2010 OpenLogic
297
+ #
298
+ # Licensed under MIT license. See LICENSE.txt
299
+