Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto redirect on login page #175

Merged
merged 1 commit into from
Nov 14, 2022
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
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