From b51b7dcfadcf26e5408e4d4f981edd251b5ce26c Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Tue, 20 Feb 2024 14:27:18 +0100 Subject: [PATCH] Iframe changes to SSO (#1899) * change(ui): iframe check for sso redirect * change(ui): removed login.js * change(ui): sso link * change(ui): sso link * change(ui): iframe check and sso redirect --- frontend/app/components/Login/Login.js | 224 ----------------------- frontend/app/components/Login/Login.tsx | 229 ++++++++++++++++++++++++ 2 files changed, 229 insertions(+), 224 deletions(-) delete mode 100644 frontend/app/components/Login/Login.js create mode 100644 frontend/app/components/Login/Login.tsx diff --git a/frontend/app/components/Login/Login.js b/frontend/app/components/Login/Login.js deleted file mode 100644 index 69c8fb521..000000000 --- a/frontend/app/components/Login/Login.js +++ /dev/null @@ -1,224 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import withPageTitle from 'HOCs/withPageTitle'; -import { Icon, Loader, Button, Link, Input, Form, Popover, Tooltip } from 'UI'; -import { login } from 'Duck/user'; -import { forgotPassword, signup } from 'App/routes'; -import ReCAPTCHA from 'react-google-recaptcha'; -import { withRouter } from 'react-router-dom'; -import stl from './login.module.css'; -import cn from 'classnames'; -import { setJwt } from 'Duck/user'; -import LoginBg from '../../svg/login-illustration.svg'; -import { ENTERPRISE_REQUEIRED } from 'App/constants'; -import { fetchTenants } from 'Duck/user'; -import Copyright from 'Shared/Copyright'; - -const FORGOT_PASSWORD = forgotPassword(); -const SIGNUP_ROUTE = signup(); -const recaptchaRef = React.createRef(); - -export default -@connect( - (state, props) => ({ - errors: state.getIn(['user', 'loginRequest', 'errors']), - loading: state.getIn(['user', 'loginRequest', 'loading']), - authDetails: state.getIn(['user', 'authDetails']), - params: new URLSearchParams(props.location.search), - }), - { login, setJwt, fetchTenants } -) -@withPageTitle('Login - OpenReplay') -@withRouter -class Login extends React.Component { - state = { - email: '', - password: '', - CAPTCHA_ENABLED: window.env.CAPTCHA_ENABLED === 'true', - }; - - static getDerivedStateFromProps(nextProps, prevState) { - const { authDetails } = nextProps; - if (Object.keys(authDetails).length === 0) { - return null; - } - - if (!authDetails.tenants) { - nextProps.history.push(SIGNUP_ROUTE); - } - - return null; - } - - componentDidMount() { - const { params } = this.props; - this.props.fetchTenants(); - const jwt = params.get('jwt'); - if (jwt) { - this.props.setJwt(jwt); - } - } - - handleSubmit = (token) => { - const { email, password } = this.state; - this.props.login({ email: email.trim(), password, 'g-recaptcha-response': token }); - }; - - onSubmit = (e) => { - e.preventDefault(); - const { CAPTCHA_ENABLED } = this.state; - if (CAPTCHA_ENABLED && recaptchaRef.current) { - recaptchaRef.current.execute(); - } else if (!CAPTCHA_ENABLED) { - this.handleSubmit(); - } - }; - - write = ({ target: { value, name } }) => this.setState({ [name]: value }); - - render() { - const { errors, loading, authDetails } = this.props; - const { CAPTCHA_ENABLED } = this.state; - - return ( -
-
-
- -
-
-

- Login to your account -

-
-
- - {CAPTCHA_ENABLED && ( - this.handleSubmit(token)} - /> - )} -
- - - - - - - - -
-
- {errors && errors.length ? ( -
- {errors.map((error) => ( -
- - - {error} -
-
-
- ))} -
- ) : null} - -
- - -
- Having trouble logging in?{' '} - - {'Reset password'} - -
-
-
- -
- {authDetails.sso ? ( - - - - ) : ( - - {authDetails.edition === 'ee' ? ( - - SSO has not been configured.
Please reach out to your admin. -
- ) : ( - ENTERPRISE_REQUEIRED - )} -
- } - placement="top" - > - - - )} -
-
-
- - - -
-
-
- - - - ); - } -} diff --git a/frontend/app/components/Login/Login.tsx b/frontend/app/components/Login/Login.tsx new file mode 100644 index 000000000..e4140308f --- /dev/null +++ b/frontend/app/components/Login/Login.tsx @@ -0,0 +1,229 @@ +import React, {useState, useEffect, useRef} from 'react'; +// import {useSelector, useDispatch} from 'react-redux'; +import {useHistory, useLocation} from 'react-router-dom'; +import {login, setJwt, fetchTenants} from 'Duck/user'; +import withPageTitle from 'HOCs/withPageTitle'; // Consider using a different approach for titles in functional components +import ReCAPTCHA from 'react-google-recaptcha'; +import {Button, Form, Input, Link, Loader, Popover, Tooltip, Icon} from 'UI'; +import {forgotPassword, signup} from 'App/routes'; +import LoginBg from '../../svg/login-illustration.svg'; +import {ENTERPRISE_REQUEIRED} from 'App/constants'; +import cn from 'classnames'; +import stl from './login.module.css'; +import Copyright from 'Shared/Copyright'; +import {connect} from 'react-redux'; + +const FORGOT_PASSWORD = forgotPassword(); +const SIGNUP_ROUTE = signup(); + +interface LoginProps { + errors: any; // Adjust the type based on your state shape + loading: boolean; + authDetails: any; // Adjust the type based on your state shape + login: typeof login; + setJwt: typeof setJwt; + fetchTenants: typeof fetchTenants; + location: Location; +} + +const Login: React.FC = ({errors, loading, authDetails, login, setJwt, fetchTenants, location}) => { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [CAPTCHA_ENABLED, setCAPTCHA_ENABLED] = useState(window.env.CAPTCHA_ENABLED === 'true'); + const recaptchaRef = useRef(null); + + const history = useHistory(); + const params = new URLSearchParams(location.search); + + useEffect(() => { + if (Object.keys(authDetails).length !== 0) { + if (!authDetails.tenants) { + history.push(SIGNUP_ROUTE); + } + } + }, [authDetails]); + + useEffect(() => { + fetchTenants() + const jwt = params.get('jwt'); + if (jwt) { + setJwt(jwt); + } + }, []); + + const handleSubmit = (token?: string) => { + login({email: email.trim(), password, 'g-recaptcha-response': token}); + }; + + const onSubmit = (e: React.FormEvent) => { + e.preventDefault(); + if (CAPTCHA_ENABLED && recaptchaRef.current) { + recaptchaRef.current.execute(); + } else if (!CAPTCHA_ENABLED) { + handleSubmit(); + } + }; + + const onSSOClick = () => { + if (window !== window.top) { // if in iframe + window.parent.location.href = `${window.location.origin}/api/sso/saml2?iFrame=true`; + } else { + window.location.href = `${window.location.origin}/api/sso/saml2`; + } + }; + + return ( +
+
+
+ +
+
+

