ruby-saml 0.7.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ruby-saml might be problematic. Click here for more details.
- data/Gemfile +1 -1
- data/README.md +70 -65
- data/changelog.md +7 -0
- data/lib/onelogin/ruby-saml/authrequest.rb +1 -1
- data/lib/onelogin/ruby-saml/logging.rb +1 -1
- data/lib/onelogin/ruby-saml/logoutrequest.rb +1 -1
- data/lib/onelogin/ruby-saml/logoutresponse.rb +1 -2
- data/lib/onelogin/ruby-saml/metadata.rb +2 -2
- data/lib/onelogin/ruby-saml/response.rb +1 -1
- data/lib/onelogin/ruby-saml/settings.rb +1 -1
- data/lib/onelogin/ruby-saml/validation_error.rb +1 -1
- data/lib/onelogin/ruby-saml/version.rb +2 -2
- data/lib/xml_security.rb +4 -4
- data/ruby-saml.gemspec +2 -3
- data/test/logoutrequest_test.rb +15 -15
- data/test/logoutresponse_test.rb +19 -19
- data/test/request_test.rb +17 -17
- data/test/response_test.rb +52 -52
- data/test/responses/logoutresponse_fixtures.rb +2 -2
- data/test/settings_test.rb +2 -2
- data/test/xml_security_test.rb +9 -9
- metadata +11 -26
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# Ruby SAML [![Build Status](https://secure.travis-ci.org/onelogin/ruby-saml.png)](http://travis-ci.org/onelogin/ruby-saml)
|
2
2
|
|
3
|
+
## Updating from 0.7.x to 0.8.x
|
4
|
+
Version `0.8.0` changes the namespace of the gem from `Onelogin::Saml` to `Onelogin::RubySaml`. Please update your implementations of the gem accordingly.
|
5
|
+
|
6
|
+
## Overview
|
7
|
+
|
3
8
|
The Ruby SAML library is for implementing the client side of a SAML authorization, i.e. it provides a means for managing authorization initialization and confirmation requests from identity providers.
|
4
9
|
|
5
10
|
SAML authorization is a two step process and you are expected to implement support for both.
|
@@ -9,92 +14,92 @@ SAML authorization is a two step process and you are expected to implement suppo
|
|
9
14
|
This is the first request you will get from the identity provider. It will hit your application at a specific URL (that you've announced as being your SAML initialization point). The response to this initialization, is a redirect back to the identity provider, which can look something like this (ignore the saml_settings method call for now):
|
10
15
|
|
11
16
|
```ruby
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
17
|
+
def init
|
18
|
+
request = Onelogin::RubySaml::Authrequest.new
|
19
|
+
redirect_to(request.create(saml_settings))
|
20
|
+
end
|
16
21
|
```
|
17
22
|
|
18
23
|
Once you've redirected back to the identity provider, it will ensure that the user has been authorized and redirect back to your application for final consumption, this is can look something like this (the authorize_success and authorize_failure methods are specific to your application):
|
19
24
|
|
20
25
|
```ruby
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
def consume
|
27
|
+
response = Onelogin::RubySaml::Response.new(params[:SAMLResponse])
|
28
|
+
response.settings = saml_settings
|
29
|
+
|
30
|
+
if response.is_valid? && user = current_account.users.find_by_email(response.name_id)
|
31
|
+
authorize_success(user)
|
32
|
+
else
|
33
|
+
authorize_failure(user)
|
34
|
+
end
|
35
|
+
end
|
31
36
|
```
|
32
37
|
|
33
38
|
In the above there are a few assumptions in place, one being that the response.name_id is an email address. This is all handled with how you specify the settings that are in play via the saml_settings method. That could be implemented along the lines of this:
|
34
39
|
|
35
40
|
```ruby
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
41
|
+
def saml_settings
|
42
|
+
settings = Onelogin::RubySaml::Settings.new
|
43
|
+
|
44
|
+
settings.assertion_consumer_service_url = "http://#{request.host}/saml/finalize"
|
45
|
+
settings.issuer = request.host
|
46
|
+
settings.idp_sso_target_url = "https://app.onelogin.com/saml/signon/#{OneLoginAppId}"
|
47
|
+
settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
|
48
|
+
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
49
|
+
# Optional for most SAML IdPs
|
50
|
+
settings.authn_context = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
|
51
|
+
|
52
|
+
settings
|
53
|
+
end
|
49
54
|
```
|
50
55
|
|
51
56
|
What's left at this point, is to wrap it all up in a controller and point the initialization and consumption URLs in OneLogin at that. A full controller example could look like this:
|
52
57
|
|
53
58
|
```ruby
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
59
|
+
# This controller expects you to use the URLs /saml/init and /saml/consume in your OneLogin application.
|
60
|
+
class SamlController < ApplicationController
|
61
|
+
def init
|
62
|
+
request = Onelogin::RubySaml::Authrequest.new
|
63
|
+
redirect_to(request.create(saml_settings))
|
64
|
+
end
|
60
65
|
|
61
|
-
|
62
|
-
|
63
|
-
|
66
|
+
def consume
|
67
|
+
response = Onelogin::RubySaml::Response.new(params[:SAMLResponse])
|
68
|
+
response.settings = saml_settings
|
64
69
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
+
if response.is_valid? && user = current_account.users.find_by_email(response.name_id)
|
71
|
+
authorize_success(user)
|
72
|
+
else
|
73
|
+
authorize_failure(user)
|
70
74
|
end
|
75
|
+
end
|
71
76
|
|
72
|
-
|
77
|
+
private
|
73
78
|
|
74
|
-
|
75
|
-
|
79
|
+
def saml_settings
|
80
|
+
settings = Onelogin::RubySaml::Settings.new
|
76
81
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
82
|
+
settings.assertion_consumer_service_url = "http://#{request.host}/saml/consume"
|
83
|
+
settings.issuer = request.host
|
84
|
+
settings.idp_sso_target_url = "https://app.onelogin.com/saml/signon/#{OneLoginAppId}"
|
85
|
+
settings.idp_cert_fingerprint = OneLoginAppCertFingerPrint
|
86
|
+
settings.name_identifier_format = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
87
|
+
# Optional for most SAML IdPs
|
88
|
+
settings.authn_context = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
|
84
89
|
|
85
|
-
|
86
|
-
end
|
90
|
+
settings
|
87
91
|
end
|
92
|
+
end
|
88
93
|
```
|
89
94
|
|
90
95
|
If are using saml:AttributeStatement to transfare metadata, like the user name, you can access all the attributes through response.attributes. It
|
91
96
|
contains all the saml:AttributeStatement with its 'Name' as a indifferent key and the one saml:AttributeValue as value.
|
92
97
|
|
93
98
|
```ruby
|
94
|
-
|
95
|
-
|
99
|
+
response = Onelogin::RubySaml::Response.new(params[:SAMLResponse])
|
100
|
+
response.settings = saml_settings
|
96
101
|
|
97
|
-
|
102
|
+
response.attributes[:username]
|
98
103
|
```
|
99
104
|
|
100
105
|
## Service Provider Metadata
|
@@ -102,20 +107,20 @@ contains all the saml:AttributeStatement with its 'Name' as a indifferent key an
|
|
102
107
|
To form a trusted pair relationship with the IdP, the SP (you) need to provide metadata XML
|
103
108
|
to the IdP for various good reasons. (Caching, certificate lookups, relaying party permissions, etc)
|
104
109
|
|
105
|
-
The class Onelogin::
|
110
|
+
The class Onelogin::RubySaml::Metadata takes care of this by reading the Settings and returning XML. All
|
106
111
|
you have to do is add a controller to return the data, then give this URL to the IdP administrator.
|
107
112
|
The metdata will be polled by the IdP every few minutes, so updating your settings should propagate
|
108
113
|
to the IdP settings.
|
109
114
|
|
110
115
|
```ruby
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
end
|
116
|
+
class SamlController < ApplicationController
|
117
|
+
# ... the rest of your controller definitions ...
|
118
|
+
def metadata
|
119
|
+
settings = Account.get_saml_settings
|
120
|
+
meta = Onelogin::RubySaml::Metadata.new
|
121
|
+
render :xml => meta.generate(settings)
|
118
122
|
end
|
123
|
+
end
|
119
124
|
```
|
120
125
|
|
121
126
|
## Clock Drift
|
@@ -127,7 +132,7 @@ First, ensure that both systems synchronize their clocks, using for example the
|
|
127
132
|
Even then you may experience intermittent issues though, because the clock of the Identity Provider may drift slightly ahead of your system clocks. To allow for a small amount of clock drift you can initialize the response passing in an option named `:allowed_clock_drift`. Its value must be given in a number (and/or fraction) of seconds. The value given is added to the current time at which the response is validated before it's tested against the `NotBefore` assertion. For example:
|
128
133
|
|
129
134
|
```ruby
|
130
|
-
|
135
|
+
response = Onelogin::RubySaml::Response.new(params[:SAMLResponse], :allowed_clock_drift => 1)
|
131
136
|
```
|
132
137
|
|
133
138
|
Make sure to keep the value as comfortably small as possible to keep security risks to a minimum.
|
data/changelog.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# RubySaml Changelog
|
2
|
+
|
3
|
+
### 0.8.0 (Feb 21, 2014)
|
4
|
+
Changed namespace of the gem from `Onelogin::Saml` to `Onelogin::RubySaml`. Please update your implementations of the gem accordingly.
|
5
|
+
|
6
|
+
### 0.7.3 (Feb 20, 2014)
|
7
|
+
Updated gem dependencies to be compatible with Ruby 1.8.7-p374 and 1.9.3-p448. Removed unnecessary `canonix` gem dependency.
|
@@ -3,11 +3,11 @@ require "rexml/xpath"
|
|
3
3
|
require "uri"
|
4
4
|
|
5
5
|
# Class to return SP metadata based on the settings requested.
|
6
|
-
# Return this XML in a controller, then give that URL to the the
|
6
|
+
# Return this XML in a controller, then give that URL to the the
|
7
7
|
# IdP administrator. The IdP will poll the URL and your settings
|
8
8
|
# will be updated automatically
|
9
9
|
module Onelogin
|
10
|
-
module
|
10
|
+
module RubySaml
|
11
11
|
include REXML
|
12
12
|
class Metadata
|
13
13
|
def generate(settings)
|
data/lib/xml_security.rb
CHANGED
@@ -47,7 +47,7 @@ module XMLSecurity
|
|
47
47
|
def validate_document(idp_cert_fingerprint, soft = true)
|
48
48
|
# get cert from response
|
49
49
|
cert_element = REXML::XPath.first(self, "//ds:X509Certificate", { "ds"=>DSIG })
|
50
|
-
raise Onelogin::
|
50
|
+
raise Onelogin::RubySaml::ValidationError.new("Certificate element missing in response (ds:X509Certificate)") unless cert_element
|
51
51
|
base64_cert = cert_element.text
|
52
52
|
cert_text = Base64.decode64(base64_cert)
|
53
53
|
cert = OpenSSL::X509::Certificate.new(cert_text)
|
@@ -56,7 +56,7 @@ module XMLSecurity
|
|
56
56
|
fingerprint = Digest::SHA1.hexdigest(cert.to_der)
|
57
57
|
|
58
58
|
if fingerprint != idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/,"").downcase
|
59
|
-
return soft ? false : (raise Onelogin::
|
59
|
+
return soft ? false : (raise Onelogin::RubySaml::ValidationError.new("Fingerprint mismatch"))
|
60
60
|
end
|
61
61
|
|
62
62
|
validate_signature(base64_cert, soft)
|
@@ -102,7 +102,7 @@ module XMLSecurity
|
|
102
102
|
digest_value = Base64.decode64(REXML::XPath.first(ref, "//ds:DigestValue", {"ds"=>DSIG}).text)
|
103
103
|
|
104
104
|
unless digests_match?(hash, digest_value)
|
105
|
-
return soft ? false : (raise Onelogin::
|
105
|
+
return soft ? false : (raise Onelogin::RubySaml::ValidationError.new("Digest mismatch"))
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
@@ -117,7 +117,7 @@ module XMLSecurity
|
|
117
117
|
signature_algorithm = algorithm(REXML::XPath.first(signed_info_element, "//ds:SignatureMethod", {"ds"=>DSIG}))
|
118
118
|
|
119
119
|
unless cert.public_key.verify(signature_algorithm.new, signature, canon_string)
|
120
|
-
return soft ? false : (raise Onelogin::
|
120
|
+
return soft ? false : (raise Onelogin::RubySaml::ValidationError.new("Key validation error"))
|
121
121
|
end
|
122
122
|
|
123
123
|
return true
|
data/ruby-saml.gemspec
CHANGED
@@ -3,7 +3,7 @@ require 'onelogin/ruby-saml/version'
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = 'ruby-saml'
|
6
|
-
s.version = Onelogin::
|
6
|
+
s.version = Onelogin::RubySaml::VERSION
|
7
7
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
9
|
s.authors = ["OneLogin LLC"]
|
@@ -23,7 +23,6 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.summary = %q{SAML Ruby Tookit}
|
24
24
|
s.test_files = `git ls-files test/*`.split("\n")
|
25
25
|
|
26
|
-
s.add_runtime_dependency("canonix", ["0.1.1"])
|
27
26
|
s.add_runtime_dependency("uuid", ["~> 2.3"])
|
28
|
-
s.add_runtime_dependency("nokogiri", ["
|
27
|
+
s.add_runtime_dependency("nokogiri", [">= 1.5.0"])
|
29
28
|
end
|
data/test/logoutrequest_test.rb
CHANGED
@@ -3,13 +3,13 @@ require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
|
3
3
|
class RequestTest < Test::Unit::TestCase
|
4
4
|
|
5
5
|
context "Logoutrequest" do
|
6
|
-
settings = Onelogin::
|
6
|
+
settings = Onelogin::RubySaml::Settings.new
|
7
7
|
|
8
8
|
should "create the deflated SAMLRequest URL parameter" do
|
9
9
|
settings.idp_slo_target_url = "http://unauth.com/logout"
|
10
10
|
settings.name_identifier_value = "f00f00"
|
11
11
|
|
12
|
-
unauth_url = Onelogin::
|
12
|
+
unauth_url = Onelogin::RubySaml::Logoutrequest.new.create(settings)
|
13
13
|
assert unauth_url =~ /^http:\/\/unauth\.com\/logout\?SAMLRequest=/
|
14
14
|
|
15
15
|
inflated = decode_saml_request_payload(unauth_url)
|
@@ -19,10 +19,10 @@ class RequestTest < Test::Unit::TestCase
|
|
19
19
|
|
20
20
|
should "support additional params" do
|
21
21
|
|
22
|
-
unauth_url = Onelogin::
|
22
|
+
unauth_url = Onelogin::RubySaml::Logoutrequest.new.create(settings, { :hello => nil })
|
23
23
|
assert unauth_url =~ /&hello=$/
|
24
24
|
|
25
|
-
unauth_url = Onelogin::
|
25
|
+
unauth_url = Onelogin::RubySaml::Logoutrequest.new.create(settings, { :foo => "bar" })
|
26
26
|
assert unauth_url =~ /&foo=bar$/
|
27
27
|
end
|
28
28
|
|
@@ -31,7 +31,7 @@ class RequestTest < Test::Unit::TestCase
|
|
31
31
|
sessionidx = UUID.new.generate
|
32
32
|
settings.sessionindex = sessionidx
|
33
33
|
|
34
|
-
unauth_url = Onelogin::
|
34
|
+
unauth_url = Onelogin::RubySaml::Logoutrequest.new.create(settings, { :name_id => "there" })
|
35
35
|
inflated = decode_saml_request_payload(unauth_url)
|
36
36
|
|
37
37
|
assert_match /<samlp:SessionIndex/, inflated
|
@@ -39,13 +39,13 @@ class RequestTest < Test::Unit::TestCase
|
|
39
39
|
end
|
40
40
|
|
41
41
|
should "set name_identifier_value" do
|
42
|
-
settings = Onelogin::
|
42
|
+
settings = Onelogin::RubySaml::Settings.new
|
43
43
|
settings.idp_slo_target_url = "http://example.com"
|
44
44
|
settings.name_identifier_format = "transient"
|
45
45
|
name_identifier_value = "abc123"
|
46
46
|
settings.name_identifier_value = name_identifier_value
|
47
47
|
|
48
|
-
unauth_url = Onelogin::
|
48
|
+
unauth_url = Onelogin::RubySaml::Logoutrequest.new.create(settings, { :name_id => "there" })
|
49
49
|
inflated = decode_saml_request_payload(unauth_url)
|
50
50
|
|
51
51
|
assert_match /<saml:NameID/, inflated
|
@@ -53,42 +53,42 @@ class RequestTest < Test::Unit::TestCase
|
|
53
53
|
end
|
54
54
|
|
55
55
|
should "require name_identifier_value" do
|
56
|
-
settings = Onelogin::
|
56
|
+
settings = Onelogin::RubySaml::Settings.new
|
57
57
|
settings.idp_slo_target_url = "http://example.com"
|
58
58
|
settings.name_identifier_format = nil
|
59
59
|
|
60
|
-
assert_raises(Onelogin::
|
60
|
+
assert_raises(Onelogin::RubySaml::ValidationError) { Onelogin::RubySaml::Logoutrequest.new.create(settings) }
|
61
61
|
end
|
62
62
|
|
63
63
|
context "when the target url doesn't contain a query string" do
|
64
64
|
should "create the SAMLRequest parameter correctly" do
|
65
|
-
settings = Onelogin::
|
65
|
+
settings = Onelogin::RubySaml::Settings.new
|
66
66
|
settings.idp_slo_target_url = "http://example.com"
|
67
67
|
settings.name_identifier_value = "f00f00"
|
68
68
|
|
69
|
-
unauth_url = Onelogin::
|
69
|
+
unauth_url = Onelogin::RubySaml::Logoutrequest.new.create(settings)
|
70
70
|
assert unauth_url =~ /^http:\/\/example.com\?SAMLRequest/
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
74
|
context "when the target url contains a query string" do
|
75
75
|
should "create the SAMLRequest parameter correctly" do
|
76
|
-
settings = Onelogin::
|
76
|
+
settings = Onelogin::RubySaml::Settings.new
|
77
77
|
settings.idp_slo_target_url = "http://example.com?field=value"
|
78
78
|
settings.name_identifier_value = "f00f00"
|
79
79
|
|
80
|
-
unauth_url = Onelogin::
|
80
|
+
unauth_url = Onelogin::RubySaml::Logoutrequest.new.create(settings)
|
81
81
|
assert unauth_url =~ /^http:\/\/example.com\?field=value&SAMLRequest/
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
85
|
context "consumation of logout may need to track the transaction" do
|
86
86
|
should "have access to the request uuid" do
|
87
|
-
settings = Onelogin::
|
87
|
+
settings = Onelogin::RubySaml::Settings.new
|
88
88
|
settings.idp_slo_target_url = "http://example.com?field=value"
|
89
89
|
settings.name_identifier_value = "f00f00"
|
90
90
|
|
91
|
-
unauth_req = Onelogin::
|
91
|
+
unauth_req = Onelogin::RubySaml::Logoutrequest.new
|
92
92
|
unauth_url = unauth_req.create(settings)
|
93
93
|
|
94
94
|
inflated = decode_saml_request_payload(unauth_url)
|
data/test/logoutresponse_test.rb
CHANGED
@@ -6,23 +6,23 @@ class RubySamlTest < Test::Unit::TestCase
|
|
6
6
|
context "Logoutresponse" do
|
7
7
|
context "#new" do
|
8
8
|
should "raise an exception when response is initialized with nil" do
|
9
|
-
assert_raises(ArgumentError) { Onelogin::
|
9
|
+
assert_raises(ArgumentError) { Onelogin::RubySaml::Logoutresponse.new(nil) }
|
10
10
|
end
|
11
11
|
should "default to empty settings" do
|
12
|
-
logoutresponse = Onelogin::
|
12
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new( valid_response)
|
13
13
|
assert logoutresponse.settings.nil?
|
14
14
|
end
|
15
15
|
should "accept constructor-injected settings" do
|
16
|
-
logoutresponse = Onelogin::
|
16
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new(valid_response, settings)
|
17
17
|
assert !logoutresponse.settings.nil?
|
18
18
|
end
|
19
19
|
should "accept constructor-injected options" do
|
20
|
-
logoutresponse = Onelogin::
|
20
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new(valid_response, nil, { :foo => :bar} )
|
21
21
|
assert !logoutresponse.options.empty?
|
22
22
|
end
|
23
23
|
should "support base64 encoded responses" do
|
24
24
|
expected_response = valid_response
|
25
|
-
logoutresponse = Onelogin::
|
25
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new(Base64.encode64(expected_response), settings)
|
26
26
|
|
27
27
|
assert_equal expected_response, logoutresponse.response
|
28
28
|
end
|
@@ -32,7 +32,7 @@ class RubySamlTest < Test::Unit::TestCase
|
|
32
32
|
should "validate the response" do
|
33
33
|
in_relation_to_request_id = random_id
|
34
34
|
|
35
|
-
logoutresponse = Onelogin::
|
35
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new(valid_response({:uuid => in_relation_to_request_id}), settings)
|
36
36
|
|
37
37
|
assert logoutresponse.validate
|
38
38
|
|
@@ -47,14 +47,14 @@ class RubySamlTest < Test::Unit::TestCase
|
|
47
47
|
expected_request_id = "_some_other_expected_uuid"
|
48
48
|
opts = { :matches_request_id => expected_request_id}
|
49
49
|
|
50
|
-
logoutresponse = Onelogin::
|
50
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new(valid_response, settings, opts)
|
51
51
|
|
52
52
|
assert !logoutresponse.validate
|
53
53
|
assert_not_equal expected_request_id, logoutresponse.in_response_to
|
54
54
|
end
|
55
55
|
|
56
56
|
should "invalidate responses with wrong request status" do
|
57
|
-
logoutresponse = Onelogin::
|
57
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new(unsuccessful_response, settings)
|
58
58
|
|
59
59
|
assert !logoutresponse.validate
|
60
60
|
assert !logoutresponse.success?
|
@@ -65,7 +65,7 @@ class RubySamlTest < Test::Unit::TestCase
|
|
65
65
|
should "validates good responses" do
|
66
66
|
in_relation_to_request_id = random_id
|
67
67
|
|
68
|
-
logoutresponse = Onelogin::
|
68
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new(valid_response({:uuid => in_relation_to_request_id}), settings)
|
69
69
|
|
70
70
|
logoutresponse.validate!
|
71
71
|
end
|
@@ -75,34 +75,34 @@ class RubySamlTest < Test::Unit::TestCase
|
|
75
75
|
expected_request_id = "_some_other_expected_id"
|
76
76
|
opts = { :matches_request_id => expected_request_id}
|
77
77
|
|
78
|
-
logoutresponse = Onelogin::
|
78
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new(valid_response, settings, opts)
|
79
79
|
|
80
|
-
assert_raises(Onelogin::
|
80
|
+
assert_raises(Onelogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
81
81
|
end
|
82
82
|
|
83
83
|
should "raise validation error for wrong request status" do
|
84
|
-
logoutresponse = Onelogin::
|
84
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new(unsuccessful_response, settings)
|
85
85
|
|
86
|
-
assert_raises(Onelogin::
|
86
|
+
assert_raises(Onelogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
87
87
|
end
|
88
88
|
|
89
89
|
should "raise validation error when in bad state" do
|
90
90
|
# no settings
|
91
|
-
logoutresponse = Onelogin::
|
92
|
-
assert_raises(Onelogin::
|
91
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new(unsuccessful_response)
|
92
|
+
assert_raises(Onelogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
93
93
|
end
|
94
94
|
|
95
95
|
should "raise validation error when in lack of issuer setting" do
|
96
96
|
bad_settings = settings
|
97
97
|
bad_settings.issuer = nil
|
98
|
-
logoutresponse = Onelogin::
|
99
|
-
assert_raises(Onelogin::
|
98
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new(unsuccessful_response, bad_settings)
|
99
|
+
assert_raises(Onelogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
100
100
|
end
|
101
101
|
|
102
102
|
should "raise error for invalid xml" do
|
103
|
-
logoutresponse = Onelogin::
|
103
|
+
logoutresponse = Onelogin::RubySaml::Logoutresponse.new(invalid_xml_response, settings)
|
104
104
|
|
105
|
-
assert_raises(Onelogin::
|
105
|
+
assert_raises(Onelogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
data/test/request_test.rb
CHANGED
@@ -4,9 +4,9 @@ class RequestTest < Test::Unit::TestCase
|
|
4
4
|
|
5
5
|
context "Authrequest" do
|
6
6
|
should "create the deflated SAMLRequest URL parameter" do
|
7
|
-
settings = Onelogin::
|
7
|
+
settings = Onelogin::RubySaml::Settings.new
|
8
8
|
settings.idp_sso_target_url = "http://example.com"
|
9
|
-
auth_url = Onelogin::
|
9
|
+
auth_url = Onelogin::RubySaml::Authrequest.new.create(settings)
|
10
10
|
assert auth_url =~ /^http:\/\/example\.com\?SAMLRequest=/
|
11
11
|
payload = CGI.unescape(auth_url.split("=").last)
|
12
12
|
decoded = Base64.decode64(payload)
|
@@ -20,9 +20,9 @@ class RequestTest < Test::Unit::TestCase
|
|
20
20
|
end
|
21
21
|
|
22
22
|
should "create the deflated SAMLRequest URL parameter including the Destination" do
|
23
|
-
settings = Onelogin::
|
23
|
+
settings = Onelogin::RubySaml::Settings.new
|
24
24
|
settings.idp_sso_target_url = "http://example.com"
|
25
|
-
auth_url = Onelogin::
|
25
|
+
auth_url = Onelogin::RubySaml::Authrequest.new.create(settings)
|
26
26
|
payload = CGI.unescape(auth_url.split("=").last)
|
27
27
|
decoded = Base64.decode64(payload)
|
28
28
|
|
@@ -35,10 +35,10 @@ class RequestTest < Test::Unit::TestCase
|
|
35
35
|
end
|
36
36
|
|
37
37
|
should "create the SAMLRequest URL parameter without deflating" do
|
38
|
-
settings = Onelogin::
|
38
|
+
settings = Onelogin::RubySaml::Settings.new
|
39
39
|
settings.compress_request = false
|
40
40
|
settings.idp_sso_target_url = "http://example.com"
|
41
|
-
auth_url = Onelogin::
|
41
|
+
auth_url = Onelogin::RubySaml::Authrequest.new.create(settings)
|
42
42
|
assert auth_url =~ /^http:\/\/example\.com\?SAMLRequest=/
|
43
43
|
payload = CGI.unescape(auth_url.split("=").last)
|
44
44
|
decoded = Base64.decode64(payload)
|
@@ -47,10 +47,10 @@ class RequestTest < Test::Unit::TestCase
|
|
47
47
|
end
|
48
48
|
|
49
49
|
should "create the SAMLRequest URL parameter with IsPassive" do
|
50
|
-
settings = Onelogin::
|
50
|
+
settings = Onelogin::RubySaml::Settings.new
|
51
51
|
settings.idp_sso_target_url = "http://example.com"
|
52
52
|
settings.passive = true
|
53
|
-
auth_url = Onelogin::
|
53
|
+
auth_url = Onelogin::RubySaml::Authrequest.new.create(settings)
|
54
54
|
assert auth_url =~ /^http:\/\/example\.com\?SAMLRequest=/
|
55
55
|
payload = CGI.unescape(auth_url.split("=").last)
|
56
56
|
decoded = Base64.decode64(payload)
|
@@ -64,32 +64,32 @@ class RequestTest < Test::Unit::TestCase
|
|
64
64
|
end
|
65
65
|
|
66
66
|
should "accept extra parameters" do
|
67
|
-
settings = Onelogin::
|
67
|
+
settings = Onelogin::RubySaml::Settings.new
|
68
68
|
settings.idp_sso_target_url = "http://example.com"
|
69
69
|
|
70
|
-
auth_url = Onelogin::
|
70
|
+
auth_url = Onelogin::RubySaml::Authrequest.new.create(settings, { :hello => "there" })
|
71
71
|
assert auth_url =~ /&hello=there$/
|
72
72
|
|
73
|
-
auth_url = Onelogin::
|
73
|
+
auth_url = Onelogin::RubySaml::Authrequest.new.create(settings, { :hello => nil })
|
74
74
|
assert auth_url =~ /&hello=$/
|
75
75
|
end
|
76
76
|
|
77
77
|
context "when the target url doesn't contain a query string" do
|
78
78
|
should "create the SAMLRequest parameter correctly" do
|
79
|
-
settings = Onelogin::
|
79
|
+
settings = Onelogin::RubySaml::Settings.new
|
80
80
|
settings.idp_sso_target_url = "http://example.com"
|
81
|
-
|
82
|
-
auth_url = Onelogin::
|
81
|
+
|
82
|
+
auth_url = Onelogin::RubySaml::Authrequest.new.create(settings)
|
83
83
|
assert auth_url =~ /^http:\/\/example.com\?SAMLRequest/
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
87
|
context "when the target url contains a query string" do
|
88
88
|
should "create the SAMLRequest parameter correctly" do
|
89
|
-
settings = Onelogin::
|
89
|
+
settings = Onelogin::RubySaml::Settings.new
|
90
90
|
settings.idp_sso_target_url = "http://example.com?field=value"
|
91
|
-
|
92
|
-
auth_url = Onelogin::
|
91
|
+
|
92
|
+
auth_url = Onelogin::RubySaml::Authrequest.new.create(settings)
|
93
93
|
assert auth_url =~ /^http:\/\/example.com\?field=value&SAMLRequest/
|
94
94
|
end
|
95
95
|
end
|
data/test/response_test.rb
CHANGED
@@ -4,40 +4,40 @@ class RubySamlTest < Test::Unit::TestCase
|
|
4
4
|
|
5
5
|
context "Response" do
|
6
6
|
should "raise an exception when response is initialized with nil" do
|
7
|
-
assert_raises(ArgumentError) { Onelogin::
|
7
|
+
assert_raises(ArgumentError) { Onelogin::RubySaml::Response.new(nil) }
|
8
8
|
end
|
9
9
|
|
10
10
|
should "be able to parse a document which contains ampersands" do
|
11
11
|
XMLSecurity::SignedDocument.any_instance.stubs(:digests_match?).returns(true)
|
12
|
-
Onelogin::
|
12
|
+
Onelogin::RubySaml::Response.any_instance.stubs(:validate_conditions).returns(true)
|
13
13
|
|
14
|
-
response = Onelogin::
|
15
|
-
settings = Onelogin::
|
14
|
+
response = Onelogin::RubySaml::Response.new(ampersands_response)
|
15
|
+
settings = Onelogin::RubySaml::Settings.new
|
16
16
|
settings.idp_cert_fingerprint = 'c51985d947f1be57082025050846eb27f6cab783'
|
17
17
|
response.settings = settings
|
18
18
|
response.validate!
|
19
19
|
end
|
20
20
|
|
21
21
|
should "adapt namespace" do
|
22
|
-
response = Onelogin::
|
22
|
+
response = Onelogin::RubySaml::Response.new(response_document)
|
23
23
|
assert !response.name_id.nil?
|
24
|
-
response = Onelogin::
|
24
|
+
response = Onelogin::RubySaml::Response.new(response_document_2)
|
25
25
|
assert !response.name_id.nil?
|
26
|
-
response = Onelogin::
|
26
|
+
response = Onelogin::RubySaml::Response.new(response_document_3)
|
27
27
|
assert !response.name_id.nil?
|
28
28
|
end
|
29
29
|
|
30
30
|
should "default to raw input when a response is not Base64 encoded" do
|
31
31
|
decoded = Base64.decode64(response_document_2)
|
32
|
-
response = Onelogin::
|
32
|
+
response = Onelogin::RubySaml::Response.new(decoded)
|
33
33
|
assert response.document
|
34
34
|
end
|
35
35
|
|
36
36
|
context "Assertion" do
|
37
37
|
should "only retreive an assertion with an ID that matches the signature's reference URI" do
|
38
|
-
response = Onelogin::
|
38
|
+
response = Onelogin::RubySaml::Response.new(wrapped_response_2)
|
39
39
|
response.stubs(:conditions).returns(nil)
|
40
|
-
settings = Onelogin::
|
40
|
+
settings = Onelogin::RubySaml::Settings.new
|
41
41
|
settings.idp_cert_fingerprint = signature_fingerprint_1
|
42
42
|
response.settings = settings
|
43
43
|
assert response.name_id.nil?
|
@@ -46,8 +46,8 @@ class RubySamlTest < Test::Unit::TestCase
|
|
46
46
|
|
47
47
|
context "#validate!" do
|
48
48
|
should "raise when encountering a condition that prevents the document from being valid" do
|
49
|
-
response = Onelogin::
|
50
|
-
assert_raise(Onelogin::
|
49
|
+
response = Onelogin::RubySaml::Response.new(response_document)
|
50
|
+
assert_raise(Onelogin::RubySaml::ValidationError) do
|
51
51
|
response.validate!
|
52
52
|
end
|
53
53
|
end
|
@@ -55,20 +55,20 @@ class RubySamlTest < Test::Unit::TestCase
|
|
55
55
|
|
56
56
|
context "#is_valid?" do
|
57
57
|
should "return false when response is initialized with blank data" do
|
58
|
-
response = Onelogin::
|
58
|
+
response = Onelogin::RubySaml::Response.new('')
|
59
59
|
assert !response.is_valid?
|
60
60
|
end
|
61
61
|
|
62
62
|
should "return false if settings have not been set" do
|
63
|
-
response = Onelogin::
|
63
|
+
response = Onelogin::RubySaml::Response.new(response_document)
|
64
64
|
assert !response.is_valid?
|
65
65
|
end
|
66
66
|
|
67
67
|
should "return true when the response is initialized with valid data" do
|
68
|
-
response = Onelogin::
|
68
|
+
response = Onelogin::RubySaml::Response.new(response_document_4)
|
69
69
|
response.stubs(:conditions).returns(nil)
|
70
70
|
assert !response.is_valid?
|
71
|
-
settings = Onelogin::
|
71
|
+
settings = Onelogin::RubySaml::Settings.new
|
72
72
|
assert !response.is_valid?
|
73
73
|
response.settings = settings
|
74
74
|
assert !response.is_valid?
|
@@ -77,18 +77,18 @@ class RubySamlTest < Test::Unit::TestCase
|
|
77
77
|
end
|
78
78
|
|
79
79
|
should "should be idempotent when the response is initialized with invalid data" do
|
80
|
-
response = Onelogin::
|
80
|
+
response = Onelogin::RubySaml::Response.new(response_document_4)
|
81
81
|
response.stubs(:conditions).returns(nil)
|
82
|
-
settings = Onelogin::
|
82
|
+
settings = Onelogin::RubySaml::Settings.new
|
83
83
|
response.settings = settings
|
84
84
|
assert !response.is_valid?
|
85
85
|
assert !response.is_valid?
|
86
86
|
end
|
87
87
|
|
88
88
|
should "should be idempotent when the response is initialized with valid data" do
|
89
|
-
response = Onelogin::
|
89
|
+
response = Onelogin::RubySaml::Response.new(response_document_4)
|
90
90
|
response.stubs(:conditions).returns(nil)
|
91
|
-
settings = Onelogin::
|
91
|
+
settings = Onelogin::RubySaml::Settings.new
|
92
92
|
response.settings = settings
|
93
93
|
settings.idp_cert_fingerprint = signature_fingerprint_1
|
94
94
|
assert response.is_valid?
|
@@ -96,18 +96,18 @@ class RubySamlTest < Test::Unit::TestCase
|
|
96
96
|
end
|
97
97
|
|
98
98
|
should "return true when using certificate instead of fingerprint" do
|
99
|
-
response = Onelogin::
|
99
|
+
response = Onelogin::RubySaml::Response.new(response_document_4)
|
100
100
|
response.stubs(:conditions).returns(nil)
|
101
|
-
settings = Onelogin::
|
101
|
+
settings = Onelogin::RubySaml::Settings.new
|
102
102
|
response.settings = settings
|
103
103
|
settings.idp_cert = signature_1
|
104
104
|
assert response.is_valid?
|
105
105
|
end
|
106
106
|
|
107
107
|
should "not allow signature wrapping attack" do
|
108
|
-
response = Onelogin::
|
108
|
+
response = Onelogin::RubySaml::Response.new(response_document_4)
|
109
109
|
response.stubs(:conditions).returns(nil)
|
110
|
-
settings = Onelogin::
|
110
|
+
settings = Onelogin::RubySaml::Settings.new
|
111
111
|
settings.idp_cert_fingerprint = signature_fingerprint_1
|
112
112
|
response.settings = settings
|
113
113
|
assert response.is_valid?
|
@@ -115,9 +115,9 @@ class RubySamlTest < Test::Unit::TestCase
|
|
115
115
|
end
|
116
116
|
|
117
117
|
should "support dynamic namespace resolution on signature elements" do
|
118
|
-
response = Onelogin::
|
118
|
+
response = Onelogin::RubySaml::Response.new(fixture("no_signature_ns.xml"))
|
119
119
|
response.stubs(:conditions).returns(nil)
|
120
|
-
settings = Onelogin::
|
120
|
+
settings = Onelogin::RubySaml::Settings.new
|
121
121
|
response.settings = settings
|
122
122
|
settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
123
123
|
XMLSecurity::SignedDocument.any_instance.expects(:validate_signature).returns(true)
|
@@ -125,18 +125,18 @@ class RubySamlTest < Test::Unit::TestCase
|
|
125
125
|
end
|
126
126
|
|
127
127
|
should "validate ADFS assertions" do
|
128
|
-
response = Onelogin::
|
128
|
+
response = Onelogin::RubySaml::Response.new(fixture(:adfs_response_sha256))
|
129
129
|
response.stubs(:conditions).returns(nil)
|
130
|
-
settings = Onelogin::
|
130
|
+
settings = Onelogin::RubySaml::Settings.new
|
131
131
|
settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
132
132
|
response.settings = settings
|
133
133
|
assert response.validate!
|
134
134
|
end
|
135
135
|
|
136
136
|
should "validate the digest" do
|
137
|
-
response = Onelogin::
|
137
|
+
response = Onelogin::RubySaml::Response.new(r1_response_document_6)
|
138
138
|
response.stubs(:conditions).returns(nil)
|
139
|
-
settings = Onelogin::
|
139
|
+
settings = Onelogin::RubySaml::Settings.new
|
140
140
|
settings.idp_cert = Base64.decode64(r1_signature_2)
|
141
141
|
response.settings = settings
|
142
142
|
assert response.validate!
|
@@ -144,112 +144,112 @@ class RubySamlTest < Test::Unit::TestCase
|
|
144
144
|
|
145
145
|
should "validate SAML 2.0 XML structure" do
|
146
146
|
resp_xml = Base64.decode64(response_document_4).gsub(/emailAddress/,'test')
|
147
|
-
response = Onelogin::
|
147
|
+
response = Onelogin::RubySaml::Response.new(Base64.encode64(resp_xml))
|
148
148
|
response.stubs(:conditions).returns(nil)
|
149
|
-
settings = Onelogin::
|
149
|
+
settings = Onelogin::RubySaml::Settings.new
|
150
150
|
settings.idp_cert_fingerprint = signature_fingerprint_1
|
151
151
|
response.settings = settings
|
152
|
-
assert_raises(Onelogin::
|
152
|
+
assert_raises(Onelogin::RubySaml::ValidationError, 'Digest mismatch'){ response.validate! }
|
153
153
|
end
|
154
154
|
end
|
155
155
|
|
156
156
|
context "#name_id" do
|
157
157
|
should "extract the value of the name id element" do
|
158
|
-
response = Onelogin::
|
158
|
+
response = Onelogin::RubySaml::Response.new(response_document)
|
159
159
|
assert_equal "support@onelogin.com", response.name_id
|
160
160
|
|
161
|
-
response = Onelogin::
|
161
|
+
response = Onelogin::RubySaml::Response.new(response_document_3)
|
162
162
|
assert_equal "someone@example.com", response.name_id
|
163
163
|
end
|
164
164
|
|
165
165
|
should "be extractable from an OpenSAML response" do
|
166
|
-
response = Onelogin::
|
166
|
+
response = Onelogin::RubySaml::Response.new(fixture(:open_saml))
|
167
167
|
assert_equal "someone@example.org", response.name_id
|
168
168
|
end
|
169
169
|
|
170
170
|
should "be extractable from a Simple SAML PHP response" do
|
171
|
-
response = Onelogin::
|
171
|
+
response = Onelogin::RubySaml::Response.new(fixture(:simple_saml_php))
|
172
172
|
assert_equal "someone@example.com", response.name_id
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
176
176
|
context "#check_conditions" do
|
177
177
|
should "check time conditions" do
|
178
|
-
response = Onelogin::
|
178
|
+
response = Onelogin::RubySaml::Response.new(response_document)
|
179
179
|
assert !response.send(:validate_conditions, true)
|
180
|
-
response = Onelogin::
|
180
|
+
response = Onelogin::RubySaml::Response.new(response_document_6)
|
181
181
|
assert response.send(:validate_conditions, true)
|
182
182
|
time = Time.parse("2011-06-14T18:25:01.516Z")
|
183
183
|
Time.stubs(:now).returns(time)
|
184
|
-
response = Onelogin::
|
184
|
+
response = Onelogin::RubySaml::Response.new(response_document_5)
|
185
185
|
assert response.send(:validate_conditions, true)
|
186
186
|
end
|
187
187
|
|
188
188
|
should "optionally allow for clock drift" do
|
189
189
|
# The NotBefore condition in the document is 2011-06-14T18:21:01.516Z
|
190
190
|
Time.stubs(:now).returns(Time.parse("2011-06-14T18:21:01Z"))
|
191
|
-
response = Onelogin::
|
191
|
+
response = Onelogin::RubySaml::Response.new(response_document_5, :allowed_clock_drift => 0.515)
|
192
192
|
assert !response.send(:validate_conditions, true)
|
193
193
|
|
194
194
|
Time.stubs(:now).returns(Time.parse("2011-06-14T18:21:01Z"))
|
195
|
-
response = Onelogin::
|
195
|
+
response = Onelogin::RubySaml::Response.new(response_document_5, :allowed_clock_drift => 0.516)
|
196
196
|
assert response.send(:validate_conditions, true)
|
197
197
|
end
|
198
198
|
end
|
199
199
|
|
200
200
|
context "#attributes" do
|
201
201
|
should "extract the first attribute in a hash accessed via its symbol" do
|
202
|
-
response = Onelogin::
|
202
|
+
response = Onelogin::RubySaml::Response.new(response_document)
|
203
203
|
assert_equal "demo", response.attributes[:uid]
|
204
204
|
end
|
205
205
|
|
206
206
|
should "extract the first attribute in a hash accessed via its name" do
|
207
|
-
response = Onelogin::
|
207
|
+
response = Onelogin::RubySaml::Response.new(response_document)
|
208
208
|
assert_equal "demo", response.attributes["uid"]
|
209
209
|
end
|
210
210
|
|
211
211
|
should "extract all attributes" do
|
212
|
-
response = Onelogin::
|
212
|
+
response = Onelogin::RubySaml::Response.new(response_document)
|
213
213
|
assert_equal "demo", response.attributes[:uid]
|
214
214
|
assert_equal "value", response.attributes[:another_value]
|
215
215
|
end
|
216
216
|
|
217
217
|
should "work for implicit namespaces" do
|
218
|
-
response = Onelogin::
|
218
|
+
response = Onelogin::RubySaml::Response.new(response_document_3)
|
219
219
|
assert_equal "someone@example.com", response.attributes["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]
|
220
220
|
end
|
221
221
|
|
222
222
|
should "not raise on responses without attributes" do
|
223
|
-
response = Onelogin::
|
223
|
+
response = Onelogin::RubySaml::Response.new(response_document_4)
|
224
224
|
assert_equal Hash.new, response.attributes
|
225
225
|
end
|
226
226
|
end
|
227
227
|
|
228
228
|
context "#session_expires_at" do
|
229
229
|
should "extract the value of the SessionNotOnOrAfter attribute" do
|
230
|
-
response = Onelogin::
|
230
|
+
response = Onelogin::RubySaml::Response.new(response_document)
|
231
231
|
assert response.session_expires_at.is_a?(Time)
|
232
232
|
|
233
|
-
response = Onelogin::
|
233
|
+
response = Onelogin::RubySaml::Response.new(response_document_2)
|
234
234
|
assert response.session_expires_at.nil?
|
235
235
|
end
|
236
236
|
end
|
237
237
|
|
238
238
|
context "#issuer" do
|
239
239
|
should "return the issuer inside the response assertion" do
|
240
|
-
response = Onelogin::
|
240
|
+
response = Onelogin::RubySaml::Response.new(response_document)
|
241
241
|
assert_equal "https://app.onelogin.com/saml/metadata/13590", response.issuer
|
242
242
|
end
|
243
243
|
|
244
244
|
should "return the issuer inside the response" do
|
245
|
-
response = Onelogin::
|
245
|
+
response = Onelogin::RubySaml::Response.new(response_document_2)
|
246
246
|
assert_equal "wibble", response.issuer
|
247
247
|
end
|
248
248
|
end
|
249
249
|
|
250
250
|
context "#success" do
|
251
251
|
should "find a status code that says success" do
|
252
|
-
response = Onelogin::
|
252
|
+
response = Onelogin::RubySaml::Response.new(response_document)
|
253
253
|
response.success?
|
254
254
|
end
|
255
255
|
end
|
@@ -52,7 +52,7 @@ def invalid_xml_response
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def settings
|
55
|
-
@settings ||= Onelogin::
|
55
|
+
@settings ||= Onelogin::RubySaml::Settings.new(
|
56
56
|
{
|
57
57
|
:assertion_consumer_service_url => "http://app.muda.no/sso/consume",
|
58
58
|
:assertion_consumer_logout_service_url => "http://app.muda.no/sso/consume_logout",
|
@@ -64,4 +64,4 @@ def settings
|
|
64
64
|
:name_identifier_format => "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
|
65
65
|
}
|
66
66
|
)
|
67
|
-
end
|
67
|
+
end
|
data/test/settings_test.rb
CHANGED
@@ -4,7 +4,7 @@ class SettingsTest < Test::Unit::TestCase
|
|
4
4
|
|
5
5
|
context "Settings" do
|
6
6
|
setup do
|
7
|
-
@settings = Onelogin::
|
7
|
+
@settings = Onelogin::RubySaml::Settings.new
|
8
8
|
end
|
9
9
|
should "should provide getters and settings" do
|
10
10
|
accessors = [
|
@@ -35,7 +35,7 @@ class SettingsTest < Test::Unit::TestCase
|
|
35
35
|
:passive => true,
|
36
36
|
:protocol_binding => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
|
37
37
|
}
|
38
|
-
@settings = Onelogin::
|
38
|
+
@settings = Onelogin::RubySaml::Settings.new(config)
|
39
39
|
|
40
40
|
config.each do |k,v|
|
41
41
|
assert_equal v, @settings.send(k)
|
data/test/xml_security_test.rb
CHANGED
@@ -15,7 +15,7 @@ class XmlSecurityTest < Test::Unit::TestCase
|
|
15
15
|
end
|
16
16
|
|
17
17
|
should "should run validate with throwing NS related exceptions" do
|
18
|
-
assert_raise(Onelogin::
|
18
|
+
assert_raise(Onelogin::RubySaml::ValidationError) do
|
19
19
|
@document.validate_signature(@base64cert, false)
|
20
20
|
end
|
21
21
|
end
|
@@ -27,14 +27,14 @@ class XmlSecurityTest < Test::Unit::TestCase
|
|
27
27
|
end
|
28
28
|
|
29
29
|
should "should raise Fingerprint mismatch" do
|
30
|
-
exception = assert_raise(Onelogin::
|
30
|
+
exception = assert_raise(Onelogin::RubySaml::ValidationError) do
|
31
31
|
@document.validate_document("no:fi:ng:er:pr:in:t", false)
|
32
32
|
end
|
33
33
|
assert_equal("Fingerprint mismatch", exception.message)
|
34
34
|
end
|
35
35
|
|
36
36
|
should "should raise Digest mismatch" do
|
37
|
-
exception = assert_raise(Onelogin::
|
37
|
+
exception = assert_raise(Onelogin::RubySaml::ValidationError) do
|
38
38
|
@document.validate_signature(@base64cert, false)
|
39
39
|
end
|
40
40
|
assert_equal("Digest mismatch", exception.message)
|
@@ -46,7 +46,7 @@ class XmlSecurityTest < Test::Unit::TestCase
|
|
46
46
|
"<ds:DigestValue>b9xsAXLsynugg3Wc1CI3kpWku+0=</ds:DigestValue>")
|
47
47
|
document = XMLSecurity::SignedDocument.new(response)
|
48
48
|
base64cert = document.elements["//ds:X509Certificate"].text
|
49
|
-
exception = assert_raise(Onelogin::
|
49
|
+
exception = assert_raise(Onelogin::RubySaml::ValidationError) do
|
50
50
|
document.validate_signature(base64cert, false)
|
51
51
|
end
|
52
52
|
assert_equal("Key validation error", exception.message)
|
@@ -56,7 +56,7 @@ class XmlSecurityTest < Test::Unit::TestCase
|
|
56
56
|
response = Base64.decode64(response_document)
|
57
57
|
response.sub!(/<ds:X509Certificate>.*<\/ds:X509Certificate>/, "")
|
58
58
|
document = XMLSecurity::SignedDocument.new(response)
|
59
|
-
exception = assert_raise(Onelogin::
|
59
|
+
exception = assert_raise(Onelogin::RubySaml::ValidationError) do
|
60
60
|
document.validate_document("a fingerprint", false) # The fingerprint isn't relevant to this test
|
61
61
|
end
|
62
62
|
assert_equal("Certificate element missing in response (ds:X509Certificate)", exception.message)
|
@@ -106,10 +106,10 @@ class XmlSecurityTest < Test::Unit::TestCase
|
|
106
106
|
|
107
107
|
should_eventually 'support inclusive canonicalization' do
|
108
108
|
|
109
|
-
response = Onelogin::
|
109
|
+
response = Onelogin::RubySaml::Response.new(fixture("tdnf_response.xml"))
|
110
110
|
response.stubs(:conditions).returns(nil)
|
111
111
|
assert !response.is_valid?
|
112
|
-
settings = Onelogin::
|
112
|
+
settings = Onelogin::RubySaml::Settings.new
|
113
113
|
assert !response.is_valid?
|
114
114
|
response.settings = settings
|
115
115
|
assert !response.is_valid?
|
@@ -130,8 +130,8 @@ class XmlSecurityTest < Test::Unit::TestCase
|
|
130
130
|
|
131
131
|
context "StarfieldTMS" do
|
132
132
|
setup do
|
133
|
-
@response = Onelogin::
|
134
|
-
@response.settings = Onelogin::
|
133
|
+
@response = Onelogin::RubySaml::Response.new(fixture(:starfield_response))
|
134
|
+
@response.settings = Onelogin::RubySaml::Settings.new(
|
135
135
|
:idp_cert_fingerprint => "8D:BA:53:8E:A3:B6:F9:F1:69:6C:BB:D9:D8:BD:41:B3:AC:4F:9D:4D"
|
136
136
|
)
|
137
137
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-saml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 63
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 8
|
9
|
+
- 0
|
10
|
+
version: 0.8.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- OneLogin LLC
|
@@ -15,28 +15,12 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2014-02-
|
18
|
+
date: 2014-02-24 00:00:00 Z
|
19
19
|
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
21
|
-
name: canonix
|
22
|
-
prerelease: false
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
-
none: false
|
25
|
-
requirements:
|
26
|
-
- - "="
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
hash: 25
|
29
|
-
segments:
|
30
|
-
- 0
|
31
|
-
- 1
|
32
|
-
- 1
|
33
|
-
version: 0.1.1
|
34
|
-
type: :runtime
|
35
|
-
version_requirements: *id001
|
36
20
|
- !ruby/object:Gem::Dependency
|
37
21
|
name: uuid
|
38
22
|
prerelease: false
|
39
|
-
requirement: &
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
40
24
|
none: false
|
41
25
|
requirements:
|
42
26
|
- - ~>
|
@@ -47,14 +31,14 @@ dependencies:
|
|
47
31
|
- 3
|
48
32
|
version: "2.3"
|
49
33
|
type: :runtime
|
50
|
-
version_requirements: *
|
34
|
+
version_requirements: *id001
|
51
35
|
- !ruby/object:Gem::Dependency
|
52
36
|
name: nokogiri
|
53
37
|
prerelease: false
|
54
|
-
requirement: &
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
55
39
|
none: false
|
56
40
|
requirements:
|
57
|
-
- -
|
41
|
+
- - ">="
|
58
42
|
- !ruby/object:Gem::Version
|
59
43
|
hash: 3
|
60
44
|
segments:
|
@@ -63,7 +47,7 @@ dependencies:
|
|
63
47
|
- 0
|
64
48
|
version: 1.5.0
|
65
49
|
type: :runtime
|
66
|
-
version_requirements: *
|
50
|
+
version_requirements: *id002
|
67
51
|
description: SAML toolkit for Ruby on Rails
|
68
52
|
email: support@onelogin.com
|
69
53
|
executables: []
|
@@ -81,6 +65,7 @@ files:
|
|
81
65
|
- LICENSE
|
82
66
|
- README.md
|
83
67
|
- Rakefile
|
68
|
+
- changelog.md
|
84
69
|
- lib/onelogin/ruby-saml/authrequest.rb
|
85
70
|
- lib/onelogin/ruby-saml/logging.rb
|
86
71
|
- lib/onelogin/ruby-saml/logoutrequest.rb
|