From c41b39488b46ac772d3b0c0ba5c9c3b060e495e6 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 25 Mar 2020 23:35:36 +0000 Subject: [PATCH 1/9] Automatically redirect to SSO when the user clicks through to Login Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/auth/Login.js | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index bfabc34a62..36df08627e 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -53,6 +53,10 @@ _td("Invalid base_url for m.identity_server"); _td("Identity server URL does not appear to be a valid identity server"); _td("General failure"); +const M_LOGIN_CAS = "m.login.cas"; +const M_LOGIN_SSO = "m.login.sso"; +const SSO_FLOWS = [M_LOGIN_SSO, M_LOGIN_CAS]; + /** * A wire component which glues together login UI components and Login logic */ @@ -122,11 +126,11 @@ export default createReactClass({ 'm.login.password': this._renderPasswordStep, // CAS and SSO are the same thing, modulo the url we link to - 'm.login.cas': () => this._renderSsoStep("cas"), - 'm.login.sso': () => this._renderSsoStep("sso"), + [M_LOGIN_CAS]: () => this._renderSsoStep("cas"), + [M_LOGIN_SSO]: () => this._renderSsoStep("sso"), }; - this._initLoginLogic(); + this._initLoginLogic(true); }, componentWillUnmount: function() { @@ -138,7 +142,7 @@ export default createReactClass({ newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return; // Ensure that we end up actually logging in to the right place - this._initLoginLogic(newProps.serverConfig.hsUrl, newProps.serverConfig.isUrl); + this._initLoginLogic(false, newProps.serverConfig.hsUrl, newProps.serverConfig.isUrl); }, onPasswordLoginError: function(errorText) { @@ -342,12 +346,12 @@ export default createReactClass({ onTryRegisterClick: function(ev) { const step = this._getCurrentFlowStep(); - if (step === 'm.login.sso' || step === 'm.login.cas') { + if (SSO_FLOWS.includes(step)) { // If we're showing SSO it means that registration is also probably disabled, // so intercept the click and instead pretend the user clicked 'Sign in with SSO'. ev.preventDefault(); 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); } else { // Don't intercept - just go through to the register page @@ -369,7 +373,7 @@ export default createReactClass({ }); }, - _initLoginLogic: async function(hsUrl, isUrl) { + _initLoginLogic: async function(initial, hsUrl, isUrl) { hsUrl = hsUrl || this.props.serverConfig.hsUrl; isUrl = isUrl || this.props.serverConfig.isUrl; @@ -429,6 +433,13 @@ export default createReactClass({ continue; } + // if this is the initial render and the flow we choose is SSO/CAS then go to it automatically + // we do not do this when the user has changed to the server manually as that may be jarring. + if (initial && SSO_FLOWS.includes(flows[i].type)) { + const tmpCli = this._loginLogic.createTemporaryClient(); + PlatformPeg.get().startSingleSignOn(tmpCli, flows[i].type === M_LOGIN_SSO ? "sso": "cas"); + } + // we just pick the first flow where we support all the // steps. (we don't have a UI for multiple logins so let's skip // that for now). From 7fbfd73e11e03a192d2bb74e3146b9ea07189e5d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 01:17:42 +0000 Subject: [PATCH 2/9] Show modal on "instant SSO" Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/BasePlatform.js | 19 ++++++++++++++++++- src/components/structures/auth/Login.js | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/BasePlatform.js b/src/BasePlatform.js index 5d809eb28f..489d9474a1 100644 --- a/src/BasePlatform.js +++ b/src/BasePlatform.js @@ -22,6 +22,11 @@ limitations under the License. import {MatrixClient} from "matrix-js-sdk"; import dis from './dispatcher'; import BaseEventIndexManager from './indexing/BaseEventIndexManager'; +import Modal from "./Modal"; +import InfoDialog from "./components/views/dialogs/InfoDialog"; +import {_t} from "./languageHandler"; +import Spinner from "./components/views/elements/Spinner"; +import React from "react"; /** * Base class for classes that provide platform-specific functionality @@ -183,9 +188,21 @@ export default class BasePlatform { * Begin Single Sign On flows. * @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 {boolean} showModal whether or not to show the spinner modal. */ - startSingleSignOn(mxClient: MatrixClient, loginType: "sso"|"cas") { + startSingleSignOn(mxClient: MatrixClient, loginType: "sso"|"cas", showModal: boolean) { const callbackUrl = this.getSSOCallbackUrl(mxClient.getHomeserverUrl(), mxClient.getIdentityServerUrl()); + if (showModal) { + Modal.createTrackedDialog('BasePlatform', 'SSO', InfoDialog, { + title: _t("Single sign-on"), + description:
+ + + {_t("Click here if you're not redirected automatically")} + +
, + }); + } window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType); // redirect to SSO } } diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 36df08627e..6c6a8bedbd 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -437,7 +437,7 @@ export default createReactClass({ // we do not do this when the user has changed to the server manually as that may be jarring. if (initial && SSO_FLOWS.includes(flows[i].type)) { const tmpCli = this._loginLogic.createTemporaryClient(); - PlatformPeg.get().startSingleSignOn(tmpCli, flows[i].type === M_LOGIN_SSO ? "sso": "cas"); + PlatformPeg.get().startSingleSignOn(tmpCli, flows[i].type === M_LOGIN_SSO ? "sso": "cas", true); } // we just pick the first flow where we support all the From 98f9f1e956235c290586f95e9b10fcfe2231c487 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 09:59:43 +0000 Subject: [PATCH 3/9] i18n Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/i18n/strings/en_EN.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 12bd462937..4677f40ce1 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -25,6 +25,8 @@ "Error": "Error", "Unable to load! Check your network connectivity and try again.": "Unable to load! Check your network connectivity and try again.", "Dismiss": "Dismiss", + "Single sign-on": "Single sign-on", + "Click here if you're not redirected automatically": "Click here if you're not redirected automatically", "Call Failed": "Call Failed", "There are unknown sessions in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "There are unknown sessions in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.", "Review Sessions": "Review Sessions", From 548e9184372d9a7c8a74a07841f97134ee55fbb4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 12:01:10 +0000 Subject: [PATCH 4/9] only auto-sso when disable_custom_urls is true Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/auth/Login.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 6c6a8bedbd..134f6fa6f3 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -435,7 +435,8 @@ export default createReactClass({ // if this is the initial render and the flow we choose is SSO/CAS then go to it automatically // we do not do this when the user has changed to the server manually as that may be jarring. - if (initial && SSO_FLOWS.includes(flows[i].type)) { + // Only allow it when disable_custom_urls is asserted so that we don't prevent user from changing HS URL + if (initial && SdkConfig.get()['disable_custom_urls'] && SSO_FLOWS.includes(flows[i].type)) { const tmpCli = this._loginLogic.createTemporaryClient(); PlatformPeg.get().startSingleSignOn(tmpCli, flows[i].type === M_LOGIN_SSO ? "sso": "cas", true); } From db6f88c66a76736ce72ec0d22df6e6627b0a59ed Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 14:02:32 +0000 Subject: [PATCH 5/9] Welcome page, support $ssoUrl and $casUrl placeholders Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/EmbeddedPage.js | 9 +++++++++ src/components/structures/MatrixChat.js | 2 +- src/components/views/auth/Welcome.js | 15 ++++++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/components/structures/EmbeddedPage.js b/src/components/structures/EmbeddedPage.js index f854dc955f..a0a95ac6f1 100644 --- a/src/components/structures/EmbeddedPage.js +++ b/src/components/structures/EmbeddedPage.js @@ -37,6 +37,8 @@ export default class EmbeddedPage extends React.PureComponent { className: PropTypes.string, // Whether to wrap the page in a scrollbar scrollbar: PropTypes.bool, + // Map of keys to replace with values, e.g {$placeholder: "value"} + replaceMap: PropTypes.object, }; static contextType = MatrixClientContext; @@ -81,6 +83,13 @@ export default class EmbeddedPage extends React.PureComponent { } body = body.replace(/_t\(['"]([\s\S]*?)['"]\)/mg, (match, g1)=>this.translate(g1)); + + if (this.props.replaceMap) { + Object.keys(this.props.replaceMap).forEach(key => { + body = body.split(key).join(this.props.replaceMap[key]); + }); + } + this.setState({ page: body }); }, ); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 52002f0591..e6702e385e 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -2021,7 +2021,7 @@ export default createReactClass({ } } else if (this.state.view === VIEWS.WELCOME) { const Welcome = sdk.getComponent('auth.Welcome'); - view = ; + view = ; } else if (this.state.view === VIEWS.REGISTER) { const Registration = sdk.getComponent('structures.auth.Registration'); view = ( diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index 58f117ea36..60ceae5343 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -18,6 +18,7 @@ import React from 'react'; import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import AuthPage from "./AuthPage"; +import * as Matrix from "matrix-js-sdk"; export default class Welcome extends React.PureComponent { render() { @@ -33,11 +34,23 @@ export default class Welcome extends React.PureComponent { pageUrl = 'welcome.html'; } + const {hsUrl, isUrl} = this.props.serverConfig; + const tmpClient = Matrix.createClient({ + baseUrl: hsUrl, + idBaseUrl: isUrl, + }); + const callbackUrl = this.getSSOCallbackUrl(tmpClient.getHomeserverUrl(), tmpClient.getIdentityServerUrl()); + return (
-
From f4d3cc8ee62671336981f486561be58d4e3e0f6c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 14:05:14 +0000 Subject: [PATCH 6/9] revert stale changes Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/BasePlatform.js | 19 +----------------- src/components/structures/auth/Login.js | 26 +++++++------------------ src/components/views/auth/Welcome.js | 4 ++++ 3 files changed, 12 insertions(+), 37 deletions(-) diff --git a/src/BasePlatform.js b/src/BasePlatform.js index 489d9474a1..5d809eb28f 100644 --- a/src/BasePlatform.js +++ b/src/BasePlatform.js @@ -22,11 +22,6 @@ limitations under the License. import {MatrixClient} from "matrix-js-sdk"; import dis from './dispatcher'; import BaseEventIndexManager from './indexing/BaseEventIndexManager'; -import Modal from "./Modal"; -import InfoDialog from "./components/views/dialogs/InfoDialog"; -import {_t} from "./languageHandler"; -import Spinner from "./components/views/elements/Spinner"; -import React from "react"; /** * Base class for classes that provide platform-specific functionality @@ -188,21 +183,9 @@ export default class BasePlatform { * Begin Single Sign On flows. * @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 {boolean} showModal whether or not to show the spinner modal. */ - startSingleSignOn(mxClient: MatrixClient, loginType: "sso"|"cas", showModal: boolean) { + startSingleSignOn(mxClient: MatrixClient, loginType: "sso"|"cas") { const callbackUrl = this.getSSOCallbackUrl(mxClient.getHomeserverUrl(), mxClient.getIdentityServerUrl()); - if (showModal) { - Modal.createTrackedDialog('BasePlatform', 'SSO', InfoDialog, { - title: _t("Single sign-on"), - description:
- - - {_t("Click here if you're not redirected automatically")} - -
, - }); - } window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType); // redirect to SSO } } diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 134f6fa6f3..bfabc34a62 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -53,10 +53,6 @@ _td("Invalid base_url for m.identity_server"); _td("Identity server URL does not appear to be a valid identity server"); _td("General failure"); -const M_LOGIN_CAS = "m.login.cas"; -const M_LOGIN_SSO = "m.login.sso"; -const SSO_FLOWS = [M_LOGIN_SSO, M_LOGIN_CAS]; - /** * A wire component which glues together login UI components and Login logic */ @@ -126,11 +122,11 @@ export default createReactClass({ 'm.login.password': this._renderPasswordStep, // CAS and SSO are the same thing, modulo the url we link to - [M_LOGIN_CAS]: () => this._renderSsoStep("cas"), - [M_LOGIN_SSO]: () => this._renderSsoStep("sso"), + 'm.login.cas': () => this._renderSsoStep("cas"), + 'm.login.sso': () => this._renderSsoStep("sso"), }; - this._initLoginLogic(true); + this._initLoginLogic(); }, componentWillUnmount: function() { @@ -142,7 +138,7 @@ export default createReactClass({ newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return; // Ensure that we end up actually logging in to the right place - this._initLoginLogic(false, newProps.serverConfig.hsUrl, newProps.serverConfig.isUrl); + this._initLoginLogic(newProps.serverConfig.hsUrl, newProps.serverConfig.isUrl); }, onPasswordLoginError: function(errorText) { @@ -346,12 +342,12 @@ export default createReactClass({ onTryRegisterClick: function(ev) { const step = this._getCurrentFlowStep(); - if (SSO_FLOWS.includes(step)) { + if (step === 'm.login.sso' || step === 'm.login.cas') { // If we're showing SSO it means that registration is also probably disabled, // so intercept the click and instead pretend the user clicked 'Sign in with SSO'. ev.preventDefault(); 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); } else { // Don't intercept - just go through to the register page @@ -373,7 +369,7 @@ export default createReactClass({ }); }, - _initLoginLogic: async function(initial, hsUrl, isUrl) { + _initLoginLogic: async function(hsUrl, isUrl) { hsUrl = hsUrl || this.props.serverConfig.hsUrl; isUrl = isUrl || this.props.serverConfig.isUrl; @@ -433,14 +429,6 @@ export default createReactClass({ continue; } - // if this is the initial render and the flow we choose is SSO/CAS then go to it automatically - // we do not do this when the user has changed to the server manually as that may be jarring. - // Only allow it when disable_custom_urls is asserted so that we don't prevent user from changing HS URL - if (initial && SdkConfig.get()['disable_custom_urls'] && SSO_FLOWS.includes(flows[i].type)) { - const tmpCli = this._loginLogic.createTemporaryClient(); - PlatformPeg.get().startSingleSignOn(tmpCli, flows[i].type === M_LOGIN_SSO ? "sso": "cas", true); - } - // we just pick the first flow where we support all the // steps. (we don't have a UI for multiple logins so let's skip // that for now). diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index 60ceae5343..70c5569cd9 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -19,6 +19,10 @@ import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import AuthPage from "./AuthPage"; import * as Matrix from "matrix-js-sdk"; +import {_td} from "../../../languageHandler"; + +// translatable strings for Welcome pages +_td("Sign in with SSO"); export default class Welcome extends React.PureComponent { render() { From 6664535a269da603a88562f1cf943d405d2c425e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 14:05:32 +0000 Subject: [PATCH 7/9] change welcome page placeholders Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/auth/Welcome.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index 70c5569cd9..1893b04d76 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -52,8 +52,8 @@ export default class Welcome extends React.PureComponent { className="mx_WelcomePage" url={pageUrl} replaceMap={{ - "$ssoUrl": tmpClient.getSsoLoginUrl(callbackUrl.toString(), "sso"), - "$casUrl": tmpClient.getSsoLoginUrl(callbackUrl.toString(), "cas"), + "$riot:ssoUrl": tmpClient.getSsoLoginUrl(callbackUrl.toString(), "sso"), + "$riot:casUrl": tmpClient.getSsoLoginUrl(callbackUrl.toString(), "cas"), }} /> From de0895b88193aca8e01c61b4e175a7812317dfa2 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 14:06:21 +0000 Subject: [PATCH 8/9] i18n Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/i18n/strings/en_EN.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 4677f40ce1..fbb3fd9f6f 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -25,8 +25,6 @@ "Error": "Error", "Unable to load! Check your network connectivity and try again.": "Unable to load! Check your network connectivity and try again.", "Dismiss": "Dismiss", - "Single sign-on": "Single sign-on", - "Click here if you're not redirected automatically": "Click here if you're not redirected automatically", "Call Failed": "Call Failed", "There are unknown sessions in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "There are unknown sessions in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.", "Review Sessions": "Review Sessions", @@ -1872,6 +1870,7 @@ "Find other public servers or use a custom server": "Find other public servers or use a custom server", "Sign in to your Matrix account on %(serverName)s": "Sign in to your Matrix account on %(serverName)s", "Sign in to your Matrix account on ": "Sign in to your Matrix account on ", + "Sign in with SSO": "Sign in with SSO", "Sorry, your browser is not able to run Riot.": "Sorry, your browser is not able to run Riot.", "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.", "Please install Chrome, Firefox, or Safari for the best experience.": "Please install Chrome, Firefox, or Safari for the best experience.", From 9d0ed6e80040502fb8d8c3db359826133c97ab53 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 14:19:43 +0000 Subject: [PATCH 9/9] fix copy-pasta error Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/auth/Welcome.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index 1893b04d76..7cbcf65d3c 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -20,6 +20,7 @@ import SdkConfig from '../../../SdkConfig'; import AuthPage from "./AuthPage"; import * as Matrix from "matrix-js-sdk"; import {_td} from "../../../languageHandler"; +import PlatformPeg from "../../../PlatformPeg"; // translatable strings for Welcome pages _td("Sign in with SSO"); @@ -43,7 +44,8 @@ export default class Welcome extends React.PureComponent { baseUrl: hsUrl, idBaseUrl: isUrl, }); - const callbackUrl = this.getSSOCallbackUrl(tmpClient.getHomeserverUrl(), tmpClient.getIdentityServerUrl()); + const plaf = PlatformPeg.get(); + const callbackUrl = plaf.getSSOCallbackUrl(tmpClient.getHomeserverUrl(), tmpClient.getIdentityServerUrl()); return (