Class: Occi::Api::Client::Http::AuthnPlugins::Keystone

Inherits:
Base
  • Object
show all
Defined in:
lib/occi/api/client/http/authn_plugins/keystone.rb

Constant Summary collapse

KEYSTONE_URI_REGEXP =
/^(Keystone|snf-auth) uri=("|')(.+)("|')$/
KEYSTONE_VERSION_REGEXP =
/^v([0-9]).*$/

Instance Attribute Summary

Attributes inherited from Base

#env_ref, #fallbacks, #options

Instance Method Summary collapse

Methods inherited from Base

#initialize

Constructor Details

This class inherits a constructor from Occi::Api::Client::Http::AuthnPlugins::Base

Instance Method Details

#authenticate(options = {}) ⇒ Object



23
24
25
26
27
28
# 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

#get_req_headersObject (private)



96
97
98
99
100
101
102
# 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) ⇒ Object (private)



43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 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) ⇒ Object (private)



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# 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_urlObject (private)



32
33
34
35
36
37
38
39
40
41
# 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

#setup(options = {}) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 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