Comparing changes
v0.2.9
→
v0.2.10
6 commits
4 files changed
Commits
Changed files (4)
lib
saml
kit
spec
saml
bindings
lib/saml/kit/bindings/http_redirect.rb
@@ -16,9 +16,9 @@ module Saml
end
def deserialize(params, configuration: Saml::Kit.configuration)
- document = deserialize_document_from!(params, configuration)
- ensure_valid_signature!(params, document)
- document.signature_verified!
+ parameters = normalize(params)
+ document = deserialize_document_from!(parameters, configuration)
+ ensure_valid_signature!(parameters, document)
document
end
@@ -26,21 +26,24 @@ module Saml
def deserialize_document_from!(params, configuration)
xml = inflate(decode(unescape(saml_param_from(params))))
- Saml::Kit.logger.debug(xml)
Saml::Kit::Document.to_saml_document(xml, configuration: configuration)
end
def ensure_valid_signature!(params, document)
- return if params['Signature'].blank? || params['SigAlg'].blank?
+ return if params[:Signature].blank? || params[:SigAlg].blank?
- signature = decode(params['Signature'])
- canonical_form = ['SAMLRequest', 'SAMLResponse', 'RelayState', 'SigAlg'].map do |key|
+ signature = decode(params[:Signature])
+ canonical_form = [:SAMLRequest, :SAMLResponse, :RelayState, :SigAlg].map do |key|
value = params[key]
value.present? ? "#{key}=#{value}" : nil
end.compact.join('&')
- valid = document.provider.verify(algorithm_for(params['SigAlg']), signature, canonical_form)
- raise ArgumentError.new("Invalid Signature") unless valid
+ return if document.provider.nil?
+ if document.provider.verify(algorithm_for(params[:SigAlg]), signature, canonical_form)
+ document.signature_verified!
+ else
+ raise ArgumentError.new("Invalid Signature")
+ end
end
def algorithm_for(algorithm)
@@ -55,6 +58,23 @@ module Saml
OpenSSL::Digest::SHA1.new
end
end
+
+ def normalize(params)
+ if params.respond_to? :inject
+ params.inject({}) do |memo, (key, value)|
+ memo[key.to_sym] = value
+ memo
+ end
+ else
+ {
+ SAMLRequest: params['SAMLRequest'] || params[:SAMLRequest],
+ SAMLResponse: params['SAMLResponse'] || params[:SAMLResponse],
+ RelayState: params['RelayState'] || params[:RelayState],
+ Signature: params['Signature'] || params[:Signature],
+ SigAlg: params['SigAlg'] || params[:SigAlg],
+ }
+ end
+ end
end
end
end
lib/saml/kit/trustable.rb
@@ -6,11 +6,11 @@ module Saml
included do
validate :must_have_valid_signature, unless: :signature_manually_verified
validate :must_be_registered
- validate :must_be_trusted, unless: :signature_manually_verified
+ validate :must_be_trusted
end
def signed?
- signature.present?
+ signature_manually_verified || signature.present?
end
def signature
@@ -19,6 +19,7 @@ module Saml
end
def trusted?
+ return true if signature_manually_verified
return false unless signed?
signature.trusted?(provider)
end
lib/saml/kit/version.rb
@@ -1,5 +1,5 @@
module Saml
module Kit
- VERSION = "0.2.9"
+ VERSION = "0.2.10"
end
end
spec/saml/bindings/http_redirect_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
end
it 'encodes the request using the HTTP-Redirect encoding' do
- builder = Saml::Kit::AuthenticationRequest.builder_class.new(configuration: configuration)
+ builder = Saml::Kit::AuthenticationRequest.builder(configuration: configuration)
url, _ = subject.serialize(builder, relay_state: relay_state)
expect(url).to start_with(location)
expect(url).to have_query_param('SAMLRequest')
@@ -32,13 +32,28 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
end
it 'deserializes the SAMLRequest to an AuthnRequest' do
- url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder_class.new)
+ url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder)
result = subject.deserialize(query_params_from(url))
expect(result).to be_instance_of(Saml::Kit::AuthenticationRequest)
end
it 'deserializes the SAMLRequest to an AuthnRequest with symbols for keys' do
- url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder_class.new)
+ configuration = Saml::Kit::Configuration.new do |config|
+ config.issuer = issuer
+ config.generate_key_pair_for(use: :signing)
+ end
+ provider = Saml::Kit::IdentityProviderMetadata.build(configuration: configuration)
+ url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder(configuration: configuration))
+ allow(configuration.registry).to receive(:metadata_for).with(issuer).and_return(provider)
+
+ result = subject.deserialize(query_params_from(url).symbolize_keys, configuration: configuration)
+ expect(result).to be_instance_of(Saml::Kit::AuthenticationRequest)
+ expect(result).to be_signed
+ expect(result).to be_trusted
+ end
+
+ it 'deserializes the SAMLRequest to an AuthnRequest with symbols for keys' do
+ url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder)
result = subject.deserialize(query_params_from(url).symbolize_keys)
expect(result).to be_instance_of(Saml::Kit::AuthenticationRequest)
end
@@ -53,14 +68,14 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
@params[key]
end
end
- url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder_class.new)
+ url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder)
result = subject.deserialize(Parameters.new(query_params_from(url)))
expect(result).to be_instance_of(Saml::Kit::AuthenticationRequest)
end
it 'deserializes the SAMLRequest to a LogoutRequest' do
user = double(:user, name_id_for: SecureRandom.uuid)
- url, _ = subject.serialize(Saml::Kit::LogoutRequest.builder_class.new(user))
+ url, _ = subject.serialize(Saml::Kit::LogoutRequest.builder(user))
result = subject.deserialize(query_params_from(url))
expect(result).to be_instance_of(Saml::Kit::LogoutRequest)
end
@@ -74,7 +89,7 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
it 'deserializes the SAMLResponse to a Response' do
user = double(:user, name_id_for: SecureRandom.uuid, assertion_attributes_for: [])
request = double(:request, id: SecureRandom.uuid, provider: nil, assertion_consumer_service_url: FFaker::Internet.http_url, name_id_format: Saml::Kit::Namespaces::PERSISTENT, issuer: issuer, signed?: true, trusted?: true)
- url, _ = subject.serialize(Saml::Kit::Response.builder_class.new(user, request))
+ url, _ = subject.serialize(Saml::Kit::Response.builder(user, request))
result = subject.deserialize(query_params_from(url))
expect(result).to be_instance_of(Saml::Kit::Response)
end
@@ -82,14 +97,14 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
it 'deserializes the SAMLResponse to a LogoutResponse' do
user = double(:user, name_id_for: SecureRandom.uuid, assertion_attributes_for: [])
request = double(:request, id: SecureRandom.uuid, provider: provider, assertion_consumer_service_url: FFaker::Internet.http_url, name_id_format: Saml::Kit::Namespaces::PERSISTENT, issuer: FFaker::Internet.http_url)
- url, _ = subject.serialize(Saml::Kit::LogoutResponse.builder_class.new(user, request))
+ url, _ = subject.serialize(Saml::Kit::LogoutResponse.builder(user, request))
result = subject.deserialize(query_params_from(url))
expect(result).to be_instance_of(Saml::Kit::LogoutResponse)
end
- it 'raise an error when the content is invalid' do
+ it 'raises an error when the content is invalid' do
expect do
- subject.deserialize({ 'SAMLResponse' => "nonsense" })
+ subject.deserialize('SAMLResponse' => "nonsense")
end.to raise_error(Zlib::DataError)
end
@@ -122,10 +137,24 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
end
allow(Saml::Kit.configuration.registry).to receive(:metadata_for).with(issuer).and_return(provider)
- url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder_class.new)
+ url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder)
result = subject.deserialize(query_params_from(url))
expect(result).to be_instance_of(Saml::Kit::AuthenticationRequest)
expect(result).to be_valid
end
+
+ it 'returns an unverfied document when the provider is unknown' do
+ configuration = Saml::Kit::Configuration.new do |config|
+ config.generate_key_pair_for(use: :signing)
+ end
+ url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder(configuration: configuration))
+
+ other_configuration = Saml::Kit::Configuration.new
+ allow(other_configuration.registry).to receive(:metadata_for).and_return(nil)
+
+ result = subject.deserialize(query_params_from(url), configuration: other_configuration)
+ expect(result).to_not be_signed
+ expect(result).to_not be_trusted
+ end
end
end