class OmniAuth::Strategies::SAML

Constants

OTHER_REQUEST_OPTIONS

Public Class Methods

inherited(subclass) click to toggle source
# File lib/omniauth/strategies/saml.rb, line 9
def self.inherited(subclass)
  OmniAuth::Strategy.included(subclass)
end

Public Instance Methods

callback_phase() click to toggle source
Calls superclass method
# File lib/omniauth/strategies/saml.rb, line 46
def callback_phase
  unless request.params['SAMLResponse']
    raise OmniAuth::Strategies::SAML::ValidationError.new("SAML response missing")
  end

  # Call a fingerprint validation method if there's one
  if options.idp_cert_fingerprint_validator
    fingerprint_exists = options.idp_cert_fingerprint_validator[response_fingerprint]
    unless fingerprint_exists
      raise OmniAuth::Strategies::SAML::ValidationError.new("Non-existent fingerprint")
    end
    # id_cert_fingerprint becomes the given fingerprint if it exists
    options.idp_cert_fingerprint = fingerprint_exists
  end

  settings = OneLogin::RubySaml::Settings.new(options)
  # filter options to select only extra parameters
  opts = options.select {|k,_| OTHER_REQUEST_OPTIONS.include?(k.to_sym)}
  # symbolize keys without activeSupport/symbolize_keys (ruby-saml use symbols)
  opts =
    opts.inject({}) do |new_hash, (key, value)|
      new_hash[key.to_sym] = value
      new_hash
    end
  response = OneLogin::RubySaml::Response.new(request.params['SAMLResponse'], opts.merge(settings: settings))
  response.attributes['fingerprint'] = options.idp_cert_fingerprint

  # will raise an error since we are not in soft mode
  response.soft = false
  response.is_valid?

  @name_id = response.name_id
  @attributes = response.attributes

  if @name_id.nil? || @name_id.empty?
    raise OmniAuth::Strategies::SAML::ValidationError.new("SAML response missing 'name_id'")
  end

  super
rescue OmniAuth::Strategies::SAML::ValidationError
  fail!(:invalid_ticket, $!)
rescue OneLogin::RubySaml::ValidationError
  fail!(:invalid_ticket, $!)
end
find_attribute_by(keys) click to toggle source
# File lib/omniauth/strategies/saml.rb, line 140
def find_attribute_by(keys)
  keys.each do |key|
    return @attributes[key] if @attributes[key]
  end

  nil
end
on_metadata_path?() click to toggle source
# File lib/omniauth/strategies/saml.rb, line 103
def on_metadata_path?
  on_path?("#{request_path}/metadata")
end
other_phase() click to toggle source
# File lib/omniauth/strategies/saml.rb, line 107
def other_phase
  if on_metadata_path?
    # omniauth does not set the strategy on the other_phase
    @env['omniauth.strategy'] ||= self
    setup_phase

    response = OneLogin::RubySaml::Metadata.new
    settings = OneLogin::RubySaml::Settings.new(options)
    if options.request_attributes.length > 0
      settings.attribute_consuming_service.service_name options.attribute_service_name
      options.request_attributes.each do |attribute|
        settings.attribute_consuming_service.add_attribute attribute
      end
    end
    Rack::Response.new(response.generate(settings), 200, { "Content-Type" => "application/xml" }).finish
  else
    call_app!
  end
end
request_phase() click to toggle source
# File lib/omniauth/strategies/saml.rb, line 31
def request_phase
  options[:assertion_consumer_service_url] ||= callback_url
  runtime_request_parameters = options.delete(:idp_sso_target_url_runtime_params)

  additional_params = {}
  runtime_request_parameters.each_pair do |request_param_key, mapped_param_key|
    additional_params[mapped_param_key] = request.params[request_param_key.to_s] if request.params.has_key?(request_param_key.to_s)
  end if runtime_request_parameters

  authn_request = OneLogin::RubySaml::Authrequest.new
  settings = OneLogin::RubySaml::Settings.new(options)

  redirect(authn_request.create(settings, additional_params))
end
response_fingerprint() click to toggle source

Obtain an idp certificate fingerprint from the response.

# File lib/omniauth/strategies/saml.rb, line 92
def response_fingerprint
  response = request.params['SAMLResponse']
  response = (response =~ /^</) ? response : Base64.decode64(response)
  document = XMLSecurity::SignedDocument::new(response)
  cert_element = REXML::XPath.first(document, "//ds:X509Certificate", { "ds"=> 'http://www.w3.org/2000/09/xmldsig#' })
  base64_cert = cert_element.text
  cert_text = Base64.decode64(base64_cert)
  cert = OpenSSL::X509::Certificate.new(cert_text)
  Digest::SHA1.hexdigest(cert.to_der).upcase.scan(/../).join(':')
end