Module: Nucleus::Adapters::AuthenticationRetryWrapper

Extended by:
Logging
Defined in:
lib/nucleus/core/adapter_extensions/auth/authentication_retry_wrapper.rb

Overview

The AuthenticationRetryWrapper module can be used to invoke commands in a block that repeats its execution in case the first attempt raises an Errors::EndpointAuthenticationError.

Class Method Summary collapse

Methods included from Logging

configure_logger_for, log, logger_for

Class Method Details

.re_authenticate(adapter, env) ⇒ void

This method returns an undefined value.

Re-authenticate the user with the help of the current adapter. The method shall only be invoked when there are cached authentication information that appear to be outdated. It calls the authentication for the current user to override the cached authentication headers.

Parameters:

  • adapter (Nucleus::Adapters::BaseAdapter)

    adapter that is used for the ongoing request

  • env (Hash<String, String>)

    Rack environment, shall contain HTTP authentication information

Raises:



60
61
62
63
64
65
66
# File 'lib/nucleus/core/adapter_extensions/auth/authentication_retry_wrapper.rb', line 60

def self.re_authenticate(adapter, env)
  log.debug('Invoked re-authentication')
  username, password = username_password(env)
  auth_client = adapter.cached(adapter.cache_key(username, password))
  # raises 401 if the authentication did not only expire, but became completely invalid
  auth_client.authenticate(username, password)
end

.refresh_token(auth_client) ⇒ void

This method returns an undefined value.

Try to refresh a token based authentication that can be renewed. The method shall only be invoked when there are cached authentication information that appear to be outdated.
If the refresh fails, a complete re-authentication will be forced.

Parameters:

Raises:



45
46
47
48
49
50
# File 'lib/nucleus/core/adapter_extensions/auth/authentication_retry_wrapper.rb', line 45

def self.refresh_token(auth_client)
  # we first try to renew our token before invalidating the cache
  log.debug 'Call failed (401), start refreshing auth token'
  auth_client.refresh unless auth_client.nil?
  log.debug '... the auth token refresh succeeded'
end

.username_password(env) ⇒ Array<String>

Extract the username and password from the current HTTP request.

Parameters:

  • env (Hash<String, String>)

    Rack environment, shall contain HTTP authentication information

Returns:



71
72
73
74
75
76
# File 'lib/nucleus/core/adapter_extensions/auth/authentication_retry_wrapper.rb', line 71

def self.username_password(env)
  # resolve username & password for authentication request
  auth_keys = %w(HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION)
  authorization_key = auth_keys.detect { |k| env.key?(k) }
  env[authorization_key].split(' ', 2).last.unpack('m*').first.split(/:/, 2)
end

.with_authentication(adapter, env) ⇒ Hash, void

Executes a block, which should be an adapter call, using the authentication information. If the first call fails due to cached authentication information, the cache is going to get evicted, authentication repeated and finally the call will be executed again.

Parameters:

  • adapter (Nucleus::Adapters::BaseAdapter)

    adapter that is used for the ongoing request

  • env (Hash<String, String>)

    Rack environment, shall contain HTTP authentication information

Returns:

  • (Hash, void)

    result of the yield block execution, usually a Hash matching the Grape::Entity to represent



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/nucleus/core/adapter_extensions/auth/authentication_retry_wrapper.rb', line 15

def self.with_authentication(adapter, env)
  begin
    response = yield
  rescue Errors::EndpointAuthenticationError
    # first attempt with actually valid credentials failed, try to refresh token based clients
    username, password = username_password(env)
    begin
      auth_client = adapter.cached(adapter.cache_key(username, password))
      auth_client.refresh
      response = yield
    rescue Errors::EndpointAuthenticationError
      # refresh failed, too
      log.debug 'Call failed (401), start repetition by removing outdated cache entry'
      re_authenticate(adapter, env)
      log.debug 'Repeating call block...'
      response = yield
      log.debug '... the repetition did pass just fine!'
    end
  end
  response
end