class Occi::Api::Client::Http::AuthnPlugins::Keystone

Constants

KEYSTONE_URI_REGEXP
KEYSTONE_VERSION_REGEXP

Public Instance Methods

authenticate(options = {}) click to toggle source
# File lib/occi/api/client/http/authn_plugins/keystone.rb, line 23
def authenticate(options = {})
  # OCCI-OS doesn't support HEAD method!
  response = @env_ref.class.get "#{@env_ref.endpoint}/-/"
  raise ::Occi::Api::Client::Errors::AuthnError,
        "Authentication failed with code #{response.code}!" unless response.success?
end
setup(options = {}) click to toggle source
# File lib/occi/api/client/http/authn_plugins/keystone.rb, line 8
def setup(options = {})
  # get Keystone URL if possible
  set_keystone_base_url

  # discover Keystone API version
  @env_ref.class.headers.delete 'X-Auth-Token'

  keystone_version = '3' if @options[:type] == 'oauth2'
  set_auth_token ENV['ROCCI_CLIENT_KEYSTONE_TENANT'], keystone_version

  if @env_ref.class.headers['X-Auth-Token'].blank?
    raise ::Occi::Api::Client::Errors::AuthnError, "Unable to get a tenant from Keystone, fallback failed!"
  end
end

Private Instance Methods

get_req_headers() click to toggle source
# File lib/occi/api/client/http/authn_plugins/keystone.rb, line 96
def get_req_headers
  headers = @env_ref.class.headers.clone
  headers['Content-Type'] = "application/json"
  headers['Accept'] = headers['Content-Type']

  headers
end
process_headers(response) click to toggle source
# File lib/occi/api/client/http/authn_plugins/keystone.rb, line 43
def process_headers(response)
  authN_header = response.headers['www-authenticate']

  if authN_header.blank?
    raise ::Occi::Api::Client::Errors::AuthnError,
          "Response does not contain the www-authenticate header, fallback failed!"
  end

  match = KEYSTONE_URI_REGEXP.match(authN_header)
  raise ::Occi::Api::Client::Errors::AuthnError,
        "Unable to get Keystone's URL from the response, fallback failed!" unless match && match[3]

  @keystone_url = match[3]
end
set_auth_token(tenant = nil, keystone_version = nil) click to toggle source
# File lib/occi/api/client/http/authn_plugins/keystone.rb, line 58
def set_auth_token(tenant = nil, keystone_version = nil)
  response = @env_ref.class.get(@keystone_url, :headers => get_req_headers)
  Occi::Api::Log.debug response.inspect

  unless response.success? || response.multiple_choices?
    raise ::Occi::Api::Client::Errors::AuthnError,
          'Unable to get Keystone API version from the response, fallback failed!'
  end

  versions = if response.multiple_choices?
               response['versions']['values'].sort_by { |v| v['id'] } # multiple versions, sort by version id
             else
               [response['version']] # assume a single version
             end

  versions.each do |v|
    match = KEYSTONE_VERSION_REGEXP.match(v['id'])
    raise ::Occi::Api::Client::Errors::AuthnError,
          "Unable to get Keystone API version from the response, fallback failed!" unless match && match[1]
    next if keystone_version && keystone_version != match[1]

    handler_class = match[1] == '3' ? KeystoneV3 : KeystoneV2
    v['links'].each do |link|
      begin
        next unless link['rel'] == 'self'

        keystone_url = link['href'].chomp('/')
        keystone_handler = handler_class.new(keystone_url, @env_ref, @options)
        keystone_handler.set_auth_token tenant

        return # found a working keystone, stop looking
      rescue ::Occi::Api::Client::Errors::AuthnError
        # ignore and try with next link
      end
    end
  end
end
set_keystone_base_url() click to toggle source
# File lib/occi/api/client/http/authn_plugins/keystone.rb, line 32
def set_keystone_base_url
  response = @env_ref.class.get "#{@env_ref.endpoint}/-/"
  Occi::Api::Log.debug response.inspect

  return if response.success?
  raise ::Occi::Api::Client::Errors::AuthnError,
        "Keystone AuthN failed with #{response.code}!" unless response.unauthorized?

  process_headers response
end