Skip to content

Commit f579b15

Browse files
authored
Merge pull request saml-idp#102 from saml-idp/validate-acs-url
Validate acs url
2 parents 1cced85 + 2381e98 commit f579b15

File tree

8 files changed

+42
-6
lines changed

8 files changed

+42
-6
lines changed

.ruby-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2.5.1

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,11 @@ CERT
171171
service_providers = {
172172
"some-issuer-url.com/saml" => {
173173
fingerprint: "9E:65:2E:03:06:8D:80:F2:86:C7:6C:77:A1:D9:14:97:0A:4D:F4:4D",
174-
metadata_url: "http://some-issuer-url.com/saml/metadata"
174+
metadata_url: "http://some-issuer-url.com/saml/metadata",
175+
176+
# We now validate AssertionConsumerServiceURL will match the MetadataURL set above.
177+
# *If* it's not going to match your Metadata URL's Host, then set this so we can validate the host using this list
178+
response_hosts: ["foo.some-issuer-url.com"]
175179
},
176180
}
177181

lib/saml_idp/configurator.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class Configurator
1717
attr_accessor :single_logout_service_redirect_location
1818
attr_accessor :attributes
1919
attr_accessor :service_provider
20+
attr_accessor :assertion_consumer_service_hosts
2021
attr_accessor :session_expiry
2122

2223
def initialize

lib/saml_idp/request.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ def valid?
105105
return false
106106
end
107107

108+
if !service_provider.acceptable_response_hosts.include?(response_host)
109+
log "No acceptable AssertionConsumerServiceURL, either configure them via config.service_provider.response_hosts or match to your metadata_url host"
110+
return false
111+
end
112+
108113
return true
109114
end
110115

@@ -136,6 +141,14 @@ def session_index
136141
@_session_index ||= xpath("//samlp:SessionIndex", samlp: samlp).first.try(:content)
137142
end
138143

144+
def response_host
145+
uri = URI(response_url)
146+
if uri
147+
uri.host
148+
end
149+
end
150+
private :response_host
151+
139152
def document
140153
@_document ||= Saml::XML::Document.parse(raw_xml)
141154
end

lib/saml_idp/service_provider.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class ServiceProvider
1313
attribute :validate_signature
1414
attribute :acs_url
1515
attribute :assertion_consumer_logout_service_url
16+
attribute :response_hosts
1617

1718
delegate :config, to: :SamlIdp
1819

@@ -46,6 +47,19 @@ def current_metadata
4647
@current_metadata ||= get_current_or_build
4748
end
4849

50+
def acceptable_response_hosts
51+
hosts = Array(self.response_hosts)
52+
hosts.push(metadata_url_host) if metadata_url_host
53+
54+
hosts
55+
end
56+
57+
def metadata_url_host
58+
if metadata_url.present?
59+
URI(metadata_url).host
60+
end
61+
end
62+
4963
def get_current_or_build
5064
persisted = metadata_getter[identifier, self]
5165
if persisted.is_a? Hash

spec/acceptance/idp_controller_spec.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
scenario 'Login via default signup page' do
55
saml_request = make_saml_request("http://foo.example.com/saml/consume")
66
visit "/saml/auth?SAMLRequest=#{CGI.escape(saml_request)}"
7-
fill_in 'Email', :with => "foo@example.com"
8-
fill_in 'Password', :with => "okidoki"
7+
expect(status_code).to eq(200)
8+
fill_in 'email', :with => "foo@example.com"
9+
fill_in 'password', :with => "okidoki"
910
click_button 'Sign in'
1011
click_button 'Submit' # simulating onload
1112
expect(current_url).to eq('http://foo.example.com/saml/consume')

spec/lib/saml_idp/encryptor_spec.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@
55
module SamlIdp
66
describe Encryptor do
77
let (:encryption_opts) do
8-
{
8+
{
99
cert: Default::X509_CERTIFICATE,
1010
block_encryption: 'aes256-cbc',
1111
key_transport: 'rsa-oaep-mgf1p',
12-
}
12+
}
1313
end
1414

1515
subject { described_class.new encryption_opts }
1616

1717
it "encrypts XML" do
1818
raw_xml = '<foo>bar</foo>'
1919
encrypted_xml = subject.encrypt(raw_xml)
20-
expect(encrypted_xml).to_not match 'bar'
20+
expect(encrypted_xml).to_not match raw_xml
2121
encrypted_doc = Nokogiri::XML::Document.parse(encrypted_xml)
2222
encrypted_data = Xmlenc::EncryptedData.new(encrypted_doc.at_xpath('//xenc:EncryptedData', Xmlenc::NAMESPACES))
2323
decrypted_xml = encrypted_data.decrypt(subject.encryption_key)

spec/spec_helper.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,7 @@
4545
end
4646
end
4747

48+
SamlIdp::Default::SERVICE_PROVIDER[:metadata_url] = 'https://example.com/meta'
49+
SamlIdp::Default::SERVICE_PROVIDER[:response_hosts] = ['foo.example.com']
4850
SamlIdp::Default::SERVICE_PROVIDER[:assertion_consumer_logout_service_url] = 'https://foo.example.com/saml/logout'
4951
Capybara.default_host = "https://app.example.com"

0 commit comments

Comments
 (0)