diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ef9eb44610b1c38c84cca2997353c38211416781..34673fe5d8940544b6e614c0767701375fe5f5e1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -84,7 +84,7 @@ deploy: - apk --no-cache add --update python python-dev py-pip - pip install ecs-deploy # Deploy - - ecs deploy ${CI_CLUSTER_NAME} ${CI_SERVICE_NAME} --region ${AWS_REGION} --timeout 600 -e ${CI_CONTAINER_NAME} AWS_S3_ACCESS_KEY $AWS_S3_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_S3_SECRET_KEY $AWS_S3_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_S3_REGION $AWS_S3_REGION -e ${CI_CONTAINER_NAME} AWS_S3_BUCKET $AWS_S3_BUCKET -e ${CI_CONTAINER_NAME} AWS_SES_SECRET_KEY $AWS_SES_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_SES_ACCESS_KEY $AWS_SES_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_SES_REGION $AWS_SES_REGION -e ${CI_CONTAINER_NAME} EMAIL_SENDER $EMAIL_SENDER -e ${CI_CONTAINER_NAME} secret $SECRET -e ${CI_CONTAINER_NAME} DATABASE $DATABASE -e ${CI_CONTAINER_NAME} DB_USER $DB_USER -e ${CI_CONTAINER_NAME} DB_PASS $DB_PASS -e ${CI_CONTAINER_NAME} DB_HOST $DB_HOST + - ecs deploy ${CI_CLUSTER_NAME} ${CI_SERVICE_NAME} --region ${AWS_REGION} --timeout 600 -e ${CI_CONTAINER_NAME} AWS_S3_ACCESS_KEY $AWS_S3_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_S3_SECRET_KEY $AWS_S3_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_S3_REGION $AWS_S3_REGION -e ${CI_CONTAINER_NAME} AWS_S3_BUCKET $AWS_S3_BUCKET -e ${CI_CONTAINER_NAME} AWS_SES_SECRET_KEY $AWS_SES_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_SES_ACCESS_KEY $AWS_SES_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_SES_REGION $AWS_SES_REGION -e ${CI_CONTAINER_NAME} EMAIL_SENDER $EMAIL_SENDER -e ${CI_CONTAINER_NAME} secret $SECRET -e ${CI_CONTAINER_NAME} DATABASE $DATABASE -e ${CI_CONTAINER_NAME} DB_USER $DB_USER -e ${CI_CONTAINER_NAME} DB_PASS $DB_PASS -e ${CI_CONTAINER_NAME} DB_HOST $DB_HOST -e ${CI_CONTAINER_NAME} ORCID_CLIENT_ID $ORCID_CLIENT_ID -e ${CI_CONTAINER_NAME} ORCID_CLIENT_SECRET $ORCID_CLIENT_SECRET -e ${CI_CONTAINER_NAME} CLIENT_BASE_URL $CLIENT_BASE_URL environment: name: qa url: $CI_ALB_URL @@ -101,7 +101,7 @@ aws-qa: - apk --no-cache add --update python python-dev py-pip - pip install ecs-deploy # Deploy - - ecs deploy ${CI_CLUSTER_NAME} ${CI_SERVICE_NAME} --region ${AWS_REGION} --timeout 600 -e ${CI_CONTAINER_NAME} AWS_S3_ACCESS_KEY $AWS_S3_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_S3_SECRET_KEY $AWS_S3_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_S3_REGION $AWS_S3_REGION -e ${CI_CONTAINER_NAME} AWS_S3_BUCKET $AWS_S3_BUCKET -e ${CI_CONTAINER_NAME} AWS_SES_SECRET_KEY $AWS_SES_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_SES_ACCESS_KEY $AWS_SES_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_SES_REGION $AWS_SES_REGION -e ${CI_CONTAINER_NAME} EMAIL_SENDER $EMAIL_SENDER -e ${CI_CONTAINER_NAME} secret $SECRET -e ${CI_CONTAINER_NAME} DATABASE $DATABASE -e ${CI_CONTAINER_NAME} DB_USER $DB_USER -e ${CI_CONTAINER_NAME} DB_PASS $DB_PASS -e ${CI_CONTAINER_NAME} DB_HOST $DB_HOST + - ecs deploy ${CI_CLUSTER_NAME} ${CI_SERVICE_NAME} --region ${AWS_REGION} --timeout 600 -e ${CI_CONTAINER_NAME} AWS_S3_ACCESS_KEY $AWS_S3_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_S3_SECRET_KEY $AWS_S3_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_S3_REGION $AWS_S3_REGION -e ${CI_CONTAINER_NAME} AWS_S3_BUCKET $AWS_S3_BUCKET -e ${CI_CONTAINER_NAME} AWS_SES_SECRET_KEY $AWS_SES_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_SES_ACCESS_KEY $AWS_SES_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_SES_REGION $AWS_SES_REGION -e ${CI_CONTAINER_NAME} EMAIL_SENDER $EMAIL_SENDER -e ${CI_CONTAINER_NAME} secret $SECRET -e ${CI_CONTAINER_NAME} DATABASE $DATABASE -e ${CI_CONTAINER_NAME} DB_USER $DB_USER -e ${CI_CONTAINER_NAME} DB_PASS $DB_PASS -e ${CI_CONTAINER_NAME} DB_HOST $DB_HOST -e ${CI_CONTAINER_NAME} ORCID_CLIENT_ID $ORCID_CLIENT_ID -e ${CI_CONTAINER_NAME} ORCID_CLIENT_SECRET $ORCID_CLIENT_SECRET -e ${CI_CONTAINER_NAME} CLIENT_BASE_URL $CLIENT_BASE_URL environment: name: qa url: $CI_ALB_URL @@ -136,7 +136,7 @@ rollback: - aws s3 cp s3://${CI_REV_BUCKET}/${CI_SERVICE_NAME} ./ - REV=`cat ./${CI_SERVICE_NAME}` - echo rev is $REV - - ecs deploy --region ${AWS_REGION} ${CLUSTER_NAME} ${CI_SERVICE_NAME} --task ${REV} -e ${CI_CONTAINER_NAME} AWS_S3_ACCESS_KEY $AWS_S3_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_S3_SECRET_KEY $AWS_S3_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_S3_REGION $AWS_S3_REGION -e ${CI_CONTAINER_NAME} AWS_S3_BUCKET $AWS_S3_BUCKET -e ${CI_CONTAINER_NAME} AWS_SES_SECRET_KEY $AWS_SES_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_SES_ACCESS_KEY $AWS_SES_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_SES_REGION $AWS_SES_REGION -e ${CI_CONTAINER_NAME} EMAIL_SENDER $EMAIL_SENDER -e ${CI_CONTAINER_NAME} secret $SECRET -e ${CI_CONTAINER_NAME} DATABASE $DATABASE -e ${CI_CONTAINER_NAME} DB_USER $DB_USER -e ${CI_CONTAINER_NAME} DB_PASS $DB_PASS -e ${CI_CONTAINER_NAME} DB_HOST $DB_HOST + - ecs deploy --region ${AWS_REGION} ${CLUSTER_NAME} ${CI_SERVICE_NAME} --task ${REV} -e ${CI_CONTAINER_NAME} AWS_S3_ACCESS_KEY $AWS_S3_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_S3_SECRET_KEY $AWS_S3_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_S3_REGION $AWS_S3_REGION -e ${CI_CONTAINER_NAME} AWS_S3_BUCKET $AWS_S3_BUCKET -e ${CI_CONTAINER_NAME} AWS_SES_SECRET_KEY $AWS_SES_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_SES_ACCESS_KEY $AWS_SES_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_SES_REGION $AWS_SES_REGION -e ${CI_CONTAINER_NAME} EMAIL_SENDER $EMAIL_SENDER -e ${CI_CONTAINER_NAME} secret $SECRET -e ${CI_CONTAINER_NAME} DATABASE $DATABASE -e ${CI_CONTAINER_NAME} DB_USER $DB_USER -e ${CI_CONTAINER_NAME} DB_PASS $DB_PASS -e ${CI_CONTAINER_NAME} DB_HOST $DB_HOST -e ${CI_CONTAINER_NAME} ORCID_CLIENT_ID $ORCID_CLIENT_ID -e ${CI_CONTAINER_NAME} ORCID_CLIENT_SECRET $ORCID_CLIENT_SECRET -e ${CI_CONTAINER_NAME} CLIENT_BASE_URL $CLIENT_BASE_URL environment: name: qa url: $CI_ALB_URL @@ -157,7 +157,7 @@ rollback-qa: - aws s3 cp s3://${CI_REV_BUCKET}/${CI_SERVICE_NAME} ./ - REV=`cat ./${CI_SERVICE_NAME}` - echo rev is $REV - - ecs deploy --region ${AWS_REGION} ${CLUSTER_NAME} ${CI_SERVICE_NAME} --task ${REV} -e ${CI_CONTAINER_NAME} AWS_S3_ACCESS_KEY $AWS_S3_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_S3_SECRET_KEY $AWS_S3_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_S3_REGION $AWS_S3_REGION -e ${CI_CONTAINER_NAME} AWS_S3_BUCKET $AWS_S3_BUCKET -e ${CI_CONTAINER_NAME} AWS_SES_SECRET_KEY $AWS_SES_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_SES_ACCESS_KEY $AWS_SES_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_SES_REGION $AWS_SES_REGION -e ${CI_CONTAINER_NAME} EMAIL_SENDER $EMAIL_SENDER -e ${CI_CONTAINER_NAME} secret $SECRET -e ${CI_CONTAINER_NAME} DATABASE $DATABASE -e ${CI_CONTAINER_NAME} DB_USER $DB_USER -e ${CI_CONTAINER_NAME} DB_PASS $DB_PASS -e ${CI_CONTAINER_NAME} DB_HOST $DB_HOST + - ecs deploy --region ${AWS_REGION} ${CLUSTER_NAME} ${CI_SERVICE_NAME} --task ${REV} -e ${CI_CONTAINER_NAME} AWS_S3_ACCESS_KEY $AWS_S3_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_S3_SECRET_KEY $AWS_S3_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_S3_REGION $AWS_S3_REGION -e ${CI_CONTAINER_NAME} AWS_S3_BUCKET $AWS_S3_BUCKET -e ${CI_CONTAINER_NAME} AWS_SES_SECRET_KEY $AWS_SES_SECRET_KEY -e ${CI_CONTAINER_NAME} AWS_SES_ACCESS_KEY $AWS_SES_ACCESS_KEY -e ${CI_CONTAINER_NAME} AWS_SES_REGION $AWS_SES_REGION -e ${CI_CONTAINER_NAME} EMAIL_SENDER $EMAIL_SENDER -e ${CI_CONTAINER_NAME} secret $SECRET -e ${CI_CONTAINER_NAME} DATABASE $DATABASE -e ${CI_CONTAINER_NAME} DB_USER $DB_USER -e ${CI_CONTAINER_NAME} DB_PASS $DB_PASS -e ${CI_CONTAINER_NAME} DB_HOST $DB_HOST -e ${CI_CONTAINER_NAME} ORCID_CLIENT_ID $ORCID_CLIENT_ID -e ${CI_CONTAINER_NAME} ORCID_CLIENT_SECRET $ORCID_CLIENT_SECRET -e ${CI_CONTAINER_NAME} CLIENT_BASE_URL $CLIENT_BASE_URL environment: name: qa url: $CI_ALB_URL \ No newline at end of file diff --git a/packages/component-user-manager/package.json b/packages/component-user-manager/package.json index c65b0553de09100b8c477dfdab49531406d95536..52b907483b0e7dac1aaf67cf1ee091b671cd809e 100644 --- a/packages/component-user-manager/package.json +++ b/packages/component-user-manager/package.json @@ -20,13 +20,14 @@ }, "dependencies": { "body-parser": "^1.17.2", - "chance": "^1.0.13" + "chance": "^1.0.13", + "passport-orcid": "^0.0.3" }, "peerDependencies": { "@pubsweet/logger": "^0.0.1", + "pubsweet-component-helper-service": "0.0.1", "pubsweet-component-mail-service": "0.0.1", - "pubsweet-server": "^1.0.1", - "pubsweet-component-helper-service": "0.0.1" + "pubsweet-server": "^1.0.1" }, "devDependencies": { "apidoc": "^0.17.6", diff --git a/packages/component-user-manager/src/Users.js b/packages/component-user-manager/src/Users.js index d3a71ed9de7a52e50d913683cbf2027b70914a78..95d064990c554472413277282e82986111fc8609 100644 --- a/packages/component-user-manager/src/Users.js +++ b/packages/component-user-manager/src/Users.js @@ -1,4 +1,5 @@ const bodyParser = require('body-parser') +const orcidRoutes = require('./routes/users/linkOrcid') const Users = app => { app.use(bodyParser.json()) @@ -123,6 +124,9 @@ const Users = app => { authBearer, require('./routes/users/changePassword')(app.locals.models), ) + + // register ORCID authentication strategy + orcidRoutes(app) } module.exports = Users diff --git a/packages/component-user-manager/src/routes/users/linkOrcid.js b/packages/component-user-manager/src/routes/users/linkOrcid.js new file mode 100644 index 0000000000000000000000000000000000000000..afb9a1e3d2ac5532d072790e2698309b1d0bd149 --- /dev/null +++ b/packages/component-user-manager/src/routes/users/linkOrcid.js @@ -0,0 +1,61 @@ +const OrcidStrategy = require('passport-orcid') +const config = require('config') +const get = require('lodash/get') + +const { clientID, clientSecret, callbackPath, successPath } = config.get( + 'orcid', +) + +let userId +const LinkOrcid = app => { + const { passport } = app.locals + + passport.serializeUser((user, done) => { + done(null, user) + }) + + passport.deserializeUser((user, done) => { + done(null, user) + }) + + passport.use( + new OrcidStrategy( + { + sandbox: process.env.NODE_ENV !== 'production', + callbackURL: `${config.get('pubsweet-client.baseUrl')}${callbackPath}`, + clientID, + clientSecret, + }, + (accessToken, refreshToken, params, profile, done) => { + profile = { orcid: params.orcid, name: params.name } + return done(null, profile) + }, + ), + ) + + app.get( + '/api/users/orcid', + (req, res, next) => { + userId = get(req, 'query.userId') + next() + }, + passport.authenticate('orcid'), + ) + + app.get( + callbackPath, + passport.authenticate('orcid', { + failureRedirect: successPath, + }), + linkOrcidHandler(app.locals.models), + ) +} + +const linkOrcidHandler = models => async (req, res) => { + const user = await models.User.find(userId) + user.orcid = req.user.orcid + await user.save() + res.redirect(successPath) +} + +module.exports = LinkOrcid diff --git a/packages/components-faraday/src/components/UserProfile/LinkOrcID.js b/packages/components-faraday/src/components/UserProfile/LinkOrcID.js index 827c75eda4d4f1fea800e04d02f8112ae3f197c2..8b8532ee384fc73df15deaa487eb30d91697bdc1 100644 --- a/packages/components-faraday/src/components/UserProfile/LinkOrcID.js +++ b/packages/components-faraday/src/components/UserProfile/LinkOrcID.js @@ -4,12 +4,12 @@ import styled from 'styled-components' import { Row, RowItem, - LabelHeader, - LabelTitle, LinkText, + LabelTitle, + LabelHeader, } from '../UIComponents/FormItems' -const LinkOrcID = ({ orcid = '' }) => ( +const LinkOrcID = ({ orcid = '', id }) => ( <Root> <Row noMargin> <RowItem> @@ -19,14 +19,13 @@ const LinkOrcID = ({ orcid = '' }) => ( {!orcid ? ( <Row noMargin> <RowItem> - <LinkText>Link</LinkText> + <Link href={`/api/users/orcid?userId=${id}`}>Link</Link> </RowItem> </Row> ) : ( <Row noMargin> <RowItem> - <LabelTitle> {orcid} </LabelTitle> - <LinkText>Unlink</LinkText> + <LabelTitle>{orcid}</LabelTitle> </RowItem> </Row> )} @@ -41,4 +40,6 @@ const Root = styled.div` flex-direction: column; max-width: 30em; ` + +const Link = LinkText.withComponent('a') // #endregion diff --git a/packages/components-faraday/src/components/UserProfile/UserProfilePage.js b/packages/components-faraday/src/components/UserProfile/UserProfilePage.js index 64dd9d28ea62c185a147e141bf307b7fb3d0d084..462abc4c48ed0be8bc05cbab2e7a147cc640b537 100644 --- a/packages/components-faraday/src/components/UserProfile/UserProfilePage.js +++ b/packages/components-faraday/src/components/UserProfile/UserProfilePage.js @@ -21,7 +21,7 @@ const UserProfilePage = ({ history, user }) => ( /> <AccountDetails history={history} user={user} /> <EmailNotifications subscribed={get(user, 'subscription')} /> - <LinkOrcID orcid={get(user, 'orcid')} /> + <LinkOrcID id={get(user, 'id')} orcid={get(user, 'orcid')} /> </Root> ) diff --git a/packages/xpub-faraday/app/FaradayApp.js b/packages/xpub-faraday/app/FaradayApp.js index 05d83b3361bea32267f77fc663ef3f834ae27717..b4c0a56e20d0107fb104afa779e09aadb7f00a1b 100644 --- a/packages/xpub-faraday/app/FaradayApp.js +++ b/packages/xpub-faraday/app/FaradayApp.js @@ -45,5 +45,5 @@ const Root = styled.div` const MainContainer = styled.div` background-color: ${props => props.theme.backgroundColor || '#fff'}; padding: 110px 10px 0 10px; - height: 100vh; + min-height: 100vh; ` diff --git a/packages/xpub-faraday/config/default.js b/packages/xpub-faraday/config/default.js index 19ac346db1ac276c83197297b728bbcf89cb83cc..522a8f83e554e5fd3085232ad640418d3bcba56b 100644 --- a/packages/xpub-faraday/config/default.js +++ b/packages/xpub-faraday/config/default.js @@ -44,10 +44,17 @@ module.exports = { }, 'pubsweet-client': { API_ENDPOINT: '/api', + baseUrl: process.env.CLIENT_BASE_URL || 'http://localhost:3000', 'login-redirect': '/', - 'redux-log': true, + 'redux-log': false, theme: process.env.PUBSWEET_THEME, }, + orcid: { + clientID: process.env.ORCID_CLIENT_ID, + clientSecret: process.env.ORCID_CLIENT_SECRET, + callbackPath: '/api/users/orcid/callback', + successPath: '/profile', + }, 'mail-transport': { sendmail: true, }, diff --git a/packages/xpub-faraday/config/validations.js b/packages/xpub-faraday/config/validations.js index 393cc22519ba1f69dd87784acdc0a16585a6da9b..61e603fe92ae1d12ffedecae79d2774207df71ed 100644 --- a/packages/xpub-faraday/config/validations.js +++ b/packages/xpub-faraday/config/validations.js @@ -116,6 +116,7 @@ module.exports = { }, ], user: { + orcid: Joi.string(), name: Joi.string(), username: Joi.string(), isConfirmed: Joi.boolean(), diff --git a/yarn.lock b/yarn.lock index efc87c5ed07ef412dee8ed8bb153ba68180c55ab..7bf0e81ba34114a537cb52a9e70798f0434e7d41 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6640,6 +6640,10 @@ oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" +oauth@0.9.x: + version "0.9.15" + resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" + object-assign@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" @@ -6942,6 +6946,21 @@ passport-local@^1.0.0: dependencies: passport-strategy "1.x.x" +passport-oauth2@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.4.0.tgz#f62f81583cbe12609be7ce6f160b9395a27b86ad" + dependencies: + oauth "0.9.x" + passport-strategy "1.x.x" + uid2 "0.0.x" + utils-merge "1.x.x" + +passport-orcid@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/passport-orcid/-/passport-orcid-0.0.3.tgz#802126a4e0dac0dc1406b9521b29b0dd13644ec4" + dependencies: + passport-oauth2 "^1.4.0" + passport-strategy@1.x.x: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" @@ -9742,6 +9761,10 @@ uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" +uid2@0.0.x: + version "0.0.3" + resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82" + ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" @@ -9920,7 +9943,7 @@ utile@0.3.x: ncp "1.0.x" rimraf "2.x.x" -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"