require 'spec_helper' shared_examples_for "an authentication provider" do include Rack::Test::Methods let(:version) { SoarAuthenticationToken::VERSION } def create_valid_token_generator keypair_generator = SoarAuthenticationToken::KeypairGenerator.new private_key, public_key = keypair_generator.generate configuration = { 'provider' => 'SoarAuthenticationToken::RemoteTokenGenerator', 'generator-url' => 'http://authentication-token-generator-service:9393/generate', 'generator-client-auth-token' => 'test_ecosystem_token_for_auth_token_aaapi_authenticator_service' } generator = SoarAuthenticationToken::TokenGenerator.new(configuration) generator.inject_store_provider(get_store) [ generator, private_key, public_key ] end def create_invalid_token_generator keypair_generator = SoarAuthenticationToken::KeypairGenerator.new private_key, public_key = keypair_generator.generate configuration = { 'provider' => 'SoarAuthenticationToken::JwtTokenGenerator', 'private_key' => private_key, 'public_key' => public_key } generator = SoarAuthenticationToken::TokenGenerator.new(configuration) generator.inject_store_provider(get_store) [ generator, private_key, public_key ] end def get_store AuthTokenStoreProvider::Client.new({ 'service_url' => 'http://authentication-token-store:9393/', 'auth_token' => 'test_ecosystem_token_for_auth_token_generator_service'}) end before :all do @local_valid_generator, @valid_private_key, @valid_public_key = create_valid_token_generator @local_invalid_generator, @invalid_private_key, @invalid_public_key = create_invalid_token_generator @failure_response_json = [ { 'status' => 'fail', 'data' => { 'notifications' => ['Not authenticated'] } }.to_json ] end before :each do @test_app = lambda do |env| request = Rack::Request.new env session = request.session test_app_response_data = { 'message' => "tested with authenticated user #{session['user']}", 'user' => session['user'], 'auth_token_meta' => session['auth_token_meta'] } [200, {"Content-Type" => "application/json"}, test_app_response_data ] end @iut_configuration = { 'provider' => 'SoarAuthenticationToken::RemoteTokenValidator', 'validator-url' => 'http://authentication-token-validator-service:9393/validate', 'authentication_token' => { 'provider' => auth_provider, 'header_name' => 'HTTP_AUTHORIZATION', 'cookie_name' => 'kh2.auth' } } @iut = SoarAuthenticationToken::RackMiddleware.new(@test_app, @iut_configuration, "test-service", nil) end it 'has a version number' do expect(SoarAuthenticationToken::VERSION).not_to be nil end context "when initialized" do it 'remembers the app provided' do expect(@iut.instance_variable_get("@app")).to eq(@test_app) end it 'remembers the configuration provided' do expect(@iut.instance_variable_get("@configuration")).to eq(@iut_configuration) end end context "when called with a request environment" do context 'with no authentication token' do it "return with 401" do stub_response_body = {'status' => 'success', 'data' => { 'token_validity' => false, 'token_meta' => nil, 'notifications' => ['none'] }}.to_json stub_request(:post, "http://authentication-token-validator-service:9393/validate?flow_identifier"). with(body: "{\"authentication_token\":null,\"request_information\":{\"source_address\":\"1.1.1.1\",\"user_agent\":null,\"service\":\"test-service\",\"resource\":\"/\",\"method\":\"GET\",\"base_url\":\"http://service\",\"version\":\"#{version}\"}}", headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}). to_return(status: 200, body: stub_response_body, headers: {}) opts = { 'REMOTE_ADDR' => '1.1.1.1', 'HTTP_AUTHORIZATION' => nil } code, env, body = @iut.call Rack::MockRequest.env_for('http://service', opts) expect([code, env, body]).to eq([401, {"Content-Type" => "application/json"}, @failure_response_json]) end end context 'with an invalid authentication token' do it "return with 401" do stub_response_body = {'status' => 'success', 'data' => { 'token_validity' => false, 'token_meta' => nil, 'notifications' => ['none'] }}.to_json stub_request(:post, "http://authentication-token-validator-service:9393/validate?flow_identifier"). with(body: "{\"authentication_token\":\"bad_token\",\"request_information\":{\"source_address\":\"1.1.1.1\",\"user_agent\":null,\"service\":\"test-service\",\"resource\":\"/\",\"method\":\"GET\",\"base_url\":\"http://service\",\"version\":\"#{version}\"}}", headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}). to_return(status: 200, body: stub_response_body, headers: {}) opts = { 'REMOTE_ADDR' => '1.1.1.1', 'HTTP_AUTHORIZATION' => 'bad_token' } code, env, body = @iut.call Rack::MockRequest.env_for('http://service', opts) expect([code, env, body]).to eq([401, {"Content-Type" => "application/json"}, @failure_response_json]) end end context 'with a valid authentiation token' do it "pass requests to the application" do skip if auth_provider == 'SoarAuthenticationToken::CookieProvider' stub_response_body = {'status' => 'success', 'data' => { 'token_validity' => true, 'token_meta' => { 'authenticated_identifier' => 'a@b.com' }, 'notifications' => ['none'] }}.to_json stub_request(:post, "http://authentication-token-validator-service:9393/validate?flow_identifier"). with(body: "{\"authentication_token\":\"valid_token\",\"request_information\":{\"source_address\":\"1.1.1.1\",\"user_agent\":null,\"service\":\"test-service\",\"resource\":\"/\",\"method\":\"GET\",\"base_url\":\"http://service\",\"version\":\"#{version}\"}}", headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}). to_return(status: 200, body: stub_response_body, headers: {}) opts = { 'REMOTE_ADDR' => '1.1.1.1', 'HTTP_AUTHORIZATION' => 'valid_token' } code, env, body = @iut.call Rack::MockRequest.env_for('http://service', opts) expect([code, env, body['message']]).to eq([200, {"Content-Type"=>"application/json"}, "tested with authenticated user a@b.com" ]) end it "populate the 'user' key in the rack session with the authenticated user" do skip if auth_provider == 'SoarAuthenticationToken::CookieProvider' stub_response_body = {'status' => 'success', 'data' => { 'token_validity' => true, 'token_meta' => { 'authenticated_identifier' => 'a@b.com' }, 'notifications' => ['none'] }}.to_json stub_request(:post, "http://authentication-token-validator-service:9393/validate?flow_identifier"). with(body: "{\"authentication_token\":\"valid_token\",\"request_information\":{\"source_address\":\"1.1.1.1\",\"user_agent\":null,\"service\":\"test-service\",\"resource\":\"/\",\"method\":\"GET\",\"base_url\":\"http://service\",\"version\":\"#{version}\"}}", headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}). to_return(status: 200, body: stub_response_body, headers: {}) opts = { 'REMOTE_ADDR' => '1.1.1.1', 'HTTP_AUTHORIZATION' => 'valid_token' } code, env, body = @iut.call Rack::MockRequest.env_for('http://service', opts) expect(body['user']).to eq('a@b.com') end it "populate the 'auth_token_meta' key in the rack session with the hash containing the token meta" do skip if auth_provider == 'SoarAuthenticationToken::CookieProvider' stub_response_body = {'status' => 'success', 'data' => { 'token_validity' => true, 'token_meta' => { 'authenticated_identifier' => 'a@b.com' }, 'notifications' => ['none'] }}.to_json stub_request(:post, "http://authentication-token-validator-service:9393/validate?flow_identifier"). with(body: "{\"authentication_token\":\"valid_token\",\"request_information\":{\"source_address\":\"1.1.1.1\",\"user_agent\":null,\"service\":\"test-service\",\"resource\":\"/\",\"method\":\"GET\",\"base_url\":\"http://service\",\"version\":\"#{version}\"}}", headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}). to_return(status: 200, body: stub_response_body, headers: {}) opts = { 'REMOTE_ADDR' => '1.1.1.1', 'HTTP_AUTHORIZATION' => 'valid_token' } code, env, body = @iut.call Rack::MockRequest.env_for('http://service', opts) expect(body['auth_token_meta']['authenticated_identifier']).to eq('a@b.com') end end end end