Comparing changes
v1.0.24
→
v1.0.25
2 commits
17 files changed
Commits
Changed files (17)
lib
saml
spec
saml
kit
builders
lib/saml/kit/bindings/binding.rb
@@ -58,6 +58,7 @@ module Saml
}
return parameters[:SAMLRequest] if parameters[:SAMLRequest].present?
return parameters[:SAMLResponse] if parameters[:SAMLResponse].present?
+
message = 'SAMLRequest or SAMLResponse parameter is required.'
raise ArgumentError, message
end
lib/saml/kit/bindings/http_redirect.rb
@@ -52,6 +52,7 @@ module Saml
decode(signature),
canonicalize(params)
)
+
raise ArgumentError, 'Invalid Signature'
end
@@ -87,6 +88,7 @@ module Saml
def params_to_hash(value)
return value unless value.is_a?(String)
+
Hash[URI.parse(value).query.split('&').map { |xx| xx.split('=', 2) }]
end
end
lib/saml/kit/builders/templates/assertion.builder
@@ -25,7 +25,13 @@ xml.Assertion(assertion_options) do
xml.AttributeStatement do
assertion_attributes.each do |key, value|
xml.Attribute Name: key do
- xml.AttributeValue value.to_s
+ if value.respond_to?(:each)
+ value.each do |x|
+ xml.AttributeValue x.to_s
+ end
+ else
+ xml.AttributeValue value.to_s
+ end
end
end
end
lib/saml/kit/builders/assertion.rb
@@ -35,6 +35,7 @@ module Saml
def assertion_attributes
return {} unless user.respond_to?(:assertion_attributes_for)
+
user.assertion_attributes_for(request)
end
lib/saml/kit/concerns/trustable.rb
@@ -30,6 +30,7 @@ module Saml
def trusted?
return true if signature_verified
return false unless signed?
+
signature.trusted?(provider)
end
@@ -60,12 +61,14 @@ module Saml
def must_be_registered
return unless expected_type?
return if provider.present?
+
errors[:provider] << error_message(:unregistered)
end
def must_be_trusted
return if trusted?
return if provider.present? && !signed?
+
errors[:fingerprint] << error_message(:invalid_fingerprint)
end
end
lib/saml/kit/concerns/xml_parseable.rb
@@ -45,6 +45,7 @@ module Saml
# @!visibility private
def at_xpath(xpath)
return unless present?
+
to_nokogiri.at_xpath(xpath, NAMESPACES)
end
lib/saml/kit/concerns/xml_templatable.rb
@@ -20,6 +20,7 @@ module Saml
# signing certificate is available via the configuration.
def sign?
return configuration.sign? if embed_signature.nil?
+
(embed_signature && configuration.sign?) ||
(embed_signature && signing_key_pair.present?)
end
lib/saml/kit/assertion.rb
@@ -90,6 +90,7 @@ module Saml
def decryptable?
return true unless encrypted?
+
!@cannot_decrypt
end
@@ -103,6 +104,7 @@ module Saml
encrypted_assertion = at_xpath('./xmlenc:EncryptedData')
@encrypted = encrypted_assertion.present?
return unless @encrypted
+
@to_nokogiri = decryptor.decrypt_node(encrypted_assertion)
rescue Xml::Kit::DecryptionError => error
@cannot_decrypt = true
@@ -111,16 +113,19 @@ module Saml
def must_match_issuer
return if audiences.empty? || audiences.include?(configuration.entity_id)
+
errors[:audience] << error_message(:must_match_issuer)
end
def must_be_active_session
return if active?
+
errors[:base] << error_message(:expired)
end
def must_have_valid_signature
return if !signed? || signature.valid?
+
signature.errors.each do |attribute, message|
errors.add(attribute, message)
end
lib/saml/kit/document.rb
@@ -111,6 +111,7 @@ module Saml
def must_be_valid_version
return unless expected_type?
return if version == '2.0'
+
errors[:version] << error_message(:invalid_version)
end
end
lib/saml/kit/identity_provider_metadata.rb
@@ -57,6 +57,7 @@ module Saml
xpath = "/md:EntityDescriptor/md:#{name}"
attribute = at_xpath(xpath).attribute('WantAuthnRequestsSigned')
return true if attribute.nil?
+
attribute.text.casecmp('true').zero?
end
lib/saml/kit/logout_request.rb
@@ -67,6 +67,7 @@ module Saml
def single_logout_service
return if provider.nil?
+
urls = provider.single_logout_services
urls.first
end
lib/saml/kit/metadata.rb
@@ -191,6 +191,7 @@ module Saml
def must_have_valid_signature
return if !signature.present? || signature.valid?
+
signature.errors.each do |attribute, error|
errors[attribute] << error
end
lib/saml/kit/response.rb
@@ -51,6 +51,7 @@ module Saml
def must_contain_single_assertion
return if assertion_nodes.count <= 1
+
errors[:base] << error_message(:must_contain_single_assertion)
end
lib/saml/kit/service_provider_metadata.rb
@@ -28,6 +28,7 @@ module Saml
element = at_xpath("/md:EntityDescriptor/md:#{name}")
attribute = element.attribute('WantAssertionsSigned')
return true if attribute.nil?
+
attribute.text.casecmp('true').zero?
end
lib/saml/kit/signature.rb
@@ -24,6 +24,7 @@ module Saml
xpath = './ds:KeyInfo/ds:X509Data/ds:X509Certificate'
value = at_xpath(xpath).try(:text)
return if value.nil?
+
::Xml::Kit::Certificate.new(value, use: :signing)
end
@@ -31,6 +32,7 @@ module Saml
# the certificates registered in the metadata.
def trusted?(metadata)
return false if metadata.nil?
+
metadata.matches?(certificate.fingerprint, use: :signing).present?
end
@@ -121,6 +123,7 @@ module Saml
def at_xpath(xpath)
return nil unless node
+
node.at_xpath(xpath, Saml::Kit::Document::NAMESPACES)
end
lib/saml/kit/version.rb
@@ -2,6 +2,6 @@
module Saml
module Kit
- VERSION = '1.0.24'.freeze
+ VERSION = '1.0.25'.freeze
end
end
spec/saml/kit/builders/response_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe Saml::Kit::Builders::Response do
end
let(:email) { FFaker::Internet.email }
let(:assertion_consumer_service_url) { FFaker::Internet.uri('https') }
- let(:user) { User.new(attributes: { email: email, created_at: Time.now.utc.iso8601 }) }
+ let(:user) { User.new(attributes: { email: email, created_at: Time.now.utc.iso8601, roles: ['husband', 'father', 'programmer'] }) }
let(:request) { instance_double(Saml::Kit::AuthenticationRequest, id: Xml::Kit::Id.generate, assertion_consumer_service_url: assertion_consumer_service_url, issuer: issuer, name_id_format: Saml::Kit::Namespaces::EMAIL_ADDRESS, provider: provider, trusted?: true, signed?: true) }
let(:provider) { instance_double(Saml::Kit::ServiceProviderMetadata, want_assertions_signed: false, encryption_certificates: [configuration.certificates(use: :encryption).last]) }
let(:issuer) { FFaker::Internet.uri('https') }
@@ -110,6 +110,9 @@ RSpec.describe Saml::Kit::Builders::Response do
expect(hash['Response']['Assertion']['AttributeStatement']['Attribute'][1]['Name']).to eql('created_at')
expect(hash['Response']['Assertion']['AttributeStatement']['Attribute'][1]['AttributeValue']).to be_present
+
+ expect(hash['Response']['Assertion']['AttributeStatement']['Attribute'][2]['Name']).to eql('roles')
+ expect(hash['Response']['Assertion']['AttributeStatement']['Attribute'][2]['AttributeValue']).to match_array(['husband', 'father', 'programmer'])
end
it 'does not add a signature when the SP does not want assertions signed' do