Skip to content

Commit

Permalink
Merge pull request #6 from mdouchement/tp-keystone_v2
Browse files Browse the repository at this point in the history
Keystone v2 support
  • Loading branch information
kuon committed Jul 7, 2015
2 parents 8efb6f0 + 77d0523 commit feb2dd1
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 74 deletions.
12 changes: 12 additions & 0 deletions lib/swift-storage.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "net/http"
require "swift_storage/version"
require "swift_storage/configuration"
require "swift_storage/errors"
require "swift_storage/utils"
require "swift_storage/headers"
Expand All @@ -12,4 +13,15 @@
require "swift_storage/service"

module SwiftStorage
class << self
attr_accessor :configuration
end

def self.configuration
@configuration ||= Configuration.new
end

def self.configure
yield configuration
end
end
31 changes: 31 additions & 0 deletions lib/swift_storage/auth/v1_0.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module SwiftStorage
module Auth
module V1_0
attr_accessor :auth_path

def authenticate!
headers = {
Headers::AUTH_USER => "#{tenant}:#{username}",
Headers::AUTH_KEY => password
}
res = request(auth_url, headers: headers)

h = res.header
self.storage_url = h[Headers::STORAGE_URL]
@auth_token = h[Headers::AUTH_TOKEN]
@storage_token = h[Headers::STORAGE_TOKEN]
@auth_at = Time.now
end

def authenticated?
!!(self.storage_url && auth_token)
end

private

def auth_url
File.join(endpoint, @auth_path || 'auth/v1.0')
end
end
end
end
76 changes: 76 additions & 0 deletions lib/swift_storage/auth/v2_0.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
module SwiftStorage
module Auth
module V2_0
extend Forwardable
def_delegators SwiftStorage, :configuration

attr_accessor :auth_path

def authenticate!
res = request("#{auth_url}/tokens", method: :post, json_data: auth_data)

JSON.parse(res.body).tap do |body|
@auth_token = body['access']['token']['id']
storage_endpoint(body['access']['serviceCatalog']) do |endpoint|
self.storage_url = endpoint['publicURL']
@storage_token = endpoint['id']
@auth_at = Time.now
end
end
end

def authenticated?
!!(self.storage_url && auth_token)
end

private

def auth_url
File.join(endpoint, @auth_path || 'v2.0').chomp('/')
end

def auth_data
case configuration.auth_method
when :password
{
auth: {
passwordCredentials: {
username: username,
password: password
},
configuration.authtenant_type => tenant || username
}
}
when :rax_kskey
{
auth: {
'RAX-KSKEY:apiKeyCredentials' => {
username: username,
apiKey: password
}
}
}
when :key
{
auth: {
apiAccessKeyCredentials: {
accessKey: username,
secretKey: password
},
configuration.authtenant_type => tenant || username
}
}
else
fail "Unsupported authentication method #{configuration.auth_method}"
end
end

def storage_endpoint(service_catalog)
unless (swift = service_catalog.find { |service| service['type'] == 'object-store' })
fail SwiftStorage::Errors::NotFoundError.new 'No object-store service found'
end
yield swift['endpoints'].sample
end
end
end
end
18 changes: 18 additions & 0 deletions lib/swift_storage/configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module SwiftStorage
class Configuration
attr_accessor :auth_version, :tenant, :username, :password, :endpoint, :temp_url_key,
:auth_method, :authtenant_type

def initialize
@auth_version = ENV['SWIFT_STORAGE_AUTH_VERSION'] || '1.0'
@tenant = ENV['SWIFT_STORAGE_TENANT']
@username = ENV['SWIFT_STORAGE_USERNAME']
@password = ENV['SWIFT_STORAGE_PASSWORD']
@endpoint = ENV['SWIFT_STORAGE_ENDPOINT']
@temp_url_key = ENV['SWIFT_STORAGE_TEMP_URL_KEY']

@auth_method = :password
@authtenant_type = 'tenantName' # `tenantName` or `tenantId`
end
end
end
84 changes: 40 additions & 44 deletions lib/swift_storage/service.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
require 'uri'
require 'json'
require 'swift_storage/auth/v1_0'
require 'swift_storage/auth/v2_0'

class SwiftStorage::Service

include SwiftStorage::Utils
include SwiftStorage
extend Forwardable
def_delegators SwiftStorage, :configuration

attr_reader :tenant,
:endpoint,
Expand All @@ -17,41 +21,31 @@ class SwiftStorage::Service
:storage_path,
:temp_url_key

def initialize(tenant: ENV['SWIFT_STORAGE_TENANT'],
username: ENV['SWIFT_STORAGE_USERNAME'],
password: ENV['SWIFT_STORAGE_PASSWORD'],
endpoint: ENV['SWIFT_STORAGE_ENDPOINT'],
temp_url_key: ENV['SWIFT_STORAGE_TEMP_URL_KEY'])
def initialize(tenant: configuration.tenant,
username: configuration.username,
password: configuration.password,
endpoint: configuration.endpoint,
temp_url_key: configuration.temp_url_key)
@temp_url_key = temp_url_key

