class AdsCommon::Auth::OAuth2Handler

Credentials class to handle OAuth2 authentication.

Constants

DEFAULT_CALLBACK
OAUTH2_CONFIG

Public Class Methods

new(config, scope) click to toggle source

Initializes the OAuthHandler2 with all the necessary details.

Args:

  • config: Config object with library configuration

  • scope: OAuth authorization scope

Calls superclass method AdsCommon::Auth::BaseHandler::new
# File lib/ads_common/auth/oauth2_handler.rb, line 47
def initialize(config, scope)
  super(config)
  @scopes = []
  @scopes << scope unless scope.nil?
  additional_scopes = @config.read('authentication.oauth2_extra_scopes')
  @scopes += additional_scopes if additional_scopes.is_a?(Array)
  @client = nil
end

Public Instance Methods

auth_string(credentials) click to toggle source

Generates auth string for OAuth2 method of authentication.

Args:

  • credentials: credentials set for authorization

Returns:

  • Authentication string

# File lib/ads_common/auth/oauth2_handler.rb, line 78
def auth_string(credentials)
  token = get_token(credentials)
  if token.nil?
    raise AdsCommon::Errors::AuthError.new(
      'Could not get auth token. Are you missing a refresh token?')
  end
  return ::Signet::OAuth2.generate_bearer_authorization_header(
      token[:access_token])
end
get_token(credentials = nil, force_refresh = false) click to toggle source

Overrides base get_token method to account for the token expiration.

Calls superclass method AdsCommon::Auth::BaseHandler#get_token
# File lib/ads_common/auth/oauth2_handler.rb, line 89
def get_token(credentials = nil, force_refresh = false)
  token = super(credentials)
  token = refresh_token! if !@client.nil? &&
      (force_refresh || @client.expired?)
  return token
end
handle_error(error) click to toggle source
# File lib/ads_common/auth/oauth2_handler.rb, line 64
def handle_error(error)
  # TODO: Add support.
  get_logger().error(error)
  raise error
end
property_changed(prop, value) click to toggle source

Invalidates the stored token if the required credential has changed.

# File lib/ads_common/auth/oauth2_handler.rb, line 57
def property_changed(prop, value)
  oauth2_keys = [:oauth2_client_id, :oauth2_client_secret, :oauth2_token]
  if oauth2_keys.include?(prop)
    @token, @client = nil, nil
  end
end
refresh_token!() click to toggle source

Refreshes access token from refresh token.

# File lib/ads_common/auth/oauth2_handler.rb, line 97
def refresh_token!()
  return nil if @token.nil? or @token[:refresh_token].nil?
  begin
    if @client.issued_at.is_a?(String)
      @client.issued_at = Time.parse(@client.issued_at)
    end
    @client.refresh!
  rescue Signet::AuthorizationError => e
    raise AdsCommon::Errors::AuthError.new("OAuth2 token refresh failed",
        e, (e.response.nil?) ? nil : e.response.body)
  end
  @token = token_from_client(@client)
  return @token
end

Private Instance Methods

create_client(credentials) click to toggle source
# File lib/ads_common/auth/oauth2_handler.rb, line 171
def create_client(credentials)
  oauth_options = OAUTH2_CONFIG.merge({
      :client_id => credentials[:oauth2_client_id],
      :client_secret => credentials[:oauth2_client_secret],
      :scope => @scopes.join(' '),
      :redirect_uri => credentials[:oauth2_callback] || DEFAULT_CALLBACK,
      :state => credentials[:oauth2_state]
  }).reject {|k, v| v.nil?}
  return Signet::OAuth2::Client.new(oauth_options)
end
create_token(credentials) click to toggle source

Auxiliary method to generate an authentication token for logging via the OAuth2 API.

Args:

  • credentials: a hash with the credentials for the account being accessed

Returns:

  • The auth token for the account (as an AccessToken)

Raises:

# File lib/ads_common/auth/oauth2_handler.rb, line 164
def create_token(credentials)
  validate_credentials(credentials)
  @client ||= create_client(credentials)
  return create_token_from_credentials(credentials, @client) ||
      generate_access_token(credentials, @client)
end
create_token_from_credentials(credentials, client) click to toggle source

Creates access token based on data from credentials.

Args:

  • credentials: a hash with the credentials for the account being accessed. Has to include :oauth2_token key with a hash value that represents a stored OAuth2 access token

  • client: OAuth2 client for the current configuration

Returns:

  • The auth token for the account (as an AccessToken)

# File lib/ads_common/auth/oauth2_handler.rb, line 193
def create_token_from_credentials(credentials, client)
  oauth2_token_hash = credentials[:oauth2_token]
  if !oauth2_token_hash.nil? && oauth2_token_hash.kind_of?(Hash)
    token_data = AdsCommon::Utils.hash_keys_to_str(oauth2_token_hash)
    client.update_token!(token_data)
  end
  return token_from_client(client)
end
generate_access_token(credentials, client) click to toggle source

Generates new request tokens and authorizes it to get access token.

Args:

  • credentials: a hash with the credentials for the account being accessed

  • client: OAuth2 client for the current configuration

Returns:

  • The auth token for the account (as Hash)

# File lib/ads_common/auth/oauth2_handler.rb, line 212
def generate_access_token(credentials, client)
  token = nil
  begin
    verification_code = credentials[:oauth2_verification_code]
    if verification_code.nil? || verification_code.empty?
      uri_options = {
        :access_type => credentials[:oauth2_access_type],
        :prompt => credentials[:oauth2_prompt]
      }.reject {|k, v| v.nil?}
      oauth_url = client.authorization_uri(uri_options)
      raise AdsCommon::Errors::OAuth2VerificationRequired.new(oauth_url)
    else
      client.code = verification_code
      proxy = @config.read('connection.proxy')
      connection = (proxy.nil?) ? nil : Faraday.new(:proxy => proxy)
      client.fetch_access_token!(:connection => connection)
      token = token_from_client(client)
    end
  rescue Signet::AuthorizationError => e
    raise AdsCommon::Errors::AuthError,
        'Authorization error occured: %s' % e
  end
  return token
end
token_from_client(client) click to toggle source

Create a token Hash from a client.

# File lib/ads_common/auth/oauth2_handler.rb, line 238
def token_from_client(client)
  return nil if client.refresh_token.nil? && client.access_token.nil?
  return {
    :access_token => client.access_token,
    :refresh_token => client.refresh_token,
    :issued_at => client.issued_at,
    :expires_in => client.expires_in,
    :id_token => client.id_token
  }
end
validate_credentials(credentials) click to toggle source

Auxiliary method to validate the credentials for token generation.

Args:

  • credentials: a hash with the credentials for the account being accessed

Raises:

# File lib/ads_common/auth/oauth2_handler.rb, line 123
def validate_credentials(credentials)
  if @scopes.empty?
    raise AdsCommon::Errors::AuthError, 'Scope is not specified.'
  end

  if credentials.nil?
    raise AdsCommon::Errors::AuthError, 'No credentials supplied.'
  end

  if credentials[:oauth2_client_id].nil?
    raise AdsCommon::Errors::AuthError,
        'Client id is not included in the credentials.'
  end

  if credentials[:oauth2_client_secret].nil?
    raise AdsCommon::Errors::AuthError,
        'Client secret is not included in the credentials.'
  end

  if credentials[:oauth2_token] &&
      !credentials[:oauth2_token].kind_of?(Hash)
    raise AdsCommon::Errors::AuthError,
        'OAuth2 token provided must be a Hash'
  end
end