Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Fix login loop where the sso flow returns to #/login to release #4693

Merged
merged 2 commits into from
Jun 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions src/BasePlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import {CheckUpdatesPayload} from "./dispatcher/payloads/CheckUpdatesPayload";
import {Action} from "./dispatcher/actions";
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 {
Checking = "CHECKING",
Error = "ERROR",
Expand All @@ -47,6 +50,7 @@ export default abstract class BasePlatform {

constructor() {
dis.register(this.onAction);
this.startUpdateCheck = this.startUpdateCheck.bind(this);
}

protected onAction = (payload: ActionPayload) => {
Expand Down Expand Up @@ -217,11 +221,9 @@ export default abstract class BasePlatform {

setLanguage(preferredLangs: string[]) {}

getSSOCallbackUrl(hsUrl: string, isUrl: string, fragmentAfterLogin: string): URL {
getSSOCallbackUrl(fragmentAfterLogin: string): URL {
const url = new URL(window.location.href);
url.hash = fragmentAfterLogin || "";
url.searchParams.set("homeserver", hsUrl);
url.searchParams.set("identityServer", isUrl);
return url;
}

Expand All @@ -232,8 +234,12 @@ export default abstract class BasePlatform {
* @param {string} fragmentAfterLogin the hash to pass to the app during sso callback.
*/
startSingleSignOn(mxClient: MatrixClient, loginType: "sso" | "cas", fragmentAfterLogin: string) {
const callbackUrl = this.getSSOCallbackUrl(mxClient.getHomeserverUrl(), mxClient.getIdentityServerUrl(),
fragmentAfterLogin);
// persist hs url and is url for when the user is returned to the app with the login token
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
}

Expand Down
17 changes: 10 additions & 7 deletions src/Lifecycle.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {IntegrationManagers} from "./integrations/IntegrationManagers";
import {Mjolnir} from "./mjolnir/Mjolnir";
import DeviceListener from "./DeviceListener";
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
Expand Down Expand Up @@ -163,14 +164,16 @@ export function attemptTokenLogin(queryParams, defaultDeviceDisplayName) {
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");
return Promise.resolve(false);
}

return sendLoginRequest(
queryParams.homeserver,
queryParams.identityServer,
homeserver,
identityServer,
"m.login.token", {
token: queryParams.loginToken,
initial_device_display_name: defaultDeviceDisplayName,
Expand Down Expand Up @@ -256,8 +259,8 @@ function _registerAsGuest(hsUrl, isUrl, defaultDeviceDisplayName) {
* @returns {Object} Information about the session - see implementation for variables.
*/
export function getLocalStorageSessionVars() {
const hsUrl = localStorage.getItem("mx_hs_url");
const isUrl = localStorage.getItem("mx_is_url");
const hsUrl = localStorage.getItem(HOMESERVER_URL_KEY);
const isUrl = localStorage.getItem(ID_SERVER_URL_KEY);
const accessToken = localStorage.getItem("mx_access_token");
const userId = localStorage.getItem("mx_user_id");
const deviceId = localStorage.getItem("mx_device_id");
Expand Down Expand Up @@ -486,9 +489,9 @@ function _showStorageEvictedDialog() {
class AbortLoginAndRebuildStorage extends Error { }

function _persistCredentialsToLocalStorage(credentials) {
localStorage.setItem("mx_hs_url", credentials.homeserverUrl);
localStorage.setItem(HOMESERVER_URL_KEY, credentials.homeserverUrl);
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_access_token", credentials.accessToken);
Expand Down
5 changes: 4 additions & 1 deletion src/components/structures/MatrixChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1942,7 +1942,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// console.log(`Rendering MatrixChat with view ${this.state.view}`);

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}`;
}

Expand Down
9 changes: 5 additions & 4 deletions src/components/structures/auth/SoftLogout.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {MatrixClientPeg} from "../../../MatrixClientPeg";
import {sendLoginRequest} from "../../../Login";
import AuthPage from "../../views/auth/AuthPage";
import SSOButton from "../../views/elements/SSOButton";
import {HOMESERVER_URL_KEY, ID_SERVER_URL_KEY} from "../../../BasePlatform";

const LOGIN_VIEW = {
LOADING: 1,
Expand All @@ -43,7 +44,7 @@ const FLOWS_TO_VIEWS = {
export default class SoftLogout extends React.Component {
static propTypes = {
// Query parameters from MatrixChat
realQueryParams: PropTypes.object, // {homeserver, identityServer, loginToken}
realQueryParams: PropTypes.object, // {loginToken}

// Called when the SSO login completes
onTokenLoginCompleted: PropTypes.func,
Expand Down Expand Up @@ -90,7 +91,7 @@ export default class SoftLogout extends React.Component {

async _initLogin() {
const queryParams = this.props.realQueryParams;
const hasAllParams = queryParams && queryParams['homeserver'] && queryParams['loginToken'];
const hasAllParams = queryParams && queryParams['loginToken'];
if (hasAllParams) {
this.setState({loginView: LOGIN_VIEW.LOADING});
this.trySsoLogin();
Expand Down Expand Up @@ -157,8 +158,8 @@ export default class SoftLogout extends React.Component {
async trySsoLogin() {
this.setState({busy: true});

const hsUrl = this.props.realQueryParams['homeserver'];
const isUrl = this.props.realQueryParams['identityServer'] || MatrixClientPeg.get().getIdentityServerUrl();
const hsUrl = localStorage.getItem(HOMESERVER_URL_KEY);
const isUrl = localStorage.getItem(ID_SERVER_URL_KEY) || MatrixClientPeg.get().getIdentityServerUrl();
const loginType = "m.login.token";
const loginParams = {
token: this.props.realQueryParams['loginToken'],
Expand Down