diff --git a/app/assets/javascripts/discourse/controllers/login.js.es6 b/app/assets/javascripts/discourse/controllers/login.js.es6 index 50abf282d73..157bbaf841d 100644 --- a/app/assets/javascripts/discourse/controllers/login.js.es6 +++ b/app/assets/javascripts/discourse/controllers/login.js.es6 @@ -78,9 +78,15 @@ export default Ember.Controller.extend(ModalFunctionality, { const $hidden_login_form = $('#hidden-login-form'); const destinationUrl = $.cookie('destination_url'); const shouldRedirectToUrl = self.session.get("shouldRedirectToUrl"); + const ssoDestinationUrl = $.cookie('sso_destination_url'); $hidden_login_form.find('input[name=username]').val(self.get('loginName')); $hidden_login_form.find('input[name=password]').val(self.get('loginPassword')); - if (destinationUrl) { + + if (ssoDestinationUrl) { + $.cookie('sso_destination_url', null); + window.location.assign(ssoDestinationUrl); + return; + } else if (destinationUrl) { // redirect client to the original URL $.cookie('destination_url', null); $hidden_login_form.find('input[name=redirect]').val(destinationUrl); diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index a2a771a354a..60765e0cd8f 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -37,7 +37,11 @@ class SessionController < ApplicationController sso.external_id = current_user.id.to_s sso.admin = current_user.admin? sso.moderator = current_user.moderator? - redirect_to sso.to_url(sso.return_sso_url) + if request.xhr? + cookies[:sso_destination_url] = sso.to_url(sso.return_sso_url) + else + redirect_to sso.to_url(sso.return_sso_url) + end else session[:sso_payload] = request.query_string redirect_to path('/login') @@ -266,9 +270,8 @@ class SessionController < ApplicationController if payload = session.delete(:sso_payload) sso_provider(payload) - else - render_serialized(user, UserSerializer) end + render_serialized(user, UserSerializer) end end diff --git a/spec/controllers/session_controller_spec.rb b/spec/controllers/session_controller_spec.rb index 26d9b7f579c..3f1af05533a 100644 --- a/spec/controllers/session_controller_spec.rb +++ b/spec/controllers/session_controller_spec.rb @@ -264,40 +264,61 @@ describe SessionController do expect(response.code).to eq('419') end - it 'can act as an SSO provider' do - SiteSetting.enable_sso_provider = true - SiteSetting.enable_sso = false - SiteSetting.enable_local_logins = true - SiteSetting.sso_secret = "topsecret" + describe 'can act as an SSO provider' do + before do + SiteSetting.enable_sso_provider = true + SiteSetting.enable_sso = false + SiteSetting.enable_local_logins = true + SiteSetting.sso_secret = "topsecret" - sso = SingleSignOn.new - sso.nonce = "mynonce" - sso.sso_secret = SiteSetting.sso_secret - sso.return_sso_url = "http://somewhere.over.rainbow/sso" + @sso = SingleSignOn.new + @sso.nonce = "mynonce" + @sso.sso_secret = SiteSetting.sso_secret + @sso.return_sso_url = "http://somewhere.over.rainbow/sso" - get :sso_provider, Rack::Utils.parse_query(sso.payload) + @user = Fabricate(:user, password: "frogs", active: true, admin: true) + EmailToken.update_all(confirmed: true) + end - expect(response).to redirect_to("/login") + it "successfully logs in and redirects user to return_sso_url when the user is not logged in" do + get :sso_provider, Rack::Utils.parse_query(@sso.payload) + expect(response).to redirect_to("/login") - user = Fabricate(:user, password: "frogs", active: true, admin: true) - EmailToken.update_all(confirmed: true) + xhr :post, :create, login: @user.username, password: "frogs", format: :json - xhr :post, :create, login: user.username, password: "frogs", format: :json + location = cookies[:sso_destination_url] + # javascript code will handle redirection of user to return_sso_url + expect(location).to match(/^http:\/\/somewhere.over.rainbow\/sso/) - location = response.header["Location"] - expect(location).to match(/^http:\/\/somewhere.over.rainbow\/sso/) + payload = location.split("?")[1] + sso2 = SingleSignOn.parse(payload, "topsecret") - payload = location.split("?")[1] + expect(sso2.email).to eq(@user.email) + expect(sso2.name).to eq(@user.name) + expect(sso2.username).to eq(@user.username) + expect(sso2.external_id).to eq(@user.id.to_s) + expect(sso2.admin).to eq(true) + expect(sso2.moderator).to eq(false) + end - sso2 = SingleSignOn.parse(payload, "topsecret") + it "successfully redirects user to return_sso_url when the user is logged in" do + log_in_user(@user) - expect(sso2.email).to eq(user.email) - expect(sso2.name).to eq(user.name) - expect(sso2.username).to eq(user.username) - expect(sso2.external_id).to eq(user.id.to_s) - expect(sso2.admin).to eq(true) - expect(sso2.moderator).to eq(false) + get :sso_provider, Rack::Utils.parse_query(@sso.payload) + location = response.header["Location"] + expect(location).to match(/^http:\/\/somewhere.over.rainbow\/sso/) + + payload = location.split("?")[1] + sso2 = SingleSignOn.parse(payload, "topsecret") + + expect(sso2.email).to eq(@user.email) + expect(sso2.name).to eq(@user.name) + expect(sso2.username).to eq(@user.username) + expect(sso2.external_id).to eq(@user.id.to_s) + expect(sso2.admin).to eq(true) + expect(sso2.moderator).to eq(false) + end end describe 'local attribute override from SSO payload' do