diff --git a/app/controllers/pseudonym_sessions_controller.rb b/app/controllers/pseudonym_sessions_controller.rb index 9b20988e949..0b28b2f0fa8 100644 --- a/app/controllers/pseudonym_sessions_controller.rb +++ b/app/controllers/pseudonym_sessions_controller.rb @@ -72,8 +72,9 @@ class PseudonymSessionsController < ApplicationController return else logger.warn "Received CAS login for unknown user: #{st.response.user}" + reset_session session[:delegated_message] = t 'errors.no_matching_user', "Canvas doesn't have an account for user: %{user}", :user => st.response.user - redirect_to :action => :destroy + redirect_to(cas_client.logout_url(login_url :no_auto => true)) return end else @@ -88,6 +89,7 @@ class PseudonymSessionsController < ApplicationController elsif @is_saml && !params[:no_auto] initiate_saml_login(request.env['canvas.account_domain']) end + flash[:delegated_message] = session.delete :delegated_message end def create diff --git a/lib/authentication_methods.rb b/lib/authentication_methods.rb index 7c1780d4db3..d2af72b1b8b 100644 --- a/lib/authentication_methods.rb +++ b/lib/authentication_methods.rb @@ -241,11 +241,11 @@ module AuthenticationMethods reset_session_for_login if @domain_root_account.account_authorization_config.log_in_url.present? session[:exit_frame] = true - redirect_to(@domain_root_account.account_authorization_config.log_in_url) + delegated_auth_redirect(@domain_root_account.account_authorization_config.log_in_url) else config = { :cas_base_url => @domain_root_account.account_authorization_config.auth_base } cas_client ||= CASClient::Client.new(config) - redirect_to(cas_client.add_service_to_login_url(login_url)) + delegated_auth_redirect(cas_client.add_service_to_login_url(login_url)) end end @@ -253,6 +253,10 @@ module AuthenticationMethods reset_session_for_login settings = @domain_root_account.account_authorization_config.saml_settings(preferred_account_domain) request = Onelogin::Saml::AuthRequest.create(settings) - redirect_to(request) + delegated_auth_redirect(request) + end + + def delegated_auth_redirect(uri) + redirect_to(uri) end end diff --git a/spec/controllers/pseudonym_sessions_controller_spec.rb b/spec/controllers/pseudonym_sessions_controller_spec.rb index 704d3b838b8..f6fb1f5c902 100644 --- a/spec/controllers/pseudonym_sessions_controller_spec.rb +++ b/spec/controllers/pseudonym_sessions_controller_spec.rb @@ -127,90 +127,5 @@ describe PseudonymSessionsController do session[:cas_login].should == true Pseudonym.find(session[:pseudonym_credentials_id]).should == user2.pseudonyms.first end - - it "should log in and log out a user CAS has validated" do - account = account_with_cas({:account => Account.default}) - user = user_with_pseudonym({:active_all => true}) - - get 'new' - response.should redirect_to(controller.cas_client.add_service_to_login_url(login_url)) - - stubby("yes\n#{user.pseudonyms.first.unique_id}\n", false) - - get 'new', :ticket => 'ST-abcd' - response.should redirect_to(dashboard_url(:login_success => 1)) - session[:cas_login].should == true - - get 'destroy' - response.should redirect_to(controller.cas_client.logout_url(login_url)) - end - - it "should inform the user CAS validation denied" do - account = account_with_cas({:account => Account.default}) - - get 'new' - response.should redirect_to(controller.cas_client.add_service_to_login_url(login_url)) - - stubby("no\n\n", false) - - get 'new', :ticket => 'ST-abcd' - response.should redirect_to(:action => 'new', :no_auto => true) - flash[:delegated_message].should match(/There was a problem logging in/) - end - - it "should inform the user CAS validation failed" do - account = account_with_cas({:account => Account.default}) - - get 'new' - response.should redirect_to(controller.cas_client.add_service_to_login_url(login_url)) - - cas_client = controller.cas_client - def cas_client.validate_service_ticket(st) - raise "Nope" - end - - get 'new', :ticket => 'ST-abcd' - response.should redirect_to(:action => 'new', :no_auto => true) - flash[:delegated_message].should match(/There was a problem logging in/) - end - - it "should inform the user that CAS account doesn't exist" do - account = account_with_cas({:account => Account.default}) - - get 'new' - response.should redirect_to(controller.cas_client.add_service_to_login_url(login_url)) - - stubby("yes\nnonexistentuser\n") - - get 'new', :ticket => 'ST-abcd' - response.should redirect_to(:action => 'destroy') - get 'destroy' - response.should redirect_to(:action => 'new', :no_auto => true) - flash[:delegated_message].should match(/Canvas doesn't have an account for user/) - end - - it "should redirect to alternate CAS login page if so configured, and frame bust on login" do - account = account_with_cas({:account => Account.default, :cas_log_in_url => 'http://example.com/cas'}) - - get 'new' - response.should redirect_to('http://example.com/cas') - - get 'new', :ticket => 'ST-abcd' - response.should render_template('shared/exit_frame') - end - - it "should login case insensitively" do - account = account_with_cas({:account => Account.default}) - user = user_with_pseudonym({:active_all => true}) - - get 'new' - response.should redirect_to(controller.cas_client.add_service_to_login_url(login_url)) - - stubby("yes\n#{user.pseudonyms.first.unique_id.capitalize}\n") - - get 'new', :ticket => 'ST-abcd' - response.should redirect_to(dashboard_url(:login_success => 1)) - session[:cas_login].should == true - end end end diff --git a/spec/integration/pseudonym_sessions_controller_spec.rb b/spec/integration/pseudonym_sessions_controller_spec.rb new file mode 100644 index 00000000000..27b9e399b20 --- /dev/null +++ b/spec/integration/pseudonym_sessions_controller_spec.rb @@ -0,0 +1,127 @@ +# +# Copyright (C) 2011 Instructure, Inc. +# +# This file is part of Canvas. +# +# Canvas is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the Free +# Software Foundation, version 3 of the License. +# +# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see . +# + +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe PseudonymSessionsController do + def redirect_until(uri) + count = 0 + while true + response.should be_redirect + return if response.location == uri + count += 1 + count.should < 5 + follow_redirect! + end + end + + context "cas" do + def stubby(stub_response) + @cas_client = CASClient::Client.new({:cas_base_url => @account.account_authorization_config.auth_base}) + @cas_client.instance_variable_set(:@stub_response, stub_response) + def @cas_client.validate_service_ticket(st) + st.response = CASClient::ValidationResponse.new(@stub_response) + end + PseudonymSessionsController.any_instance.stubs(:cas_client).returns(@cas_client) + end + + it "should log in and log out a user CAS has validated" do + account_with_cas({:account => Account.default}) + user = user_with_pseudonym({:active_all => true}) + + stubby("yes\n#{user.pseudonyms.first.unique_id}\n") + + get login_url + redirect_until(@cas_client.add_service_to_login_url(login_url)) + + get login_url :ticket => 'ST-abcd' + response.should redirect_to(dashboard_url(:login_success => 1)) + session[:cas_login].should == true + + get logout_url + response.should redirect_to(@cas_client.logout_url(login_url)) + end + + it "should inform the user CAS validation denied" do + account_with_cas({:account => Account.default}) + + stubby("no\n\n") + + get login_url + redirect_until(@cas_client.add_service_to_login_url(login_url)) + + get login_url :ticket => 'ST-abcd' + response.should redirect_to(login_url :no_auto => true) + flash[:delegated_message].should match(/There was a problem logging in/) + end + + it "should inform the user CAS validation failed" do + account_with_cas({:account => Account.default}) + + stubby('') + def @cas_client.validate_service_ticket(st) + raise "Nope" + end + + get login_url + redirect_until(@cas_client.add_service_to_login_url(login_url)) + + get login_url :ticket => 'ST-abcd' + response.should redirect_to(login_url :no_auto => true) + flash[:delegated_message].should match(/There was a problem logging in/) + end + + it "should inform the user that CAS account doesn't exist" do + account_with_cas({:account => Account.default}) + + stubby("yes\nnonexistentuser\n") + + get login_url + redirect_until(@cas_client.add_service_to_login_url(login_url)) + + get login_url :ticket => 'ST-abcd' + response.should redirect_to(@cas_client.logout_url(login_url :no_auto => true)) + get login_url :no_auto => true + flash[:delegated_message].should match(/Canvas doesn't have an account for user/) + end + + it "should redirect to alternate CAS login page if so configured, and frame bust on login" do + account_with_cas({:account => Account.default, :cas_log_in_url => 'http://example.com/cas'}) + + get login_url + redirect_until('http://example.com/cas') + + get login_url :ticket => 'ST-abcd' + response.should render_template('shared/exit_frame') + end + + it "should login case insensitively" do + account_with_cas({:account => Account.default}) + user = user_with_pseudonym({:active_all => true}) + + stubby("yes\n#{user.pseudonyms.first.unique_id.capitalize}\n") + + get login_url + redirect_until(@cas_client.add_service_to_login_url(login_url)) + + get login_url :ticket => 'ST-abcd' + response.should redirect_to(dashboard_url(:login_success => 1)) + session[:cas_login].should == true + end + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 331570c4ef7..e10157e82c2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -83,25 +83,25 @@ Spec::Runner.configure do |config| end def account_with_cas(opts={}) - account = opts[:account] - account ||= Account.create! + @account = opts[:account] + @account ||= Account.create! config = AccountAuthorizationConfig.new cas_url = opts[:cas_url] || "https://localhost/cas" config.auth_type = "cas" config.auth_base = cas_url config.log_in_url = opts[:cas_log_in_url] if opts[:cas_log_in_url] - account.account_authorization_configs << config - account + @account.account_authorization_configs << config + @account end def account_with_saml(opts={}) - account = opts[:account] - account ||= Account.create! + @account = opts[:account] + @account ||= Account.create! config = AccountAuthorizationConfig.new config.auth_type = "saml" config.log_in_url = opts[:saml_log_in_url] if opts[:saml_log_in_url] - account.account_authorization_configs << config - account + @account.account_authorization_configs << config + @account end def course(opts={})