# File lib/fog/openstack.rb, line 443
    def self.retrieve_tokens_v3(options, connection_options = {})

      api_key           = options[:openstack_api_key].to_s
      username          = options[:openstack_username].to_s
      userid            = options[:openstack_userid]
      domain_id         = options[:openstack_domain_id]
      domain_name       = options[:openstack_domain_name]
      project_domain    = options[:openstack_project_domain]
      project_domain_id = options[:openstack_project_domain_id]
      user_domain       = options[:openstack_user_domain]
      user_domain_id    = options[:openstack_user_domain_id]
      project_name      = options[:openstack_project_name]
      project_id        = options[:openstack_project_id]
      auth_token        = options[:openstack_auth_token] || options[:unscoped_token]
      uri               = options[:openstack_auth_uri]
      omit_default_port = options[:openstack_auth_omit_default_port]
      cache_ttl         = options[:openstack_cache_ttl] || 0

      connection = Fog::Core::Connection.new(uri.to_s, false, connection_options)
      request_body = {:auth => {}}

      scope = {}

      if project_name || project_id
        scope[:project] = if project_id.nil? then
                            if project_domain || project_domain_id
                              {:name => project_name, :domain => project_domain_id.nil? ? {:name => project_domain} : {:id => project_domain_id}}
                            else
                              {:name => project_name, :domain => domain_id.nil? ? {:name => domain_name} : {:id => domain_id}}
                            end
                          else
                            {:id => project_id}
                          end
      elsif domain_name || domain_id
        scope[:domain] = domain_id.nil? ? {:name => domain_name} : {:id => domain_id}
      else
        # unscoped token
      end

      if auth_token
        request_body[:auth][:identity] = {
            :methods => %w{token},
            :token => {
                :id => auth_token
            }
        }
      else
        request_body[:auth][:identity] = {
            :methods => %w{password},
            :password => {
                :user => {
                    :password => api_key
                }
            }
        }

        if userid
          request_body[:auth][:identity][:password][:user][:id] = userid
        else
          if user_domain || user_domain_id
            request_body[:auth][:identity][:password][:user].merge! :domain => user_domain_id.nil? ? {:name => user_domain} : {:id => user_domain_id}
          elsif domain_name || domain_id
            request_body[:auth][:identity][:password][:user].merge! :domain => domain_id.nil? ? {:name => domain_name} : {:id => domain_id}
          end
          request_body[:auth][:identity][:password][:user][:name] = username
        end

      end
      request_body[:auth][:scope] = scope unless scope.empty?

      path     = (uri.path and not uri.path.empty?) ? uri.path : 'v3'

      response, expires = Fog::OpenStack.token_cache[{:body => request_body, :path => path}] if cache_ttl > 0

      unless response && expires > Time.now
        request = {
          :expects => [201],
          :headers => {'Content-Type' => 'application/json'},
          :body    => Fog::JSON.encode(request_body),
          :method  => 'POST',
          :path    => path
        }
        request[:omit_default_port] = omit_default_port unless omit_default_port.nil?

        response = connection.request(request)
        if cache_ttl > 0
          cache = Fog::OpenStack.token_cache
          cache[{:body => request_body, :path => path}] = response, Time.now + cache_ttl
          Fog::OpenStack.token_cache = cache
        end
      end

      [response.headers["X-Subject-Token"], Fog::JSON.decode(response.body)]
    end