Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 11 additions & 24 deletions app/services/proofing/aamva/authentication_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,20 @@ module Proofing
module Aamva
class AuthenticationClient
AAMVA_TOKEN_FRESHNESS_SECONDS = 28 * 60
AUTH_TOKEN_CACHE_KEY = 'aamva_api_auth_token'

class << self
attr_accessor :auth_token
attr_accessor :auth_token_expiration
end

def self.token_mutex
@token_mutex ||= Mutex.new
end

def fetch_token(config)
AuthenticationClient.token_mutex.synchronize do
if AuthenticationClient.auth_token.nil? || auth_token_expired?
send_auth_token_request(config)
end
AuthenticationClient.auth_token
def self.auth_token(config)
Rails.cache.fetch(
AUTH_TOKEN_CACHE_KEY,
skip_nil: true,
expires_in: AAMVA_TOKEN_FRESHNESS_SECONDS,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh i really like just having the cache handle the expiration

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also a chance this reduces the number of requests to AAMVA for tokens since the mutex would have been a local cache for an individual web server process, but moving it to Rails.cache (backed by Redis) will allow all instances to share the token.

) do
send_auth_token_request(config)
end
end

private

def send_auth_token_request(config)
private_class_method
def self.send_auth_token_request(config)
sct_request = Request::SecurityTokenRequest.new(config)
sct_response = sct_request.send
token_request = Request::AuthenticationTokenRequest.new(
Expand All @@ -34,12 +26,7 @@ def send_auth_token_request(config)
server_hmac_secret: sct_response.nonce,
)
token_response = token_request.send
AuthenticationClient.auth_token = token_response.auth_token
AuthenticationClient.auth_token_expiration = Time.zone.now + AAMVA_TOKEN_FRESHNESS_SECONDS
end

def auth_token_expired?
(AuthenticationClient.auth_token_expiration - Time.zone.now).negative?
token_response.auth_token
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/services/proofing/aamva/verification_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def send_verification_request(applicant:, session_id: nil)
private

def auth_token
@auth_token ||= AuthenticationClient.new.fetch_token(config)
@auth_token ||= AuthenticationClient.auth_token(config)
end
end
end
Expand Down
62 changes: 13 additions & 49 deletions spec/services/proofing/aamva/authentication_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

describe Proofing::Aamva::AuthenticationClient do
let(:config) { AamvaFixtures.example_config }
let(:current_time) { Time.utc(2017) }
let(:security_token_request_stub) do
stub_request(:post, config.auth_url).
with(body: AamvaFixtures.security_token_request).
Expand Down Expand Up @@ -48,71 +47,36 @@
).
and_return(auth_token_request)
auth_token_request_stub

allow(Time).to receive(:now).and_return(current_time)
end

context 'when the auth token is nil' do
before do
Proofing::Aamva::AuthenticationClient.auth_token = nil
Proofing::Aamva::AuthenticationClient.auth_token_expiration = nil
end

context 'when the auth token is not set' do
it 'should send an authentication request then save and return the token' do
token = subject.fetch_token(AamvaFixtures.example_config)
token = Proofing::Aamva::AuthenticationClient.auth_token(AamvaFixtures.example_config)
token2 = Proofing::Aamva::AuthenticationClient.auth_token(AamvaFixtures.example_config)

expect(token).to eq('KEYKEYKEY')
expect(Proofing::Aamva::AuthenticationClient.auth_token).to eq('KEYKEYKEY')
expect(Proofing::Aamva::AuthenticationClient.auth_token_expiration).to eq(
current_time + Proofing::Aamva::AuthenticationClient::AAMVA_TOKEN_FRESHNESS_SECONDS,
)
expect(security_token_request_stub).to have_been_requested
expect(auth_token_request_stub).to have_been_requested
expect(token2).to eq('KEYKEYKEY')
expect(security_token_request_stub).to have_been_requested.once
expect(auth_token_request_stub).to have_been_requested.once
end
end

context 'when the auth token is present and fresh' do
before do
Proofing::Aamva::AuthenticationClient.auth_token = 'THEOTHERKEY'
Proofing::Aamva::AuthenticationClient.auth_token_expiration = current_time + 60
Rails.cache.write(
Proofing::Aamva::AuthenticationClient::AUTH_TOKEN_CACHE_KEY,
'THEOTHERKEY',
expires_in: Proofing::Aamva::AuthenticationClient::AAMVA_TOKEN_FRESHNESS_SECONDS,
)
end

it 'should return the auth token' do
token = subject.fetch_token(AamvaFixtures.example_config)

token = Proofing::Aamva::AuthenticationClient.auth_token(AamvaFixtures.example_config)
expect(token).to eq('THEOTHERKEY')
expect(Proofing::Aamva::AuthenticationClient.auth_token).to eq('THEOTHERKEY')
expect(Proofing::Aamva::AuthenticationClient.auth_token_expiration).to eq(
current_time + 60,
)

expect(security_token_request_stub).to_not have_been_requested
expect(auth_token_request_stub).to_not have_been_requested
end
end

context 'when the auth token is present and expired' do
before do
Proofing::Aamva::AuthenticationClient.auth_token = 'THEOTHERKEY'
Proofing::Aamva::AuthenticationClient.auth_token_expiration = current_time - 60
end

it 'should send an authentication request then save and return the token' do
token = subject.fetch_token(AamvaFixtures.example_config)

expect(token).to eq('KEYKEYKEY')
expect(Proofing::Aamva::AuthenticationClient.auth_token).to eq('KEYKEYKEY')
expect(Proofing::Aamva::AuthenticationClient.auth_token_expiration).to eq(
current_time + Proofing::Aamva::AuthenticationClient::AAMVA_TOKEN_FRESHNESS_SECONDS,
)
expect(security_token_request_stub).to have_been_requested
expect(auth_token_request_stub).to have_been_requested
end
end

it 'should use the token mutex' do
expect(Proofing::Aamva::AuthenticationClient.token_mutex).to receive(:synchronize)

subject.fetch_token(AamvaFixtures.example_config)
end
end
end
10 changes: 4 additions & 6 deletions spec/services/proofing/aamva/verification_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@

describe '#send_verification_request' do
before do
auth_client = instance_double(Proofing::Aamva::AuthenticationClient)
allow(auth_client).to receive(:fetch_token).and_return('ThisIsTheToken')
allow(Proofing::Aamva::AuthenticationClient).to receive(:new).and_return(auth_client)
allow(Proofing::Aamva::AuthenticationClient).to receive(:auth_token).
and_return('ThisIsTheToken')
end

it 'gets the auth token from the auth client' do
Expand All @@ -46,9 +45,8 @@
let(:response_http_status) { 200 }

before do
auth_client = instance_double(Proofing::Aamva::AuthenticationClient)
allow(auth_client).to receive(:fetch_token).and_return('ThisIsTheToken')
allow(Proofing::Aamva::AuthenticationClient).to receive(:new).and_return(auth_client)
allow(Proofing::Aamva::AuthenticationClient).to receive(:auth_token).
and_return('ThisIsTheToken')

stub_request(:post, AamvaFixtures.example_config.verification_url).
to_return(body: response_body, status: response_http_status)
Expand Down