From b97383ff18a46d1bda5db7ba2002255c706dacc6 Mon Sep 17 00:00:00 2001 From: HichamELBSI Date: Fri, 6 Aug 2021 17:31:02 +0200 Subject: [PATCH] Migrate SSO providers view Signed-off-by: HichamELBSI --- examples/getstarted/config/server.js | 30 +++ examples/getstarted/package.json | 1 + .../src/layouts/UnauthenticatedLayout.js | 30 ++- .../AuthPage/components/Login/BaseLogin.js | 176 ++++++++++-------- .../pages/AuthPage/components/Login/Form.js | 8 +- .../core/admin/admin/src/translations/en.json | 4 +- .../pages/AuthPage/components/Login/index.js | 31 +-- .../components/Providers/SSOProviders.js | 2 +- .../AuthPage/components/Providers/index.js | 108 ++++++----- yarn.lock | 35 +++- 10 files changed, 266 insertions(+), 159 deletions(-) diff --git a/examples/getstarted/config/server.js b/examples/getstarted/config/server.js index 9ae03d02e7..33f7e1370f 100644 --- a/examples/getstarted/config/server.js +++ b/examples/getstarted/config/server.js @@ -1,3 +1,7 @@ +'use strict'; + +const GoogleStrategy = require('passport-google-oauth2'); + module.exports = ({ env }) => ({ host: env('HOST', '0.0.0.0'), port: env.int('PORT', 1337), @@ -5,6 +9,32 @@ module.exports = ({ env }) => ({ // autoOpen: true, auth: { secret: env('ADMIN_JWT_SECRET', 'example-token'), + providers: [ + { + uid: 'google', + displayName: 'Google', + icon: 'https://cdn2.iconfinder.com/data/icons/social-icons-33/128/Google-512.png', + createStrategy: strapi => + new GoogleStrategy( + { + clientID: env('GOOGLE_CLIENT_ID'), + clientSecret: env('GOOGLE_CLIENT_SECRET'), + scope: [ + 'https://www.googleapis.com/auth/userinfo.email', + 'https://www.googleapis.com/auth/userinfo.profile', + ], + callbackURL: strapi.admin.services.passport.getStrategyCallbackURL('google'), + }, + (request, accessToken, refreshToken, profile, done) => { + done(null, { + email: profile.email, + firstname: profile.given_name, + lastname: profile.family_name, + }); + } + ), + }, + ], }, }, }); diff --git a/examples/getstarted/package.json b/examples/getstarted/package.json index 20fd014a86..dca7112dee 100644 --- a/examples/getstarted/package.json +++ b/examples/getstarted/package.json @@ -28,6 +28,7 @@ "@strapi/utils": "3.6.6", "lodash": "4.17.21", "mysql": "2.18.1", + "passport-google-oauth2": "0.2.0", "pg": "8.6.0", "sqlite3": "5.0.2", "strapi-middleware-views": "3.6.6" diff --git a/packages/core/admin/admin/src/layouts/UnauthenticatedLayout.js b/packages/core/admin/admin/src/layouts/UnauthenticatedLayout.js index 6d99c91460..a44d088419 100644 --- a/packages/core/admin/admin/src/layouts/UnauthenticatedLayout.js +++ b/packages/core/admin/admin/src/layouts/UnauthenticatedLayout.js @@ -13,24 +13,34 @@ export const Column = styled(Row)` flex-direction: column; `; +export const LayoutContent = ({ children }) => ( + + {children} + +); +LayoutContent.propTypes = { + children: PropTypes.node.isRequired, +}; + const UnauthenticatedLayout = ({ children }) => { return (
- + - - {children} - + {children}
); diff --git a/packages/core/admin/admin/src/pages/AuthPage/components/Login/BaseLogin.js b/packages/core/admin/admin/src/pages/AuthPage/components/Login/BaseLogin.js index 6e65046efb..1ddb897b76 100644 --- a/packages/core/admin/admin/src/pages/AuthPage/components/Login/BaseLogin.js +++ b/packages/core/admin/admin/src/pages/AuthPage/components/Login/BaseLogin.js @@ -11,13 +11,15 @@ import { TextInput, Main, FieldAction, + Row, + Link, } from '@strapi/parts'; import PropTypes from 'prop-types'; import styled from 'styled-components'; import { useIntl } from 'react-intl'; import { Formik } from 'formik'; -import { Column } from '../../../../layouts/UnauthenticatedLayout'; +import { Column, LayoutContent } from '../../../../layouts/UnauthenticatedLayout'; import Form from './Form'; import Logo from '../Logo'; @@ -35,101 +37,113 @@ const FieldActionWrapper = styled(FieldAction)` } `; -const Login = ({ onSubmit, schema }) => { +const Login = ({ onSubmit, schema, children }) => { const [passwordShown, setPasswordShown] = useState(false); const { formatMessage } = useIntl(); return (
- - {({ values, errors, handleChange }) => ( -
- - - -

{formatMessage({ id: 'Auth.form.welcome.title' })}

-
- - - {formatMessage({ id: 'Auth.form.welcome.subtitle' })} - - - {errors.errorMessage && ( - - {errors.errorMessage} - - )} -
+ + + {({ values, errors, handleChange }) => ( + + + + +

{formatMessage({ id: 'Auth.form.welcome.title' })}

+
+ + + {formatMessage({ id: 'Auth.form.welcome.subtitle' })} + + + {errors.errorMessage && ( + + {errors.errorMessage} + + )} +
- - - { - e.stopPropagation(); - setPasswordShown(prev => !prev); - }} - label={formatMessage({ - id: passwordShown - ? 'Auth.form.password.show-password' - : 'Auth.form.password.hide-password', - })} - > - {passwordShown ? : } - - } - required - /> - { - handleChange({ target: { value: checked, name: 'rememberMe' } }); - }} - value={values.rememberMe} - name="rememberMe" - > - {formatMessage({ id: 'Auth.form.rememberMe.label' })} - - - {formatMessage({ id: 'Auth.form.button.login' })} - - - - )} -
+ + + { + e.stopPropagation(); + setPasswordShown(prev => !prev); + }} + label={formatMessage({ + id: passwordShown + ? 'Auth.form.password.show-password' + : 'Auth.form.password.hide-password', + })} + > + {passwordShown ? : } + + } + required + /> + { + handleChange({ target: { value: checked, name: 'rememberMe' } }); + }} + value={values.rememberMe} + name="rememberMe" + > + {formatMessage({ id: 'Auth.form.rememberMe.label' })} + + + {formatMessage({ id: 'Auth.form.button.login' })} + + + + )} +
+ {children} + + + + + {formatMessage({ id: 'Auth.link.forgot-password' })} + + +
); }; Login.defaultProps = { + children: null, onSubmit: () => {}, }; Login.propTypes = { + children: PropTypes.node, onSubmit: PropTypes.func, schema: PropTypes.shape({ type: PropTypes.string.isRequired, diff --git a/packages/core/admin/admin/src/pages/AuthPage/components/Login/Form.js b/packages/core/admin/admin/src/pages/AuthPage/components/Login/Form.js index ee273000cb..0c6e8fc00b 100644 --- a/packages/core/admin/admin/src/pages/AuthPage/components/Login/Form.js +++ b/packages/core/admin/admin/src/pages/AuthPage/components/Login/Form.js @@ -6,13 +6,7 @@ const FormWithFocus = props => { useEffect(() => { if (isSubmitting && !isValidating) { - const errorNames = Object.keys(touched).reduce((prev, key) => { - if (getIn(errors, key)) { - prev.push(key); - } - - return prev; - }, []); + const errorNames = Object.keys(touched).filter(error => getIn(errors, error)); if (errorNames.length) { let errorEl; diff --git a/packages/core/admin/admin/src/translations/en.json b/packages/core/admin/admin/src/translations/en.json index 030477126d..42ba98db5b 100644 --- a/packages/core/admin/admin/src/translations/en.json +++ b/packages/core/admin/admin/src/translations/en.json @@ -6,7 +6,7 @@ "Auth.form.button.login": "Login", "Auth.form.button.login.providers.error": "We cannot connect you through the selected provider.", "Auth.form.button.login.providers.see-more": "See more", - "Auth.form.button.login.strapi": "LOG IN VIA STRAPI", + "Auth.form.button.login.strapi": "Log in via Strapi", "Auth.form.button.register": "LET'S START", "Auth.form.button.reset-password": "Change password", "Auth.form.confirmPassword.label": "Confirmation Password", @@ -47,6 +47,8 @@ "Auth.link.signin": "Sign in", "Auth.link.signin.account": "Already have an account?", "Auth.login.sso.divider": "Or login with", + "Auth.login.sso.loading": "Loading providers...", + "Auth.login.sso.subtitle": "Login to your account via SSO", "Auth.privacy-policy-agreement.policy": "privacy policy", "Auth.privacy-policy-agreement.terms": "terms", "Content Manager": "Content Manager", diff --git a/packages/core/admin/ee/admin/pages/AuthPage/components/Login/index.js b/packages/core/admin/ee/admin/pages/AuthPage/components/Login/index.js index fefca630df..034684ab60 100644 --- a/packages/core/admin/ee/admin/pages/AuthPage/components/Login/index.js +++ b/packages/core/admin/ee/admin/pages/AuthPage/components/Login/index.js @@ -27,21 +27,22 @@ const Login = loginProps => { return ( - - - - - - - - {formatMessage({ id: 'Auth.login.sso.divider' })} - - - - - - - + + + + + + + + {formatMessage({ id: 'Auth.login.sso.divider' })} + + + + + + + + ); }; diff --git a/packages/core/admin/ee/admin/pages/AuthPage/components/Providers/SSOProviders.js b/packages/core/admin/ee/admin/pages/AuthPage/components/Providers/SSOProviders.js index 4c9620694e..6d9665601c 100644 --- a/packages/core/admin/ee/admin/pages/AuthPage/components/Providers/SSOProviders.js +++ b/packages/core/admin/ee/admin/pages/AuthPage/components/Providers/SSOProviders.js @@ -84,7 +84,7 @@ const SSOProviders = ({ providers, displayAllProviders }) => { })} > - ••• + ••• diff --git a/packages/core/admin/ee/admin/pages/AuthPage/components/Providers/index.js b/packages/core/admin/ee/admin/pages/AuthPage/components/Providers/index.js index 920c245036..ac9d3d86de 100644 --- a/packages/core/admin/ee/admin/pages/AuthPage/components/Providers/index.js +++ b/packages/core/admin/ee/admin/pages/AuthPage/components/Providers/index.js @@ -1,18 +1,35 @@ import React from 'react'; -import { Button, Flex, Padded, Separator } from '@buffetjs/core'; -import { LoadingIndicator } from '@buffetjs/styles'; import { Redirect, useHistory } from 'react-router-dom'; import styled from 'styled-components'; +import { + Divider, + Stack, + Row, + Box, + TableLabel, + Button, + Main, + Subtitle, + H1, + Link, + Text, + Loader, +} from '@strapi/parts'; import { useIntl } from 'react-intl'; -import { BaselineAlignment } from '@strapi/helper-plugin'; -import Box from '../../../../../../admin/src/pages/AuthPage/components/Box'; -import Logo from '../../../../../../admin/src/pages/AuthPage/components/Logo'; -import Section from '../../../../../../admin/src/pages/AuthPage/components/Section'; -import ProviderButton from '../../../../components/ProviderButton'; import { useAuthProviders } from '../../../../hooks'; +import UnauthenticatedLayout, { + Column, + LayoutContent, +} from '../../../../../../admin/src/layouts/UnauthenticatedLayout'; +import SSOProviders from './SSOProviders'; +import Logo from '../../../../../../admin/src/pages/AuthPage/components/Logo'; -const ProviderWrapper = styled.div` - padding: 5px 4px; +const DividerFull = styled(Divider)` + flex: 1; +`; +const AuthButton = styled(Button)` + display: inline-block; + width: 100%; `; const Providers = () => { @@ -31,44 +48,49 @@ const Providers = () => { } return ( - <> -
- -
-
- - + +
+ + + + +

{formatMessage({ id: 'Auth.form.welcome.title' })}

+
+ + + {formatMessage({ id: 'Auth.login.sso.subtitle' })} + + +
+ {isLoading ? ( - + + {formatMessage({ id: 'Auth.login.sso.loading' })} + ) : ( - - {providers.map(provider => ( - - - - ))} - + )} - - - - - - + + + + {formatMessage({ id: 'or' })} + + + + + {formatMessage({ id: 'Auth.form.button.login.strapi' })} + + +
+ + + + {formatMessage({ id: 'Auth.link.forgot-password' })} + - -
- + + + ); }; diff --git a/yarn.lock b/yarn.lock index b158bdf6dc..222b1c3e21 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5558,6 +5558,11 @@ base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +base64url@3.x.x: + version "3.0.1" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" + integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -15115,6 +15120,11 @@ oauth-sign@^0.9.0, oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +oauth@0.9.x: + version "0.9.15" + resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" + integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE= + object-assign@4.x, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -15813,6 +15823,13 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +passport-google-oauth2@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/passport-google-oauth2/-/passport-google-oauth2-0.2.0.tgz#fc9ea59e7091f02e24fd16d6be9257ea982ebbc3" + integrity sha512-62EdPtbfVdc55nIXi0p1WOa/fFMM8v/M8uQGnbcXA4OexZWCnfsEi3wo2buag+Is5oqpuHzOtI64JpHk0Xi5RQ== + dependencies: + passport-oauth2 "^1.1.2" + passport-local@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee" @@ -15820,6 +15837,17 @@ passport-local@1.0.0: dependencies: passport-strategy "1.x.x" +passport-oauth2@^1.1.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.6.0.tgz#5f599735e0ea40ea3027643785f81a3a9b4feb50" + integrity sha512-emXPLqLcVEcLFR/QvQXZcwLmfK8e9CqvMgmOFJxcNT3okSFMtUbRRKpY20x5euD+01uHsjjCa07DYboEeLXYiw== + dependencies: + base64url "3.x.x" + oauth "0.9.x" + passport-strategy "1.x.x" + uid2 "0.0.x" + utils-merge "1.x.x" + passport-strategy@1.x.x: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" @@ -20800,6 +20828,11 @@ uid-number@0.0.6: resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= +uid2@0.0.x: + version "0.0.3" + resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82" + integrity sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I= + umask@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" @@ -21139,7 +21172,7 @@ utila@~0.4: resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= -utils-merge@1.0.1: +utils-merge@1.0.1, utils-merge@1.x.x: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=