Skip to content

Commit

Permalink
Auto redirect on login page when single auth method configured, fixes…
Browse files Browse the repository at this point in the history
… #59739
  • Loading branch information
daniel-illi committed Nov 14, 2022
1 parent 397868b commit 50ff026
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 9 deletions.
4 changes: 4 additions & 0 deletions app/controllers/employees/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@ def default
# TODO: Username wegspeichern
alias keycloakopenid default
alias saml default

def after_omniauth_failure_path_for(scope)
new_session_path(scope, prevent_auto_login: true)
end
end
34 changes: 34 additions & 0 deletions app/controllers/employees/sessions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

# Copyright (c) 2006-2022, Puzzle ITC GmbH. This file is part of
# PuzzleTime and licensed under the Affero General Public License version 3
# or later. See the COPYING file at the top-level directory or at
# https://github.com/puzzle/puzzletime.

class Employees::SessionsController < Devise::SessionsController
helper_method :auto_redirect?

private

def no_local_auth?
!Settings.auth.db.active
end

def omniauth_providers_active
Settings.auth&.omniauth&.map(&:second)&.map(&:active)
end

def single_omniauth_provider?
omniauth_providers_active&.one?
end

def auto_login_allowed?
return true unless prevent = params[:prevent_auto_login]

!ActiveRecord::Type::Boolean.new.deserialize(prevent)
end

def auto_redirect?
auto_login_allowed? && no_local_auth? && single_omniauth_provider?
end
end
7 changes: 0 additions & 7 deletions app/models/employee.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,6 @@ def providers
end

class << self
# Tries to login a user with the passed data.
# Returns the logged-in Employee or nil if the login failed.
def login(username, pwd)
find_by(shortname: username.upcase, passwd: encode(pwd)) ||
LdapAuthenticator.new.login(username, pwd)
end

def employed_ones(period, sort = true)
result = joins('left join employments em on em.employee_id = employees.id').
where('(em.end_date IS null or em.end_date >= ?) AND em.start_date <= ?',
Expand Down
8 changes: 7 additions & 1 deletion app/views/devise/shared/_links.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
= link_to "Mit #{provider_label} anmelden",
public_send("#{resource_name}_#{provider}_omniauth_authorize_path"),
method: :post,
class: 'btn btn-primary'
class: try(:auto_redirect?) ? 'btn btn-primary auto-login' : 'btn btn-primary'
%br
%br

- if try(:auto_redirect?)
:coffeescript
$(document).on('turbolinks:load', ->
$('.auto-login').click();
)
2 changes: 1 addition & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# https://github.com/puzzle/puzzletime.

Rails.application.routes.draw do
devise_for :employees, controllers: { omniauth_callbacks: 'employees/omniauth_callbacks' }, skip: [:registrations]
devise_for :employees, controllers: { sessions: 'employees/sessions', omniauth_callbacks: 'employees/omniauth_callbacks' }, skip: [:registrations]
as :employee do
get 'employees/edit' => 'devise/registrations#edit', :as => 'edit_employee_registration'
patch 'employees' => 'devise/registrations#update', :as => 'employee_registration'
Expand Down
59 changes: 59 additions & 0 deletions test/controllers/employees/sessions_controller_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright (c) 2006-2022, Puzzle ITC GmbH. This file is part of
# PuzzleTime and licensed under the Affero General Public License version 3
# or later. See the COPYING file at the top-level directory or at
# https://github.com/puzzle/puzzletime.

require 'test_helper'

class Employees::SessionsControllerTest < ActionController::TestCase
setup do
@request.env['devise.mapping'] = Devise.mappings[:employee]
end

test "helper auto_redirect? with only omniauth keycloadopenid active" do
Settings.auth.db.active = false
Settings.auth.omniauth.keycloakopenid.active = true
Settings.auth.omniauth.saml.active = false
assert @controller.view_context.auto_redirect?
end

test "helper auto_redirect? with only omniauth saml active" do
Settings.auth.db.active = false
Settings.auth.omniauth.keycloakopenid.active = false
Settings.auth.omniauth.saml.active = true
assert @controller.view_context.auto_redirect?
end

test "helper auto_redirect? with only local auth active" do
Settings.auth.db.active = true
Settings.auth.omniauth.keycloakopenid.active = false
Settings.auth.omniauth.saml.active = false
refute @controller.view_context.auto_redirect?
end

test "helper auto_redirect? with multiple omniauth active" do
Settings.auth.db.active = false
Settings.auth.omniauth.keycloakopenid.active = true
Settings.auth.omniauth.saml.active = true
refute @controller.view_context.auto_redirect?
end

test "helper auto_redirect? with local auth and single omniauth active" do
Settings.auth.db.active = true
Settings.auth.omniauth.keycloakopenid.active = true
Settings.auth.omniauth.saml.active = false
refute @controller.view_context.auto_redirect?
end

test "helper auto_redirect? depending on param prevent_auto_login" do
Settings.auth.db.active = false
Settings.auth.omniauth.keycloakopenid.active = true
Settings.auth.omniauth.saml.active = false

get :new
assert @controller.view_context.auto_redirect?

get :new, params: {prevent_auto_login: true}
refute @controller.view_context.auto_redirect?
end
end
57 changes: 57 additions & 0 deletions test/integration/employees/new_session_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Copyright (c) 2006-2022, Puzzle ITC GmbH. This file is part of
# PuzzleTime and licensed under the Affero General Public License version 3
# or later. See the COPYING file at the top-level directory or at
# https://github.com/puzzle/puzzletime.

require 'test_helper'

class Employees::NewSessionTest < ActionDispatch::IntegrationTest
def setup
# We use the rack_test driver as this one does not evaluate javascript.
# This is required as we want to test if the page contains the necessary class attribute and javascript snippet
# to execute the auto login. For this the auto login redirect can't actually happen.
Capybara.current_driver = :rack_test
end

def teardown
# Let's restore the original driver.
Capybara.use_default_driver
end

test 'login button has auto-login class if eligible' do
Settings.auth.db.active = false
Settings.auth.omniauth.keycloakopenid.active = true
Settings.auth.omniauth.saml.active = false

visit new_employee_session_path
assert_selector 'a.auto-login', text: 'Mit Puzzle SSO anmelden'
end

test 'login button does not have auto-login class if uneligible' do
Settings.auth.db.active = true
Settings.auth.omniauth.keycloakopenid.active = true
Settings.auth.omniauth.saml.active = false

visit new_employee_session_path
assert_selector 'a', text: 'Mit Puzzle SSO anmelden'
assert_no_selector 'a.auto-login', text: 'Mit Puzzle SSO anmelden'
end

test 'page includes auto-login javascript if eligible' do
Settings.auth.db.active = false
Settings.auth.omniauth.keycloakopenid.active = true
Settings.auth.omniauth.saml.active = false

visit new_employee_session_path
assert page.text(:all).include? "$('.auto-login').click()"
end

test 'page excludes auto-login javascript if uneligible' do
Settings.auth.db.active = true
Settings.auth.omniauth.keycloakopenid.active = true
Settings.auth.omniauth.saml.active = false

visit new_employee_session_path
assert page.text(:all).exclude? "$('.auto-login').click()"
end
end

0 comments on commit 50ff026

Please sign in to comment.