module SamlIdp
module Controller
require 'openssl'
require 'base64'
require 'time'
attr_accessor :x509_certificate, :secret_key, :algorithm
attr_accessor :saml_acs_url
def x509_certificate
return @x509_certificate if defined?(@x509_certificate)
@x509_certificate = SamlIdp.config.x509_certificate
end
def secret_key
return @secret_key if defined?(@secret_key)
@secret_key = SamlIdp.config.secret_key
end
def algorithm
return @algorithm if defined?(@algorithm)
self.algorithm = SamlIdp.config.algorithm
@algorithm
end
def algorithm=(algorithm)
@algorithm = algorithm
if algorithm.is_a?(Symbol)
@algorithm = case algorithm
when :sha256 then OpenSSL::Digest::SHA256
when :sha384 then OpenSSL::Digest::SHA384
when :sha512 then OpenSSL::Digest::SHA512
else
OpenSSL::Digest::SHA1
end
end
@algorithm
end
def algorithm_name
algorithm.to_s.split('::').last.downcase
end
protected
def validate_saml_request(saml_request = params[:SAMLRequest])
decode_SAMLRequest(saml_request) rescue false
end
def decode_SAMLRequest(saml_request)
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
@saml_request = zstream.inflate(Base64.decode64(saml_request))
zstream.finish
zstream.close
@saml_request_id = @saml_request[/ID=['"](.+?)['"]/, 1]
@saml_acs_url = @saml_request[/AssertionConsumerServiceURL=['"](.+?)['"]/, 1]
end
def encode_SAMLResponse(nameID, opts = {})
now = Time.now.utc
response_id, reference_id = SecureRandom.uuid, SecureRandom.uuid
audience_uri = opts[:audience_uri] || saml_acs_url[/^(.*?\/\/.*?\/)/, 1]
issuer_uri = opts[:issuer_uri] || (defined?(request) && request.url) || "http://example.com"
attributes_statement = attributes(opts[:attributes_provider], nameID)
assertion = %[#{issuer_uri}#{nameID}#{audience_uri}#{attributes_statement}urn:federation:authentication:windows]
digest_value = Base64.encode64(algorithm.digest(assertion)).gsub(/\n/, '')
signed_info = %[#{digest_value}]
signature_value = sign(signed_info).gsub(/\n/, '')
signature = %[#{signed_info}#{signature_value}#{self.x509_certificate}]
assertion_and_signature = assertion.sub(/Issuer\>\#{signature}#{issuer_uri}#{assertion_and_signature}]
Base64.encode64(xml)
end
private
def sign(data)
key = OpenSSL::PKey::RSA.new(self.secret_key)
Base64.encode64(key.sign(algorithm.new, data))
end
def attributes(provider, nameID)
provider ? provider : %[#{nameID}]
end
end
end