Merge pull request #4693 from matrix-org/t3chguy/sso-query

Fix login loop where the sso flow returns to `#/login` to release
This commit is contained in:
Michael Telatynski 2020-06-04 01:09:30 +01:00 committed by GitHub
commit e6a776be7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 17 deletions

View File

@ -25,6 +25,9 @@ import {CheckUpdatesPayload} from "./dispatcher/payloads/CheckUpdatesPayload";
import {Action} from "./dispatcher/actions"; import {Action} from "./dispatcher/actions";
import {hideToast as hideUpdateToast} from "./toasts/UpdateToast"; import {hideToast as hideUpdateToast} from "./toasts/UpdateToast";
export const HOMESERVER_URL_KEY = "mx_hs_url";
export const ID_SERVER_URL_KEY = "mx_is_url";
export enum UpdateCheckStatus { export enum UpdateCheckStatus {
Checking = "CHECKING", Checking = "CHECKING",
Error = "ERROR", Error = "ERROR",
@ -47,6 +50,7 @@ export default abstract class BasePlatform {
constructor() { constructor() {
dis.register(this.onAction); dis.register(this.onAction);
this.startUpdateCheck = this.startUpdateCheck.bind(this);
} }
protected onAction = (payload: ActionPayload) => { protected onAction = (payload: ActionPayload) => {
@ -217,11 +221,9 @@ export default abstract class BasePlatform {
setLanguage(preferredLangs: string[]) {} setLanguage(preferredLangs: string[]) {}
getSSOCallbackUrl(hsUrl: string, isUrl: string, fragmentAfterLogin: string): URL { getSSOCallbackUrl(fragmentAfterLogin: string): URL {
const url = new URL(window.location.href); const url = new URL(window.location.href);
url.hash = fragmentAfterLogin || ""; url.hash = fragmentAfterLogin || "";
url.searchParams.set("homeserver", hsUrl);
url.searchParams.set("identityServer", isUrl);
return url; return url;
} }
@ -232,8 +234,12 @@ export default abstract class BasePlatform {
* @param {string} fragmentAfterLogin the hash to pass to the app during sso callback. * @param {string} fragmentAfterLogin the hash to pass to the app during sso callback.
*/ */
startSingleSignOn(mxClient: MatrixClient, loginType: "sso" | "cas", fragmentAfterLogin: string) { startSingleSignOn(mxClient: MatrixClient, loginType: "sso" | "cas", fragmentAfterLogin: string) {
const callbackUrl = this.getSSOCallbackUrl(mxClient.getHomeserverUrl(), mxClient.getIdentityServerUrl(), // persist hs url and is url for when the user is returned to the app with the login token
fragmentAfterLogin); localStorage.setItem(HOMESERVER_URL_KEY, mxClient.getHomeserverUrl());
if (mxClient.getIdentityServerUrl()) {
localStorage.setItem(ID_SERVER_URL_KEY, mxClient.getIdentityServerUrl());
}
const callbackUrl = this.getSSOCallbackUrl(fragmentAfterLogin);
window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType); // redirect to SSO window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType); // redirect to SSO
} }

View File

@ -41,6 +41,7 @@ import {IntegrationManagers} from "./integrations/IntegrationManagers";
import {Mjolnir} from "./mjolnir/Mjolnir"; import {Mjolnir} from "./mjolnir/Mjolnir";
import DeviceListener from "./DeviceListener"; import DeviceListener from "./DeviceListener";
import {Jitsi} from "./widgets/Jitsi"; import {Jitsi} from "./widgets/Jitsi";
import {HOMESERVER_URL_KEY, ID_SERVER_URL_KEY} from "./BasePlatform";
/** /**
* Called at startup, to attempt to build a logged-in Matrix session. It tries * Called at startup, to attempt to build a logged-in Matrix session. It tries
@ -163,14 +164,16 @@ export function attemptTokenLogin(queryParams, defaultDeviceDisplayName) {
return Promise.resolve(false); return Promise.resolve(false);
} }
if (!queryParams.homeserver) { const homeserver = localStorage.getItem(HOMESERVER_URL_KEY);
const identityServer = localStorage.getItem(ID_SERVER_URL_KEY);
if (!homeserver) {
console.warn("Cannot log in with token: can't determine HS URL to use"); console.warn("Cannot log in with token: can't determine HS URL to use");
return Promise.resolve(false); return Promise.resolve(false);
} }
return sendLoginRequest( return sendLoginRequest(
queryParams.homeserver, homeserver,
queryParams.identityServer, identityServer,
"m.login.token", { "m.login.token", {
token: queryParams.loginToken, token: queryParams.loginToken,
initial_device_display_name: defaultDeviceDisplayName, initial_device_display_name: defaultDeviceDisplayName,
@ -256,8 +259,8 @@ function _registerAsGuest(hsUrl, isUrl, defaultDeviceDisplayName) {
* @returns {Object} Information about the session - see implementation for variables. * @returns {Object} Information about the session - see implementation for variables.
*/ */
export function getLocalStorageSessionVars() { export function getLocalStorageSessionVars() {
const hsUrl = localStorage.getItem("mx_hs_url"); const hsUrl = localStorage.getItem(HOMESERVER_URL_KEY);
const isUrl = localStorage.getItem("mx_is_url"); const isUrl = localStorage.getItem(ID_SERVER_URL_KEY);
const accessToken = localStorage.getItem("mx_access_token"); const accessToken = localStorage.getItem("mx_access_token");
const userId = localStorage.getItem("mx_user_id"); const userId = localStorage.getItem("mx_user_id");
const deviceId = localStorage.getItem("mx_device_id"); const deviceId = localStorage.getItem("mx_device_id");
@ -486,9 +489,9 @@ function _showStorageEvictedDialog() {
class AbortLoginAndRebuildStorage extends Error { } class AbortLoginAndRebuildStorage extends Error { }
function _persistCredentialsToLocalStorage(credentials) { function _persistCredentialsToLocalStorage(credentials) {
localStorage.setItem("mx_hs_url", credentials.homeserverUrl); localStorage.setItem(HOMESERVER_URL_KEY, credentials.homeserverUrl);
if (credentials.identityServerUrl) { if (credentials.identityServerUrl) {
localStorage.setItem("mx_is_url", credentials.identityServerUrl); localStorage.setItem(ID_SERVER_URL_KEY, credentials.identityServerUrl);
} }
localStorage.setItem("mx_user_id", credentials.userId); localStorage.setItem("mx_user_id", credentials.userId);
localStorage.setItem("mx_access_token", credentials.accessToken); localStorage.setItem("mx_access_token", credentials.accessToken);

View File

@ -1942,7 +1942,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// console.log(`Rendering MatrixChat with view ${this.state.view}`); // console.log(`Rendering MatrixChat with view ${this.state.view}`);
let fragmentAfterLogin = ""; let fragmentAfterLogin = "";
if (this.props.initialScreenAfterLogin) { if (this.props.initialScreenAfterLogin &&
// XXX: workaround for https://github.com/vector-im/riot-web/issues/11643 causing a login-loop
!["welcome", "login", "register"].includes(this.props.initialScreenAfterLogin.screen)
) {
fragmentAfterLogin = `/${this.props.initialScreenAfterLogin.screen}`; fragmentAfterLogin = `/${this.props.initialScreenAfterLogin.screen}`;
} }

View File

@ -25,6 +25,7 @@ import {MatrixClientPeg} from "../../../MatrixClientPeg";
import {sendLoginRequest} from "../../../Login"; import {sendLoginRequest} from "../../../Login";
import AuthPage from "../../views/auth/AuthPage"; import AuthPage from "../../views/auth/AuthPage";
import SSOButton from "../../views/elements/SSOButton"; import SSOButton from "../../views/elements/SSOButton";
import {HOMESERVER_URL_KEY, ID_SERVER_URL_KEY} from "../../../BasePlatform";
const LOGIN_VIEW = { const LOGIN_VIEW = {
LOADING: 1, LOADING: 1,
@ -43,7 +44,7 @@ const FLOWS_TO_VIEWS = {
export default class SoftLogout extends React.Component { export default class SoftLogout extends React.Component {
static propTypes = { static propTypes = {
// Query parameters from MatrixChat // Query parameters from MatrixChat
realQueryParams: PropTypes.object, // {homeserver, identityServer, loginToken} realQueryParams: PropTypes.object, // {loginToken}
// Called when the SSO login completes // Called when the SSO login completes
onTokenLoginCompleted: PropTypes.func, onTokenLoginCompleted: PropTypes.func,
@ -90,7 +91,7 @@ export default class SoftLogout extends React.Component {
async _initLogin() { async _initLogin() {
const queryParams = this.props.realQueryParams; const queryParams = this.props.realQueryParams;
const hasAllParams = queryParams && queryParams['homeserver'] && queryParams['loginToken']; const hasAllParams = queryParams && queryParams['loginToken'];
if (hasAllParams) { if (hasAllParams) {
this.setState({loginView: LOGIN_VIEW.LOADING}); this.setState({loginView: LOGIN_VIEW.LOADING});
this.trySsoLogin(); this.trySsoLogin();
@ -157,8 +158,8 @@ export default class SoftLogout extends React.Component {
async trySsoLogin() { async trySsoLogin() {
this.setState({busy: true}); this.setState({busy: true});
const hsUrl = this.props.realQueryParams['homeserver']; const hsUrl = localStorage.getItem(HOMESERVER_URL_KEY);
const isUrl = this.props.realQueryParams['identityServer'] || MatrixClientPeg.get().getIdentityServerUrl(); const isUrl = localStorage.getItem(ID_SERVER_URL_KEY) || MatrixClientPeg.get().getIdentityServerUrl();
const loginType = "m.login.token"; const loginType = "m.login.token";
const loginParams = { const loginParams = {
token: this.props.realQueryParams['loginToken'], token: this.props.realQueryParams['loginToken'],