Merge pull request #4585 from matrix-org/t3chguy/sso_hash

Pass screenAfterLogin through SSO in the callback url
This commit is contained in:
Michael Telatynski 2020-05-14 17:30:31 +01:00 committed by GitHub
commit dd747a9a09
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 27 additions and 15 deletions

View file

@ -167,13 +167,9 @@ export default class BasePlatform {
setLanguage(preferredLangs: string[]) {} setLanguage(preferredLangs: string[]) {}
getSSOCallbackUrl(hsUrl: string, isUrl: string): URL { getSSOCallbackUrl(hsUrl: string, isUrl: string, fragmentAfterLogin: string): URL {
const url = new URL(window.location.href); const url = new URL(window.location.href);
// XXX: at this point, the fragment will always be #/login, which is no url.hash = fragmentAfterLogin || "";
// use to anyone. Ideally, we would get the intended fragment from
// MatrixChat.screenAfterLogin so that you could follow #/room links etc
// through an SSO login.
url.hash = "";
url.searchParams.set("homeserver", hsUrl); url.searchParams.set("homeserver", hsUrl);
url.searchParams.set("identityServer", isUrl); url.searchParams.set("identityServer", isUrl);
return url; return url;
@ -183,9 +179,11 @@ export default class BasePlatform {
* Begin Single Sign On flows. * Begin Single Sign On flows.
* @param {MatrixClient} mxClient the matrix client using which we should start the flow * @param {MatrixClient} mxClient the matrix client using which we should start the flow
* @param {"sso"|"cas"} loginType the type of SSO it is, CAS/SSO. * @param {"sso"|"cas"} loginType the type of SSO it is, CAS/SSO.
* @param {string} fragmentAfterLogin the hash to pass to the app during sso callback.
*/ */
startSingleSignOn(mxClient: MatrixClient, loginType: "sso"|"cas") { startSingleSignOn(mxClient: MatrixClient, loginType: "sso" | "cas", fragmentAfterLogin: string) {
const callbackUrl = this.getSSOCallbackUrl(mxClient.getHomeserverUrl(), mxClient.getIdentityServerUrl()); const callbackUrl = this.getSSOCallbackUrl(mxClient.getHomeserverUrl(), mxClient.getIdentityServerUrl(),
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

@ -1973,6 +1973,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
render() { render() {
// console.log(`Rendering MatrixChat with view ${this.state.view}`); // console.log(`Rendering MatrixChat with view ${this.state.view}`);
let fragmentAfterLogin = "";
if (this.props.initialScreenAfterLogin) {
fragmentAfterLogin = `/${this.props.initialScreenAfterLogin.screen}`;
}
let view; let view;
if (this.state.view === Views.LOADING) { if (this.state.view === Views.LOADING) {
@ -2052,7 +2057,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
} else if (this.state.view === Views.WELCOME) { } else if (this.state.view === Views.WELCOME) {
const Welcome = sdk.getComponent('auth.Welcome'); const Welcome = sdk.getComponent('auth.Welcome');
view = <Welcome {...this.getServerProperties()} />; view = <Welcome {...this.getServerProperties()} fragmentAfterLogin={fragmentAfterLogin} />;
} else if (this.state.view === Views.REGISTER) { } else if (this.state.view === Views.REGISTER) {
const Registration = sdk.getComponent('structures.auth.Registration'); const Registration = sdk.getComponent('structures.auth.Registration');
view = ( view = (
@ -2091,6 +2096,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName} defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
onForgotPasswordClick={this.onForgotPasswordClick} onForgotPasswordClick={this.onForgotPasswordClick}
onServerConfigChange={this.onServerConfigChange} onServerConfigChange={this.onServerConfigChange}
fragmentAfterLogin={fragmentAfterLogin}
{...this.getServerProperties()} {...this.getServerProperties()}
/> />
); );
@ -2100,6 +2106,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
<SoftLogout <SoftLogout
realQueryParams={this.props.realQueryParams} realQueryParams={this.props.realQueryParams}
onTokenLoginCompleted={this.props.onTokenLoginCompleted} onTokenLoginCompleted={this.props.onTokenLoginCompleted}
fragmentAfterLogin={fragmentAfterLogin}
/> />
); );
} else { } else {

View file

@ -355,7 +355,8 @@ export default createReactClass({
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
const ssoKind = step === 'm.login.sso' ? 'sso' : 'cas'; const ssoKind = step === 'm.login.sso' ? 'sso' : 'cas';
PlatformPeg.get().startSingleSignOn(this._loginLogic.createTemporaryClient(), ssoKind); PlatformPeg.get().startSingleSignOn(this._loginLogic.createTemporaryClient(), ssoKind,
this.props.fragmentAfterLogin);
} else { } else {
// Don't intercept - just go through to the register page // Don't intercept - just go through to the register page
this.onRegisterClick(ev); this.onRegisterClick(ev);
@ -628,7 +629,9 @@ export default createReactClass({
<SSOButton <SSOButton
className="mx_Login_sso_link mx_Login_submit" className="mx_Login_sso_link mx_Login_submit"
matrixClient={this._loginLogic.createTemporaryClient()} matrixClient={this._loginLogic.createTemporaryClient()}
loginType={loginType} /> loginType={loginType}
fragmentAfterLogin={this.props.fragmentAfterLogin}
/>
</div> </div>
); );
}, },

View file

@ -244,7 +244,9 @@ export default class SoftLogout extends React.Component {
<p>{introText}</p> <p>{introText}</p>
<SSOButton <SSOButton
matrixClient={MatrixClientPeg.get()} matrixClient={MatrixClientPeg.get()}
loginType={this.state.loginView === LOGIN_VIEW.CAS ? "cas" : "sso"} /> loginType={this.state.loginView === LOGIN_VIEW.CAS ? "cas" : "sso"}
fragmentAfterLogin={this.props.fragmentAfterLogin}
/>
</div> </div>
); );
} }

View file

@ -45,7 +45,8 @@ export default class Welcome extends React.PureComponent {
idBaseUrl: isUrl, idBaseUrl: isUrl,
}); });
const plaf = PlatformPeg.get(); const plaf = PlatformPeg.get();
const callbackUrl = plaf.getSSOCallbackUrl(tmpClient.getHomeserverUrl(), tmpClient.getIdentityServerUrl()); const callbackUrl = plaf.getSSOCallbackUrl(tmpClient.getHomeserverUrl(), tmpClient.getIdentityServerUrl(),
this.props.fragmentAfterLogin);
return ( return (
<AuthPage> <AuthPage>

View file

@ -21,9 +21,9 @@ import PlatformPeg from "../../../PlatformPeg";
import AccessibleButton from "./AccessibleButton"; import AccessibleButton from "./AccessibleButton";
import {_t} from "../../../languageHandler"; import {_t} from "../../../languageHandler";
const SSOButton = ({matrixClient, loginType, ...props}) => { const SSOButton = ({matrixClient, loginType, fragmentAfterLogin, ...props}) => {
const onClick = () => { const onClick = () => {
PlatformPeg.get().startSingleSignOn(matrixClient, loginType); PlatformPeg.get().startSingleSignOn(matrixClient, loginType, fragmentAfterLogin);
}; };
return ( return (
@ -36,6 +36,7 @@ const SSOButton = ({matrixClient, loginType, ...props}) => {
SSOButton.propTypes = { SSOButton.propTypes = {
matrixClient: PropTypes.object.isRequired, // does not use context as may use a temporary client matrixClient: PropTypes.object.isRequired, // does not use context as may use a temporary client
loginType: PropTypes.oneOf(["sso", "cas"]), // defaults to "sso" in base-apis loginType: PropTypes.oneOf(["sso", "cas"]), // defaults to "sso" in base-apis
fragmentAfterLogin: PropTypes.string,
}; };
export default SSOButton; export default SSOButton;