From 15ab288d2c6f589c4c53fbd837ae2f529ecc7bbd Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Wed, 25 Mar 2020 15:48:01 +0100 Subject: [PATCH 01/41] add authentication layer Signed-off-by: ChamseddineBhd --- .env | 5 ++ .env.development | 5 ++ package-lock.json | 36 ++++++++++++++ package.json | 2 + public/signin-callback.html | 30 ++++++++++++ public/silent-renew.html | 7 +++ src/components/app.js | 45 ++++++++++++++++- src/components/top-bar.js | 96 +++++++++++++++++++++++++++++++++++-- src/services/AuthService.js | 39 +++++++++++++++ src/translations/en.json | 4 ++ src/translations/fr.json | 3 ++ 11 files changed, 266 insertions(+), 6 deletions(-) create mode 100644 public/signin-callback.html create mode 100644 public/silent-renew.html create mode 100644 src/services/AuthService.js diff --git a/.env b/.env index 50bbb13e35..01ac8c0a71 100644 --- a/.env +++ b/.env @@ -1,2 +1,7 @@ REACT_APP_API_STUDY_SERVER=api/study-server REACT_APP_API_CASE_SERVER=api/case-server + +REACT_APP_CLIENT_ID=# +REACT_APP_CLIENT_ROOT=# +REACT_APP_CLIENT_SCOPE=# +REACT_APP_STS_AUTHORITY=# \ No newline at end of file diff --git a/.env.development b/.env.development index 017a0b6416..a1d06f4e92 100644 --- a/.env.development +++ b/.env.development @@ -1,2 +1,7 @@ REACT_APP_API_STUDY_SERVER=http://localhost:5001 REACT_APP_API_CASE_SERVER=http://localhost:5000 + +REACT_APP_CLIENT_ID=9c402461-b2ab-4767-9db3-66859bb0fcd0 +REACT_APP_CLIENT_ROOT=http://localhost:3000/ +REACT_APP_CLIENT_SCOPE='openid User.read email' +REACT_APP_STS_AUTHORITY=https://login.microsoftonline.com/7502dad5-d64c-46c7-9d47-b16f580fcfa9/v2.0 diff --git a/package-lock.json b/package-lock.json index 49f8b02a42..c16cbc21c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4528,6 +4528,11 @@ "randomfill": "^1.0.3" } }, + "crypto-js": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" + }, "css": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", @@ -8723,6 +8728,11 @@ } } }, + "jquery": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz", + "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==" + }, "js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", @@ -10053,6 +10063,24 @@ "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" }, + "oidc-client": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/oidc-client/-/oidc-client-1.10.1.tgz", + "integrity": "sha512-/QB5Nl7c9GmT9ir1E+OVY3+yZZnuk7Qa9ZEAJqSvDq0bAyAU9KAgeKipTEfKjGdGLTeOLy9FRWuNpULMkfZydQ==", + "requires": { + "base64-js": "^1.3.0", + "core-js": "^2.6.4", + "crypto-js": "^3.1.9-1", + "uuid": "^3.3.2" + }, + "dependencies": { + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" + } + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -13994,6 +14022,14 @@ "repeat-string": "^1.6.1" } }, + "toastr": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/toastr/-/toastr-2.1.4.tgz", + "integrity": "sha1-i0O+ZPudDEFIcURvLbjoyk6V8YE=", + "requires": { + "jquery": ">=1.12.0" + } + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", diff --git a/package.json b/package.json index d1c9ecb78b..c7961cde39 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "core-js": "^3.6.4", "deck.gl": "^8.0.0", "mjolnir.js": "^2.4.0", + "oidc-client": "^1.10.1", "qs": "^6.9.1", "react": "^16.12.0", "react-dom": "^16.12.0", @@ -21,6 +22,7 @@ "react-scripts": "3.3.0", "react-window": "^1.8.5", "redux": "^4.0.5", + "toastr": "^2.1.4", "typeface-roboto": "0.0.75" }, "scripts": { diff --git a/public/signin-callback.html b/public/signin-callback.html new file mode 100644 index 0000000000..d692646a12 --- /dev/null +++ b/public/signin-callback.html @@ -0,0 +1,30 @@ + + + + + Authentification callback processing.. + + + + + +

Authentification callback processing...