%w(tenant username password endpoint).each do |n|
eval("#{n} or raise ArgumentError, '#{n} is required'")
eval("@#{n} = #{n}")
end
self.storage_url = File.join(endpoint, 'v1', "AUTH_#{tenant}")

setup_auth
@sessions = {}
end

def authenticate!
@auth_token = nil
@storage_token = nil
@auth_at = nil
headers = {
Headers::AUTH_USER => "#{tenant}:#{username}",
Headers::AUTH_KEY => password
}
res = request(auth_url, :headers => headers)

h = res.header
self.storage_url = h[Headers::STORAGE_URL]
@auth_token = h[Headers::AUTH_TOKEN]
@storage_token = h[Headers::STORAGE_TOKEN]
@auth_at = Time.new
end

def authenticated?
!!(storage_url && auth_token)
def setup_auth
case configuration.auth_version
when '1.0'
extend SwiftStorage::Auth::V1_0
when '2.0'
extend SwiftStorage::Auth::V2_0
else
fail "Unsupported auth version #{configuration.auth_version}"
end
end

def containers
Expand All @@ -77,10 +71,10 @@ def create_temp_url(container, object, expires, method, options = {})

method = method.to_s.upcase
# Limit methods
%w{GET PUT HEAD}.include?(method) or raise ArgumentError, "Only GET, PUT, HEAD supported"
%w{GET PUT HEAD}.include?(method) or raise ArgumentError, 'Only GET, PUT, HEAD supported'

expires = expires.to_i
object_path_escaped = File.join(storage_path, escape(container), escape(object,"/"))
object_path_escaped = File.join(storage_path, escape(container), escape(object, '/'))
object_path_unescaped = File.join(storage_path, escape(container), object)

string_to_sign = "#{method}\n#{expires}\n#{object_path_unescaped}"
Expand All @@ -90,13 +84,13 @@ def create_temp_url(container, object, expires, method, options = {})
klass = scheme == 'http' ? URI::HTTP : URI::HTTPS

temp_url_options = {
:scheme => scheme,
:host => storage_host,
:port => storage_port,
:path => object_path_escaped,
:query => URI.encode_www_form(
:temp_url_sig => sig,
:temp_url_expires => expires
scheme: scheme,
host: storage_host,
port: storage_port,
path: object_path_escaped,
query: URI.encode_www_form(
temp_url_sig: sig,
temp_url_expires: expires
)
}
klass.build(temp_url_options).to_s
Expand All @@ -115,13 +109,15 @@ def escape(*args)
end

def request(path_or_url,
method: :get,
headers: nil,
params: nil,
input_stream: nil,
output_stream: nil)
method: :get,
headers: nil,
params: nil,
json_data: nil,
input_stream: nil,
output_stream: nil)
headers ||= {}
headers.merge!(Headers::AUTH_TOKEN => auth_token) if authenticated?
headers.merge!(Headers::CONTENT_TYPE => 'application/json') if json_data
headers.merge!(Headers::CONNECTION => 'keep-alive', Headers::PROXY_CONNECTION => 'keep-alive')

if !(path_or_url =~ /^http/)
Expand Down Expand Up @@ -163,6 +159,10 @@ def request(path_or_url,
raise ArgumentError, "Method #{method} not supported"
end

if json_data
req.body = JSON.generate(json_data)
end

if input_stream
if String === input_stream
input_stream = StringIO.new(input_stream)
Expand Down Expand Up @@ -200,10 +200,6 @@ def request(path_or_url,
:username,
:password

def auth_url
File.join(endpoint, 'auth/v1.0')
end

def check_response!(response)
case response.code
when /^2/
Expand Down
12 changes: 4 additions & 8 deletions lib/swift_storage/utils.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module SwiftStorage::Utils
require 'openssl'

module SwiftStorage::Utils
include SwiftStorage::Errors

def hmac(type, key, data)
Expand All @@ -8,16 +9,11 @@ def hmac(type, key, data)
end

def sig_to_hex(str)
str.unpack("C*").map { |c|
c.to_s(16)
}.map { |h|
h.size == 1 ? "0#{h}" : h
}.join
Digest.hexencode(str)
end

def struct(h)
return nil if h.empty?
return if h.empty?
Struct.new(*h.keys.map(&:to_sym)).new(*h.values)
end

end
3 changes: 1 addition & 2 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
require_relative "support/local_server"

module TestServerMixin

def h
SwiftStorage::Headers
end
Expand Down Expand Up @@ -30,7 +29,7 @@ def swift_service
:password => 'testpassword',
:endpoint => server.base_url,
:temp_url_key => 'A1234'
)
).tap { |s| s.storage_url = test_storage_url }
end

def test_storage_url
Expand Down
Loading

0 comments on commit feb2dd1

Please sign in to comment.