From 532e06d0b3af7abb83da95450fac69a408b9ee1b Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Sat, 17 Oct 2020 00:57:53 +0200 Subject: [PATCH 01/15] Add top level keycloak element --- ui/package-lock.json | 69 +++++++++++++++++++ ui/package.json | 18 ++--- .../AuthRoutesContainer.js | 25 +++++-- 3 files changed, 98 insertions(+), 14 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 3bf75d32..0a75adb1 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -400,6 +400,54 @@ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" }, + "@react-keycloak/core": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@react-keycloak/core/-/core-3.0.0.tgz", + "integrity": "sha512-T2w5phBXu8Uye8OcB0nzNccWcI1xDFKcp36KjBfBUHz8Ehc59ylvZicS+woNOxARmUsnbigcM9NcbARPW7pciA==", + "requires": { + "react-fast-compare": "^3.2.0" + }, + "dependencies": { + "react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + } + } + }, + "@react-keycloak/web": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@react-keycloak/web/-/web-3.0.0.tgz", + "integrity": "sha512-Lolk3kuFT6e1LIdPdiIuzA/dJ/cD2/G1O+hG5Otgbgelx7ZmesM1w36LmAPGUpwLhYtPXdgUsOjjPBPK06agew==", + "requires": { + "@babel/runtime": "^7.9.0", + "@react-keycloak/core": "^3.0.0", + "hoist-non-react-statics": "^3.3.2" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.1.tgz", + "integrity": "sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + } + } + }, "@types/hammerjs": { "version": "2.0.36", "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.36.tgz", @@ -6435,6 +6483,11 @@ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.0.tgz", "integrity": "sha512-Wehd+7Pf9tFvGb+ydPm9TjYjV8X1YHOVyG8QyELZxEMqOhemVwGRmoG8iQ/soqI3n8v4xn59zaLxiCJiaaRzKA==" }, + "js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -6564,6 +6617,22 @@ "resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.2.0.tgz", "integrity": "sha1-+m6i5DuQpoAohD0n8gddNajD5vk=" }, + "keycloak-js": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-11.0.2.tgz", + "integrity": "sha512-dnvzgTetovu3eTjJtvBQQhxRN4jqvd/DaA2wFaE4aWIFXhwRcoPpZT8ZJ7MwlICDPdCgzbCsOsBjpL8CbYOZsg==", + "requires": { + "base64-js": "1.3.1", + "js-sha256": "0.9.0" + }, + "dependencies": { + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + } + } + }, "killable": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.0.tgz", diff --git a/ui/package.json b/ui/package.json index b7fe6109..e5a69eb8 100644 --- a/ui/package.json +++ b/ui/package.json @@ -18,9 +18,11 @@ }, "dependencies": { "@apollo/client": "3.1.3", + "@react-keycloak/web": "^3.0.0", "auth0-js": "^8.12.1", "autoprefixer": "7.1.6", "babel-core": "6.26.0", + "babel-eslint": "^8.0.3", "babel-jest": "20.0.3", "babel-loader": "7.1.2", "babel-plugin-transform-decorators-legacy": "^1.3.4", @@ -30,6 +32,7 @@ "bootstrap": "^4.1.3", "case-sensitive-paths-webpack-plugin": "2.1.1", "chalk": "1.1.3", + "css-loader": "^0.28.7", "dotenv": "4.0.0", "downshift": "6.0.6", "eslint": "4.10.0", @@ -40,6 +43,7 @@ "eslint-plugin-jsx-a11y": "6.0.2", "eslint-plugin-react": "7.4.0", "extract-text-webpack-plugin": "3.0.2", + "file-loader": "^1.1.5", "formik": "2.1.5", "fs-extra": "3.0.1", "graphql": "15.3.0", @@ -47,9 +51,11 @@ "html-webpack-plugin": "2.29.0", "jest": "20.0.4", "jquery": "^3.2.1", + "keycloak-js": "^11.0.2", "lodash": "^4.17.4", "mime": "^2.0.3", "node-fetch": "^2.3.0", + "node-sass": "4.14.1", "object-assign": "4.1.1", "popper.js": "^1.12.9", "postcss-flexbugs-fixes": "3.2.0", @@ -67,22 +73,18 @@ "react-router-dom": "5.2.0", "react-tag-input": "^4.7.2", "reactstrap": "8.5.1", + "sass-loader": "^6.0.6", "store": "^2.0.12", + "style-loader": "^0.19.0", "styled-components": "5.2.0", "subscriptions-transport-ws": "^0.9.15", "sw-precache-webpack-plugin": "0.11.4", "url-loader": "0.6.2", + "webpack": "^3.8.1", "webpack-dev-server": "2.9.4", "webpack-manifest-plugin": "1.3.2", "whatwg-fetch": "2.0.3", - "yup": "^0.26.6", - "babel-eslint": "^8.0.3", - "css-loader": "^0.28.7", - "file-loader": "^1.1.5", - "node-sass": "4.14.1", - "sass-loader": "^6.0.6", - "style-loader": "^0.19.0", - "webpack": "^3.8.1" + "yup": "^0.26.6" }, "jest": { "collectCoverageFrom": [ diff --git a/ui/src/App/components/AuthRoutesContainer/AuthRoutesContainer.js b/ui/src/App/components/AuthRoutesContainer/AuthRoutesContainer.js index 28302b67..5603320a 100644 --- a/ui/src/App/components/AuthRoutesContainer/AuthRoutesContainer.js +++ b/ui/src/App/components/AuthRoutesContainer/AuthRoutesContainer.js @@ -4,18 +4,31 @@ import { Route, Switch, } from 'react-router-dom'; +import Keycloak from 'keycloak-js'; +import { ReactKeycloakProvider } from '@react-keycloak/web'; import history from '@/services/history'; import AuthCallback from './components/AuthCallback'; import RoutesContainer from './components/RoutesContainer'; +const keycloak = Keycloak({ + realm: 'plato', + 'auth-server-url': 'https://auth.platoproject.org/auth/', + 'ssl-required': 'external', + resource: 'realities', + 'public-client': true, + 'confidential-port': 0, + clientId: 'realities', +}); const AuthRoutesContainer = () => ( - - - - - - + + + + + + + + ); export default AuthRoutesContainer; From e9d815d1c61828e8f96c5288eecea744151c931d Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Sat, 17 Oct 2020 02:15:48 +0200 Subject: [PATCH 02/15] Start refactoring auth into a hook --- .../RealitiesNavbar/RealitiesNavbar.js | 117 +++++++----------- ui/src/services/auth/auth.js | 100 ++++++++------- ui/src/services/auth/index.js | 2 + 3 files changed, 97 insertions(+), 122 deletions(-) diff --git a/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js b/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js index 06d4deca..191cd7c8 100644 --- a/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js +++ b/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js @@ -1,5 +1,4 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; +import React, { useState } from 'react'; import { Collapse, DropdownItem, @@ -15,7 +14,7 @@ import { } from 'reactstrap'; import { Link } from 'react-router-dom'; import styled from 'styled-components'; -import withAuth from '@/components/withAuth'; +import { useAuth } from '@/services/auth'; import Search from '@/components/Search'; import ViewerName from '@/components/ViewerName'; @@ -23,81 +22,51 @@ const StyledNavbarBrand = styled(NavbarBrand)` font-weight: bold; `; -class RealitiesNavbar extends Component { - constructor(props) { - super(props); +const RealitiesNavbar = () => { + const [isOpen, setIsOpen] = useState(false); + const { isLoggedIn, login, logout } = useAuth(); - this.state = { - isOpen: false, - }; - } - - toggle = () => { - this.setState({ - isOpen: !this.state.isOpen, - }); - }; - - render() { - return ( - - + return ( + + Realities - -
- -
- - - + +
+ ); }; -export default withAuth(RealitiesNavbar); +export default RealitiesNavbar; diff --git a/ui/src/services/auth/auth.js b/ui/src/services/auth/auth.js index 2f040006..1e89c4e4 100644 --- a/ui/src/services/auth/auth.js +++ b/ui/src/services/auth/auth.js @@ -17,53 +17,57 @@ function fireHandlers() { handlers.forEach(fn => fn()); } -export default { - login: () => { - auth0.authorize({ title: 'Realities' }); - }, - handleAuthentication: () => ( - new Promise((resolve, reject) => { - auth0.parseHash((err, authResult) => { - if (authResult && authResult.accessToken && authResult.idToken) { - const auth = { - accessToken: authResult.accessToken, - idToken: authResult.idToken, - expiresAt: (authResult.expiresIn * 1000) + new Date().getTime(), - email: authResult.idTokenPayload && authResult.idTokenPayload.email, - }; - store.set('auth', auth); - fireHandlers(); - resolve(auth); - } else { - reject(err); - } - }); - }) - ), - logout: () => { - store.remove('auth'); - fireHandlers(); - history.push('/'); - }, - isLoggedIn: () => !!store.get('auth'), - getAccessToken: () => { - const storedAuth = store.get('auth') || {}; - const tokenExpired = storedAuth.expiresAt < new Date().getTime(); - if (tokenExpired) { +export function useAuth() { + return { + login: () => { + auth0.authorize({ title: 'Realities' }); + }, + handleAuthentication: () => ( + new Promise((resolve, reject) => { + auth0.parseHash((err, authResult) => { + if (authResult && authResult.accessToken && authResult.idToken) { + const auth = { + accessToken: authResult.accessToken, + idToken: authResult.idToken, + expiresAt: (authResult.expiresIn * 1000) + new Date().getTime(), + email: authResult.idTokenPayload && authResult.idTokenPayload.email, + }; + store.set('auth', auth); + fireHandlers(); + resolve(auth); + } else { + reject(err); + } + }); + }) + ), + logout: () => { store.remove('auth'); fireHandlers(); - return null; - } - return storedAuth.accessToken; - }, - getEmail: () => { - const storedAuth = store.get('auth') || {}; - return storedAuth.email; - }, - subscribe: (fn) => { - handlers.push(fn); - }, - unsubscribe: (fn) => { - handlers = handlers.filter(item => item !== fn); - }, -}; + history.push('/'); + }, + isLoggedIn: () => !!store.get('auth'), + getAccessToken: () => { + const storedAuth = store.get('auth') || {}; + const tokenExpired = storedAuth.expiresAt < new Date().getTime(); + if (tokenExpired) { + store.remove('auth'); + fireHandlers(); + return null; + } + return storedAuth.accessToken; + }, + getEmail: () => { + const storedAuth = store.get('auth') || {}; + return storedAuth.email; + }, + subscribe: (fn) => { + handlers.push(fn); + }, + unsubscribe: (fn) => { + handlers = handlers.filter(item => item !== fn); + }, + }; +} + +export default useAuth(); diff --git a/ui/src/services/auth/index.js b/ui/src/services/auth/index.js index 687af623..0f0a71ae 100644 --- a/ui/src/services/auth/index.js +++ b/ui/src/services/auth/index.js @@ -1,3 +1,5 @@ import auth from './auth'; export default auth; +export * from './auth'; + From 43a047a6718d9f501275063b424f7200e9742f3e Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Mon, 19 Oct 2020 15:31:45 +0200 Subject: [PATCH 03/15] Use the auth hook in withAuth --- ui/src/App/App.js | 30 +++++- .../AuthRoutesContainer.js | 26 ++--- .../components/AuthCallback/AuthCallback.js | 72 ++++++------- .../RealitiesNavbar/RealitiesNavbar.js | 2 +- ui/src/components/withAuth/withAuth.js | 51 ++++----- ui/src/services/apolloClient/apolloClient.js | 100 +++++++++--------- ui/src/services/auth/auth.js | 35 +++--- ui/src/services/auth/index.js | 1 - 8 files changed, 161 insertions(+), 156 deletions(-) diff --git a/ui/src/App/App.js b/ui/src/App/App.js index 3cd08944..4c0cbe96 100644 --- a/ui/src/App/App.js +++ b/ui/src/App/App.js @@ -1,12 +1,36 @@ import React from 'react'; +import Keycloak from 'keycloak-js'; +import { ReactKeycloakProvider } from '@react-keycloak/web'; +import useAuth from '@/services/auth'; import { ApolloProvider } from '@apollo/client'; import apolloClient from '@/services/apolloClient'; import AuthRoutesContainer from './components/AuthRoutesContainer'; +const keycloak = Keycloak({ + realm: 'plato', + 'auth-server-url': 'https://auth.platoproject.org/auth/', + 'ssl-required': 'external', + resource: 'realities', + 'public-client': true, + 'confidential-port': 0, + clientId: 'realities', +}); + +const ApolloSetup = () => { + const { getAccessToken } = useAuth(); + console.log('token', getAccessToken()); + + return ( + + + + ); +}; + const App = () => ( - - - + + + ); export default App; diff --git a/ui/src/App/components/AuthRoutesContainer/AuthRoutesContainer.js b/ui/src/App/components/AuthRoutesContainer/AuthRoutesContainer.js index 5603320a..ca68e0bc 100644 --- a/ui/src/App/components/AuthRoutesContainer/AuthRoutesContainer.js +++ b/ui/src/App/components/AuthRoutesContainer/AuthRoutesContainer.js @@ -4,31 +4,17 @@ import { Route, Switch, } from 'react-router-dom'; -import Keycloak from 'keycloak-js'; -import { ReactKeycloakProvider } from '@react-keycloak/web'; import history from '@/services/history'; import AuthCallback from './components/AuthCallback'; import RoutesContainer from './components/RoutesContainer'; -const keycloak = Keycloak({ - realm: 'plato', - 'auth-server-url': 'https://auth.platoproject.org/auth/', - 'ssl-required': 'external', - resource: 'realities', - 'public-client': true, - 'confidential-port': 0, - clientId: 'realities', -}); - const AuthRoutesContainer = () => ( - - - - - - - - + + + + + + ); export default AuthRoutesContainer; diff --git a/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js b/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js index 4b46c4dc..cc950bba 100644 --- a/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js +++ b/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js @@ -1,46 +1,46 @@ import React, { Component } from 'react'; -import { gql } from '@apollo/client'; +// import { gql } from '@apollo/client'; import Loader from 'react-loader'; -import auth from '@/services/auth'; -import apolloClient from '@/services/apolloClient'; -import history from '@/services/history'; +// import auth from '@/services/auth'; +// import apolloClient from '@/services/apolloClient'; +// import history from '@/services/history'; -const GET_VIEWER = gql` - query AuthCallback_person($email: String!) { - person(email: $email) { - nodeId - email - name - } - } -`; +// const GET_VIEWER = gql` +// query AuthCallback_person($email: String!) { +// person(email: $email) { +// nodeId +// email +// name +// } +// } +// `; -const CREATE_VIEWER = gql` - mutation AuthCallback_createViewer { - createViewer { - nodeId - email - } - } -`; +// const CREATE_VIEWER = gql` +// mutation AuthCallback_createViewer { +// createViewer { +// nodeId +// email +// } +// } +// `; class AuthCallback extends Component { componentWillMount() { - auth.handleAuthentication().then(({ email }) => { - apolloClient - .query({ query: GET_VIEWER, variables: { email } }) - .then(({ data }) => { - if (data.person) { - history.replace('/'); - } else { - apolloClient - .mutate({ mutation: CREATE_VIEWER }) - .then(() => history.replace('/profile')) - .catch(err => console.log(err)); - } - }) - .catch(err => console.log(err)); - }); + // auth.handleAuthentication().then(({ email }) => { + // apolloClient + // .query({ query: GET_VIEWER, variables: { email } }) + // .then(({ data }) => { + // if (data.person) { + // history.replace('/'); + // } else { + // apolloClient + // .mutate({ mutation: CREATE_VIEWER }) + // .then(() => history.replace('/profile')) + // .catch(err => console.log(err)); + // } + // }) + // .catch(err => console.log(err)); + // }); } render() { diff --git a/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js b/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js index 191cd7c8..74fc31fb 100644 --- a/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js +++ b/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js @@ -14,7 +14,7 @@ import { } from 'reactstrap'; import { Link } from 'react-router-dom'; import styled from 'styled-components'; -import { useAuth } from '@/services/auth'; +import useAuth from '@/services/auth'; import Search from '@/components/Search'; import ViewerName from '@/components/ViewerName'; diff --git a/ui/src/components/withAuth/withAuth.js b/ui/src/components/withAuth/withAuth.js index 3ce69336..2105c1bc 100644 --- a/ui/src/components/withAuth/withAuth.js +++ b/ui/src/components/withAuth/withAuth.js @@ -1,42 +1,33 @@ -import React, { Component } from 'react'; -import auth from '@/services/auth'; +import React, { useState, useEffect } from 'react'; +import useAuth from '@/services/auth'; export default (WrappedComponent) => { - function getAuthProps() { - return { + const EnhancedComponent = (props) => { + const auth = useAuth(); + + const getAuthProps = () => ({ login: auth.login, logout: auth.logout, isLoggedIn: auth.isLoggedIn(), email: auth.getEmail(), + }); + + const [authProps, setAuthProps] = useState(getAuthProps()); + + const handleChange = () => { + setAuthProps(getAuthProps()); }; - } - class EnhancedComponent extends Component { - constructor(props) { - super(props); - this.state = { - auth: getAuthProps(), + useEffect(() => { + auth.subscribe(handleChange); + + return () => { + auth.unsubscribe(handleChange); }; - } - - componentDidMount() { - auth.subscribe(this.handleChange); - } - - componentWillUnmount() { - auth.unsubscribe(this.handleChange); - } - - handleChange = () => { - this.setState({ - auth: getAuthProps(), - }); - } - - render() { - return ; - } - } + }); + + return ; + }; const wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || 'Component'; EnhancedComponent.displayName = `WithAuth(${wrappedComponentName})`; diff --git a/ui/src/services/apolloClient/apolloClient.js b/ui/src/services/apolloClient/apolloClient.js index 1f7d7883..c37dd90c 100644 --- a/ui/src/services/apolloClient/apolloClient.js +++ b/ui/src/services/apolloClient/apolloClient.js @@ -2,7 +2,6 @@ import { ApolloClient, ApolloLink, split, HttpLink } from '@apollo/client'; import { getMainDefinition } from '@apollo/client/utilities'; import { WebSocketLink } from '@apollo/client/link/ws'; import { InMemoryCache } from '@apollo/client/cache'; -import auth from '@/services/auth'; import { SET_CACHE } from '@/services/queries'; import { resolvers, defaults } from './localState'; // import introspectionQueryResultData from './fragmentTypes.json'; @@ -13,61 +12,62 @@ import { resolvers, defaults } from './localState'; introspectionQueryResultData, }); */ -const cache = new InMemoryCache({ - dataIdFromObject: object => `${object.__typename}:${object.nodeId}`, - // fragmentMatcher, -}); - -const authMiddleware = new ApolloLink((operation, forward) => { - const accessToken = auth.getAccessToken(); - if (accessToken) { - operation.setContext({ - headers: { - Authorization: `Bearer ${accessToken}`, - }, - }); - } - return forward(operation); -}); +export default function apolloClient(token) { + const cache = new InMemoryCache({ + dataIdFromObject: object => `${object.__typename}:${object.nodeId}`, + // fragmentMatcher, + }); -const httpLink = new HttpLink({ - uri: process.env.REACT_APP_GRAPHQL_ENDPOINT, -}); + const authMiddleware = new ApolloLink((operation, forward) => { + if (token) { + operation.setContext({ + headers: { + Authorization: `Bearer ${token}`, + }, + }); + } + return forward(operation); + }); -const wsLink = new WebSocketLink({ - uri: process.env.REACT_APP_GRAPHQL_SUBSCRIPTION, - options: { - reconnect: true, - }, -}); + const httpLink = new HttpLink({ + uri: process.env.REACT_APP_GRAPHQL_ENDPOINT, + }); -// using the ability to split links, you can send data to each link -// depending on what kind of operation is being sent -const terminatingLink = split( - // split based on operation type - ({ query }) => { - const { kind, operation } = getMainDefinition(query); - return kind === 'OperationDefinition' && operation === 'subscription'; - }, - wsLink, - httpLink, -); + const wsLink = new WebSocketLink({ + uri: process.env.REACT_APP_GRAPHQL_SUBSCRIPTION, + options: { + reconnect: true, + }, + }); -const client = new ApolloClient({ - cache, - resolvers, - link: ApolloLink.from([authMiddleware, terminatingLink]), -}); + // using the ability to split links, you can send data to each link + // depending on what kind of operation is being sent + const terminatingLink = split( + // split based on operation type + ({ query }) => { + const { kind, operation } = getMainDefinition(query); + return kind === 'OperationDefinition' && operation === 'subscription'; + }, + wsLink, + httpLink, + ); -const initStore = () => { - cache.writeQuery({ - query: SET_CACHE, - data: defaults, + const client = new ApolloClient({ + cache, + resolvers, + link: ApolloLink.from([authMiddleware, terminatingLink]), }); -}; -initStore(); + const initStore = () => { + cache.writeQuery({ + query: SET_CACHE, + data: defaults, + }); + }; + + initStore(); -client.onResetStore(initStore); + client.onResetStore(initStore); -export default client; + return client; +} diff --git a/ui/src/services/auth/auth.js b/ui/src/services/auth/auth.js index 1e89c4e4..c0f063f2 100644 --- a/ui/src/services/auth/auth.js +++ b/ui/src/services/auth/auth.js @@ -1,4 +1,5 @@ import Auth0 from 'auth0-js'; +import { useKeycloak } from '@react-keycloak/web'; import store from 'store'; import history from '@/services/history'; @@ -17,10 +18,13 @@ function fireHandlers() { handlers.forEach(fn => fn()); } -export function useAuth() { +export default function useAuth() { + const { keycloak } = useKeycloak(); + return { login: () => { - auth0.authorize({ title: 'Realities' }); + // auth0.authorize({ title: 'Realities' }); + keycloak.login(); }, handleAuthentication: () => ( new Promise((resolve, reject) => { @@ -46,17 +50,20 @@ export function useAuth() { fireHandlers(); history.push('/'); }, - isLoggedIn: () => !!store.get('auth'), - getAccessToken: () => { - const storedAuth = store.get('auth') || {}; - const tokenExpired = storedAuth.expiresAt < new Date().getTime(); - if (tokenExpired) { - store.remove('auth'); - fireHandlers(); - return null; - } - return storedAuth.accessToken; - }, + isLoggedIn: () => + // !!store.get('auth') + keycloak.authenticated, + getAccessToken: () => + keycloak.token, + // const storedAuth = store.get('auth') || {}; + // const tokenExpired = storedAuth.expiresAt < new Date().getTime(); + // if (tokenExpired) { + // store.remove('auth'); + // fireHandlers(); + // return null; + // } + // return storedAuth.accessToken; + getEmail: () => { const storedAuth = store.get('auth') || {}; return storedAuth.email; @@ -69,5 +76,3 @@ export function useAuth() { }, }; } - -export default useAuth(); diff --git a/ui/src/services/auth/index.js b/ui/src/services/auth/index.js index 0f0a71ae..258ada7c 100644 --- a/ui/src/services/auth/index.js +++ b/ui/src/services/auth/index.js @@ -1,5 +1,4 @@ import auth from './auth'; export default auth; -export * from './auth'; From 3bb707d01a2ec248ae121a2cbf8a38bfc8db27ac Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Mon, 19 Oct 2020 15:34:09 +0200 Subject: [PATCH 04/15] Rename auth file -> useAuth --- ui/src/App/App.js | 2 +- .../components/RealitiesNavbar/RealitiesNavbar.js | 2 +- ui/src/components/withAuth/withAuth.js | 2 +- ui/src/services/auth/index.js | 4 ---- ui/src/services/useAuth/index.js | 4 ++++ ui/src/services/{auth/auth.js => useAuth/useAuth.js} | 0 6 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 ui/src/services/auth/index.js create mode 100644 ui/src/services/useAuth/index.js rename ui/src/services/{auth/auth.js => useAuth/useAuth.js} (100%) diff --git a/ui/src/App/App.js b/ui/src/App/App.js index 4c0cbe96..842ed021 100644 --- a/ui/src/App/App.js +++ b/ui/src/App/App.js @@ -1,7 +1,7 @@ import React from 'react'; import Keycloak from 'keycloak-js'; import { ReactKeycloakProvider } from '@react-keycloak/web'; -import useAuth from '@/services/auth'; +import useAuth from '@/services/useAuth'; import { ApolloProvider } from '@apollo/client'; import apolloClient from '@/services/apolloClient'; import AuthRoutesContainer from './components/AuthRoutesContainer'; diff --git a/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js b/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js index 74fc31fb..ccc4e747 100644 --- a/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js +++ b/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js @@ -14,7 +14,7 @@ import { } from 'reactstrap'; import { Link } from 'react-router-dom'; import styled from 'styled-components'; -import useAuth from '@/services/auth'; +import useAuth from '@/services/useAuth'; import Search from '@/components/Search'; import ViewerName from '@/components/ViewerName'; diff --git a/ui/src/components/withAuth/withAuth.js b/ui/src/components/withAuth/withAuth.js index 2105c1bc..c8d58390 100644 --- a/ui/src/components/withAuth/withAuth.js +++ b/ui/src/components/withAuth/withAuth.js @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import useAuth from '@/services/auth'; +import useAuth from '@/services/useAuth'; export default (WrappedComponent) => { const EnhancedComponent = (props) => { diff --git a/ui/src/services/auth/index.js b/ui/src/services/auth/index.js deleted file mode 100644 index 258ada7c..00000000 --- a/ui/src/services/auth/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import auth from './auth'; - -export default auth; - diff --git a/ui/src/services/useAuth/index.js b/ui/src/services/useAuth/index.js new file mode 100644 index 00000000..1af7a820 --- /dev/null +++ b/ui/src/services/useAuth/index.js @@ -0,0 +1,4 @@ +import useAuth from './useAuth'; + +export default useAuth; + diff --git a/ui/src/services/auth/auth.js b/ui/src/services/useAuth/useAuth.js similarity index 100% rename from ui/src/services/auth/auth.js rename to ui/src/services/useAuth/useAuth.js From 94532c9b93090f134d1040770ab54715c1f93cb5 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Wed, 21 Oct 2020 16:00:47 +0200 Subject: [PATCH 05/15] Technically make authing with keycloak work --- ui/.env | 1 + ui/src/App/App.js | 19 +++++- .../components/AuthCallback/AuthCallback.js | 59 +++++++++------- ui/src/services/useAuth/useAuth.js | 68 +++++++++++-------- 4 files changed, 89 insertions(+), 58 deletions(-) diff --git a/ui/.env b/ui/.env index 1e05ae35..2abc8090 100644 --- a/ui/.env +++ b/ui/.env @@ -4,3 +4,4 @@ REACT_APP_AUTH0_DOMAIN=platoproject.eu.auth0.com REACT_APP_AUTH0_CLIENT_ID=LEdrYzy4Gg5Eoj4WJWPjPKpR8u3tpVhm REACT_APP_AUTH0_AUDIENCE=https://realities-api.platoproject.org REACT_APP_AUTH0_CALLBACK_URL=http://localhost:3000/auth-callback +REACT_APP_KEYCLOAK_CALLBACK_URL=http://localhost:3000/auth-callback diff --git a/ui/src/App/App.js b/ui/src/App/App.js index 842ed021..3b23619c 100644 --- a/ui/src/App/App.js +++ b/ui/src/App/App.js @@ -8,14 +8,19 @@ import AuthRoutesContainer from './components/AuthRoutesContainer'; const keycloak = Keycloak({ realm: 'plato', - 'auth-server-url': 'https://auth.platoproject.org/auth/', + // 'auth-server-url': 'https://auth.platoproject.org/auth/', + url: 'https://auth.platoproject.org/auth/', 'ssl-required': 'external', - resource: 'realities', + // resource: 'realities', 'public-client': true, 'confidential-port': 0, clientId: 'realities', }); +const eventLogger = (event, error) => { + console.log('onKeycloakEvent', event, error); +}; + const ApolloSetup = () => { const { getAccessToken } = useAuth(); console.log('token', getAccessToken()); @@ -28,7 +33,15 @@ const ApolloSetup = () => { }; const App = () => ( - + ); diff --git a/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js b/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js index cc950bba..8b21bcf3 100644 --- a/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js +++ b/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js @@ -1,9 +1,9 @@ -import React, { Component } from 'react'; +import React, { useEffect } from 'react'; // import { gql } from '@apollo/client'; import Loader from 'react-loader'; -// import auth from '@/services/auth'; +import useAuth from '@/services/useAuth'; // import apolloClient from '@/services/apolloClient'; -// import history from '@/services/history'; +import history from '@/services/history'; // const GET_VIEWER = gql` // query AuthCallback_person($email: String!) { @@ -24,27 +24,34 @@ import Loader from 'react-loader'; // } // `; -class AuthCallback extends Component { - componentWillMount() { - // auth.handleAuthentication().then(({ email }) => { - // apolloClient - // .query({ query: GET_VIEWER, variables: { email } }) - // .then(({ data }) => { - // if (data.person) { - // history.replace('/'); - // } else { - // apolloClient - // .mutate({ mutation: CREATE_VIEWER }) - // .then(() => history.replace('/profile')) - // .catch(err => console.log(err)); - // } - // }) - // .catch(err => console.log(err)); - // }); - } +const AuthCallback = () => { + const auth = useAuth(); + // const client = apolloClient(auth.getAccessToken()); - render() { - return ( + useEffect(() => { + if (auth.initialized && auth.isLoggedIn()) { + // auth.handleAuthentication().then(({ email }) => { + // apolloClient + // .query({ query: GET_VIEWER, variables: { email } }) + // .then(({ data }) => { + // if (data.person) { + // history.replace('/'); + // } else { + // apolloClient + // .mutate({ mutation: CREATE_VIEWER }) + // .then(() => history.replace('/profile')) + // .catch(err => console.log(err)); + // } + // }) + // .catch(err => console.log(err)); + // }); + history.replace('/'); + } + }, [auth.initialized]); + + return ( +
+
{auth.initialized ? 'inited' : 'NOT inited'}
- ); - } -} +
+ ); +}; export default AuthCallback; diff --git a/ui/src/services/useAuth/useAuth.js b/ui/src/services/useAuth/useAuth.js index c0f063f2..51eec591 100644 --- a/ui/src/services/useAuth/useAuth.js +++ b/ui/src/services/useAuth/useAuth.js @@ -1,16 +1,16 @@ -import Auth0 from 'auth0-js'; +// import Auth0 from 'auth0-js'; import { useKeycloak } from '@react-keycloak/web'; import store from 'store'; import history from '@/services/history'; -const auth0 = new Auth0.WebAuth({ - domain: process.env.REACT_APP_AUTH0_DOMAIN, - clientID: process.env.REACT_APP_AUTH0_CLIENT_ID, - audience: process.env.REACT_APP_AUTH0_AUDIENCE, - redirectUri: process.env.REACT_APP_AUTH0_CALLBACK_URL, - responseType: 'token id_token', - scope: 'openid email', -}); +// const auth0 = new Auth0.WebAuth({ +// domain: process.env.REACT_APP_AUTH0_DOMAIN, +// clientID: process.env.REACT_APP_AUTH0_CLIENT_ID, +// audience: process.env.REACT_APP_AUTH0_AUDIENCE, +// redirectUri: process.env.REACT_APP_AUTH0_CALLBACK_URL, +// responseType: 'token id_token', +// scope: 'openid email', +// }); let handlers = []; @@ -19,34 +19,40 @@ function fireHandlers() { } export default function useAuth() { - const { keycloak } = useKeycloak(); + const { keycloak, initialized } = useKeycloak(); return { login: () => { // auth0.authorize({ title: 'Realities' }); - keycloak.login(); + keycloak.login({ + redirectUri: process.env.REACT_APP_KEYCLOAK_CALLBACK_URL, + }); }, handleAuthentication: () => ( - new Promise((resolve, reject) => { - auth0.parseHash((err, authResult) => { - if (authResult && authResult.accessToken && authResult.idToken) { - const auth = { - accessToken: authResult.accessToken, - idToken: authResult.idToken, - expiresAt: (authResult.expiresIn * 1000) + new Date().getTime(), - email: authResult.idTokenPayload && authResult.idTokenPayload.email, - }; - store.set('auth', auth); - fireHandlers(); - resolve(auth); - } else { - reject(err); - } - }); - }) + 'potato' + // new Promise((resolve, reject) => { + // auth0.parseHash((err, authResult) => { + // if (authResult && authResult.accessToken && authResult.idToken) { + // const auth = { + // accessToken: authResult.accessToken, + // idToken: authResult.idToken, + // expiresAt: (authResult.expiresIn * 1000) + new Date().getTime(), + // email: authResult.idTokenPayload && authResult.idTokenPayload.email, + // }; + // store.set('auth', auth); + // fireHandlers(); + // resolve(auth); + // } else { + // reject(err); + // } + // }); + // }) ), logout: () => { - store.remove('auth'); + // store.remove('auth'); + keycloak.logout({ + redirectUri: process.env.REACT_APP_KEYCLOAK_CALLBACK_URL, + }); fireHandlers(); history.push('/'); }, @@ -68,11 +74,15 @@ export default function useAuth() { const storedAuth = store.get('auth') || {}; return storedAuth.email; }, + // TODO: only used in withAuth, we can probably remove this. the hooks + // should make it reactive enough or? subscribe: (fn) => { handlers.push(fn); }, unsubscribe: (fn) => { handlers = handlers.filter(item => item !== fn); }, + keycloak, + initialized, }; } From 201fc68b95adcbac9348e00307f28ccaa660f292 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Wed, 21 Oct 2020 18:38:14 +0200 Subject: [PATCH 06/15] Start verifying keycloak logins in the backend --- api/package-lock.json | 410 +++++++++++++++++++++ api/package.json | 2 + api/src/index.js | 42 ++- ui/src/components/ViewerName/ViewerName.js | 2 + ui/src/components/withAuth/withAuth.js | 1 + ui/src/services/useAuth/useAuth.js | 7 +- 6 files changed, 446 insertions(+), 18 deletions(-) diff --git a/api/package-lock.json b/api/package-lock.json index 539813cd..e0614a95 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -1225,6 +1225,12 @@ "@sendgrid/helpers": "^6.3.0" } }, + "@testim/chrome-version": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.0.7.tgz", + "integrity": "sha512-8UT/J+xqCYfn3fKtOznAibsHpiuDshCb0fwgWxRazTT19Igp9ovoXMPhXyLD6m3CKQGTMHgqoxaFfMWaL40Rnw==", + "optional": true + }, "@types/accepts": { "version": "1.3.5", "resolved": "http://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", @@ -1355,6 +1361,16 @@ "@types/node": "*" } }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "optional": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, "@types/graphql-upload": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/@types/graphql-upload/-/graphql-upload-8.0.3.tgz", @@ -1424,6 +1440,12 @@ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz", "integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==" }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "optional": true + }, "@types/node": { "version": "10.12.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.10.tgz", @@ -1509,6 +1531,15 @@ "@types/node": "*" } }, + "@types/yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, "@types/zen-observable": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.0.tgz", @@ -1594,6 +1625,32 @@ } } }, + "agent-base": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.1.tgz", + "integrity": "sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg==", + "optional": true, + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "optional": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -3519,6 +3576,12 @@ } } }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "optional": true + }, "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -3680,6 +3743,38 @@ "upath": "^1.0.5" } }, + "chromedriver": { + "version": "86.0.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-86.0.0.tgz", + "integrity": "sha512-byLJWhAfuYOmzRYPDf4asJgGDbI4gJGHa+i8dnQZGuv+6WW1nW1Fg+8zbBMOfLvGn7sKL41kVdmCEVpQHn9oyg==", + "optional": true, + "requires": { + "@testim/chrome-version": "^1.0.7", + "axios": "^0.19.2", + "del": "^5.1.0", + "extract-zip": "^2.0.1", + "https-proxy-agent": "^5.0.0", + "mkdirp": "^1.0.4", + "tcp-port-used": "^1.0.1" + }, + "dependencies": { + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "optional": true, + "requires": { + "follow-redirects": "1.5.10" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true + } + } + }, "ci-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", @@ -4227,6 +4322,82 @@ } } }, + "del": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz", + "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==", + "optional": true, + "requires": { + "globby": "^10.0.1", + "graceful-fs": "^4.2.2", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.1", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0" + }, + "dependencies": { + "globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "optional": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "optional": true + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "optional": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "optional": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-path-inside": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", + "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "optional": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "optional": true + } + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4408,6 +4579,15 @@ } } }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "optional": true, + "requires": { + "once": "^1.4.0" + } + }, "enhanced-resolve": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", @@ -5078,6 +5258,44 @@ "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-9.0.0.tgz", "integrity": "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==" }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "optional": true, + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "optional": true, + "requires": { + "ms": "2.1.2" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "optional": true, + "requires": { + "pump": "^3.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -5210,6 +5428,15 @@ "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "optional": true, + "requires": { + "pend": "~1.2.0" + } + }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -6344,6 +6571,33 @@ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "optional": true, + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "optional": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, "iconv-lite": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", @@ -6466,6 +6720,12 @@ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "optional": true + }, "ipaddr.js": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", @@ -6700,6 +6960,12 @@ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "optional": true + }, "is-path-inside": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", @@ -6797,6 +7063,12 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "optional": true + }, "is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", @@ -6812,6 +7084,17 @@ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" }, + "is2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.1.tgz", + "integrity": "sha512-+WaJvnaA7aJySz2q/8sLjMb2Mw14KTplHmSwcSpZ/fWJPkUmqw3YTzSWbPJ7OAwRvdYTWF2Wg+yYJ1AdP5Z8CA==", + "optional": true, + "requires": { + "deep-is": "^0.1.3", + "ip-regex": "^2.1.0", + "is-url": "^1.2.2" + } + }, "isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -6984,6 +7267,43 @@ "safe-buffer": "^5.0.1" } }, + "jwk-to-pem": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.4.tgz", + "integrity": "sha512-4CCK9UBHNWjWtfSHdyu3I6rA8vlN5cWqnVuwY0cOMyXtw6M1tP+yrM8GZpwk+P932Dc3cLag4d35B6CqyIf89A==", + "requires": { + "asn1.js": "^5.3.0", + "elliptic": "^6.5.3", + "safe-buffer": "^5.0.1" + }, + "dependencies": { + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "elliptic": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + } + } + }, "jwks-rsa": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.3.0.tgz", @@ -7006,6 +7326,34 @@ "safe-buffer": "^5.0.1" } }, + "keycloak-connect": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/keycloak-connect/-/keycloak-connect-11.0.2.tgz", + "integrity": "sha512-pfPnOpoDrkvH2zHyMKOS/H/gagKyXpckqHay9aCuLIEiETEIH0ogSt5JUJ12MFBE8O0wpVYVpz0erFNP01uZGQ==", + "requires": { + "chromedriver": "^86.0.0", + "jwk-to-pem": "^2.0.0" + } + }, + "keycloak-connect-graphql": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/keycloak-connect-graphql/-/keycloak-connect-graphql-0.6.3.tgz", + "integrity": "sha512-FC7yhC/uraXbW+JnBDtX/VFKMhquXljxRhcPE3iYh0NU3ywAJAfrP9VzW5O/wUZK8ZtwhjQAgL7kTbBodZ9RJA==", + "requires": { + "@graphql-tools/utils": "6.0.18" + }, + "dependencies": { + "@graphql-tools/utils": { + "version": "6.0.18", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-6.0.18.tgz", + "integrity": "sha512-8ntYuXJucBtjViOYljeKBzScfpVTnv7BfqIPU/WJ65h6nXD+qf8fMUR1C4MpCUeFvSjMiDSB5Z4enJmau/9D3A==", + "requires": { + "@ardatan/aggregate-error": "0.0.1", + "camel-case": "4.1.1" + } + } + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -7967,6 +8315,15 @@ "p-limit": "^1.1.0" } }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "optional": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", @@ -8132,6 +8489,12 @@ "sha.js": "^2.4.8" } }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "optional": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -8390,6 +8753,16 @@ "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.7.tgz", "integrity": "sha1-wA1cUSi6xYBr7BXSt+fNq+QlMfM=" }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "optional": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -9711,6 +10084,33 @@ "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=" }, + "tcp-port-used": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.1.tgz", + "integrity": "sha512-rwi5xJeU6utXoEIiMvVBMc9eJ2/ofzB+7nLOdnZuFTmNCLqRiQh2sMG9MqCxHU/69VC/Fwp5dV9306Qd54ll1Q==", + "optional": true, + "requires": { + "debug": "4.1.0", + "is2": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", + "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, "term-size": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", @@ -10706,6 +11106,16 @@ "camelcase": "^4.1.0" } }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "optional": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "zen-observable": { "version": "0.8.15", "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", diff --git a/api/package.json b/api/package.json index d2b96228..dfe8196a 100644 --- a/api/package.json +++ b/api/package.json @@ -47,6 +47,8 @@ "graphql-resolvers": "0.4.2", "graphql-tools": "6.2.0", "jwks-rsa": "^1.2.1", + "keycloak-connect": "^11.0.2", + "keycloak-connect-graphql": "^0.6.3", "lodash": "^4.17.11", "mime": "^2.0.3", "mocha": "^4.0.1", diff --git a/api/src/index.js b/api/src/index.js index 8457e099..a5dbe308 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -2,8 +2,10 @@ import express from 'express'; import cors from 'cors'; import { createServer } from 'http'; import { ApolloServer } from 'apollo-server-express'; -import expressJwt from 'express-jwt'; -import jwksRsa from 'jwks-rsa'; +// import expressJwt from 'express-jwt'; +// import jwksRsa from 'jwks-rsa'; +import Keycloak from 'keycloak-connect'; +import { KeycloakContext } from 'keycloak-connect-graphql'; import neo4jDriver from './db/neo4jDriver'; import schema from './graphql/schema'; import startSchedulers from './services/scheduler'; @@ -19,20 +21,32 @@ if (!NODE_ENV || NODE_ENV.includes('dev')) { app.use(cors()); } -app.use(expressJwt({ - credentialsRequired: false, - // Dynamically provide a signing key based on the kid in the header - // and the singing keys provided by the JWKS endpoint - secret: jwksRsa.expressJwtSecret({ - cache: true, - rateLimit: true, - jwksRequestsPerMinute: 5, - jwksUri: 'https://platoproject.eu.auth0.com/.well-known/jwks.json', - }), -})); +const keycloak = new Keycloak({}, { + realm: 'plato', + 'auth-server-url': 'https://auth.platoproject.org/auth/', + 'ssl-required': 'external', + resource: 'realities', + 'public-client': true, + 'confidential-port': 0, +}); + +app.use('/graphql', keycloak.middleware()); + +// app.use(expressJwt({ +// credentialsRequired: false, +// // Dynamically provide a signing key based on the kid in the header +// // and the singing keys provided by the JWKS endpoint +// secret: jwksRsa.expressJwtSecret({ +// cache: true, +// rateLimit: true, +// jwksRequestsPerMinute: 5, +// jwksUri: 'https://platoproject.eu.auth0.com/.well-known/jwks.json', +// }), +// })); function getUser(user) { if (!user) return null; + console.log('user', user); return Object.assign( {}, user, @@ -46,6 +60,8 @@ function getUser(user) { const server = new ApolloServer({ schema, context: async ({ req }) => ({ + // TODO: maybe rather use the keycloak object to generate the user object? + kauth: new KeycloakContext({ req }), user: getUser(req && req.user), driver: neo4jDriver, }), diff --git a/ui/src/components/ViewerName/ViewerName.js b/ui/src/components/ViewerName/ViewerName.js index 35a77bd4..11bd6d27 100644 --- a/ui/src/components/ViewerName/ViewerName.js +++ b/ui/src/components/ViewerName/ViewerName.js @@ -17,9 +17,11 @@ const ViewerName = withAuth(({ auth }) => { variables: { email: auth.email }, }); + console.log('auth', auth); if (loading) return auth.email; if (error) return `Error! ${error.message}`; const viewer = data.person || {}; + console.log('data', data); return viewer.name || auth.email; }); diff --git a/ui/src/components/withAuth/withAuth.js b/ui/src/components/withAuth/withAuth.js index c8d58390..cf0c3a49 100644 --- a/ui/src/components/withAuth/withAuth.js +++ b/ui/src/components/withAuth/withAuth.js @@ -10,6 +10,7 @@ export default (WrappedComponent) => { logout: auth.logout, isLoggedIn: auth.isLoggedIn(), email: auth.getEmail(), + auth, }); const [authProps, setAuthProps] = useState(getAuthProps()); diff --git a/ui/src/services/useAuth/useAuth.js b/ui/src/services/useAuth/useAuth.js index 51eec591..331f2766 100644 --- a/ui/src/services/useAuth/useAuth.js +++ b/ui/src/services/useAuth/useAuth.js @@ -1,6 +1,6 @@ // import Auth0 from 'auth0-js'; import { useKeycloak } from '@react-keycloak/web'; -import store from 'store'; +// import store from 'store'; import history from '@/services/history'; // const auth0 = new Auth0.WebAuth({ @@ -70,10 +70,7 @@ export default function useAuth() { // } // return storedAuth.accessToken; - getEmail: () => { - const storedAuth = store.get('auth') || {}; - return storedAuth.email; - }, + getEmail: () => keycloak.tokenParsed && keycloak.tokenParsed.email, // TODO: only used in withAuth, we can probably remove this. the hooks // should make it reactive enough or? subscribe: (fn) => { From 38a4ebdb916adc1c8c8deec1e99bd39e30a02d46 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Wed, 21 Oct 2020 19:11:03 +0200 Subject: [PATCH 07/15] Make auth for gql mutations work --- api/src/index.js | 32 ++++++++----------- .../components/AuthCallback/AuthCallback.js | 2 +- .../RealitiesNavbar/RealitiesNavbar.js | 2 +- ui/src/components/ViewerName/ViewerName.js | 2 -- ui/src/components/withAuth/withAuth.js | 2 +- ui/src/services/useAuth/useAuth.js | 5 ++- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/api/src/index.js b/api/src/index.js index a5dbe308..60c63467 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -44,27 +44,21 @@ app.use('/graphql', keycloak.middleware()); // }), // })); -function getUser(user) { - if (!user) return null; - console.log('user', user); - return Object.assign( - {}, - user, - { - email: user['https://realities.platoproject.org/email'], - role: user['https://realities.platoproject.org/role'], - }, - ); -} - const server = new ApolloServer({ schema, - context: async ({ req }) => ({ - // TODO: maybe rather use the keycloak object to generate the user object? - kauth: new KeycloakContext({ req }), - user: getUser(req && req.user), - driver: neo4jDriver, - }), + context: async ({ req }) => { + const kauth = new KeycloakContext({ req }); + + return { + kauth, + user: { + email: kauth.accessToken && kauth.accessToken.content.email, + role: 'user', + // TODO: put the user's tenantId here + }, + driver: neo4jDriver, + }; + }, tracing: true, }); server.applyMiddleware({ app, path: '/graphql' }); diff --git a/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js b/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js index 8b21bcf3..a982e715 100644 --- a/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js +++ b/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js @@ -29,7 +29,7 @@ const AuthCallback = () => { // const client = apolloClient(auth.getAccessToken()); useEffect(() => { - if (auth.initialized && auth.isLoggedIn()) { + if (auth.initialized && auth.isLoggedIn) { // auth.handleAuthentication().then(({ email }) => { // apolloClient // .query({ query: GET_VIEWER, variables: { email } }) diff --git a/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js b/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js index ccc4e747..cc585559 100644 --- a/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js +++ b/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js @@ -43,7 +43,7 @@ const RealitiesNavbar = () => { About - { isLoggedIn() ? ( + { isLoggedIn ? ( diff --git a/ui/src/components/ViewerName/ViewerName.js b/ui/src/components/ViewerName/ViewerName.js index 11bd6d27..35a77bd4 100644 --- a/ui/src/components/ViewerName/ViewerName.js +++ b/ui/src/components/ViewerName/ViewerName.js @@ -17,11 +17,9 @@ const ViewerName = withAuth(({ auth }) => { variables: { email: auth.email }, }); - console.log('auth', auth); if (loading) return auth.email; if (error) return `Error! ${error.message}`; const viewer = data.person || {}; - console.log('data', data); return viewer.name || auth.email; }); diff --git a/ui/src/components/withAuth/withAuth.js b/ui/src/components/withAuth/withAuth.js index cf0c3a49..14a55a70 100644 --- a/ui/src/components/withAuth/withAuth.js +++ b/ui/src/components/withAuth/withAuth.js @@ -8,7 +8,7 @@ export default (WrappedComponent) => { const getAuthProps = () => ({ login: auth.login, logout: auth.logout, - isLoggedIn: auth.isLoggedIn(), + isLoggedIn: auth.isLoggedIn, email: auth.getEmail(), auth, }); diff --git a/ui/src/services/useAuth/useAuth.js b/ui/src/services/useAuth/useAuth.js index 331f2766..636be133 100644 --- a/ui/src/services/useAuth/useAuth.js +++ b/ui/src/services/useAuth/useAuth.js @@ -21,6 +21,9 @@ function fireHandlers() { export default function useAuth() { const { keycloak, initialized } = useKeycloak(); + // TODO: doesn't seem like any of the properties of `keycloak` are actually + // reactive. so set up some system where we turn e.g. isLoggedIn into a useState + return { login: () => { // auth0.authorize({ title: 'Realities' }); @@ -56,7 +59,7 @@ export default function useAuth() { fireHandlers(); history.push('/'); }, - isLoggedIn: () => + isLoggedIn: // !!store.get('auth') keycloak.authenticated, getAccessToken: () => From 74e83f27c0de3207630174da036abb27f269a28c Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Wed, 21 Oct 2020 19:14:08 +0200 Subject: [PATCH 08/15] Only set the viewer as a user if they have auth'ed --- api/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/index.js b/api/src/index.js index 60c63467..41b777be 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -53,7 +53,7 @@ const server = new ApolloServer({ kauth, user: { email: kauth.accessToken && kauth.accessToken.content.email, - role: 'user', + role: kauth.accessToken && 'user', // TODO: put the user's tenantId here }, driver: neo4jDriver, From 68c71a25dd4722d07282c57630fb295f7effaf42 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Thu, 22 Oct 2020 17:16:02 +0200 Subject: [PATCH 09/15] Re-enable creating missing accounts on first login --- .../components/AuthCallback/AuthCallback.js | 73 +++++++++---------- .../RealitiesNavbar/RealitiesNavbar.js | 2 + ui/src/services/useAuth/useAuth.js | 10 ++- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js b/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js index a982e715..06a4fa3a 100644 --- a/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js +++ b/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js @@ -1,53 +1,52 @@ import React, { useEffect } from 'react'; -// import { gql } from '@apollo/client'; +import { gql } from '@apollo/client'; import Loader from 'react-loader'; import useAuth from '@/services/useAuth'; -// import apolloClient from '@/services/apolloClient'; +import apolloClient from '@/services/apolloClient'; import history from '@/services/history'; -// const GET_VIEWER = gql` -// query AuthCallback_person($email: String!) { -// person(email: $email) { -// nodeId -// email -// name -// } -// } -// `; +const GET_VIEWER = gql` + query AuthCallback_person($email: String!) { + person(email: $email) { + nodeId + email + name + } + } +`; -// const CREATE_VIEWER = gql` -// mutation AuthCallback_createViewer { -// createViewer { -// nodeId -// email -// } -// } -// `; +const CREATE_VIEWER = gql` + mutation AuthCallback_createViewer { + createViewer { + nodeId + email + } + } +`; const AuthCallback = () => { const auth = useAuth(); - // const client = apolloClient(auth.getAccessToken()); useEffect(() => { if (auth.initialized && auth.isLoggedIn) { - // auth.handleAuthentication().then(({ email }) => { - // apolloClient - // .query({ query: GET_VIEWER, variables: { email } }) - // .then(({ data }) => { - // if (data.person) { - // history.replace('/'); - // } else { - // apolloClient - // .mutate({ mutation: CREATE_VIEWER }) - // .then(() => history.replace('/profile')) - // .catch(err => console.log(err)); - // } - // }) - // .catch(err => console.log(err)); - // }); - history.replace('/'); + const client = apolloClient(auth.getAccessToken()); + const email = auth.getEmail(); + + client + .query({ query: GET_VIEWER, variables: { email } }) + .then(({ data }) => { + if (data.person) { + history.replace('/'); + } else { + client + .mutate({ mutation: CREATE_VIEWER }) + .then(() => history.replace('/profile')) + .catch(err => console.log(err)); + } + }) + .catch(err => console.log(err)); } - }, [auth.initialized]); + }, [auth.initialized, auth.isLoggedIn]); return (
diff --git a/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js b/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js index cc585559..565ac5e9 100644 --- a/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js +++ b/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js @@ -26,6 +26,8 @@ const RealitiesNavbar = () => { const [isOpen, setIsOpen] = useState(false); const { isLoggedIn, login, logout } = useAuth(); + console.log('navbar isloggedin', isLoggedIn); + return ( diff --git a/ui/src/services/useAuth/useAuth.js b/ui/src/services/useAuth/useAuth.js index 636be133..70368023 100644 --- a/ui/src/services/useAuth/useAuth.js +++ b/ui/src/services/useAuth/useAuth.js @@ -1,4 +1,5 @@ // import Auth0 from 'auth0-js'; +import { useState } from 'react'; import { useKeycloak } from '@react-keycloak/web'; // import store from 'store'; import history from '@/services/history'; @@ -21,6 +22,8 @@ function fireHandlers() { export default function useAuth() { const { keycloak, initialized } = useKeycloak(); + const [isLoggedIn/* , setIsLoggedIn */] = useState(keycloak.authenticated); + // TODO: doesn't seem like any of the properties of `keycloak` are actually // reactive. so set up some system where we turn e.g. isLoggedIn into a useState @@ -59,9 +62,10 @@ export default function useAuth() { fireHandlers(); history.push('/'); }, - isLoggedIn: - // !!store.get('auth') - keycloak.authenticated, + // isLoggedIn: + // // !!store.get('auth') + // keycloak.authenticated, + isLoggedIn, getAccessToken: () => keycloak.token, // const storedAuth = store.get('auth') || {}; From 1767db5d5da8ada1abd1e73a691ac32bb9da8a11 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Mon, 26 Oct 2020 16:58:28 +0100 Subject: [PATCH 10/15] Update react-keycloak --- ui/package-lock.json | 14 +++++------ ui/package.json | 2 +- .../components/AuthCallback/AuthCallback.js | 24 ++++++++++++++----- .../RealitiesNavbar/RealitiesNavbar.js | 7 ++++-- ui/src/services/useAuth/useAuth.js | 10 ++++---- 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 0a75adb1..b7ef3e4d 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -401,9 +401,9 @@ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" }, "@react-keycloak/core": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@react-keycloak/core/-/core-3.0.0.tgz", - "integrity": "sha512-T2w5phBXu8Uye8OcB0nzNccWcI1xDFKcp36KjBfBUHz8Ehc59ylvZicS+woNOxARmUsnbigcM9NcbARPW7pciA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@react-keycloak/core/-/core-3.2.0.tgz", + "integrity": "sha512-1yzU7gQzs+6E1v6hGqxy0Q+kpMHg9sEcke2yxZR29WoU8KNE8E50xS6UbI8N7rWsgyYw8r9W1cUPCOF48MYjzw==", "requires": { "react-fast-compare": "^3.2.0" }, @@ -416,12 +416,12 @@ } }, "@react-keycloak/web": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@react-keycloak/web/-/web-3.0.0.tgz", - "integrity": "sha512-Lolk3kuFT6e1LIdPdiIuzA/dJ/cD2/G1O+hG5Otgbgelx7ZmesM1w36LmAPGUpwLhYtPXdgUsOjjPBPK06agew==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@react-keycloak/web/-/web-3.4.0.tgz", + "integrity": "sha512-yKKSCyqBtn7dt+VckYOW1IM5NW999pPkxDZOXqJ6dfXPXstYhOQCkTZqh8l7UL14PkpsoaHDh7hSJH8whah01g==", "requires": { "@babel/runtime": "^7.9.0", - "@react-keycloak/core": "^3.0.0", + "@react-keycloak/core": "^3.2.0", "hoist-non-react-statics": "^3.3.2" }, "dependencies": { diff --git a/ui/package.json b/ui/package.json index e5a69eb8..92dd1cdc 100644 --- a/ui/package.json +++ b/ui/package.json @@ -18,7 +18,7 @@ }, "dependencies": { "@apollo/client": "3.1.3", - "@react-keycloak/web": "^3.0.0", + "@react-keycloak/web": "3.4.0", "auth0-js": "^8.12.1", "autoprefixer": "7.1.6", "babel-core": "6.26.0", diff --git a/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js b/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js index 06a4fa3a..d4b0dc4f 100644 --- a/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js +++ b/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js @@ -25,12 +25,16 @@ const CREATE_VIEWER = gql` `; const AuthCallback = () => { - const auth = useAuth(); + const { + initialized, isLoggedIn, getEmail, getAccessToken, + } = useAuth(); + console.log('outside inited', initialized); + console.log('outside loggedin', isLoggedIn); useEffect(() => { - if (auth.initialized && auth.isLoggedIn) { - const client = apolloClient(auth.getAccessToken()); - const email = auth.getEmail(); + if (initialized && isLoggedIn) { + const client = apolloClient(getAccessToken()); + const email = getEmail(); client .query({ query: GET_VIEWER, variables: { email } }) @@ -46,11 +50,19 @@ const AuthCallback = () => { }) .catch(err => console.log(err)); } - }, [auth.initialized, auth.isLoggedIn]); + }); return (
-
{auth.initialized ? 'inited' : 'NOT inited'}
+
+ {(() => { + console.log('inrender inited', initialized); + if (initialized) { + return 'inited'; + } + return 'NOT'; + })()} +
{ const [isOpen, setIsOpen] = useState(false); - const { isLoggedIn, login, logout } = useAuth(); + const { + isLoggedIn, login, logout, initialized, + } = useAuth(); + console.log('initialized', initialized); console.log('navbar isloggedin', isLoggedIn); return ( @@ -45,7 +48,7 @@ const RealitiesNavbar = () => { About - { isLoggedIn ? ( + { initialized && isLoggedIn ? ( diff --git a/ui/src/services/useAuth/useAuth.js b/ui/src/services/useAuth/useAuth.js index 70368023..0a4622af 100644 --- a/ui/src/services/useAuth/useAuth.js +++ b/ui/src/services/useAuth/useAuth.js @@ -1,5 +1,5 @@ // import Auth0 from 'auth0-js'; -import { useState } from 'react'; +// import { useState } from 'react'; import { useKeycloak } from '@react-keycloak/web'; // import store from 'store'; import history from '@/services/history'; @@ -22,7 +22,7 @@ function fireHandlers() { export default function useAuth() { const { keycloak, initialized } = useKeycloak(); - const [isLoggedIn/* , setIsLoggedIn */] = useState(keycloak.authenticated); + // const [isLoggedIn/* , setIsLoggedIn */] = useState(keycloak.authenticated); // TODO: doesn't seem like any of the properties of `keycloak` are actually // reactive. so set up some system where we turn e.g. isLoggedIn into a useState @@ -62,10 +62,10 @@ export default function useAuth() { fireHandlers(); history.push('/'); }, - // isLoggedIn: + isLoggedIn: // // !!store.get('auth') - // keycloak.authenticated, - isLoggedIn, + keycloak.authenticated, + // isLoggedIn, getAccessToken: () => keycloak.token, // const storedAuth = store.get('auth') || {}; From 3b9b302220f9bfaa9088d2abd5fc982cd2fce903 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Mon, 26 Oct 2020 17:50:04 +0100 Subject: [PATCH 11/15] Clean commented and unused code --- ui/package-lock.json | 6 +- ui/package.json | 2 +- ui/src/App/App.js | 1 - .../components/AuthCallback/AuthCallback.js | 47 ++++++------ ui/src/components/withAuth/withAuth.js | 20 +---- ui/src/services/useAuth/useAuth.js | 75 +++---------------- 6 files changed, 37 insertions(+), 114 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index b7ef3e4d..e095dc8c 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -6618,9 +6618,9 @@ "integrity": "sha1-+m6i5DuQpoAohD0n8gddNajD5vk=" }, "keycloak-js": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-11.0.2.tgz", - "integrity": "sha512-dnvzgTetovu3eTjJtvBQQhxRN4jqvd/DaA2wFaE4aWIFXhwRcoPpZT8ZJ7MwlICDPdCgzbCsOsBjpL8CbYOZsg==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-9.0.3.tgz", + "integrity": "sha512-c8FFPa8YiJmPbJEMZ/mIrHflBR6FIFUm5xTWtIDzlrnoeF4u0wDmTBfo1u71rWIL1HanLvg3T+9AgR1NqfmGbA==", "requires": { "base64-js": "1.3.1", "js-sha256": "0.9.0" diff --git a/ui/package.json b/ui/package.json index 92dd1cdc..102c37f7 100644 --- a/ui/package.json +++ b/ui/package.json @@ -51,7 +51,7 @@ "html-webpack-plugin": "2.29.0", "jest": "20.0.4", "jquery": "^3.2.1", - "keycloak-js": "^11.0.2", + "keycloak-js": "^9.0.0", "lodash": "^4.17.4", "mime": "^2.0.3", "node-fetch": "^2.3.0", diff --git a/ui/src/App/App.js b/ui/src/App/App.js index 3b23619c..c3574b7c 100644 --- a/ui/src/App/App.js +++ b/ui/src/App/App.js @@ -23,7 +23,6 @@ const eventLogger = (event, error) => { const ApolloSetup = () => { const { getAccessToken } = useAuth(); - console.log('token', getAccessToken()); return ( diff --git a/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js b/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js index d4b0dc4f..4ecafecf 100644 --- a/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js +++ b/ui/src/App/components/AuthRoutesContainer/components/AuthCallback/AuthCallback.js @@ -26,43 +26,38 @@ const CREATE_VIEWER = gql` const AuthCallback = () => { const { - initialized, isLoggedIn, getEmail, getAccessToken, + initialized, isLoggedIn, email, getAccessToken, } = useAuth(); console.log('outside inited', initialized); console.log('outside loggedin', isLoggedIn); useEffect(() => { - if (initialized && isLoggedIn) { - const client = apolloClient(getAccessToken()); - const email = getEmail(); + if (initialized) { + if (isLoggedIn && email) { + const client = apolloClient(getAccessToken()); - client - .query({ query: GET_VIEWER, variables: { email } }) - .then(({ data }) => { - if (data.person) { - history.replace('/'); - } else { - client - .mutate({ mutation: CREATE_VIEWER }) - .then(() => history.replace('/profile')) - .catch(err => console.log(err)); - } - }) - .catch(err => console.log(err)); + client + .query({ query: GET_VIEWER, variables: { email } }) + .then(({ data }) => { + if (data.person) { + history.replace('/'); + } else { + client + .mutate({ mutation: CREATE_VIEWER }) + .then(() => history.replace('/profile')) + .catch(err => console.log(err)); + } + }) + .catch(err => console.log(err)); + } else { + // just logged out + history.replace('/'); + } } }); return (
-
- {(() => { - console.log('inrender inited', initialized); - if (initialized) { - return 'inited'; - } - return 'NOT'; - })()} -
{ const EnhancedComponent = (props) => { const auth = useAuth(); - const getAuthProps = () => ({ + const authProps = { login: auth.login, logout: auth.logout, isLoggedIn: auth.isLoggedIn, - email: auth.getEmail(), + email: auth.email, auth, - }); - - const [authProps, setAuthProps] = useState(getAuthProps()); - - const handleChange = () => { - setAuthProps(getAuthProps()); }; - useEffect(() => { - auth.subscribe(handleChange); - - return () => { - auth.unsubscribe(handleChange); - }; - }); - return ; }; diff --git a/ui/src/services/useAuth/useAuth.js b/ui/src/services/useAuth/useAuth.js index 0a4622af..c482ad20 100644 --- a/ui/src/services/useAuth/useAuth.js +++ b/ui/src/services/useAuth/useAuth.js @@ -1,91 +1,34 @@ -// import Auth0 from 'auth0-js'; -// import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useKeycloak } from '@react-keycloak/web'; -// import store from 'store'; -import history from '@/services/history'; - -// const auth0 = new Auth0.WebAuth({ -// domain: process.env.REACT_APP_AUTH0_DOMAIN, -// clientID: process.env.REACT_APP_AUTH0_CLIENT_ID, -// audience: process.env.REACT_APP_AUTH0_AUDIENCE, -// redirectUri: process.env.REACT_APP_AUTH0_CALLBACK_URL, -// responseType: 'token id_token', -// scope: 'openid email', -// }); - -let handlers = []; - -function fireHandlers() { - handlers.forEach(fn => fn()); -} export default function useAuth() { const { keycloak, initialized } = useKeycloak(); + const [email, setEmail] = useState(''); - // const [isLoggedIn/* , setIsLoggedIn */] = useState(keycloak.authenticated); + useEffect(() => { + setEmail(keycloak.tokenParsed && keycloak.tokenParsed.email); + }); - // TODO: doesn't seem like any of the properties of `keycloak` are actually - // reactive. so set up some system where we turn e.g. isLoggedIn into a useState + // TODO: figure out the reactivity here + // https://github.com/react-keycloak/react-keycloak/issues/116 return { login: () => { - // auth0.authorize({ title: 'Realities' }); keycloak.login({ redirectUri: process.env.REACT_APP_KEYCLOAK_CALLBACK_URL, }); }, - handleAuthentication: () => ( - 'potato' - // new Promise((resolve, reject) => { - // auth0.parseHash((err, authResult) => { - // if (authResult && authResult.accessToken && authResult.idToken) { - // const auth = { - // accessToken: authResult.accessToken, - // idToken: authResult.idToken, - // expiresAt: (authResult.expiresIn * 1000) + new Date().getTime(), - // email: authResult.idTokenPayload && authResult.idTokenPayload.email, - // }; - // store.set('auth', auth); - // fireHandlers(); - // resolve(auth); - // } else { - // reject(err); - // } - // }); - // }) - ), logout: () => { - // store.remove('auth'); keycloak.logout({ redirectUri: process.env.REACT_APP_KEYCLOAK_CALLBACK_URL, }); - fireHandlers(); - history.push('/'); }, isLoggedIn: - // // !!store.get('auth') keycloak.authenticated, - // isLoggedIn, + // TODO: fun->var getAccessToken: () => keycloak.token, - // const storedAuth = store.get('auth') || {}; - // const tokenExpired = storedAuth.expiresAt < new Date().getTime(); - // if (tokenExpired) { - // store.remove('auth'); - // fireHandlers(); - // return null; - // } - // return storedAuth.accessToken; - - getEmail: () => keycloak.tokenParsed && keycloak.tokenParsed.email, - // TODO: only used in withAuth, we can probably remove this. the hooks - // should make it reactive enough or? - subscribe: (fn) => { - handlers.push(fn); - }, - unsubscribe: (fn) => { - handlers = handlers.filter(item => item !== fn); - }, + email, keycloak, initialized, }; From bcb11ac1ae5c458c338ccc6b39aef07aea5a2915 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Mon, 26 Oct 2020 18:07:38 +0100 Subject: [PATCH 12/15] Clean up more --- api/src/index.js | 14 -------------- ui/src/App/App.js | 14 ++++++-------- .../components/AuthCallback/AuthCallback.js | 6 ++---- .../components/RealitiesNavbar/RealitiesNavbar.js | 3 --- ui/src/components/withAuth/withAuth.js | 10 +--------- ui/src/services/useAuth/useAuth.js | 4 +--- 6 files changed, 10 insertions(+), 41 deletions(-) diff --git a/api/src/index.js b/api/src/index.js index 41b777be..593a49f0 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -2,8 +2,6 @@ import express from 'express'; import cors from 'cors'; import { createServer } from 'http'; import { ApolloServer } from 'apollo-server-express'; -// import expressJwt from 'express-jwt'; -// import jwksRsa from 'jwks-rsa'; import Keycloak from 'keycloak-connect'; import { KeycloakContext } from 'keycloak-connect-graphql'; import neo4jDriver from './db/neo4jDriver'; @@ -32,18 +30,6 @@ const keycloak = new Keycloak({}, { app.use('/graphql', keycloak.middleware()); -// app.use(expressJwt({ -// credentialsRequired: false, -// // Dynamically provide a signing key based on the kid in the header -// // and the singing keys provided by the JWKS endpoint -// secret: jwksRsa.expressJwtSecret({ -// cache: true, -// rateLimit: true, -// jwksRequestsPerMinute: 5, -// jwksUri: 'https://platoproject.eu.auth0.com/.well-known/jwks.json', -// }), -// })); - const server = new ApolloServer({ schema, context: async ({ req }) => { diff --git a/ui/src/App/App.js b/ui/src/App/App.js index c3574b7c..dddac46b 100644 --- a/ui/src/App/App.js +++ b/ui/src/App/App.js @@ -8,24 +8,22 @@ import AuthRoutesContainer from './components/AuthRoutesContainer'; const keycloak = Keycloak({ realm: 'plato', - // 'auth-server-url': 'https://auth.platoproject.org/auth/', url: 'https://auth.platoproject.org/auth/', 'ssl-required': 'external', - // resource: 'realities', 'public-client': true, 'confidential-port': 0, clientId: 'realities', }); -const eventLogger = (event, error) => { - console.log('onKeycloakEvent', event, error); -}; +// const eventLogger = (event, error) => { +// console.log('onKeycloakEvent', event, error); +// }; const ApolloSetup = () => { - const { getAccessToken } = useAuth(); + const { accessToken } = useAuth(); return ( - + ); @@ -34,7 +32,7 @@ const ApolloSetup = () => { const App = () => ( { const { - initialized, isLoggedIn, email, getAccessToken, + initialized, isLoggedIn, email, accessToken, } = useAuth(); - console.log('outside inited', initialized); - console.log('outside loggedin', isLoggedIn); useEffect(() => { if (initialized) { if (isLoggedIn && email) { - const client = apolloClient(getAccessToken()); + const client = apolloClient(accessToken); client .query({ query: GET_VIEWER, variables: { email } }) diff --git a/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js b/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js index 6ab6d11f..c397e088 100644 --- a/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js +++ b/ui/src/App/components/AuthRoutesContainer/components/RoutesContainer/components/RealitiesNavbar/RealitiesNavbar.js @@ -28,9 +28,6 @@ const RealitiesNavbar = () => { isLoggedIn, login, logout, initialized, } = useAuth(); - console.log('initialized', initialized); - console.log('navbar isloggedin', isLoggedIn); - return ( diff --git a/ui/src/components/withAuth/withAuth.js b/ui/src/components/withAuth/withAuth.js index 66c47679..569d98d7 100644 --- a/ui/src/components/withAuth/withAuth.js +++ b/ui/src/components/withAuth/withAuth.js @@ -5,15 +5,7 @@ export default (WrappedComponent) => { const EnhancedComponent = (props) => { const auth = useAuth(); - const authProps = { - login: auth.login, - logout: auth.logout, - isLoggedIn: auth.isLoggedIn, - email: auth.email, - auth, - }; - - return ; + return ; }; const wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || 'Component'; diff --git a/ui/src/services/useAuth/useAuth.js b/ui/src/services/useAuth/useAuth.js index c482ad20..0c43c24b 100644 --- a/ui/src/services/useAuth/useAuth.js +++ b/ui/src/services/useAuth/useAuth.js @@ -25,11 +25,9 @@ export default function useAuth() { }, isLoggedIn: keycloak.authenticated, - // TODO: fun->var - getAccessToken: () => + accessToken: keycloak.token, email, - keycloak, initialized, }; } From 278506188214c4b1f7f9449bf0e778e2b5a346ed Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Tue, 27 Oct 2020 14:07:58 +0100 Subject: [PATCH 13/15] Remove jwt deps --- api/package-lock.json | 188 ------------------------------------------ api/package.json | 2 - 2 files changed, 190 deletions(-) diff --git a/api/package-lock.json b/api/package-lock.json index e0614a95..cb1a18c7 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -1318,15 +1318,6 @@ "@types/serve-static": "*" } }, - "@types/express-jwt": { - "version": "0.0.34", - "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-0.0.34.tgz", - "integrity": "sha1-/b7kxq9cCiRu8qkz9VGZc8dxfwI=", - "requires": { - "@types/express": "*", - "@types/express-unless": "*" - } - }, "@types/express-serve-static-core": { "version": "4.16.0", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.0.tgz", @@ -1337,14 +1328,6 @@ "@types/range-parser": "*" } }, - "@types/express-unless": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.0.32.tgz", - "integrity": "sha512-6YpJyFNlDDnPnRjMOvJCoDYlSDDmG/OEEUsPk7yhNkL4G9hUYtgab6vi1CcWsGSSSM0CsvNlWTG+ywAGnvF03g==", - "requires": { - "@types/express": "*" - } - }, "@types/form-data": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz", @@ -2380,11 +2363,6 @@ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" - }, "async-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", @@ -3582,11 +3560,6 @@ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", "optional": true }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -4519,14 +4492,6 @@ "safer-buffer": "^2.1.0" } }, - "ecdsa-sig-formatter": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", - "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -5129,22 +5094,6 @@ } } }, - "express-jwt": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-5.3.1.tgz", - "integrity": "sha512-1C9RNq0wMp/JvsH/qZMlg3SIPvKu14YkZ4YYv7gJQ1Vq+Dv8LH9tLKenS5vMNth45gTlEUGx+ycp9IHIlaHP/g==", - "requires": { - "async": "^1.5.0", - "express-unless": "^0.3.0", - "jsonwebtoken": "^8.1.0", - "lodash.set": "^4.0.0" - } - }, - "express-unless": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-0.3.1.tgz", - "integrity": "sha1-JVfBRudb65A+LSR/m1ugFFJpbiA=" - }, "ext": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", @@ -7214,29 +7163,6 @@ "universalify": "^1.0.0" } }, - "jsonwebtoken": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.4.0.tgz", - "integrity": "sha512-coyXjRTCy0pw5WYBpMvWOMN+Kjaik2MwTUIq9cna/W7NpO9E+iYbumZONAz3hcr+tXFJECoQVrtmIoC3Oz0gvg==", - "requires": { - "jws": "^3.1.5", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1" - }, - "dependencies": { - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } - } - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -7257,16 +7183,6 @@ "promise": "^7.0.1" } }, - "jwa": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz", - "integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.10", - "safe-buffer": "^5.0.1" - } - }, "jwk-to-pem": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.4.tgz", @@ -7304,28 +7220,6 @@ } } }, - "jwks-rsa": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.3.0.tgz", - "integrity": "sha512-9q+d5VffK/FvFAjuXoddrq7zQybFSINV4mcwJJExGKXGyjWWpTt3vsn/aX33aB0heY02LK0qSyicdtRK0gVTig==", - "requires": { - "@types/express-jwt": "0.0.34", - "debug": "^2.2.0", - "limiter": "^1.1.0", - "lru-memoizer": "^1.6.0", - "ms": "^2.0.0", - "request": "^2.73.0" - } - }, - "jws": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz", - "integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==", - "requires": { - "jwa": "^1.1.5", - "safe-buffer": "^5.0.1" - } - }, "keycloak-connect": { "version": "11.0.2", "resolved": "https://registry.npmjs.org/keycloak-connect/-/keycloak-connect-11.0.2.tgz", @@ -7389,11 +7283,6 @@ "type-check": "~0.3.2" } }, - "limiter": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.3.tgz", - "integrity": "sha512-zrycnIMsLw/3ZxTbW7HCez56rcFGecWTx5OZNplzcXUUmJLmoYArC6qdJzmAN5BWiNXGcpjhF9RQ1HSv5zebEw==" - }, "load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -7445,11 +7334,6 @@ } } }, - "lock": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/lock/-/lock-0.1.4.tgz", - "integrity": "sha1-/sfervF+fDoKVeHaBCgD4l2RdF0=" - }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", @@ -7460,46 +7344,6 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" - }, - "lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" - }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -7550,33 +7394,6 @@ "yallist": "^3.0.2" } }, - "lru-memoizer": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-1.12.0.tgz", - "integrity": "sha1-7+ZXBsyKnMZT+A8NWm6jitlQ41I=", - "requires": { - "lock": "~0.1.2", - "lodash": "^4.17.4", - "lru-cache": "~4.0.0", - "very-fast-args": "^1.1.0" - }, - "dependencies": { - "lru-cache": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", - "integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=", - "requires": { - "pseudomap": "^1.0.1", - "yallist": "^2.0.0" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } - }, "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", @@ -10661,11 +10478,6 @@ "extsprintf": "^1.2.0" } }, - "very-fast-args": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/very-fast-args/-/very-fast-args-1.1.0.tgz", - "integrity": "sha1-4W0dH6+KbllqJGQh/ZCneWPQs5Y=" - }, "vm-browserify": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", diff --git a/api/package.json b/api/package.json index dfe8196a..e1c99333 100644 --- a/api/package.json +++ b/api/package.json @@ -42,11 +42,9 @@ "eslint-loader": "^1.9.0", "eslint-plugin-import": "^2.8.0", "express": "^4.16.2", - "express-jwt": "^5.3.0", "graphql": "15.3.0", "graphql-resolvers": "0.4.2", "graphql-tools": "6.2.0", - "jwks-rsa": "^1.2.1", "keycloak-connect": "^11.0.2", "keycloak-connect-graphql": "^0.6.3", "lodash": "^4.17.11", From 4e837ecefb11a8ee9c22ae8346bc3f5170143e40 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Tue, 27 Oct 2020 14:41:17 +0100 Subject: [PATCH 14/15] Update authentication checker --- api/src/graphql/authorization/index.js | 4 ++-- api/src/index.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/src/graphql/authorization/index.js b/api/src/graphql/authorization/index.js index e658e600..09fbf76e 100644 --- a/api/src/graphql/authorization/index.js +++ b/api/src/graphql/authorization/index.js @@ -1,8 +1,8 @@ import { skip, combineResolvers } from 'graphql-resolvers'; // eslint-disable-next-line arrow-body-style -export const isAuthenticated = (obj, args, { user }) => { - return (user && user.role) ? skip : new Error("User isn't authenticated"); +export const isAuthenticated = (obj, args, { kauth }) => { + return kauth.isAuthenticated() ? skip : new Error("User isn't authenticated"); }; export const isAdmin = combineResolvers( diff --git a/api/src/index.js b/api/src/index.js index 593a49f0..e9aeccfb 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -39,7 +39,7 @@ const server = new ApolloServer({ kauth, user: { email: kauth.accessToken && kauth.accessToken.content.email, - role: kauth.accessToken && 'user', + role: 'user', // TODO: put the user's tenantId here }, driver: neo4jDriver, From 287c6ec6f8058c5d7600c5d22509bc75d8a4bc07 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Tue, 27 Oct 2020 15:11:19 +0100 Subject: [PATCH 15/15] Update env vars and add some new ones --- api/src/index.js | 6 +++--- ui/.env | 7 +++---- ui/src/App/App.js | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/api/src/index.js b/api/src/index.js index e9aeccfb..af05f6c2 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -20,10 +20,10 @@ if (!NODE_ENV || NODE_ENV.includes('dev')) { } const keycloak = new Keycloak({}, { - realm: 'plato', - 'auth-server-url': 'https://auth.platoproject.org/auth/', + realm: process.env.KEYCLOAK_REALM, + 'auth-server-url': process.env.KEYCLOAK_SERVER_URL, 'ssl-required': 'external', - resource: 'realities', + resource: process.env.KEYCLOAK_CLIENT, 'public-client': true, 'confidential-port': 0, }); diff --git a/ui/.env b/ui/.env index 2abc8090..dd0baa0d 100644 --- a/ui/.env +++ b/ui/.env @@ -1,7 +1,6 @@ REACT_APP_GRAPHQL_ENDPOINT=http://localhost:3100/graphql REACT_APP_GRAPHQL_SUBSCRIPTION=ws://localhost:3100/graphql -REACT_APP_AUTH0_DOMAIN=platoproject.eu.auth0.com -REACT_APP_AUTH0_CLIENT_ID=LEdrYzy4Gg5Eoj4WJWPjPKpR8u3tpVhm -REACT_APP_AUTH0_AUDIENCE=https://realities-api.platoproject.org -REACT_APP_AUTH0_CALLBACK_URL=http://localhost:3000/auth-callback REACT_APP_KEYCLOAK_CALLBACK_URL=http://localhost:3000/auth-callback +REACT_APP_KEYCLOAK_SERVER_URL=https://auth.platoproject.org/auth/ +REACT_APP_KEYCLOAK_REALM=plato +REACT_APP_KEYCLOAK_CLIENT=realities diff --git a/ui/src/App/App.js b/ui/src/App/App.js index dddac46b..44807286 100644 --- a/ui/src/App/App.js +++ b/ui/src/App/App.js @@ -7,12 +7,12 @@ import apolloClient from '@/services/apolloClient'; import AuthRoutesContainer from './components/AuthRoutesContainer'; const keycloak = Keycloak({ - realm: 'plato', - url: 'https://auth.platoproject.org/auth/', + realm: process.env.REACT_APP_KEYCLOAK_REALM, + url: process.env.REACT_APP_KEYCLOAK_SERVER_URL, 'ssl-required': 'external', 'public-client': true, 'confidential-port': 0, - clientId: 'realities', + clientId: process.env.REACT_APP_KEYCLOAK_CLIENT, }); // const eventLogger = (event, error) => {