+ Login to your account +

+
+
+ + {CAPTCHA_ENABLED && ( + handleSubmit(token)} + /> + )} +
+ + + setEmail(e.target.value)} + required + icon="envelope" + /> + + + + setPassword(e.target.value)} + required + icon="key" + /> + +
+
+ {errors && errors.length ? ( +
+ {errors.map((error) => ( +
+ + {error}
+
+ ))} +
+ ) : null} + +
+ + +
+ Having trouble logging in?{' '} + + {'Reset password'} + +
+
+
+ +
+ {authDetails.sso ? ( + + + + ) : ( + + {authDetails.edition === 'ee' ? ( + + SSO has not been configured.
Please reach out to your admin. +
+ ) : ( + ENTERPRISE_REQUEIRED + )} +
+ } + placement="top" + > + + + )} +
+
+ +
+
+ + + + ); +}; + +const mapStateToProps = (state: any, ownProps: any) => ({ + errors: state.getIn(['user', 'loginRequest', 'errors']), + loading: state.getIn(['user', 'loginRequest', 'loading']), + authDetails: state.getIn(['user', 'authDetails']), + params: new URLSearchParams(ownProps.location.search), +}); + +const mapDispatchToProps = { + login, + setJwt, + fetchTenants, +}; + +export default withPageTitle('Login - OpenReplay')( + connect(mapStateToProps, mapDispatchToProps)(Login) +); \ No newline at end of file