Commit e34d28a
Changed files (3)
lib
saml
spec
saml
lib/saml/kit/binding.rb
@@ -13,57 +13,97 @@ module Saml
end
def serialize(builder, relay_state: nil)
- if http_redirect?
- builder.sign = false
- builder.destination = location
- document = builder.build
- [UrlBuilder.new.build(document, relay_state: relay_state), {}]
- elsif post?
- builder.sign = true
- builder.destination = location
- document = builder.build
- saml_params = {
- document.query_string_parameter => Base64.strict_encode64(document.to_xml),
- }
- saml_params['RelayState'] = relay_state if relay_state.present?
- [location, saml_params]
+ []
+ end
+
+ def deserialize(params)
+ raise ArgumentError.new("Unsupported binding")
+ end
+
+ def to_h
+ { binding: binding, location: location }
+ end
+
+ protected
+
+ def deserialize_request(raw_request)
+ xml = Saml::Kit::Content.deserialize(raw_request)
+ hash = Hash.from_xml(xml)
+ if hash['AuthnRequest'].present?
+ AuthenticationRequest.new(xml)
else
- []
+ LogoutRequest.new(xml)
end
+ rescue => error
+ Saml::Kit.logger.error(error)
+ Saml::Kit.logger.error(error.backtrace.join("\n"))
+ InvalidRequest.new(raw_request)
end
- def deserialize(params)
- if http_redirect?
- document = deserialize_document_from!(params)
- ensure_valid_signature!(params, document)
- document
- elsif post?
- if params['SAMLRequest'].present?
- deserialize_request(params['SAMLRequest'])
- elsif params['SAMLResponse'].present?
- deserialize_response(params['SAMLResponse'])
- else
- raise ArgumentError.new("Missing SAMLRequest or SAMLResponse")
- end
+ def deserialize_response(saml_response)
+ xml = Saml::Kit::Content.deserialize(saml_response)
+ hash = Hash.from_xml(xml)
+ if hash['Response'].present?
+ Response.new(xml)
else
- raise ArgumentError.new("Unsupported binding")
+ LogoutResponse.new(xml)
end
+ rescue => error
+ Saml::Kit.logger.error(error)
+ Saml::Kit.logger.error(error.backtrace.join("\n"))
+ InvalidResponse.new(saml_response)
end
+ end
- def http_redirect?
- binding == Namespaces::HTTP_REDIRECT
+ class HttpPostBinding < Binding
+ def serialize(builder, relay_state: nil)
+ builder.sign = true
+ builder.destination = location
+ document = builder.build
+ saml_params = {
+ document.query_string_parameter => Base64.strict_encode64(document.to_xml),
+ }
+ saml_params['RelayState'] = relay_state if relay_state.present?
+ [location, saml_params]
end
- def post?
- binding == Namespaces::POST
+ def deserialize(params)
+ if params['SAMLRequest'].present?
+ deserialize_request(params['SAMLRequest'])
+ elsif params['SAMLResponse'].present?
+ deserialize_response(params['SAMLResponse'])
+ else
+ raise ArgumentError.new("Missing SAMLRequest or SAMLResponse")
+ end
end
+ end
- def to_h
- { binding: binding, location: location }
+ class HttpRedirectBinding < Binding
+ def serialize(builder, relay_state: nil)
+ builder.sign = false
+ builder.destination = location
+ document = builder.build
+ [UrlBuilder.new.build(document, relay_state: relay_state), {}]
+ end
+
+ def deserialize(params)
+ document = deserialize_document_from!(params)
+ ensure_valid_signature!(params, document)
+ document
end
private
+ def deserialize_document_from!(params)
+ if params['SAMLRequest'].present?
+ deserialize_request(CGI.unescape(params['SAMLRequest']))
+ elsif params['SAMLResponse'].present?
+ deserialize_response(CGI.unescape(params['SAMLResponse']))
+ else
+ raise ArgumentError.new("SAMLRequest or SAMLResponse parameter is required.")
+ end
+ end
+
def ensure_valid_signature!(params, document)
return if params['Signature'].blank? || params['SigAlg'].blank?
@@ -77,15 +117,6 @@ module Saml
raise ArgumentError.new("Invalid Signature") unless valid
end
- def deserialize_document_from!(params)
- if params['SAMLRequest'].present?
- deserialize_request(CGI.unescape(params['SAMLRequest']))
- elsif params['SAMLResponse'].present?
- deserialize_response(CGI.unescape(params['SAMLResponse']))
- else
- raise ArgumentError.new("SAMLRequest or SAMLResponse parameter is required.")
- end
- end
def algorithm_for(algorithm)
case algorithm =~ /(rsa-)?sha(.*?)$/i && $2.to_i
@@ -100,33 +131,6 @@ module Saml
end
end
- def deserialize_request(raw_request)
- xml = Saml::Kit::Content.deserialize(raw_request)
- hash = Hash.from_xml(xml)
- if hash['AuthnRequest'].present?
- AuthenticationRequest.new(xml)
- else
- LogoutRequest.new(xml)
- end
- rescue => error
- Saml::Kit.logger.error(error)
- Saml::Kit.logger.error(error.backtrace.join("\n"))
- InvalidRequest.new(raw_request)
- end
-
- def deserialize_response(saml_response)
- xml = Saml::Kit::Content.deserialize(saml_response)
- hash = Hash.from_xml(xml)
- if hash['Response'].present?
- Response.new(xml)
- else
- LogoutResponse.new(xml)
- end
- rescue => error
- Saml::Kit.logger.error(error)
- Saml::Kit.logger.error(error.backtrace.join("\n"))
- InvalidResponse.new(saml_response)
- end
end
end
end
lib/saml/kit/identity_provider_metadata.rb
@@ -15,10 +15,8 @@ module Saml
def single_sign_on_services
xpath = "/md:EntityDescriptor/md:#{name}/md:SingleSignOnService"
find_all(xpath).map do |item|
- Saml::Kit::Binding.new(
- binding: item.attribute("Binding").value,
- location: item.attribute("Location").value,
- )
+ binding = item.attribute("Binding").value
+ binding_type_for(binding).new(binding: binding, location: item.attribute("Location").value)
end
end
@@ -38,6 +36,19 @@ module Saml
end
end
+ private
+
+ def binding_type_for(binding)
+ case binding
+ when Namespaces::HTTP_REDIRECT
+ Saml::Kit::HttpRedirectBinding
+ when Namespaces::POST
+ Saml::Kit::HttpPostBinding
+ else
+ Saml::Kit::Binding
+ end
+ end
+
class Builder
attr_accessor :id, :organization_name, :organization_url, :contact_email, :entity_id, :attributes, :name_id_formats
attr_accessor :want_authn_requests_signed, :sign
spec/saml/binding_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Saml::Kit::Binding do
let(:relay_state) { "ECHO" }
describe "HTTP-REDIRECT BINDING" do
- let(:subject) { Saml::Kit::Binding.new(binding: Saml::Kit::Namespaces::HTTP_REDIRECT, location: location) }
+ let(:subject) { Saml::Kit::HttpRedirectBinding.new(binding: Saml::Kit::Namespaces::HTTP_REDIRECT, location: location) }
it 'encodes the request using the HTTP-Redirect encoding' do
builder = Saml::Kit::AuthenticationRequest::Builder.new
@@ -20,7 +20,7 @@ RSpec.describe Saml::Kit::Binding do
end
describe "HTTP-POST Binding" do
- let(:subject) { Saml::Kit::Binding.new(binding: Saml::Kit::Namespaces::POST, location: location) }
+ let(:subject) { Saml::Kit::HttpPostBinding.new(binding: Saml::Kit::Namespaces::POST, location: location) }
it 'encodes the request using the HTTP-POST encoding for a AuthenticationRequest' do
builder = Saml::Kit::AuthenticationRequest::Builder.new
@@ -81,7 +81,7 @@ RSpec.describe Saml::Kit::Binding do
describe "#deserialize" do
describe "HTTP-Redirect binding" do
- let(:subject) { Saml::Kit::Binding.new(binding: Saml::Kit::Namespaces::HTTP_REDIRECT, location: location) }
+ let(:subject) { Saml::Kit::HttpRedirectBinding.new(binding: Saml::Kit::Namespaces::HTTP_REDIRECT, location: location) }
let(:issuer) { FFaker::Internet.http_url }
let(:provider) { Saml::Kit::IdentityProviderMetadata::Builder.new.build }
@@ -146,7 +146,7 @@ RSpec.describe Saml::Kit::Binding do
end
describe "HTTP Post binding" do
- let(:subject) { Saml::Kit::Binding.new(binding: Saml::Kit::Namespaces::POST, location: location) }
+ let(:subject) { Saml::Kit::HttpPostBinding.new(binding: Saml::Kit::Namespaces::POST, location: location) }
it 'deserializes to an AuthnRequest' do
builder = Saml::Kit::AuthenticationRequest::Builder.new