+ + + + + + + \ No newline at end of file diff --git a/public/silent-renew.html b/public/silent-renew.html new file mode 100644 index 0000000000..d91021c756 --- /dev/null +++ b/public/silent-renew.html @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/src/components/app.js b/src/components/app.js index 2252620bff..8eed225702 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import React from 'react'; +import React, {useEffect} from 'react'; import {useSelector} from 'react-redux' @@ -18,6 +18,7 @@ import StudyManager from './study-manager'; import TopBar from './top-bar'; import {LIGHT_THEME} from '../redux/actions' import Parameters from "./parameters"; +import { AuthService } from '../services/AuthService'; const lightTheme = createMuiTheme({ palette: { @@ -42,13 +43,20 @@ const getMuiTheme = (theme) => { }; const App = () => { + const authService = new AuthService(); const theme = useSelector(state => state.theme); + const [user, setUser] = React.useState(null); + const history = useHistory(); const location = useLocation(); + useEffect(() => { + getUser(); + }, []); + function studyClickHandler(studyName) { history.push("/studies/" + studyName); } @@ -62,11 +70,44 @@ const App = () => { } } + function login() { + authService.login(); + } + + function getUser() { + authService.getUser().then(user => { + if (user) { + console.log('User has been successfully loaded from store.'); + } else { + console.log('You are not logged in.'); + login(); + } + setUser(user); + console.log(user); + }); + } + + function renewToken() { + authService + .renewToken() + .then(user => { + console.debug('Token has been sucessfully renewed. :-)'); + this.getUser(); + }) + .catch(error => { + console.debug(error); + }); + } + + function logout() { + authService.logout(); + } + return ( - showParameters() }/> + showParameters() } onLogoutClick={() => logout()}/> studyClickHandler(name) }/> diff --git a/src/components/top-bar.js b/src/components/top-bar.js index 397fd426d4..0d52dafa75 100644 --- a/src/components/top-bar.js +++ b/src/components/top-bar.js @@ -10,11 +10,22 @@ import React from "react"; import {FormattedMessage} from "react-intl"; import AppBar from "@material-ui/core/AppBar"; -import IconButton from "@material-ui/core/IconButton"; +import ExitToAppIcon from '@material-ui/icons/ExitToApp'; + import {makeStyles} from "@material-ui/core/styles"; import Toolbar from "@material-ui/core/Toolbar"; import Typography from "@material-ui/core/Typography"; import SettingsIcon from '@material-ui/icons/Settings'; +import Button from '@material-ui/core/Button'; +import Menu from '@material-ui/core/Menu'; +import MenuItem from '@material-ui/core/MenuItem'; +import MenuIcon from '@material-ui/icons/Menu'; +import { withStyles } from '@material-ui/core/styles'; + +import ListItemIcon from '@material-ui/core/ListItemIcon'; +import ListItemText from '@material-ui/core/ListItemText'; + + import {ReactComponent as PowsyblLogo} from "../images/powsybl_logo.svg"; import PropTypes from "prop-types"; @@ -32,10 +43,53 @@ const useStyles = makeStyles(theme => ({ } })); +const StyledMenu = withStyles({ + paper: { + border: '1px solid #d3d4d5', + }, +})(props => ( + +)); + +const StyledMenuItem = withStyles(theme => ({ + root: { + '&:focus': { + backgroundColor: theme.palette.primary.main, + '& .MuiListItemIcon-root, & .MuiListItemText-primary': { + color: theme.palette.common.white, + }, + }, + }, +}))(MenuItem); + const TopBar = (props) => { const classes = useStyles(); + const [anchorEl, setAnchorEl] = React.useState(null); + const open = Boolean(anchorEl); + + const handleClick = event => { + console.log(event.currentTarget); + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + const onParametersClick = () => { if (props.onParametersClick) { props.onParametersClick(); @@ -50,9 +104,43 @@ const TopBar = (props) => {
- - - +

{props.name}

+ +
+ + + + + + + + + + + + + + + + + + + + + +
) diff --git a/src/services/AuthService.js b/src/services/AuthService.js new file mode 100644 index 0000000000..eca93d61d7 --- /dev/null +++ b/src/services/AuthService.js @@ -0,0 +1,39 @@ +import { Log, UserManager } from 'oidc-client'; + +export class AuthService { + userManager; + + constructor() { + console.log("hello"); + const settings = { + authority: process.env.REACT_APP_STS_AUTHORITY, + client_id: process.env.REACT_APP_CLIENT_ID, + redirect_uri: `${process.env.REACT_APP_CLIENT_ROOT}signin-callback.html`, + silent_redirect_uri: `${process.env.REACT_APP_CLIENT_ROOT}silent-renew.html`, + // tslint:disable-next-line:object-literal-sort-keys + post_logout_redirect_uri: `${process.env.REACT_APP_CLIENT_ROOT}`, + response_mode : 'fragment', + response_type: 'id_token token', + scope: process.env.REACT_APP_SCOPE, + }; + this.userManager = new UserManager(settings); + Log.logger = console; + Log.level = Log.INFO; + } + + getUser() { + return this.userManager.getUser(); + } + + login() { + return this.userManager.signinRedirect(); + } + + renewToken() { + return this.userManager.signinSilent(); + } + + logout() { + return this.userManager.signoutRedirect(); + } +} diff --git a/src/translations/en.json b/src/translations/en.json index 6060321ff8..c74bc58b3f 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -15,6 +15,10 @@ "delete" : "DELETE", "filter" : "Filter", + + "settings" : "Settings", + "logout" : "Logout", + "deleteStudy" : "Delete Study", "deleteStudyMsg" : "Are you sure you want to delete the study?", "studyNameDidNotMatchMsg" : "The given study name did not match with ", diff --git a/src/translations/fr.json b/src/translations/fr.json index 102f32d835..6df55ff1ef 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -15,6 +15,9 @@ "delete" : "SUPPRIMER", "filter" : "Filtre", + "settings" : "Paramètres", + "logout" : "Se déconnecter", + "deleteStudy" : "Supprimer l'étude", "deleteStudyMsg" : "Etes vous sur de vouloir supprimer l'étude?", "studyNameDidNotMatchMsg" : "Le nom d'étude donné ne correspond pas à ", From 2f89244d7cf800984788258afc54286557b7a317 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Wed, 25 Mar 2020 15:50:10 +0100 Subject: [PATCH 02/41] remove unused dependency Signed-off-by: ChamseddineBhd --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index c7961cde39..a000d5b276 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "react-scripts": "3.3.0", "react-window": "^1.8.5", "redux": "^4.0.5", - "toastr": "^2.1.4", "typeface-roboto": "0.0.75" }, "scripts": { From ceaaeb77427e93e967aae173dd32b56f5f28f797 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Wed, 25 Mar 2020 15:54:17 +0100 Subject: [PATCH 03/41] cosmetic changes Signed-off-by: ChamseddineBhd --- src/components/app.js | 5 ++--- src/components/top-bar.js | 31 ++++++++++++++----------------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/components/app.js b/src/components/app.js index 8eed225702..a225cba112 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -77,13 +77,12 @@ const App = () => { function getUser() { authService.getUser().then(user => { if (user) { - console.log('User has been successfully loaded from store.'); + console.debug('User has been successfully loaded from store.'); } else { - console.log('You are not logged in.'); + console.debug('You are not logged in.'); login(); } setUser(user); - console.log(user); }); } diff --git a/src/components/top-bar.js b/src/components/top-bar.js index 0d52dafa75..28cf635357 100644 --- a/src/components/top-bar.js +++ b/src/components/top-bar.js @@ -25,8 +25,6 @@ import { withStyles } from '@material-ui/core/styles'; import ListItemIcon from '@material-ui/core/ListItemIcon'; import ListItemText from '@material-ui/core/ListItemText'; - - import {ReactComponent as PowsyblLogo} from "../images/powsybl_logo.svg"; import PropTypes from "prop-types"; @@ -46,21 +44,20 @@ const useStyles = makeStyles(theme => ({ const StyledMenu = withStyles({ paper: { border: '1px solid #d3d4d5', - }, -})(props => ( - + },})(props => ( + )); const StyledMenuItem = withStyles(theme => ({ From 0bb964f8da0663aa7f42e6f80830ca2ce5e4b123 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Wed, 25 Mar 2020 21:25:56 +0100 Subject: [PATCH 04/41] remove logs Signed-off-by: ChamseddineBhd --- src/components/top-bar.js | 1 - src/services/AuthService.js | 1 - 2 files changed, 2 deletions(-) diff --git a/src/components/top-bar.js b/src/components/top-bar.js index 28cf635357..ef911dad78 100644 --- a/src/components/top-bar.js +++ b/src/components/top-bar.js @@ -79,7 +79,6 @@ const TopBar = (props) => { const open = Boolean(anchorEl); const handleClick = event => { - console.log(event.currentTarget); setAnchorEl(event.currentTarget); }; diff --git a/src/services/AuthService.js b/src/services/AuthService.js index eca93d61d7..02cfeb2cfa 100644 --- a/src/services/AuthService.js +++ b/src/services/AuthService.js @@ -4,7 +4,6 @@ export class AuthService { userManager; constructor() { - console.log("hello"); const settings = { authority: process.env.REACT_APP_STS_AUTHORITY, client_id: process.env.REACT_APP_CLIENT_ID, From 804961fbc309ae17e19e96f7e22f21176b0719d8 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Wed, 25 Mar 2020 23:31:09 +0100 Subject: [PATCH 05/41] delete callback html files, save user in store Signed-off-by: ChamseddineBhd --- public/signin-callback.html | 30 ----------- public/silent-renew.html | 7 --- src/components/app.js | 91 ++++++++++++++++++++------------- src/components/study-manager.js | 49 +++++++++++++++++- src/components/top-bar.js | 6 ++- src/redux/actions.js | 6 +++ src/redux/reducer.js | 10 +++- src/services/AuthService.js | 4 +- 8 files changed, 124 insertions(+), 79 deletions(-) delete mode 100644 public/signin-callback.html delete mode 100644 public/silent-renew.html diff --git a/public/signin-callback.html b/public/signin-callback.html deleted file mode 100644 index d692646a12..0000000000 --- a/public/signin-callback.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - Authentification callback processing.. - - - - - -

Authentification callback processing...

- - - - - - - \ No newline at end of file diff --git a/public/silent-renew.html b/public/silent-renew.html deleted file mode 100644 index d91021c756..0000000000 --- a/public/silent-renew.html +++ /dev/null @@ -1,7 +0,0 @@ - - \ No newline at end of file diff --git a/src/components/app.js b/src/components/app.js index a225cba112..ff2389a01b 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -19,6 +19,8 @@ import TopBar from './top-bar'; import {LIGHT_THEME} from '../redux/actions' import Parameters from "./parameters"; import { AuthService } from '../services/AuthService'; +import { UserManager } from 'oidc-client'; + const lightTheme = createMuiTheme({ palette: { @@ -42,21 +44,62 @@ const getMuiTheme = (theme) => { } }; +const SignInCallback = () => { + + function handleCallback() { + console.debug("handleCallback"); + new UserManager({ + response_mode: "fragment", + }).signinRedirectCallback().then(function () { + window.location = "/"; + }).catch(function (e) { + console.error(e); + }); + } + + useEffect(() => { + handleCallback(); + }, []); + + return ( +

Authentication callback processing...

+ ) +}; + +const SilentRenew = () => { + + function handleCallback() { + console.debug("SilentRenew"); + new UserManager({ + response_mode: "fragment", + }).signinSilentCallback().then(function () { + window.location = "/"; + }).catch(function (e) { + console.error(e); + }); + } + + useEffect(() => { + handleCallback(); + }, []); + + return ( +

Silent callback processing...

+ ) +}; + const App = () => { const authService = new AuthService(); const theme = useSelector(state => state.theme); const [user, setUser] = React.useState(null); + const [logOut, setLogOut] = React.useState(false); const history = useHistory(); const location = useLocation(); - useEffect(() => { - getUser(); - }, []); - function studyClickHandler(studyName) { history.push("/studies/" + studyName); } @@ -70,46 +113,18 @@ const App = () => { } } - function login() { - authService.login(); - } - - function getUser() { - authService.getUser().then(user => { - if (user) { - console.debug('User has been successfully loaded from store.'); - } else { - console.debug('You are not logged in.'); - login(); - } - setUser(user); - }); - } - - function renewToken() { - authService - .renewToken() - .then(user => { - console.debug('Token has been sucessfully renewed. :-)'); - this.getUser(); - }) - .catch(error => { - console.debug(error); - }); - } - function logout() { - authService.logout(); + setLogOut(true); } return ( - showParameters() } onLogoutClick={() => logout()}/> + showParameters() } onLogoutClick={() => logout()}/> - studyClickHandler(name) }/> + studyClickHandler(name) }/> @@ -117,6 +132,12 @@ const App = () => { + + + + + +

Error: bad URL; No matched Route.

diff --git a/src/components/study-manager.js b/src/components/study-manager.js index 68cfababec..a2b1efa674 100644 --- a/src/components/study-manager.js +++ b/src/components/study-manager.js @@ -31,9 +31,10 @@ import {ReactComponent as EntsoeLogo} from '../images/entsoe_logo.svg'; import {ReactComponent as UcteLogo} from '../images/ucte_logo.svg'; import {ReactComponent as IeeeLogo} from '../images/ieee_logo.svg'; -import {loadStudiesSuccess} from '../redux/actions'; +import {loadStudiesSuccess, setLoggedUser} from '../redux/actions'; import {fetchStudies, deleteStudy} from '../utils/rest-api'; import CreateStudyForm from "./create-study-form"; +import {AuthService} from "../services/AuthService"; const useStyles = makeStyles(theme => ({ addButton: { @@ -165,10 +166,47 @@ const StudyCard = (props) => { }; const StudyManager = (props) => { + const authService = new AuthService(); + + const [user, setUser] = React.useState(null); const dispatch = useDispatch(); + function login() { + authService.login(); + } + + function getUser() { + authService.getUser().then(user => { + if (user) { + dispatch(setLoggedUser(user)); + console.debug('User has been successfully loaded from store.'); + } else { + console.debug('You are not logged in.'); + login(); + } + setUser(user); + }); + } + + function renewToken() { + authService + .renewToken() + .then(user => { + console.debug('Token has been sucessfully renewed. :-)'); + getUser(); + }) + .catch(error => { + console.debug(error); + }); + } + + function logout() { + authService.logout(); + } + useEffect(() => { + getUser(); fetchStudies() .then(studies => { dispatch(loadStudiesSuccess(studies)); @@ -176,6 +214,15 @@ const StudyManager = (props) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + useEffect(() => { + if (props.logout === true) { + console.debug("logout"); + dispatch(setLoggedUser(null)); + logout(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [props.logout]); + const studies = useSelector(state => state.studies); const classes = useStyles(); diff --git a/src/components/top-bar.js b/src/components/top-bar.js index ef911dad78..b5078b507a 100644 --- a/src/components/top-bar.js +++ b/src/components/top-bar.js @@ -27,6 +27,7 @@ import ListItemText from '@material-ui/core/ListItemText'; import {ReactComponent as PowsyblLogo} from "../images/powsybl_logo.svg"; import PropTypes from "prop-types"; +import {useSelector} from "react-redux"; const useStyles = makeStyles(theme => ({ grow: { @@ -73,10 +74,11 @@ const StyledMenuItem = withStyles(theme => ({ const TopBar = (props) => { + const user = useSelector(state => state.user); + const classes = useStyles(); const [anchorEl, setAnchorEl] = React.useState(null); - const open = Boolean(anchorEl); const handleClick = event => { setAnchorEl(event.currentTarget); @@ -100,7 +102,7 @@ const TopBar = (props) => {
-

{props.name}

+

{user !== null ? user.profile.name : ""}

+
+ + + + + ); +}; + +export default Authentication; diff --git a/src/components/study-manager.js b/src/components/study-manager.js index 6ad4719559..0ad4d0b149 100644 --- a/src/components/study-manager.js +++ b/src/components/study-manager.js @@ -248,13 +248,12 @@ const StudyCard = ({study, onClick}) => { ); }; -const StudyManager = ({getUser, loggedOut, onStudyClick}) => { +const StudyManager = ({onStudyClick}) => { const dispatch = useDispatch(); const user = useSelector(state => state.user); useEffect(() => { - getUser(); fetchStudies() .then(studies => { dispatch(loadStudiesSuccess(studies)); @@ -266,24 +265,20 @@ const StudyManager = ({getUser, loggedOut, onStudyClick}) => { const classes = useStyles(); - if (user !== null) { - return ( - - - - { - studies.map(study => - - onStudyClick(study.studyName)}/> - - ) - } - - - ); - } else { - return (

User Should be logged

); - } + return ( + + + + { + studies.map(study => + + onStudyClick(study.studyName)}/> + + ) + } + + + ); }; export default StudyManager; diff --git a/src/components/top-bar.js b/src/components/top-bar.js index 86e658014f..d322b1c89a 100644 --- a/src/components/top-bar.js +++ b/src/components/top-bar.js @@ -112,8 +112,9 @@ const TopBar = (props) => {
-

{user !== null ? user.profile.name : "User Not logged"}

+

{user !== null ? user.profile.name : ""}

+ {user && (
- - - - - - - - - @@ -155,8 +148,8 @@ const TopBar = (props) => { -
+ )} ) diff --git a/src/redux/store.js b/src/redux/store.js index 6029d41366..c8aac95fe9 100644 --- a/src/redux/store.js +++ b/src/redux/store.js @@ -7,4 +7,5 @@ import {createStore} from 'redux' import {reducer} from './reducer' -export const store = createStore(reducer); \ No newline at end of file +export const store = createStore(reducer, + window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()); \ No newline at end of file From 30a3f7771bb75aeb289c6812e1f0c02c724202e9 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Mon, 30 Mar 2020 15:08:30 +0200 Subject: [PATCH 12/41] remove unused dependency Signed-off-by: ChamseddineBhd --- src/components/top-bar.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/top-bar.js b/src/components/top-bar.js index d322b1c89a..c2010ee77f 100644 --- a/src/components/top-bar.js +++ b/src/components/top-bar.js @@ -22,7 +22,6 @@ import Menu from '@material-ui/core/Menu'; import MenuItem from '@material-ui/core/MenuItem'; import MenuIcon from '@material-ui/icons/Menu'; import { withStyles } from '@material-ui/core/styles'; -import VpnKeyIcon from '@material-ui/icons/VpnKey'; import ListItemIcon from '@material-ui/core/ListItemIcon'; import ListItemText from '@material-ui/core/ListItemText'; From 9e099945bd4840dd0cad34e66111ff23bde0188f Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Mon, 30 Mar 2020 15:38:18 +0200 Subject: [PATCH 13/41] move authentication folder Signed-off-by: ChamseddineBhd --- src/components/app.js | 2 +- src/{ => utils}/authentication/AuthService.js | 0 src/{ => utils}/authentication/UserManagerMock.js | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/{ => utils}/authentication/AuthService.js (100%) rename src/{ => utils}/authentication/UserManagerMock.js (98%) diff --git a/src/components/app.js b/src/components/app.js index 80ce7845a0..d9d0fc9e66 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -18,7 +18,7 @@ import StudyManager from './study-manager'; import TopBar from './top-bar'; import {LIGHT_THEME, setLoggedUser} from '../redux/actions' import Parameters from "./parameters"; -import { AuthService } from '../authentication/AuthService'; +import { AuthService } from '../utils/authentication/AuthService'; import Authentication from "./authentication"; const lightTheme = createMuiTheme({ diff --git a/src/authentication/AuthService.js b/src/utils/authentication/AuthService.js similarity index 100% rename from src/authentication/AuthService.js rename to src/utils/authentication/AuthService.js diff --git a/src/authentication/UserManagerMock.js b/src/utils/authentication/UserManagerMock.js similarity index 98% rename from src/authentication/UserManagerMock.js rename to src/utils/authentication/UserManagerMock.js index 7c87e5552b..a988f7fd09 100644 --- a/src/authentication/UserManagerMock.js +++ b/src/utils/authentication/UserManagerMock.js @@ -10,7 +10,7 @@ export class UserManagerMock { } signinRedirect() { - window.location = "/sign-in-callback"; + window.location = "./sign-in-callback"; return Promise.resolve(null); } @@ -20,7 +20,7 @@ export class UserManagerMock { signoutRedirect() { sessionStorage.setItem("powsybl-study-app-mock-user", null); - window.location = "/"; + window.location = "."; return Promise.resolve(null); } signinRedirectCallback() { From f718cbfc14a86a3b1960451412472b05593509a7 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Mon, 30 Mar 2020 16:30:50 +0200 Subject: [PATCH 14/41] update AuthService.js Signed-off-by: ChamseddineBhd --- src/components/app.js | 12 +++++++----- src/utils/authentication/AuthService.js | 18 +++++------------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/components/app.js b/src/components/app.js index d9d0fc9e66..d42d06e890 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -18,7 +18,7 @@ import StudyManager from './study-manager'; import TopBar from './top-bar'; import {LIGHT_THEME, setLoggedUser} from '../redux/actions' import Parameters from "./parameters"; -import { AuthService } from '../utils/authentication/AuthService'; +import { userManager } from '../utils/authentication/AuthService'; import Authentication from "./authentication"; const lightTheme = createMuiTheme({ @@ -47,7 +47,7 @@ const SignInCallback = ({getUser}) => { const history = useHistory(); function handleCallback() { - AuthService.getUserManager().signinRedirectCallback().then(function () { + userManager.signinRedirectCallback().then(function () { getUser(); history.push("/"); }).catch(function (e) { @@ -65,6 +65,8 @@ const SignInCallback = ({getUser}) => { }; const App = () => { + console.log(userManager); + const theme = useSelector(state => state.theme); const user = useSelector(state => state.user); @@ -89,11 +91,11 @@ const App = () => { } function login() { - AuthService.getUserManager().signinRedirect().then(() => console.debug("login")); + userManager.signinRedirect().then(() => console.debug("login")); } function getUser() { - AuthService.getUserManager().getUser().then(user => { + userManager.getUser().then(user => { if (user) { dispatch(setLoggedUser(user)); console.debug('User has been successfully loaded from store.'); @@ -105,7 +107,7 @@ const App = () => { function logout() { dispatch(setLoggedUser(null)); - AuthService.getUserManager().signoutRedirect().then( + userManager.signoutRedirect().then( () => console.debug("logged out")); } diff --git a/src/utils/authentication/AuthService.js b/src/utils/authentication/AuthService.js index 445531a2a4..7d5d78ea02 100644 --- a/src/utils/authentication/AuthService.js +++ b/src/utils/authentication/AuthService.js @@ -1,24 +1,16 @@ -import { Log, UserManager } from 'oidc-client'; +import {UserManager} from 'oidc-client'; import {UserManagerMock} from "./UserManagerMock"; -export class AuthService { - static settings = { +const settings = { authority: process.env.REACT_APP_STS_AUTHORITY, client_id: process.env.REACT_APP_CLIENT_ID, redirect_uri: `${process.env.REACT_APP_CLIENT_ROOT}sign-in-callback`, silent_redirect_uri: `${process.env.REACT_APP_CLIENT_ROOT}silent-renew`, - // tslint:disable-next-line:object-literal-sort-keys post_logout_redirect_uri: `${process.env.REACT_APP_CLIENT_ROOT}`, response_mode : 'fragment', response_type: 'id_token token', scope: process.env.REACT_APP_SCOPE, - }; +}; - static userManager = process.env.REACT_APP_USE_AUTHENTICATION === "true" ? new UserManager(this.settings) : new UserManagerMock(this.settings); - - static getUserManager() { - Log.logger = console; - Log.level = Log.INFO; - return this.userManager; - } -} +const userManager = process.env.REACT_APP_USE_AUTHENTICATION === "true" ? new UserManager(settings) : new UserManagerMock(settings); +export {userManager} From f589f73b7f35438d92ed2f488d16652407b130d2 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Mon, 30 Mar 2020 16:36:13 +0200 Subject: [PATCH 15/41] secure paramater & studPane pages Signed-off-by: ChamseddineBhd --- src/components/app.js | 8 ++++++-- src/components/study-manager.js | 2 -- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/app.js b/src/components/app.js index d42d06e890..40729b0d10 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -127,10 +127,14 @@ const App = () => { } - + { + user !== null ? () : ( login()}/>) + } - + { + user !== null ? () : ( login()}/>) + } diff --git a/src/components/study-manager.js b/src/components/study-manager.js index 0ad4d0b149..eec698a13c 100644 --- a/src/components/study-manager.js +++ b/src/components/study-manager.js @@ -251,8 +251,6 @@ const StudyCard = ({study, onClick}) => { const StudyManager = ({onStudyClick}) => { const dispatch = useDispatch(); - const user = useSelector(state => state.user); - useEffect(() => { fetchStudies() .then(studies => { From b2a328bc9c299d14d56ee8dfd455bc573bab0f0c Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Mon, 30 Mar 2020 16:45:16 +0200 Subject: [PATCH 16/41] cosmetic changes Signed-off-by: ChamseddineBhd --- src/components/authentication.js | 6 +++--- src/translations/en.json | 1 + src/translations/fr.json | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/authentication.js b/src/components/authentication.js index 30ed04b469..138e0a2ae6 100644 --- a/src/components/authentication.js +++ b/src/components/authentication.js @@ -30,7 +30,8 @@ const useStyles = makeStyles((theme) => ({ }, submit: { margin: theme.spacing(3, 0, 2), - }, + borderRadius: '30px' + }, logo: { width: 64, height: 64, @@ -66,14 +67,13 @@ const Authentication = (props) => {
diff --git a/src/translations/en.json b/src/translations/en.json index 7d6388f47b..01c6e4b1a7 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -19,6 +19,7 @@ "settings" : "Settings", "logout" : "Logout", "login" : "Login", + "connection": "Connection", "deleteStudy" : "Delete Study", "deleteStudyMsg" : "Are you sure you want to delete the study?", diff --git a/src/translations/fr.json b/src/translations/fr.json index d1cf92773f..02811781ca 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -18,6 +18,7 @@ "settings" : "Paramètres", "logout" : "Se déconnecter", "login" : "Se connecter", + "connection": "Connexion", "deleteStudy" : "Supprimer l'étude", "deleteStudyMsg" : "Etes vous sur de vouloir supprimer l'étude?", From abb8a389e4aea31f994a87d38cd36ad34af2fc07 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Mon, 30 Mar 2020 16:47:35 +0200 Subject: [PATCH 17/41] cosmetic changes Signed-off-by: ChamseddineBhd --- .env.development | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.env.development b/.env.development index d00e9d3b51..84fe4941a5 100644 --- a/.env.development +++ b/.env.development @@ -1,7 +1,3 @@ -REACT_APP_API_STUDY_SERVER=http://localhost:5001 -REACT_APP_API_CASE_SERVER=http://localhost:5000 - - REACT_APP_CLIENT_ID=9c402461-b2ab-4767-9db3-66859bb0fcd0 REACT_APP_CLIENT_ROOT=http://localhost:3000/ REACT_APP_CLIENT_SCOPE='openid User.read email' From fe4d4609280c148af9d64695b0c1ba4ac968b4b3 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Mon, 30 Mar 2020 16:55:56 +0200 Subject: [PATCH 18/41] remove log message Signed-off-by: ChamseddineBhd --- src/components/app.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/app.js b/src/components/app.js index 40729b0d10..4d9b17b71f 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -65,8 +65,6 @@ const SignInCallback = ({getUser}) => { }; const App = () => { - console.log(userManager); - const theme = useSelector(state => state.theme); const user = useSelector(state => state.user); From 9a054b652b37220903817540fc4c6baffbdae3d0 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Tue, 31 Mar 2020 16:47:33 +0200 Subject: [PATCH 19/41] remove unused function call Signed-off-by: ChamseddineBhd --- src/components/app.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/app.js b/src/components/app.js index 4d9b17b71f..7174ad48f6 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -109,10 +109,6 @@ const App = () => { () => console.debug("logged out")); } - useEffect(() => { - getUser(); - }, []); - return ( From 9e263744cfe79ad14b4e5be047bdb2bae3792f90 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Tue, 31 Mar 2020 16:52:20 +0200 Subject: [PATCH 20/41] remove debug idp values Signed-off-by: ChamseddineBhd --- .env.development | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.env.development b/.env.development index 84fe4941a5..133c3bbf63 100644 --- a/.env.development +++ b/.env.development @@ -1,5 +1,5 @@ -REACT_APP_CLIENT_ID=9c402461-b2ab-4767-9db3-66859bb0fcd0 -REACT_APP_CLIENT_ROOT=http://localhost:3000/ -REACT_APP_CLIENT_SCOPE='openid User.read email' -REACT_APP_STS_AUTHORITY=https://login.microsoftonline.com/7502dad5-d64c-46c7-9d47-b16f580fcfa9/v2.0 +REACT_APP_CLIENT_ID=# +REACT_APP_CLIENT_ROOT=# +REACT_APP_CLIENT_SCOPE=# +REACT_APP_STS_AUTHORITY=# REACT_APP_USE_AUTHENTICATION=false From 993589e8a16a9c67e9ebb32bd236521a6c986cbe Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Tue, 31 Mar 2020 17:22:13 +0200 Subject: [PATCH 21/41] save previous route when logging in Signed-off-by: ChamseddineBhd --- src/components/app.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/app.js b/src/components/app.js index 7174ad48f6..d7e515c5a7 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -49,7 +49,8 @@ const SignInCallback = ({getUser}) => { function handleCallback() { userManager.signinRedirectCallback().then(function () { getUser(); - history.push("/"); + const previousPath = sessionStorage.getItem("powsybl-study-app-current-path"); + history.push(previousPath); }).catch(function (e) { console.error(e); }); @@ -89,6 +90,8 @@ const App = () => { } function login() { + sessionStorage.setItem("powsybl-study-app-current-path", window.location.pathname); + console.log(window.location.pathname); userManager.signinRedirect().then(() => console.debug("login")); } From 2e2952abc5e5428bbd17d5fba69ac51f6ddcd76f Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Tue, 31 Mar 2020 17:49:04 +0200 Subject: [PATCH 22/41] save previous query params Signed-off-by: ChamseddineBhd --- src/components/app.js | 51 ++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/components/app.js b/src/components/app.js index d7e515c5a7..dec29332c3 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -90,8 +90,7 @@ const App = () => { } function login() { - sessionStorage.setItem("powsybl-study-app-current-path", window.location.pathname); - console.log(window.location.pathname); + sessionStorage.setItem("powsybl-study-app-current-path", location.pathname + location.search); userManager.signinRedirect().then(() => console.debug("login")); } @@ -117,29 +116,31 @@ const App = () => { showParameters()} onLogoutClick={() => logout()}/> - - - { - user !== null ? ( studyClickHandler(name)}/>) : ( login()}/>) - } - - - { - user !== null ? () : ( login()}/>) - } - - - { - user !== null ? () : ( login()}/>) - } - - - - - -

Error: bad URL; No matched Route.

-
-
+ { user !== null ? ( + + + studyClickHandler(name)}/>) + + + + + + + + +

Error: bad URL; No matched Route.

+
+
) + : ( + + + + + + login()}/> + + + )}
) From ddf91cca821a6f6bad55c12bd9bd40924f743b45 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Tue, 31 Mar 2020 18:26:53 +0200 Subject: [PATCH 23/41] cosmetic changes Signed-off-by: ChamseddineBhd --- package-lock.json | 18 ++++++++++++++++++ src/components/app.js | 12 ++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5374850737..9c3b98eb37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12039,6 +12039,11 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==" }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, "react-map-gl": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/react-map-gl/-/react-map-gl-5.2.3.tgz", @@ -12193,6 +12198,19 @@ "prop-types": "^15.6.2" } }, + "react-virtualized": { + "version": "9.21.2", + "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.21.2.tgz", + "integrity": "sha512-oX7I7KYiUM7lVXQzmhtF4Xg/4UA5duSA+/ZcAvdWlTLFCoFYq1SbauJT5gZK9cZS/wdYR6TPGpX/dqzvTqQeBA==", + "requires": { + "babel-runtime": "^6.26.0", + "clsx": "^1.0.1", + "dom-helpers": "^5.0.0", + "loose-envify": "^1.3.0", + "prop-types": "^15.6.0", + "react-lifecycles-compat": "^3.0.4" + } + }, "react-virtualized-auto-sizer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz", diff --git a/src/components/app.js b/src/components/app.js index dec29332c3..cb34f9d153 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -91,14 +91,14 @@ const App = () => { function login() { sessionStorage.setItem("powsybl-study-app-current-path", location.pathname + location.search); - userManager.signinRedirect().then(() => console.debug("login")); + return userManager.signinRedirect().then(() => console.debug("login")); } - function getUser() { - userManager.getUser().then(user => { + function dispatchUser() { + return userManager.getUser().then(user => { if (user) { - dispatch(setLoggedUser(user)); console.debug('User has been successfully loaded from store.'); + return dispatch(setLoggedUser(user)); } else { console.debug('You are not logged in.'); } @@ -107,7 +107,7 @@ const App = () => { function logout() { dispatch(setLoggedUser(null)); - userManager.signoutRedirect().then( + return userManager.signoutRedirect().then( () => console.debug("logged out")); } @@ -134,7 +134,7 @@ const App = () => { : ( - + login()}/> From c69c36721dd732f5a0c82168746ca449d0aec719 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Tue, 31 Mar 2020 18:28:30 +0200 Subject: [PATCH 24/41] cosmetic changes Signed-off-by: ChamseddineBhd --- src/redux/store.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/redux/store.js b/src/redux/store.js index c8aac95fe9..6029d41366 100644 --- a/src/redux/store.js +++ b/src/redux/store.js @@ -7,5 +7,4 @@ import {createStore} from 'redux' import {reducer} from './reducer' -export const store = createStore(reducer, - window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()); \ No newline at end of file +export const store = createStore(reducer); \ No newline at end of file From 1d78ce49336825cdd9448b91755ef41455aa13e1 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Tue, 31 Mar 2020 18:35:25 +0200 Subject: [PATCH 25/41] remove silent redirect param Signed-off-by: ChamseddineBhd --- src/utils/authentication/AuthService.js | 1 - src/utils/authentication/UserManagerMock.js | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/utils/authentication/AuthService.js b/src/utils/authentication/AuthService.js index 7d5d78ea02..ef9b3c758b 100644 --- a/src/utils/authentication/AuthService.js +++ b/src/utils/authentication/AuthService.js @@ -5,7 +5,6 @@ const settings = { authority: process.env.REACT_APP_STS_AUTHORITY, client_id: process.env.REACT_APP_CLIENT_ID, redirect_uri: `${process.env.REACT_APP_CLIENT_ROOT}sign-in-callback`, - silent_redirect_uri: `${process.env.REACT_APP_CLIENT_ROOT}silent-renew`, post_logout_redirect_uri: `${process.env.REACT_APP_CLIENT_ROOT}`, response_mode : 'fragment', response_type: 'id_token token', diff --git a/src/utils/authentication/UserManagerMock.js b/src/utils/authentication/UserManagerMock.js index a988f7fd09..54274247e3 100644 --- a/src/utils/authentication/UserManagerMock.js +++ b/src/utils/authentication/UserManagerMock.js @@ -14,10 +14,6 @@ export class UserManagerMock { return Promise.resolve(null); } - signinSilent() { - return Promise.resolve(null); - } - signoutRedirect() { sessionStorage.setItem("powsybl-study-app-mock-user", null); window.location = "."; From 89714e73227813652fcc99f48d6eb5d34424b6e7 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Wed, 1 Apr 2020 14:58:18 +0200 Subject: [PATCH 26/41] add idp settings object Signed-off-by: ChamseddineBhd --- .env | 6 +-- .env.development | 5 -- public/idpSettings.json | 7 +++ src/components/app.js | 71 ++++++++++++++++--------- src/utils/authentication/AuthService.js | 27 +++++----- 5 files changed, 70 insertions(+), 46 deletions(-) delete mode 100644 .env.development create mode 100644 public/idpSettings.json diff --git a/.env b/.env index 5dbbb63ba9..f8c95657cf 100644 --- a/.env +++ b/.env @@ -1,8 +1,4 @@ REACT_APP_API_STUDY_SERVER=api/study-server REACT_APP_API_CASE_SERVER=api/case-server -REACT_APP_CLIENT_ID=# -REACT_APP_CLIENT_ROOT=# -REACT_APP_CLIENT_SCOPE=# -REACT_APP_STS_AUTHORITY=# -REACT_APP_USE_AUTHENTICATION=true +REACT_APP_USE_AUTHENTICATION=false diff --git a/.env.development b/.env.development deleted file mode 100644 index 133c3bbf63..0000000000 --- a/.env.development +++ /dev/null @@ -1,5 +0,0 @@ -REACT_APP_CLIENT_ID=# -REACT_APP_CLIENT_ROOT=# -REACT_APP_CLIENT_SCOPE=# -REACT_APP_STS_AUTHORITY=# -REACT_APP_USE_AUTHENTICATION=false diff --git a/public/idpSettings.json b/public/idpSettings.json new file mode 100644 index 0000000000..1b697e57f8 --- /dev/null +++ b/public/idpSettings.json @@ -0,0 +1,7 @@ +{ + "authority" : "https://login.microsoftonline.com/7502dad5-d64c-46c7-9d47-b16f580fcfa9/v2.0", + "client_id" : "9c402461-b2ab-4767-9db3-66859bb0fcd0", + "redirect_uri": "http://localhost:3000/sign-in-callback", + "post_logout_redirect_uri" : "http://localhost:3000", + "scope" : "openid User.read email" +} diff --git a/src/components/app.js b/src/components/app.js index cb34f9d153..f2fa325fe8 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import React, {useEffect} from 'react'; +import React, {useEffect, useState} from 'react'; import {useDispatch, useSelector} from 'react-redux' @@ -18,7 +18,7 @@ import StudyManager from './study-manager'; import TopBar from './top-bar'; import {LIGHT_THEME, setLoggedUser} from '../redux/actions' import Parameters from "./parameters"; -import { userManager } from '../utils/authentication/AuthService'; +import {userManagerPromise} from '../utils/authentication/AuthService'; import Authentication from "./authentication"; const lightTheme = createMuiTheme({ @@ -43,39 +43,56 @@ const getMuiTheme = (theme) => { } }; -const SignInCallback = ({getUser}) => { +const SignInCallback = (props) => { const history = useHistory(); function handleCallback() { - userManager.signinRedirectCallback().then(function () { - getUser(); - const previousPath = sessionStorage.getItem("powsybl-study-app-current-path"); - history.push(previousPath); - }).catch(function (e) { - console.error(e); - }); + if (props.userManager.instance && !props.userManager.error) { + props.userManager.instance.signinRedirectCallback().then(function () { + props.getUser(); + const previousPath = sessionStorage.getItem("powsybl-study-app-current-path"); + history.push(previousPath); + }).catch(function (e) { + console.error(e); + }); + } } useEffect(() => { handleCallback(); - }, []); + }, [props.userManager]); return (

) }; +const noUserManager = {instance: null, error: null}; + const App = () => { const theme = useSelector(state => state.theme); const user = useSelector(state => state.user); + const [userManager, setUserManager] = useState(noUserManager); + const history = useHistory(); const dispatch = useDispatch(); const location = useLocation(); + useEffect(() => { + userManagerPromise + .then(userManager => { + setUserManager({instance : userManager, error : null }); + }) + .catch(function(error) { + setUserManager({instance : null, error : error.message}); + console.debug("error when importing the idp settings") + }); + }, []); + function studyClickHandler(studyName) { history.push("/studies/" + studyName); } @@ -91,24 +108,30 @@ const App = () => { function login() { sessionStorage.setItem("powsybl-study-app-current-path", location.pathname + location.search); - return userManager.signinRedirect().then(() => console.debug("login")); + if (userManager.instance && !userManager.error) { + return userManager.instance.signinRedirect().then(() => console.debug("login")); + } } function dispatchUser() { - return userManager.getUser().then(user => { - if (user) { - console.debug('User has been successfully loaded from store.'); - return dispatch(setLoggedUser(user)); - } else { - console.debug('You are not logged in.'); - } - }); + if (userManager.instance && !userManager.error) { + return userManager.instance.getUser().then(user => { + if (user) { + console.debug('User has been successfully loaded from store.'); + return dispatch(setLoggedUser(user)); + } else { + console.debug('You are not logged in.'); + } + }); + } } function logout() { - dispatch(setLoggedUser(null)); - return userManager.signoutRedirect().then( - () => console.debug("logged out")); + if (userManager.instance && !userManager.error) { + dispatch(setLoggedUser(null)); + return userManager.instance.signoutRedirect().then( + () => console.debug("logged out")); + } } return ( @@ -134,7 +157,7 @@ const App = () => { : ( - + login()}/> diff --git a/src/utils/authentication/AuthService.js b/src/utils/authentication/AuthService.js index ef9b3c758b..d453f51cf3 100644 --- a/src/utils/authentication/AuthService.js +++ b/src/utils/authentication/AuthService.js @@ -1,15 +1,18 @@ import {UserManager} from 'oidc-client'; import {UserManagerMock} from "./UserManagerMock"; -const settings = { - authority: process.env.REACT_APP_STS_AUTHORITY, - client_id: process.env.REACT_APP_CLIENT_ID, - redirect_uri: `${process.env.REACT_APP_CLIENT_ROOT}sign-in-callback`, - post_logout_redirect_uri: `${process.env.REACT_APP_CLIENT_ROOT}`, - response_mode : 'fragment', - response_type: 'id_token token', - scope: process.env.REACT_APP_SCOPE, -}; - -const userManager = process.env.REACT_APP_USE_AUTHENTICATION === "true" ? new UserManager(settings) : new UserManagerMock(settings); -export {userManager} +const userManagerPromise = fetch('idpSettings.json') + .then(r => r.json()) + .then(idpSettings => { + let settings = { + authority: idpSettings.authority, + client_id: idpSettings.client_id, + redirect_uri: idpSettings.redirect_uri, + post_logout_redirect_uri: idpSettings.post_logout_redirect_uri, + response_mode : 'fragment', + response_type: 'id_token token', + scope: process.env.REACT_APP_SCOPE, + }; + return process.env.REACT_APP_USE_AUTHENTICATION === "true" ? new UserManager(settings) : new UserManagerMock(settings); + }); +export {userManagerPromise} From ce45795d6311aceed7092a1cc41be9d23efc128d Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Wed, 1 Apr 2020 15:18:12 +0200 Subject: [PATCH 27/41] copyright Signed-off-by: ChamseddineBhd --- src/utils/authentication/AuthService.js | 6 ++++++ src/utils/authentication/UserManagerMock.js | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/utils/authentication/AuthService.js b/src/utils/authentication/AuthService.js index d453f51cf3..2477e2fe24 100644 --- a/src/utils/authentication/AuthService.js +++ b/src/utils/authentication/AuthService.js @@ -1,3 +1,9 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ import {UserManager} from 'oidc-client'; import {UserManagerMock} from "./UserManagerMock"; diff --git a/src/utils/authentication/UserManagerMock.js b/src/utils/authentication/UserManagerMock.js index 54274247e3..c6000e4175 100644 --- a/src/utils/authentication/UserManagerMock.js +++ b/src/utils/authentication/UserManagerMock.js @@ -1,3 +1,9 @@ +/** + * Copyright (c) 2020, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ export class UserManagerMock { settings; From c6615bc7c0f8ca812483ce17a9316238ca50fe99 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Thu, 2 Apr 2020 12:02:34 +0200 Subject: [PATCH 28/41] add scope from idp settings Signed-off-by: ChamseddineBhd --- .env | 2 +- public/idpSettings.json | 5 +++-- src/utils/authentication/AuthService.js | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.env b/.env index f8c95657cf..b03b378409 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ REACT_APP_API_STUDY_SERVER=api/study-server REACT_APP_API_CASE_SERVER=api/case-server -REACT_APP_USE_AUTHENTICATION=false +REACT_APP_USE_AUTHENTICATION=true diff --git a/public/idpSettings.json b/public/idpSettings.json index 1b697e57f8..ef40bd8d65 100644 --- a/public/idpSettings.json +++ b/public/idpSettings.json @@ -1,6 +1,7 @@ { - "authority" : "https://login.microsoftonline.com/7502dad5-d64c-46c7-9d47-b16f580fcfa9/v2.0", - "client_id" : "9c402461-b2ab-4767-9db3-66859bb0fcd0", + "authority" : "http://localhost:9090", + "client_id" : "my-client", + "client_secret" : "my-secret", "redirect_uri": "http://localhost:3000/sign-in-callback", "post_logout_redirect_uri" : "http://localhost:3000", "scope" : "openid User.read email" diff --git a/src/utils/authentication/AuthService.js b/src/utils/authentication/AuthService.js index 2477e2fe24..fd6b7acef1 100644 --- a/src/utils/authentication/AuthService.js +++ b/src/utils/authentication/AuthService.js @@ -13,11 +13,12 @@ const userManagerPromise = fetch('idpSettings.json') let settings = { authority: idpSettings.authority, client_id: idpSettings.client_id, + client_secret: idpSettings.client_secret, redirect_uri: idpSettings.redirect_uri, post_logout_redirect_uri: idpSettings.post_logout_redirect_uri, response_mode : 'fragment', response_type: 'id_token token', - scope: process.env.REACT_APP_SCOPE, + scope: idpSettings.scope, }; return process.env.REACT_APP_USE_AUTHENTICATION === "true" ? new UserManager(settings) : new UserManagerMock(settings); }); From 8aaf9cacf99b95215016fd23b34554bdab46825f Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Thu, 2 Apr 2020 15:17:28 +0200 Subject: [PATCH 29/41] remove client secret param Signed-off-by: ChamseddineBhd --- public/idpSettings.json | 1 - src/utils/authentication/AuthService.js | 1 - 2 files changed, 2 deletions(-) diff --git a/public/idpSettings.json b/public/idpSettings.json index ef40bd8d65..52f669f1a8 100644 --- a/public/idpSettings.json +++ b/public/idpSettings.json @@ -1,7 +1,6 @@ { "authority" : "http://localhost:9090", "client_id" : "my-client", - "client_secret" : "my-secret", "redirect_uri": "http://localhost:3000/sign-in-callback", "post_logout_redirect_uri" : "http://localhost:3000", "scope" : "openid User.read email" diff --git a/src/utils/authentication/AuthService.js b/src/utils/authentication/AuthService.js index fd6b7acef1..12fc8e79d5 100644 --- a/src/utils/authentication/AuthService.js +++ b/src/utils/authentication/AuthService.js @@ -13,7 +13,6 @@ const userManagerPromise = fetch('idpSettings.json') let settings = { authority: idpSettings.authority, client_id: idpSettings.client_id, - client_secret: idpSettings.client_secret, redirect_uri: idpSettings.redirect_uri, post_logout_redirect_uri: idpSettings.post_logout_redirect_uri, response_mode : 'fragment', From a05235cadad5f1ce173b3f37d674d7d7a5be4766 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Thu, 2 Apr 2020 16:43:23 +0200 Subject: [PATCH 30/41] update AuthService Signed-off-by: ChamseddineBhd --- public/idpSettings.json | 2 +- src/utils/authentication/AuthService.js | 33 ++++++++++++++----------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/public/idpSettings.json b/public/idpSettings.json index 52f669f1a8..46266e3077 100644 --- a/public/idpSettings.json +++ b/public/idpSettings.json @@ -1,5 +1,5 @@ { - "authority" : "http://localhost:9090", + "authority" : "http://localhost:9080", "client_id" : "my-client", "redirect_uri": "http://localhost:3000/sign-in-callback", "post_logout_redirect_uri" : "http://localhost:3000", diff --git a/src/utils/authentication/AuthService.js b/src/utils/authentication/AuthService.js index 12fc8e79d5..82007cdcf4 100644 --- a/src/utils/authentication/AuthService.js +++ b/src/utils/authentication/AuthService.js @@ -6,19 +6,24 @@ */ import {UserManager} from 'oidc-client'; import {UserManagerMock} from "./UserManagerMock"; +let userManagerPromise; +if (process.env.REACT_APP_USE_AUTHENTICATION === "true") { + userManagerPromise = fetch('idpSettings.json') + .then(r => r.json()) + .then(idpSettings => { + let settings = { + authority: idpSettings.authority, + client_id: idpSettings.client_id, + redirect_uri: idpSettings.redirect_uri, + post_logout_redirect_uri: idpSettings.post_logout_redirect_uri, + response_mode: 'fragment', + response_type: 'id_token token', + scope: idpSettings.scope, + }; + return new UserManager(settings); + }); +} else { + userManagerPromise = Promise.resolve( new UserManagerMock({})); +} -const userManagerPromise = fetch('idpSettings.json') - .then(r => r.json()) - .then(idpSettings => { - let settings = { - authority: idpSettings.authority, - client_id: idpSettings.client_id, - redirect_uri: idpSettings.redirect_uri, - post_logout_redirect_uri: idpSettings.post_logout_redirect_uri, - response_mode : 'fragment', - response_type: 'id_token token', - scope: idpSettings.scope, - }; - return process.env.REACT_APP_USE_AUTHENTICATION === "true" ? new UserManager(settings) : new UserManagerMock(settings); - }); export {userManagerPromise} From d89465f1ee6f6cbf3e1fc44d69e6e5dc619b7b60 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Thu, 2 Apr 2020 16:43:56 +0200 Subject: [PATCH 31/41] add .env.development Signed-off-by: ChamseddineBhd --- .env.development | 1 + 1 file changed, 1 insertion(+) create mode 100644 .env.development diff --git a/.env.development b/.env.development new file mode 100644 index 0000000000..2f1d4e1a45 --- /dev/null +++ b/.env.development @@ -0,0 +1 @@ +REACT_APP_USE_AUTHENTICATION=false From 5232d3d53cdffdd18ec2458ad6e48056d647f597 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Thu, 2 Apr 2020 16:49:49 +0200 Subject: [PATCH 32/41] empty idpSettings Signed-off-by: ChamseddineBhd --- public/idpSettings.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/public/idpSettings.json b/public/idpSettings.json index 46266e3077..8423e24097 100644 --- a/public/idpSettings.json +++ b/public/idpSettings.json @@ -1,7 +1,7 @@ { - "authority" : "http://localhost:9080", - "client_id" : "my-client", - "redirect_uri": "http://localhost:3000/sign-in-callback", - "post_logout_redirect_uri" : "http://localhost:3000", - "scope" : "openid User.read email" + "authority" : "#", + "client_id" : "#", + "redirect_uri": "#", + "post_logout_redirect_uri" : "#", + "scope" : "#" } From b8d8b27f1feb4f3084e6c745f605d0c6e6a66fce Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Thu, 2 Apr 2020 16:57:31 +0200 Subject: [PATCH 33/41] update SiginCallback Signed-off-by: ChamseddineBhd --- src/components/app.js | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/components/app.js b/src/components/app.js index f2fa325fe8..5f9515ad10 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -44,22 +44,9 @@ const getMuiTheme = (theme) => { }; const SignInCallback = (props) => { - const history = useHistory(); - - function handleCallback() { - if (props.userManager.instance && !props.userManager.error) { - props.userManager.instance.signinRedirectCallback().then(function () { - props.getUser(); - const previousPath = sessionStorage.getItem("powsybl-study-app-current-path"); - history.push(previousPath); - }).catch(function (e) { - console.error(e); - }); - } - } useEffect(() => { - handleCallback(); + props.handleSigninCallback(); }, [props.userManager]); return ( @@ -134,6 +121,18 @@ const App = () => { } } + function handleSigninCallback() { + if (userManager.instance && !userManager.error) { + userManager.instance.signinRedirectCallback().then(function () { + dispatchUser(); + const previousPath = sessionStorage.getItem("powsybl-study-app-current-path"); + history.push(previousPath); + }).catch(function (e) { + console.error(e); + }); + } + } + return ( @@ -157,7 +156,7 @@ const App = () => { : ( - + login()}/> From bd16ecbf66035d285be3a02c4643da0e62c662c6 Mon Sep 17 00:00:00 2001 From: ChamseddineBhd Date: Fri, 3 Apr 2020 12:22:43 +0200 Subject: [PATCH 34/41] cosmetic changes Signed-off-by: ChamseddineBhd --- src/components/app.js | 9 ++++++--- src/components/authentication.js | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/app.js b/src/components/app.js index 5f9515ad10..ead218ab6a 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -115,9 +115,12 @@ const App = () => { function logout() { if (userManager.instance && !userManager.error) { - dispatch(setLoggedUser(null)); + return userManager.instance.signoutRedirect().then( - () => console.debug("logged out")); + () => { + dispatch(setLoggedUser(null)); + console.debug("logged out"); + }); } } @@ -159,7 +162,7 @@ const App = () => { - login()}/> + login()}/> )} diff --git a/src/components/authentication.js b/src/components/authentication.js index 138e0a2ae6..5a4ec39cb2 100644 --- a/src/components/authentication.js +++ b/src/components/authentication.js @@ -67,6 +67,7 @@ const Authentication = (props) => {