From 5884ac405316d934b5ab70e8d6f60ec2aa534e22 Mon Sep 17 00:00:00 2001 From: Pascal Zumkehr Date: Fri, 11 Nov 2022 23:07:59 +0100 Subject: [PATCH] Set new admin token only if REMOTE_USER is set --- app/controllers/auth/remote_header.rb | 14 ++++++--- app/controllers/login_controller.rb | 6 +++- config/routes.rb | 2 ++ test/controllers/auth/remote_header_test.rb | 16 +++++----- test/controllers/login_controller_test.rb | 34 +++++++++++++++++++-- 5 files changed, 58 insertions(+), 14 deletions(-) diff --git a/app/controllers/auth/remote_header.rb b/app/controllers/auth/remote_header.rb index 2d24729..9699a8b 100644 --- a/app/controllers/auth/remote_header.rb +++ b/app/controllers/auth/remote_header.rb @@ -10,12 +10,16 @@ class RemoteHeader < Base REMOTE_USER_GROUPS REMOTE_USER_FIRST_NAME REMOTE_USER_LAST_NAME - ] + ].freeze def fetch_user fetch_user_and_update_user(*remote_user_params) end + def present? + header(REMOTE_USER_HEADERS.first).present? + end + private def fetch_user_and_update_user(username, groups, first_name, last_name) @@ -31,12 +35,14 @@ def fetch_user_and_update_user(username, groups, first_name, last_name) end def remote_user_params - h = request.headers REMOTE_USER_HEADERS.map do |key| - str = h[key] || h[key.gsub('_', '-')] - str&.force_encoding('UTF-8') + header(key)&.force_encoding('UTF-8') end end + def header(key) + request.headers[key] || request.headers[key.tr('_', '-')] + end + end end diff --git a/app/controllers/login_controller.rb b/app/controllers/login_controller.rb index 076e882..e5d0c68 100644 --- a/app/controllers/login_controller.rb +++ b/app/controllers/login_controller.rb @@ -47,18 +47,21 @@ class LoginController < ApplicationController def show set_user_from_any_auth + generate_admin_token if Auth::RemoteHeader.new(request).present? render_current_user end # POST /login: Placeholder login action to act as FreeIPA endpoint. def create set_user_from_remote_header + generate_admin_token render_current_user end def update set_user_from_remote_header current_user&.regenerate_api_key! + generate_admin_token render_current_user end @@ -66,7 +69,6 @@ def update def render_current_user if current_user - generate_admin_token if current_user.admin? render json: current_user, serializer: UserSerializer else render json: { errors: request.headers['EXTERNAL_AUTH_ERROR'] || 'Not authenticated' }, @@ -75,6 +77,8 @@ def render_current_user end def generate_admin_token + return unless current_user&.admin? + headers['X-Auth-Token'] = Auth::Jwt.generate_token(current_user) end diff --git a/config/routes.rb b/config/routes.rb index 8a12280..df4b00c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -32,6 +32,8 @@ get 'login', to: 'login#show' post 'login', to: 'login#create' patch 'login', to: 'login#update' + # duplicate entry to allow different server config for checking sso authentication + get 'sso', to: 'login#show' get 'status', to: 'status#show' diff --git a/test/controllers/auth/remote_header_test.rb b/test/controllers/auth/remote_header_test.rb index 6695480..8ccd363 100644 --- a/test/controllers/auth/remote_header_test.rb +++ b/test/controllers/auth/remote_header_test.rb @@ -38,13 +38,15 @@ class RemoteHeaderTest < ActiveSupport::TestCase private def fetch_user(username, groups, first_name, last_name) - request = stub('request') - request.expects(headers: { - 'REMOTE_USER' => username, - 'REMOTE_USER_GROUPS' => groups, - 'REMOTE_USER_FIRST_NAME' => first_name, - 'REMOTE_USER_LAST_NAME' => last_name - }) + request = stub( + 'request', + headers: { + 'REMOTE_USER' => username, + 'REMOTE_USER_GROUPS' => groups, + 'REMOTE_USER_FIRST_NAME' => first_name, + 'REMOTE_USER_LAST_NAME' => last_name + } + ) Auth::RemoteHeader.new(request).fetch_user end diff --git a/test/controllers/login_controller_test.rb b/test/controllers/login_controller_test.rb index f448c44..20ecbc9 100644 --- a/test/controllers/login_controller_test.rb +++ b/test/controllers/login_controller_test.rb @@ -11,6 +11,17 @@ class LoginControllerTest < ActionController::TestCase assert_equal 'speedee', json['data']['attributes']['username'] assert_match /\A#{users(:speedee).id}\$[A-Za-z0-9]{24}\z/, json['data']['attributes']['api_token'] + assert response.headers['X-Auth-Token'].blank? + end + + test 'GET show with REMOTE_USER returns admin user object and jwt' do + request.env['REMOTE_USER'] = +'admin' + get :show + assert_response 200 + assert_equal 'admin', json['data']['attributes']['username'] + assert_match /\A#{users(:admin).id}\$[A-Za-z0-9]{24}\z/, + json['data']['attributes']['api_token'] + assert response.headers['X-Auth-Token'].present? end test 'GET show with api_token returns user object' do @@ -20,6 +31,14 @@ class LoginControllerTest < ActionController::TestCase assert_equal 'speedee', json['data']['attributes']['username'] end + test 'GET show with api_token returns admin user object but no JWT' do + get :show, + params: { api_token: users(:admin).api_token } + assert_response 200 + assert_equal 'admin', json['data']['attributes']['username'] + assert response.headers['X-Auth-Token'].blank? + end + test 'GET show with access_code returns empty user object' do code = AccessCode.create!(expires_at: 1.month.from_now).code get :show, @@ -41,6 +60,18 @@ class LoginControllerTest < ActionController::TestCase assert_equal 'speedee', json['data']['attributes']['username'] assert_match /\A#{users(:speedee).id}\$[A-Za-z0-9]{24}\z/, json['data']['attributes']['api_token'] + assert response.headers['X-Auth-Token'].blank? + end + + test 'POST login with REMOTE_USER returns admin user object and JWT' do + request.env['REMOTE_USER'] = +'admin' + post :create, + params: { username: 'admin', password: 'foo' } + assert_response 200 + assert_equal 'admin', json['data']['attributes']['username'] + assert_match /\A#{users(:admin).id}\$[A-Za-z0-9]{24}\z/, + json['data']['attributes']['api_token'] + assert response.headers['X-Auth-Token'].present? end test 'POST login without REMOTE_USER returns error' do @@ -51,9 +82,8 @@ class LoginControllerTest < ActionController::TestCase end test 'POST login with api_token responds unauthorized' do - login post :create, - params: { username: 'speedee', password: 'foo' } + params: { api_token: users(:speedee).api_token } assert_response 401 end