From 86900837efda299bd69c254bffae3945c3ae3241 Mon Sep 17 00:00:00 2001 From: Johan Vervloet Date: Thu, 26 Jun 2014 15:06:00 +0200 Subject: [PATCH] refs #9 - CAS-login for redmine with public content. This is my second attempt. If authentication is required, you will be redirected to the CAS login page whenever you are not authenticated. (Except when you visit the default login page.) If authentication is not required, the login page will show a link, that allows you to login using CAS. --- README.md | 8 ++- .../redmine_cas/_cas_login_link.html.erb | 5 ++ config/routes.rb | 3 + init.rb | 2 + lib/redmine_cas/account_controller_patch.rb | 55 +++++++++++++++++++ .../application_controller_patch.rb | 46 +--------------- lib/redmine_cas_hook_listener.rb | 5 ++ 7 files changed, 78 insertions(+), 46 deletions(-) create mode 100644 app/views/redmine_cas/_cas_login_link.html.erb create mode 100644 config/routes.rb create mode 100644 lib/redmine_cas_hook_listener.rb diff --git a/README.md b/README.md index 85d66b5..74b9e12 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,12 @@ We use [CASino](http://casino.rbcas.com) as CAS server, but it might work with o ### Usage -This plugin was made for redmine installations without public areas ("Authentication required"). -The default login page will still work when you access it directly (http://example.com/path-to-redmine/login). +If your installation has no public areas ("Authentication required") and you are not logged in, you will be +redirected to the CAS-login page. The default login page will still work when you access it directly +(http://example.com/path-to-redmine/login). + +If your installation is not "Authentication required", the login page will show a link that lets you login +with CAS. ### Single Sign Out, Single Logout diff --git a/app/views/redmine_cas/_cas_login_link.html.erb b/app/views/redmine_cas/_cas_login_link.html.erb new file mode 100644 index 0000000..37ef4b2 --- /dev/null +++ b/app/views/redmine_cas/_cas_login_link.html.erb @@ -0,0 +1,5 @@ +<% if Setting.plugin_redmine_cas[:enabled] %> +

+ <%= link_to("Login with CAS", :controller => "account", :action => "cas") %> +

+<% end %> diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..2d16db9 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,3 @@ +RedmineApp::Application.routes.draw do + get 'cas', :to => 'account#cas' +end diff --git a/init.rb b/init.rb index 60ac357..90d7e97 100644 --- a/init.rb +++ b/init.rb @@ -3,6 +3,8 @@ require 'redmine_cas' require 'redmine_cas/application_controller_patch' require 'redmine_cas/account_controller_patch' +require_dependency 'redmine_cas_hook_listener' + Redmine::Plugin.register :redmine_cas do name 'Redmine CAS' author 'Nils Caspar (Nine Internet Solutions AG)' diff --git a/lib/redmine_cas/account_controller_patch.rb b/lib/redmine_cas/account_controller_patch.rb index e6b32f0..2c04560 100644 --- a/lib/redmine_cas/account_controller_patch.rb +++ b/lib/redmine_cas/account_controller_patch.rb @@ -15,6 +15,61 @@ module RedmineCAS logout_user CASClient::Frameworks::Rails::Filter.logout(self, home_url) end + + def cas + return redirect_to_action('login') unless RedmineCAS.enabled? + + if User.current.logged? + # User already logged in. + redirect_back_or_default my_page_path + return + end + + # The rest of this file just contains what was in + # application_controller_patch.rb before. + + if CASClient::Frameworks::Rails::Filter.filter(self) + user = User.find_by_login(session[:cas_user]) + + # Auto-create user if possible + if user.nil? && RedmineCAS.autocreate_users? + user = User.new + user.login = session[:cas_user] + user.assign_attributes(RedmineCAS.user_extra_attributes_from_session(session)) + return cas_user_not_created(user) if !user.save + user.reload + end + + return cas_user_not_found if user.nil? + return cas_account_pending unless user.active? + user.update_attribute(:last_login_on, Time.now) + user.update_attributes(RedmineCAS.user_extra_attributes_from_session(session)) + if RedmineCAS.single_sign_out_enabled? + # logged_user= would start a new session and break single sign-out + User.current = user + start_user_session(user) + else + self.logged_user = user + end + redirect_to url_for(params.merge(:ticket => nil)) + else + # CASClient called redirect_to + end + end + + def cas_account_pending + render_403 :message => l(:notice_account_pending) + end + + def cas_user_not_found + render_403 :message => l(:redmine_cas_user_not_found, :user => session[:cas_user]) + end + + def cas_user_not_created(user) + logger.error "Could not auto-create user: #{user.errors.full_messages.to_sentence}" + render_403 :message => l(:redmine_cas_user_not_created, :user => session[:cas_user]) + end + end end end diff --git a/lib/redmine_cas/application_controller_patch.rb b/lib/redmine_cas/application_controller_patch.rb index f3b5e6f..484db28 100644 --- a/lib/redmine_cas/application_controller_patch.rb +++ b/lib/redmine_cas/application_controller_patch.rb @@ -15,8 +15,8 @@ module RedmineCAS return require_login_without_cas unless RedmineCAS.enabled? if !User.current.logged? respond_to do |format| - format.html { login_with_cas } - format.atom { login_with_cas } + format.html { redirect_to :controller => 'account', :action => 'cas' } + format.atom { redirect_to :controller => 'account', :action => 'cas' } format.xml { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } format.js { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } format.json { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } @@ -26,36 +26,6 @@ module RedmineCAS true end - def login_with_cas - if CASClient::Frameworks::Rails::Filter.filter(self) - user = User.find_by_login(session[:cas_user]) - - # Auto-create user if possible - if user.nil? && RedmineCAS.autocreate_users? - user = User.new - user.login = session[:cas_user] - user.assign_attributes(RedmineCAS.user_extra_attributes_from_session(session)) - return cas_user_not_created(user) if !user.save - user.reload - end - - return cas_user_not_found if user.nil? - return cas_account_pending unless user.active? - user.update_attribute(:last_login_on, Time.now) - user.update_attributes(RedmineCAS.user_extra_attributes_from_session(session)) - if RedmineCAS.single_sign_out_enabled? - # logged_user= would start a new session and break single sign-out - User.current = user - start_user_session(user) - else - self.logged_user = user - end - redirect_to url_for(params.merge(:ticket => nil)) - else - # CASClient called redirect_to - end - end - def verify_authenticity_token_with_cas if cas_logout_request? logger.info 'CAS logout request detected: Skipping validation of authenticity token' @@ -68,18 +38,6 @@ module RedmineCAS request.post? && params.has_key?('logoutRequest') end - def cas_account_pending - render_403 :message => l(:notice_account_pending) - end - - def cas_user_not_found - render_403 :message => l(:redmine_cas_user_not_found, :user => session[:cas_user]) - end - - def cas_user_not_created(user) - logger.error "Could not auto-create user: #{user.errors.full_messages.to_sentence}" - render_403 :message => l(:redmine_cas_user_not_created, :user => session[:cas_user]) - end end end end diff --git a/lib/redmine_cas_hook_listener.rb b/lib/redmine_cas_hook_listener.rb new file mode 100644 index 0000000..2142704 --- /dev/null +++ b/lib/redmine_cas_hook_listener.rb @@ -0,0 +1,5 @@ +module RedmineCAS + class RedmineCASHookListener < Redmine::Hook::ViewListener + render_on :view_account_login_top, :partial => 'redmine_cas/cas_login_link' + end +end