require 'spec_helper' require 'yaml' describe SoarAuthenticationToken::TokenValidator do subject { SoarAuthenticationToken::TokenValidator } before :all do @test_store = AuthTokenStoreProvider::StubClient.new keypair_generator = SoarAuthenticationToken::KeypairGenerator.new @valid_private_key, @valid_public_key = keypair_generator.generate @invalid_private_key, @invalid_public_key = keypair_generator.generate @test_identifier = 'a@b.co.za' @local_valid_generator_configuration = { 'provider' => 'JwtTokenGenerator', 'private_key' => @valid_private_key } @local_invalid_generator_configuration = { 'provider' => 'JwtTokenGenerator', 'private_key' => @invalid_private_key } @token_for_client_service_1 = 'some_secret_token_string_1111' @token_for_client_service_2 = 'some_secret_token_string_2222' @token_for_client_service_3_expired = 'some_secret_token_string_3333_expired' @token_for_client_service_3_unknown = 'some_secret_token_string_3333_unknown' current_time = Time.now @static_validator_configuration = { 'provider' => 'StaticTokenValidator', 'static_tokens' => [ { 'token' => 'some_secret_token_string_1111', 'authenticated_identifier' => 'calling_client_service_1', 'token_issue_time' => current_time.utc.iso8601(3), 'token_expiry_time' => (current_time + 100).utc.iso8601(3) }, { 'token' => 'some_secret_token_string_2222', 'authenticated_identifier' => 'calling_client_service_2', 'token_issue_time' => current_time.utc.iso8601(3), 'token_expiry_time' => (current_time + 100).utc.iso8601(3) }, { 'token' => 'some_secret_token_string_3333_expired', 'authenticated_identifier' => 'calling_client_service_3', 'token_issue_time' => (current_time - 100).utc.iso8601(3), 'token_expiry_time' => (current_time - 50).utc.iso8601(3) } ] } @local_validator_configuration = { 'provider' => 'JwtTokenValidator', 'public_key' => @valid_public_key } @remote_generator_configuration = { 'provider' => 'RemoteTokenGenerator', 'generator-url' => 'http://authentication-token-generator-service:9393/generate', 'generator-client-auth-token' => 'test_ecosystem_token_for_auth_token_aaapi_authenticator_service' } @remote_validator_configuration = { 'provider' => 'RemoteTokenValidator', 'validator-url' => 'http://authentication-token-validator-service:9393/validate', 'generator-client-auth-token' => 'test_ecosystem_token_for_auth_token_aaapi_authenticator_service' } @local_valid_generator = SoarAuthenticationToken::TokenGenerator.new(@local_valid_generator_configuration) @local_valid_generator.inject_store_provider(@test_store) @local_invalid_generator = SoarAuthenticationToken::TokenGenerator.new(@local_invalid_generator_configuration) @local_invalid_generator.inject_store_provider(@test_store) @remote_generator = SoarAuthenticationToken::TokenGenerator.new(@remote_generator_configuration) end before :each do @iut_local = SoarAuthenticationToken::TokenValidator.new(@local_validator_configuration) @iut_local.inject_store_provider(@test_store) @iut_remote = SoarAuthenticationToken::TokenValidator.new(@remote_validator_configuration) @iut_static = SoarAuthenticationToken::TokenValidator.new(@static_validator_configuration) end after :each do end it 'has a version number' do expect(SoarAuthenticationToken::VERSION).not_to be nil end describe "#validate" do context "given that the validator is configured for local validation" do context 'given valid token' do let!(:token_validation_result) { token, token_generator_meta = @local_valid_generator.generate(authenticated_identifier: @test_identifier) @iut_local.validate(authentication_token: token) } let!(:token_validity) { token_validation_result[0] } let!(:token_meta) { token_validation_result[1] } let!(:message) { token_validation_result[2] } it 'indicate token is valid' do expect(token_validity).to eq true end it 'provide the token meta' do expect(token_meta['authenticated_identifier']).to eq @test_identifier end it 'provide a message indicating that the token is valid' do expect(message).to match /Valid token for/ end end context 'given expired token' do let!(:token_validation_result) { token, token_generator_meta = @local_valid_generator.generate(authenticated_identifier: @test_identifier) allow(Time).to receive(:now).and_return(Time.now+one_year_in_seconds) @iut_local.validate(authentication_token: token) } let!(:token_validity) { token_validation_result[0] } let!(:token_meta) { token_validation_result[1] } let!(:message) { token_validation_result[2] } it 'indicate token is invalid' do expect(token_validity).to eq false end it 'does not provide the token meta' do expect(token_meta).to eq nil end it 'provide a message indicating that the token is invalid' do expect(message).to match /Expired token/ end end context 'given unknown token (not in store)' do let!(:token_validation_result) { token, token_generator_meta = @local_valid_generator.generate(authenticated_identifier: @test_identifier) @test_store.instance_variable_set("@store", []) #clear store @iut_local.validate(authentication_token: token) } let!(:token_validity) { token_validation_result[0] } let!(:token_meta) { token_validation_result[1] } let!(:message) { token_validation_result[2] } it 'indicate that token is invalid' do expect(token_validity).to eq false end it 'does not provide the token meta' do expect(token_meta).to eq nil end it 'provide a message indicating that the token is invalid' do expect(message).to match /Unknown token/ end end context 'given invalid token (garbage or different key)' do let!(:token_validation_result) { token, token_generator_meta = @remote_generator.generate(authenticated_identifier: @test_identifier) @iut_local.validate(authentication_token: token) } let!(:token_validity) { token_validation_result[0] } let!(:token_meta) { token_validation_result[1] } let!(:message) { token_validation_result[2] } it 'indicate token is invalid' do expect(token_validity).to eq false end it 'does not provide the token meta' do expect(token_meta).to eq nil end it 'provide a message indicating that the token is invalid' do expect(message).to match /Token decode\/verification failure/ end end end context "given that the validator is configured for remote validation" do context 'given valid token' do let!(:token_validation_result) { token, token_generator_meta = @remote_generator.generate(authenticated_identifier: @test_identifier) @iut_remote.validate(authentication_token: token) } let!(:token_validity) { token_validation_result[0] } let!(:token_meta) { token_validation_result[1] } let!(:message) { token_validation_result[2] } it 'should indicate valid if the token is valid' do expect(token_validity).to eq true end it 'should provide the authenticated_identifier if the token is valid' do expect(token_meta['authenticated_identifier']).to eq @test_identifier end end context 'given invalid (generalized) token' do let!(:token_validation_result) { token, token_generator_meta = @local_invalid_generator.generate(authenticated_identifier: @test_identifier) @iut_remote.validate(authentication_token: token) } let!(:token_validity) { token_validation_result[0] } let!(:token_meta) { token_validation_result[1] } let!(:message) { token_validation_result[2] } it 'indicate token is invalid' do expect(token_validity).to eq false end it 'does not provide the token meta' do expect(token_meta).to eq nil end it 'provides a message indicating the token is invalid' do expect(message).to match /Token decode\/verification failure/ end end end context "given that the validator is configured for static tokens" do let(:iut) { subject.new(@static_validator_configuration) } context "given a token that is in the list of static tokens and not expired" do let(:response) { iut.validate(authentication_token: @token_for_client_service_1) } let(:token_validity) { response[0] } let(:token_meta) { response[1] } let(:message) { response[2] } it 'should respond with true indicating token is valid' do expect(token_validity).to eq true end it 'should respond with token meta' do expect(token_meta).to_not eq nil end it 'should respond with a message indicating that the token is valid' do expect(message).to eq 'Valid token for ' end end context "the token is in the list of static tokens and expired" do let(:response) { @iut_static.validate(authentication_token: @token_for_client_service_3_expired) } let(:token_validity) { response[0] } let(:token_meta) { response[1] } let(:message) { response[2] } it 'should respond with false indicating token is invalid' do expect(token_validity).to eq false end it 'should respond with nil token meta' do expect(token_meta).to eq nil end it 'should respond with a message indicating that the token is expired' do expect(message).to match /Expired token/ end end context "given a token that is not in the list of static tokens" do let(:response) { @iut_static.validate(authentication_token: @token_for_client_service_3_unknown) } let(:token_validity) { response[0] } let(:token_meta) { response[1] } let(:message) { response[2] } it 'should respond with false indicating token is invalid' do expect(token_validity).to eq false end it 'should respond with no token meta' do expect(token_meta).to eq nil end it 'should respond with a message indicating that the token is valid' do expect(message).to match /Unknown static token/ end end end end end