DEV: Move logout redirect logic to server and add plugin hook (#11199)
This will allow authentication plugins to provide single-logout functionality by redirect users to the identity provider after logout.
This commit is contained in:
parent
be07853cc1
commit
255633578c
|
@ -1,30 +1,16 @@
|
|||
import getURL from "discourse-common/lib/get-url";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { findAll } from "discourse/models/login-method";
|
||||
import { helperContext } from "discourse-common/lib/helpers";
|
||||
|
||||
export default function logout() {
|
||||
export default function logout({ redirect } = {}) {
|
||||
const ctx = helperContext();
|
||||
let siteSettings = ctx.siteSettings;
|
||||
let keyValueStore = ctx.keyValueStore;
|
||||
keyValueStore.abandonLocal();
|
||||
|
||||
const redirect = siteSettings.logout_redirect;
|
||||
if (!isEmpty(redirect)) {
|
||||
window.location.href = redirect;
|
||||
return;
|
||||
}
|
||||
|
||||
const sso = siteSettings.enable_sso;
|
||||
const oneAuthenticator =
|
||||
!siteSettings.enable_local_logins && findAll().length === 1;
|
||||
|
||||
if (siteSettings.login_required && (sso || oneAuthenticator)) {
|
||||
// In this situation visiting most URLs will start the auth process again
|
||||
// Go to the `/login` page to avoid an immediate redirect
|
||||
window.location.href = getURL("/login");
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = getURL("/");
|
||||
}
|
||||
|
|
|
@ -278,7 +278,9 @@ const ApplicationRoute = DiscourseRoute.extend(OpenComposer, {
|
|||
|
||||
_handleLogout() {
|
||||
if (this.currentUser) {
|
||||
this.currentUser.destroySession().then(() => logout());
|
||||
this.currentUser
|
||||
.destroySession()
|
||||
.then((response) => logout({ redirect: response["redirect_url"] }));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -442,12 +442,30 @@ class SessionController < ApplicationController
|
|||
end
|
||||
|
||||
def destroy
|
||||
redirect_url = params[:return_url].presence || SiteSetting.logout_redirect.presence
|
||||
|
||||
sso = SiteSetting.enable_sso
|
||||
only_one_authenticator = !SiteSetting.enable_local_logins && Discourse.enabled_authenticators.length == 1
|
||||
if sso || only_one_authenticator
|
||||
# In this situation visiting most URLs will start the auth process again
|
||||
# Go to the `/login` page to avoid an immediate redirect
|
||||
redirect_url ||= path("/login")
|
||||
end
|
||||
|
||||
redirect_url ||= path("/")
|
||||
|
||||
event_data = { redirect_url: redirect_url, user: current_user }
|
||||
DiscourseEvent.trigger(:before_session_destroy, event_data)
|
||||
redirect_url = event_data[:redirect_url]
|
||||
|
||||
reset_session
|
||||
log_off_user
|
||||
if request.xhr?
|
||||
render body: nil
|
||||
render json: {
|
||||
redirect_url: redirect_url
|
||||
}
|
||||
else
|
||||
redirect_to (params[:return_url] || path("/"))
|
||||
redirect_to redirect_url
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1751,6 +1751,44 @@ RSpec.describe SessionController do
|
|||
expect(session[:current_user_id]).to be_blank
|
||||
expect(response.cookies["_t"]).to be_blank
|
||||
end
|
||||
|
||||
it 'returns the redirect URL in the body for XHR requests' do
|
||||
user = sign_in(Fabricate(:user))
|
||||
delete "/session/#{user.username}.json", xhr: true
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(session[:current_user_id]).to be_blank
|
||||
expect(response.cookies["_t"]).to be_blank
|
||||
|
||||
expect(response.parsed_body["redirect_url"]).to eq("/")
|
||||
end
|
||||
|
||||
it 'redirects to /login for SSO' do
|
||||
SiteSetting.sso_url = "https://example.com/sso"
|
||||
SiteSetting.enable_sso = true
|
||||
|
||||
user = sign_in(Fabricate(:user))
|
||||
delete "/session/#{user.username}.json", xhr: true
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["redirect_url"]).to eq("/login")
|
||||
end
|
||||
|
||||
it 'allows plugins to manipulate redirect URL' do
|
||||
callback = -> (data) do
|
||||
data[:redirect_url] = "/myredirect/#{data[:user].username}"
|
||||
end
|
||||
|
||||
DiscourseEvent.on(:before_session_destroy, &callback)
|
||||
|
||||
user = sign_in(Fabricate(:user))
|
||||
delete "/session/#{user.username}.json", xhr: true
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["redirect_url"]).to eq("/myredirect/#{user.username}")
|
||||
ensure
|
||||
DiscourseEvent.off(:before_session_destroy, &callback)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#one_time_password' do
|
||||
|
|
Loading…
Reference in New Issue