maestrano-ruby-test 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +34 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +45 -0
- data/LICENSE +21 -0
- data/README.md +794 -0
- data/Rakefile +40 -0
- data/bin/maestrano-console +9 -0
- data/lib/maestrano.rb +271 -0
- data/lib/maestrano/account/bill.rb +14 -0
- data/lib/maestrano/account/recurring_bill.rb +14 -0
- data/lib/maestrano/api/error/authentication_error.rb +8 -0
- data/lib/maestrano/api/error/base_error.rb +24 -0
- data/lib/maestrano/api/error/connection_error.rb +8 -0
- data/lib/maestrano/api/error/invalid_request_error.rb +14 -0
- data/lib/maestrano/api/list_object.rb +37 -0
- data/lib/maestrano/api/object.rb +187 -0
- data/lib/maestrano/api/operation/base.rb +215 -0
- data/lib/maestrano/api/operation/create.rb +18 -0
- data/lib/maestrano/api/operation/delete.rb +13 -0
- data/lib/maestrano/api/operation/list.rb +18 -0
- data/lib/maestrano/api/operation/update.rb +59 -0
- data/lib/maestrano/api/resource.rb +47 -0
- data/lib/maestrano/api/util.rb +122 -0
- data/lib/maestrano/open_struct.rb +11 -0
- data/lib/maestrano/saml/attribute_value.rb +15 -0
- data/lib/maestrano/saml/metadata.rb +64 -0
- data/lib/maestrano/saml/request.rb +93 -0
- data/lib/maestrano/saml/response.rb +201 -0
- data/lib/maestrano/saml/schemas/saml20assertion_schema.xsd +283 -0
- data/lib/maestrano/saml/schemas/saml20protocol_schema.xsd +302 -0
- data/lib/maestrano/saml/schemas/xenc_schema.xsd +146 -0
- data/lib/maestrano/saml/schemas/xmldsig_schema.xsd +318 -0
- data/lib/maestrano/saml/settings.rb +37 -0
- data/lib/maestrano/saml/validation_error.rb +7 -0
- data/lib/maestrano/sso.rb +86 -0
- data/lib/maestrano/sso/base_group.rb +31 -0
- data/lib/maestrano/sso/base_membership.rb +25 -0
- data/lib/maestrano/sso/base_user.rb +75 -0
- data/lib/maestrano/sso/group.rb +24 -0
- data/lib/maestrano/sso/session.rb +107 -0
- data/lib/maestrano/sso/user.rb +34 -0
- data/lib/maestrano/version.rb +3 -0
- data/lib/maestrano/xml_security/signed_document.rb +170 -0
- data/maestrano.gemspec +32 -0
- data/maestrano.png +0 -0
- data/test/helpers/api_helpers.rb +115 -0
- data/test/helpers/saml_helpers.rb +62 -0
- data/test/maestrano/account/bill_test.rb +48 -0
- data/test/maestrano/account/recurring_bill_test.rb +49 -0
- data/test/maestrano/api/list_object_test.rb +20 -0
- data/test/maestrano/api/object_test.rb +28 -0
- data/test/maestrano/api/resource_test.rb +343 -0
- data/test/maestrano/api/util_test.rb +31 -0
- data/test/maestrano/maestrano_test.rb +260 -0
- data/test/maestrano/open_struct_test.rb +10 -0
- data/test/maestrano/saml/request_test.rb +168 -0
- data/test/maestrano/saml/response_test.rb +290 -0
- data/test/maestrano/saml/settings_test.rb +51 -0
- data/test/maestrano/sso/base_group_test.rb +54 -0
- data/test/maestrano/sso/base_membership_test.rb +45 -0
- data/test/maestrano/sso/base_user_test.rb +114 -0
- data/test/maestrano/sso/group_test.rb +47 -0
- data/test/maestrano/sso/session_test.rb +161 -0
- data/test/maestrano/sso/user_test.rb +65 -0
- data/test/maestrano/sso_test.rb +105 -0
- data/test/maestrano/xml_security/signed_document.rb +163 -0
- data/test/support/saml/certificates/certificate1 +12 -0
- data/test/support/saml/certificates/r1_certificate2_base64 +1 -0
- data/test/support/saml/responses/adfs_response_sha1.xml +46 -0
- data/test/support/saml/responses/adfs_response_sha256.xml +46 -0
- data/test/support/saml/responses/adfs_response_sha384.xml +46 -0
- data/test/support/saml/responses/adfs_response_sha512.xml +46 -0
- data/test/support/saml/responses/no_signature_ns.xml +48 -0
- data/test/support/saml/responses/open_saml_response.xml +56 -0
- data/test/support/saml/responses/r1_response6.xml.base64 +1 -0
- data/test/support/saml/responses/response1.xml.base64 +1 -0
- data/test/support/saml/responses/response2.xml.base64 +79 -0
- data/test/support/saml/responses/response3.xml.base64 +66 -0
- data/test/support/saml/responses/response4.xml.base64 +93 -0
- data/test/support/saml/responses/response5.xml.base64 +102 -0
- data/test/support/saml/responses/response_with_ampersands.xml +139 -0
- data/test/support/saml/responses/response_with_ampersands.xml.base64 +93 -0
- data/test/support/saml/responses/response_with_multiple_attribute_values.xml +57 -0
- data/test/support/saml/responses/simple_saml_php.xml +71 -0
- data/test/support/saml/responses/starfield_response.xml.base64 +1 -0
- data/test/support/saml/responses/wrapped_response_2.xml.base64 +150 -0
- data/test/test_helper.rb +47 -0
- metadata +315 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.expand_path('../../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
module Maestrano
|
4
|
+
module SSO
|
5
|
+
class GroupTest < Test::Unit::TestCase
|
6
|
+
setup do
|
7
|
+
@group = mock('group')
|
8
|
+
class << @group
|
9
|
+
include Maestrano::SSO::Group
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "find_for_maestrano_auth" do
|
14
|
+
should "raise an error if not overriden" do
|
15
|
+
assert_raise(NoMethodError.new("You need to override find_for_maestrano_auth in your Mocha::Mock model")) do
|
16
|
+
@group.find_for_maestrano_auth({})
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
should "execute properly otherwise" do
|
21
|
+
def @group.find_for_maestrano_auth(auth); return true; end
|
22
|
+
assert_nothing_thrown do
|
23
|
+
@group.find_for_maestrano_auth({})
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "maestrano?" do
|
29
|
+
should "raise an error if no provider attribute and not overriden" do
|
30
|
+
assert_raise(NoMethodError.new("You need to override maestrano? in your Mocha::Mock model")) do
|
31
|
+
@group.maestrano?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
should "return true if the provider is 'maestrano'" do
|
36
|
+
@group.stubs(:provider).returns('maestrano')
|
37
|
+
assert @group.maestrano?
|
38
|
+
end
|
39
|
+
|
40
|
+
should "return false if the provider is something else" do
|
41
|
+
@group.stubs(:provider).returns('someprovider')
|
42
|
+
assert !@group.maestrano?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require File.expand_path('../../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
module Maestrano
|
4
|
+
module SSO
|
5
|
+
class SessionTest < Test::Unit::TestCase
|
6
|
+
setup do
|
7
|
+
@mno_session = {
|
8
|
+
uid: 'usr-1',
|
9
|
+
session: 'g4dfg4fdg8378d6acf45',
|
10
|
+
session_recheck: Time.now.utc.iso8601,
|
11
|
+
group_uid: 'cld-2'
|
12
|
+
}
|
13
|
+
@session = {
|
14
|
+
maestrano: Base64.encode64(@mno_session.to_json)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
should "initialize the sso session properly" do
|
19
|
+
sso_session = Maestrano::SSO::Session.new(@session)
|
20
|
+
assert_equal sso_session.uid, @mno_session[:uid]
|
21
|
+
assert_equal sso_session.session_token, @mno_session[:session]
|
22
|
+
assert_equal sso_session.recheck, Time.iso8601(@mno_session[:session_recheck])
|
23
|
+
assert_equal sso_session.group_uid, @mno_session[:group_uid]
|
24
|
+
end
|
25
|
+
|
26
|
+
context "from_user_auth_hash" do
|
27
|
+
should "set the session correctly" do
|
28
|
+
sso_session = {}
|
29
|
+
auth = {
|
30
|
+
extra: {
|
31
|
+
session: {
|
32
|
+
uid: 'usr-1',
|
33
|
+
token: '15fg6d',
|
34
|
+
recheck: Time.now,
|
35
|
+
group_uid: 'cld-3'
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
sso_session = Maestrano::SSO::Session.from_user_auth_hash(@session,auth)
|
40
|
+
assert_equal sso_session.uid, auth[:extra][:session][:uid]
|
41
|
+
assert_equal sso_session.session_token, auth[:extra][:session][:token]
|
42
|
+
assert_equal sso_session.recheck.utc.iso8601, auth[:extra][:session][:recheck].utc.iso8601
|
43
|
+
assert_equal sso_session.group_uid, auth[:extra][:session][:group_uid]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
context "remote_check_required?" do
|
49
|
+
setup do
|
50
|
+
@sso_session = Maestrano::SSO::Session.new(@session)
|
51
|
+
end
|
52
|
+
|
53
|
+
should "should return true if uid is missing" do
|
54
|
+
@sso_session.uid = nil
|
55
|
+
assert @sso_session.remote_check_required?
|
56
|
+
end
|
57
|
+
|
58
|
+
should "should return true if session_token is missing" do
|
59
|
+
@sso_session.session_token = nil
|
60
|
+
assert @sso_session.remote_check_required?
|
61
|
+
end
|
62
|
+
|
63
|
+
should "should return true if recheck is missing" do
|
64
|
+
@sso_session.recheck = nil
|
65
|
+
assert @sso_session.remote_check_required?
|
66
|
+
end
|
67
|
+
|
68
|
+
should "return true if now is after recheck" do
|
69
|
+
Timecop.freeze(@sso_session.recheck + 60) do
|
70
|
+
assert @sso_session.remote_check_required?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
should "return false if now is before recheck" do
|
75
|
+
Timecop.freeze(@sso_session.recheck - 60) do
|
76
|
+
assert !@sso_session.remote_check_required?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "perform_remote_check" do
|
82
|
+
setup do
|
83
|
+
@sso_session = Maestrano::SSO::Session.new(@session)
|
84
|
+
end
|
85
|
+
|
86
|
+
should "update the session recheck and return true if valid" do
|
87
|
+
recheck = @sso_session.recheck + 600
|
88
|
+
RestClient.stubs(:get).returns({'valid' => true, 'recheck' => recheck.utc.iso8601 }.to_json)
|
89
|
+
assert @sso_session.perform_remote_check
|
90
|
+
assert_equal @sso_session.recheck, recheck
|
91
|
+
end
|
92
|
+
|
93
|
+
should "leave the session recheck unchanged and return false if invalid" do
|
94
|
+
recheck = @sso_session.recheck
|
95
|
+
RestClient.stubs(:get).returns({'valid' => false, 'recheck' => (recheck + 600).utc.iso8601 }.to_json)
|
96
|
+
assert !@sso_session.perform_remote_check
|
97
|
+
assert_equal @sso_session.recheck, recheck
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "valid?" do
|
102
|
+
setup do
|
103
|
+
@sso_session = Maestrano::SSO::Session.new(@session)
|
104
|
+
Maestrano.configure { |c| c.sso.slo_enabled = true }
|
105
|
+
end
|
106
|
+
|
107
|
+
should "return true if Single Logout is disabled" do
|
108
|
+
Maestrano.configure { |c| c.sso.slo_enabled = false }
|
109
|
+
@sso_session.stubs(:remote_check_required?).returns(true)
|
110
|
+
@sso_session.stubs(:perform_remote_check).returns(false)
|
111
|
+
assert @sso_session.valid?
|
112
|
+
end
|
113
|
+
|
114
|
+
should "return true if_session is enabled and session is nil" do
|
115
|
+
sso_session = Maestrano::SSO::Session.new(nil)
|
116
|
+
assert sso_session.valid?(if_session: true)
|
117
|
+
end
|
118
|
+
|
119
|
+
should "return true if_session is enabled and session is empty" do
|
120
|
+
sso_session = Maestrano::SSO::Session.new({})
|
121
|
+
assert sso_session.valid?(if_session: true)
|
122
|
+
end
|
123
|
+
|
124
|
+
should "return true if no remote_check_required?" do
|
125
|
+
@sso_session.stubs(:remote_check_required?).returns(false)
|
126
|
+
assert @sso_session.valid?
|
127
|
+
assert @sso_session.valid?(if_session: true)
|
128
|
+
end
|
129
|
+
|
130
|
+
should "return true if remote_check_required? and valid" do
|
131
|
+
@sso_session.stubs(:remote_check_required?).returns(true)
|
132
|
+
@sso_session.stubs(:perform_remote_check).returns(true)
|
133
|
+
assert @sso_session.valid?
|
134
|
+
assert @sso_session.valid?(if_session: true)
|
135
|
+
end
|
136
|
+
|
137
|
+
should "update maestrano session with recheck timestamp if remote_check_required? and valid" do
|
138
|
+
recheck = (@sso_session.recheck + 600)
|
139
|
+
@sso_session.recheck = recheck
|
140
|
+
@sso_session.stubs(:remote_check_required?).returns(true)
|
141
|
+
@sso_session.stubs(:perform_remote_check).returns(true)
|
142
|
+
@sso_session.valid?
|
143
|
+
assert_equal JSON.parse(Base64.decode64(@session[:maestrano]))['session_recheck'], recheck.utc.iso8601
|
144
|
+
end
|
145
|
+
|
146
|
+
should "return false if remote_check_required? and invalid" do
|
147
|
+
@sso_session.stubs(:remote_check_required?).returns(true)
|
148
|
+
@sso_session.stubs(:perform_remote_check).returns(false)
|
149
|
+
assert_false @sso_session.valid?
|
150
|
+
assert_false @sso_session.valid?(if_session: true)
|
151
|
+
end
|
152
|
+
|
153
|
+
should "return false if internal session is nil" do
|
154
|
+
sso_session = Maestrano::SSO::Session.new(nil)
|
155
|
+
assert_false @sso_session.valid?
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.expand_path('../../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
module Maestrano
|
4
|
+
module SSO
|
5
|
+
class UserTest < Test::Unit::TestCase
|
6
|
+
setup do
|
7
|
+
@user = mock('user')
|
8
|
+
class << @user
|
9
|
+
include Maestrano::SSO::User
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "find_for_maestrano_auth" do
|
14
|
+
should "raise an error if not overriden" do
|
15
|
+
assert_raise(NoMethodError.new("You need to override find_for_maestrano_auth in your Mocha::Mock model")) do
|
16
|
+
@user.find_for_maestrano_auth({})
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
should "execute properly otherwise" do
|
21
|
+
def @user.find_for_maestrano_auth(auth); return true; end
|
22
|
+
assert_nothing_thrown do
|
23
|
+
@user.find_for_maestrano_auth({})
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "maestrano?" do
|
29
|
+
should "raise an error if no provider attribute and not overriden" do
|
30
|
+
assert_raise(NoMethodError.new("You need to override maestrano? in your Mocha::Mock model")) do
|
31
|
+
@user.maestrano?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
should "return true if the provider is 'maestrano'" do
|
36
|
+
@user.stubs(:provider).returns('maestrano')
|
37
|
+
assert @user.maestrano?
|
38
|
+
end
|
39
|
+
|
40
|
+
should "return false if the provider is something else" do
|
41
|
+
@user.stubs(:provider).returns('someprovider')
|
42
|
+
assert !@user.maestrano?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "maestrano_session_valid?" do
|
47
|
+
should "return true if the sso session is valid" do
|
48
|
+
session = {}
|
49
|
+
sso_session = mock('sso_session')
|
50
|
+
Maestrano::SSO::Session.stubs(:new).with(session).returns(sso_session)
|
51
|
+
sso_session.stubs(:valid?).returns(true)
|
52
|
+
assert @user.maestrano_session_valid?(session)
|
53
|
+
end
|
54
|
+
|
55
|
+
should "return false if the sso session is invalid" do
|
56
|
+
session = {}
|
57
|
+
sso_session = mock('sso_session')
|
58
|
+
Maestrano::SSO::Session.stubs(:new).with(session).returns(sso_session)
|
59
|
+
sso_session.stubs(:valid?).returns(false)
|
60
|
+
assert !@user.maestrano_session_valid?(session)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require File.expand_path('../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
module Maestrano
|
4
|
+
class SSOTest < Test::Unit::TestCase
|
5
|
+
include SamlTestHelper
|
6
|
+
|
7
|
+
setup do
|
8
|
+
Maestrano.config = nil
|
9
|
+
Maestrano.configure { |config| config.environment = 'production' }
|
10
|
+
end
|
11
|
+
|
12
|
+
should "return the right init_url" do
|
13
|
+
assert Maestrano::SSO.init_url == "http://localhost:3000/maestrano/auth/saml/init"
|
14
|
+
end
|
15
|
+
|
16
|
+
should "return the right consume_url" do
|
17
|
+
assert Maestrano::SSO.consume_url == "http://localhost:3000/maestrano/auth/saml/consume"
|
18
|
+
end
|
19
|
+
|
20
|
+
should "return the right logout_url" do
|
21
|
+
assert Maestrano::SSO.logout_url == "https://maestrano.com/app_logout"
|
22
|
+
end
|
23
|
+
|
24
|
+
should "return the right unauthorized_url" do
|
25
|
+
assert Maestrano::SSO.unauthorized_url == "https://maestrano.com/app_access_unauthorized"
|
26
|
+
end
|
27
|
+
|
28
|
+
should "return the right idp_url" do
|
29
|
+
assert Maestrano::SSO.idp_url == "https://maestrano.com/api/v1/auth/saml"
|
30
|
+
end
|
31
|
+
|
32
|
+
should "return the right session_check_url" do
|
33
|
+
assert Maestrano::SSO.session_check_url('usr-1','f9ds8fdg7f89') == "https://maestrano.com/api/v1/auth/saml/usr-1?session=f9ds8fdg7f89"
|
34
|
+
end
|
35
|
+
|
36
|
+
should "return the right enabled parameter" do
|
37
|
+
assert Maestrano::SSO.enabled? == !!Maestrano.param('sso.enabled')
|
38
|
+
end
|
39
|
+
|
40
|
+
should "return the right saml_settings" do
|
41
|
+
settings = Maestrano::SSO.saml_settings
|
42
|
+
assert settings.assertion_consumer_service_url == Maestrano::SSO.consume_url
|
43
|
+
assert settings.issuer == Maestrano.param('api.id')
|
44
|
+
assert settings.idp_sso_target_url == Maestrano::SSO.idp_url
|
45
|
+
assert settings.idp_cert_fingerprint == Maestrano.param('sso_x509_fingerprint')
|
46
|
+
assert settings.name_identifier_format == Maestrano.param('sso_name_id_format')
|
47
|
+
end
|
48
|
+
|
49
|
+
should "build the right saml request" do
|
50
|
+
request = mock('request')
|
51
|
+
Maestrano::Saml::Request.stubs(:new).with(group_id: "cld-3").returns(request)
|
52
|
+
assert Maestrano::SSO.build_request(group_id: "cld-3") == request
|
53
|
+
end
|
54
|
+
|
55
|
+
should "build the right saml response" do
|
56
|
+
response = mock('response')
|
57
|
+
Maestrano::Saml::Response.stubs(:new).with(response_document).returns(response)
|
58
|
+
response = Maestrano::SSO.build_response(response_document)
|
59
|
+
assert Maestrano::SSO.build_response(response_document) == response
|
60
|
+
end
|
61
|
+
|
62
|
+
context "session management" do
|
63
|
+
setup do
|
64
|
+
@session = {}
|
65
|
+
@auth = {
|
66
|
+
extra: {
|
67
|
+
session: {
|
68
|
+
uid: 'usr-1',
|
69
|
+
token: '15fg6d',
|
70
|
+
recheck: Time.now,
|
71
|
+
group_uid: 'cld-3'
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
should "set the session correctly" do
|
78
|
+
Maestrano::SSO.set_session(@session,@auth)
|
79
|
+
decrypt_session = JSON.parse(Base64.decode64(@session[:maestrano]))
|
80
|
+
assert_equal decrypt_session['uid'], @auth[:extra][:session][:uid]
|
81
|
+
assert_equal decrypt_session['session'], @auth[:extra][:session][:token]
|
82
|
+
assert_equal decrypt_session['session_recheck'], @auth[:extra][:session][:recheck].utc.iso8601
|
83
|
+
assert_equal decrypt_session['group_uid'], @auth[:extra][:session][:group_uid]
|
84
|
+
end
|
85
|
+
|
86
|
+
should "unset the session correctly" do
|
87
|
+
Maestrano::SSO.set_session(@session,@auth)
|
88
|
+
Maestrano::SSO.clear_session(@session)
|
89
|
+
assert @session[:maestrano].nil?
|
90
|
+
end
|
91
|
+
|
92
|
+
should "unset the session if key is a string" do
|
93
|
+
@session['maestrano'] = "bla"
|
94
|
+
Maestrano::SSO.clear_session(@session)
|
95
|
+
assert @session["maestrano"].nil?
|
96
|
+
end
|
97
|
+
|
98
|
+
should "alias clear_session as unset_session" do
|
99
|
+
Maestrano::SSO.set_session(@session,@auth)
|
100
|
+
Maestrano::SSO.unset_session(@session)
|
101
|
+
assert @session[:maestrano].nil?
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require File.expand_path('../../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
module Maestrano
|
4
|
+
module XMLSecurity
|
5
|
+
class XmlSecurityTest < Test::Unit::TestCase
|
6
|
+
include XMLSecurity
|
7
|
+
|
8
|
+
context "XmlSecurity" do
|
9
|
+
setup do
|
10
|
+
@document = Maestrano::XMLSecurity::SignedDocument.new(Base64.decode64(response_document))
|
11
|
+
@base64cert = @document.elements["//ds:X509Certificate"].text
|
12
|
+
end
|
13
|
+
|
14
|
+
should "should run validate without throwing NS related exceptions" do
|
15
|
+
assert !@document.validate_signature(@base64cert, true)
|
16
|
+
end
|
17
|
+
|
18
|
+
should "should run validate with throwing NS related exceptions" do
|
19
|
+
assert_raise(Maestrano::Saml::ValidationError) do
|
20
|
+
@document.validate_signature(@base64cert, false)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
should "not raise an error when softly validating the document multiple times" do
|
25
|
+
assert_nothing_raised do
|
26
|
+
2.times { @document.validate_signature(@base64cert, true) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
should "should raise Fingerprint mismatch" do
|
31
|
+
exception = assert_raise(Maestrano::Saml::ValidationError) do
|
32
|
+
@document.validate_document("no:fi:ng:er:pr:in:t", false)
|
33
|
+
end
|
34
|
+
assert_equal("Fingerprint mismatch", exception.message)
|
35
|
+
end
|
36
|
+
|
37
|
+
should "should raise Digest mismatch" do
|
38
|
+
exception = assert_raise(Maestrano::Saml::ValidationError) do
|
39
|
+
@document.validate_signature(@base64cert, false)
|
40
|
+
end
|
41
|
+
assert_equal("Digest mismatch", exception.message)
|
42
|
+
end
|
43
|
+
|
44
|
+
should "should raise Key validation error" do
|
45
|
+
response = Base64.decode64(response_document)
|
46
|
+
response.sub!("<ds:DigestValue>pJQ7MS/ek4KRRWGmv/H43ReHYMs=</ds:DigestValue>",
|
47
|
+
"<ds:DigestValue>b9xsAXLsynugg3Wc1CI3kpWku+0=</ds:DigestValue>")
|
48
|
+
document = Maestrano::XMLSecurity::SignedDocument.new(response)
|
49
|
+
base64cert = document.elements["//ds:X509Certificate"].text
|
50
|
+
exception = assert_raise(Maestrano::Saml::ValidationError) do
|
51
|
+
document.validate_signature(base64cert, false)
|
52
|
+
end
|
53
|
+
assert_equal("Key validation error", exception.message)
|
54
|
+
end
|
55
|
+
|
56
|
+
should "raise validation error when the X509Certificate is missing" do
|
57
|
+
response = Base64.decode64(response_document)
|
58
|
+
response.sub!(/<ds:X509Certificate>.*<\/ds:X509Certificate>/, "")
|
59
|
+
document = Maestrano::XMLSecurity::SignedDocument.new(response)
|
60
|
+
exception = assert_raise(Maestrano::Saml::ValidationError) do
|
61
|
+
document.validate_document("a fingerprint", false) # The fingerprint isn't relevant to this test
|
62
|
+
end
|
63
|
+
assert_equal("Certificate element missing in response (ds:X509Certificate)", exception.message)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "Algorithms" do
|
68
|
+
should "validate using SHA1" do
|
69
|
+
@document = Maestrano::XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha1, false))
|
70
|
+
assert @document.validate_document("F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72")
|
71
|
+
end
|
72
|
+
|
73
|
+
should "validate using SHA256" do
|
74
|
+
@document = Maestrano::XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha256, false))
|
75
|
+
assert @document.validate_document("28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA")
|
76
|
+
end
|
77
|
+
|
78
|
+
should "validate using SHA384" do
|
79
|
+
@document = Maestrano::XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha384, false))
|
80
|
+
assert @document.validate_document("F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72")
|
81
|
+
end
|
82
|
+
|
83
|
+
should "validate using SHA512" do
|
84
|
+
@document = Maestrano::XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha512, false))
|
85
|
+
assert @document.validate_document("F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "XmlSecurity::SignedDocument" do
|
90
|
+
|
91
|
+
context "#extract_inclusive_namespaces" do
|
92
|
+
should "support explicit namespace resolution for exclusive canonicalization" do
|
93
|
+
response = fixture(:open_saml_response, false)
|
94
|
+
document = Maestrano::XMLSecurity::SignedDocument.new(response)
|
95
|
+
inclusive_namespaces = document.send(:extract_inclusive_namespaces)
|
96
|
+
|
97
|
+
assert_equal %w[ xs ], inclusive_namespaces
|
98
|
+
end
|
99
|
+
|
100
|
+
should "support implicit namespace resolution for exclusive canonicalization" do
|
101
|
+
response = fixture(:no_signature_ns, false)
|
102
|
+
document = Maestrano::XMLSecurity::SignedDocument.new(response)
|
103
|
+
inclusive_namespaces = document.send(:extract_inclusive_namespaces)
|
104
|
+
|
105
|
+
assert_equal %w[ #default saml ds xs xsi ], inclusive_namespaces
|
106
|
+
end
|
107
|
+
|
108
|
+
should_eventually 'support inclusive canonicalization' do
|
109
|
+
|
110
|
+
response = Maestrano::Saml::Response.new(fixture("tdnf_response.xml"))
|
111
|
+
response.stubs(:conditions).returns(nil)
|
112
|
+
assert !response.is_valid?
|
113
|
+
settings = Maestrano::Saml::Settings.new
|
114
|
+
assert !response.is_valid?
|
115
|
+
response.settings = settings
|
116
|
+
assert !response.is_valid?
|
117
|
+
settings.idp_cert_fingerprint = "e6 38 9a 20 b7 4f 13 db 6a bc b1 42 6a e7 52 1d d6 56 d4 1b".upcase.gsub(" ", ":")
|
118
|
+
assert response.validate!
|
119
|
+
end
|
120
|
+
|
121
|
+
should "return an empty list when inclusive namespace element is missing" do
|
122
|
+
response = fixture(:no_signature_ns, false)
|
123
|
+
response.slice! %r{<InclusiveNamespaces xmlns="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="#default saml ds xs xsi"/>}
|
124
|
+
|
125
|
+
document = Maestrano::XMLSecurity::SignedDocument.new(response)
|
126
|
+
inclusive_namespaces = document.send(:extract_inclusive_namespaces)
|
127
|
+
|
128
|
+
assert inclusive_namespaces.empty?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context "StarfieldTMS" do
|
133
|
+
setup do
|
134
|
+
@response = Maestrano::Saml::Response.new(fixture(:starfield_response))
|
135
|
+
@response.settings = Maestrano::Saml::Settings.new(
|
136
|
+
:idp_cert_fingerprint => "8D:BA:53:8E:A3:B6:F9:F1:69:6C:BB:D9:D8:BD:41:B3:AC:4F:9D:4D"
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
140
|
+
should "be able to validate a good response" do
|
141
|
+
Timecop.freeze Time.parse('2012-11-28 17:55:00 UTC') do
|
142
|
+
assert @response.validate!
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
should "fail before response is valid" do
|
147
|
+
Timecop.freeze Time.parse('2012-11-20 17:55:00 UTC') do
|
148
|
+
assert ! @response.is_valid?
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
should "fail after response expires" do
|
153
|
+
Timecop.freeze Time.parse('2012-11-30 17:55:00 UTC') do
|
154
|
+
assert ! @response.is_valid?
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|