diff --git a/lib/fog/brightbox/compute.rb b/lib/fog/brightbox/compute.rb index be5cb3f68..fc96dea74 100644 --- a/lib/fog/brightbox/compute.rb +++ b/lib/fog/brightbox/compute.rb @@ -17,6 +17,9 @@ module Fog # User credentials (still requires client details) recognizes :brightbox_username, :brightbox_password, :brightbox_account + # Cached tokens + recognizes :brightbox_access_token, :brightbox_refresh_token + # Excon connection settings recognizes :persistent @@ -167,6 +170,9 @@ module Fog # Creates a new instance of the Brightbox Compute service # + # @note If you open a connection using just a refresh token when it + # expires the service will no longer be able to authenticate. + # # @param [Hash] options # @option options [String] :brightbox_api_url Override the default (or configured) API endpoint # @option options [String] :brightbox_auth_url Override the default (or configured) API authentication endpoint @@ -177,6 +183,8 @@ module Fog # @option options [String] :brightbox_account Account identifier to scope this connection to # @option options [String] :connection_options Settings to pass to underlying {Fog::Connection} # @option options [Boolean] :persistent Sets a persistent HTTP {Fog::Connection} + # @option options [String] :brightbox_access_token Sets the OAuth access token to use rather than requesting a new token + # @option options [String] :brightbox_refresh_token Sets the refresh token to use when requesting a newer access token # def initialize(options) # Currently authentication and api endpoints are the same but may change @@ -198,6 +206,9 @@ module Fog credential_options = {:username => username, :password => password} @credentials = CredentialSet.new(client_id, client_secret, credential_options) + + # If existing tokens have been cached, allow continued use of them in the service + @credentials.update_tokens(options[:brightbox_access_token], options[:brightbox_refresh_token]) end # Makes an API request to the given path using passed options or those @@ -247,6 +258,24 @@ module Fog @credentials.user_details? end + # Returns true if an access token is set + # @return [Boolean] + def access_token_available? + !! @credentials.access_token + end + + # Returns the current access token or nil + # @return [String,nil] + def access_token + @credentials.access_token + end + + # Returns the current refresh token or nil + # @return [String,nil] + def refresh_token + @credentials.refresh_token + end + private def get_oauth_token @@ -268,13 +297,14 @@ module Fog :method => 'POST', :body => Fog::JSON.encode(token_strategy.authorization_body_data) }) - @oauth_token = Fog::JSON.decode(response.body)["access_token"] - return @oauth_token + response_data = Fog::JSON.decode(response.body) + @credentials.update_tokens(response_data["access_token"], response_data["refresh_token"]) + @credentials.access_token end def make_request(params) begin - get_oauth_token if @oauth_token.nil? + get_oauth_token unless access_token_available? response = authenticated_request(params) rescue Excon::Errors::Unauthorized get_oauth_token @@ -287,7 +317,7 @@ module Fog def authenticated_request(options) headers = options[:headers] || {} - headers.merge!("Authorization" => "OAuth #{@oauth_token}", "Content-Type" => "application/json") + headers.merge!("Authorization" => "OAuth #{@credentials.access_token}", "Content-Type" => "application/json") options[:headers] = headers @connection.request(options) end diff --git a/lib/fog/brightbox/oauth2.rb b/lib/fog/brightbox/oauth2.rb index c8f32f0dc..530cf4d83 100644 --- a/lib/fog/brightbox/oauth2.rb +++ b/lib/fog/brightbox/oauth2.rb @@ -12,6 +12,7 @@ module Fog::Brightbox::OAuth2 # class CredentialSet attr_reader :client_id, :client_secret, :username, :password + attr_reader :access_token, :refresh_token # # @param [String] client_id # @param [String] client_secret @@ -24,6 +25,8 @@ module Fog::Brightbox::OAuth2 @client_secret = client_secret @username = options[:username] @password = options[:password] + @access_token = options[:access_token] + @refresh_token = options[:refresh_token] end # Returns true if user details are available @@ -31,6 +34,22 @@ module Fog::Brightbox::OAuth2 def user_details? !!(@username && @password) end + + # Is an access token available for these credentials? + def access_token? + !!@access_token + end + + # Is a refresh token available for these credentials? + def refresh_token? + !!@refresh_token + end + + # Updates the credentials with newer tokens + def update_tokens(access_token, refresh_token = nil) + @access_token = access_token + @refresh_token = refresh_token + end end # This strategy class is the basis for OAuth2 grant types diff --git a/tests/brightbox/compute_tests.rb b/tests/brightbox/compute_tests.rb index f3a15134a..a3f043895 100644 --- a/tests/brightbox/compute_tests.rb +++ b/tests/brightbox/compute_tests.rb @@ -18,7 +18,9 @@ Shindo.tests('Fog::Compute.new', ['brightbox']) do :brightbox_secret => "12345abdef6789", :brightbox_username => "user-12345", :brightbox_password => "password1234", - :brightbox_account => "acc-12345" + :brightbox_account => "acc-12345", + :brightbox_access_token => "12345abdef6789", + :brightbox_refresh_token => "12345abdef6789" }.each_pair do |option, sample| tests("recognises :#{option}").returns(true) do options = {:provider => "Brightbox"} diff --git a/tests/brightbox/oauth2_tests.rb b/tests/brightbox/oauth2_tests.rb index 969b81264..46fb82835 100644 --- a/tests/brightbox/oauth2_tests.rb +++ b/tests/brightbox/oauth2_tests.rb @@ -5,16 +5,30 @@ Shindo.tests("Fog::Brightbox::OAuth2", ["brightbox"]) do @client_secret = "__mashed_keys_123__" @username = "usr-12345" @password = "__mushed_keys_321__" + @access_token = "12efde32fdfe4989" + @refresh_token = "7894389f9074f071" tests("with client credentials") do credentials = Fog::Brightbox::OAuth2::CredentialSet.new(@client_id, @client_secret) tests("#user_details?").returns(false) { credentials.user_details? } + tests("#access_token?").returns(false) { credentials.access_token? } + tests("#refresh_token?").returns(false) { credentials.refresh_token? } end tests("with user credentials") do options = {:username => @username, :password => @password} credentials = Fog::Brightbox::OAuth2::CredentialSet.new(@client_id, @client_secret, options) tests("#user_details?").returns(true) { credentials.user_details? } + tests("#access_token?").returns(false) { credentials.access_token? } + tests("#refresh_token?").returns(false) { credentials.refresh_token? } + end + + tests("with existing tokens") do + options = {:username => @username, :access_token => @access_token, :refresh_token => @refresh_token} + credentials = Fog::Brightbox::OAuth2::CredentialSet.new(@client_id, @client_secret, options) + tests("#user_details?").returns(false) { credentials.user_details? } + tests("#access_token?").returns(true) { credentials.access_token? } + tests("#refresh_token?").returns(true) { credentials.refresh_token? } end end