Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support disabling Auth0 #967

Merged
merged 19 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
7ffbd44
support disabling `AUTH0_DISABLED`
miles-grant-ibigroup Jun 15, 2023
fd85a0e
refactor(LocalUserRetriever): Provide local user info for non-auth co…
binh-dam-ibigroup Jul 11, 2023
dee0615
refactor(PublicHeader): Hide logout button on non-auth configs
binh-dam-ibigroup Jul 11, 2023
617833a
refactor(UserButtons): Hide logout button on non-auth configs
binh-dam-ibigroup Jul 11, 2023
3954164
refactor(UserAccount): Hide most user account content on non-auth con…
binh-dam-ibigroup Jul 11, 2023
a895298
refactor(LocalUserRetriever): Use same email as backend.
binh-dam-ibigroup Jul 11, 2023
398d8f9
refactor(AdminPage): Hide user list on non-auth configs
binh-dam-ibigroup Jul 11, 2023
a67add3
refactor(ApplicationStatus): Hide Auth0 link on non-auth configs
binh-dam-ibigroup Jul 11, 2023
184dbbf
refactor(WatchButton): Hide watch button on no-auth configs
binh-dam-ibigroup Jul 12, 2023
6ad320a
refactor(wrapComponentInAuthStrategy): Relax some admin checks.
binh-dam-ibigroup Jul 12, 2023
8b56c67
refactor(editor/util/ui.js): Revert unneeded changes.
binh-dam-ibigroup Jul 12, 2023
cf1471d
refactor(manager/util/index): Only check user perms for enabling edit…
binh-dam-ibigroup Jul 12, 2023
62d2dad
refactor(FeedSourceTable): Evaluate admin only using user perms.
binh-dam-ibigroup Jul 12, 2023
6ff7aa3
refactor(manager/components): Use user perms for enabling features.
binh-dam-ibigroup Jul 12, 2023
6f9c156
refactor(manager/actions): Enable features using users perms only.
binh-dam-ibigroup Jul 12, 2023
46f2f90
test(ActiveProjectViewer): Update snapshots
binh-dam-ibigroup Jul 12, 2023
5b4aa34
refactor(UserButtons): Reinstate original urls.
binh-dam-ibigroup Jul 13, 2023
969af57
improvement(UserHomePage): Add info message if auth is disabled.
binh-dam-ibigroup Jul 25, 2023
9fac323
style: Sort imports and fix typos.
binh-dam-ibigroup Jul 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions i18n/english.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1316,6 +1316,9 @@ components:
myAccount: My account
logout: Log out
UserHomePage:
authDisabledInfo: >-
You are running %appTitle% without user authentication enabled.
Features such as user management, account management and feed activity watching are unavailable.
createFirst: Create my first project
help:
content: 'A project is used to group GTFS feeds. For example, the feeds in a project may be in the same region or they may collectively define a planning scenario.'
Expand Down
3 changes: 3 additions & 0 deletions i18n/german.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,9 @@ components:
logout: Abmelden
myAccount: Mein Konto
UserHomePage:
authDisabledInfo: >-
You are running %appTitle% without user authentication enabled.
Features such as user management, account management and feed activity watching are unavailable.
createFirst: Erstelle mein erstes Projekt
help:
content: Ein Projekt dient dazu, GTFS-Feeds zu gruppieren. Zum Beispiel können
Expand Down
3 changes: 3 additions & 0 deletions i18n/polish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,9 @@ components:
logout: Log out
myAccount: My account
UserHomePage:
authDisabledInfo: >-
You are running %appTitle% without user authentication enabled.
Features such as user management, account management and feed activity watching are unavailable.
createFirst: Create my first project
help:
content: A project is used to group GTFS feeds. For example, the feeds in a
Expand Down
8 changes: 5 additions & 3 deletions lib/admin/components/AdminPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {getComponentMessages, isModuleEnabled} from '../../common/util/config'
import * as projectActions from '../../manager/actions/projects'
import type {DataToolsConfig, Project} from '../../types'
import type {AppState, ManagerUserState, RouterProps} from '../../types/reducers'
import { AUTH0_DISABLED } from '../../common/constants'

import OrganizationList from './OrganizationList'
import ServerSettings from './ServerSettings'
Expand Down Expand Up @@ -51,8 +52,8 @@ class AdminPage extends React.Component<Props> {
} = this.props
// Set default path to user admin view.
if (!activeComponent) browserHistory.push('/admin/users')
// Always load a fresh list of users on load.
fetchUsers()
// Always load a fresh list of users on load, if auth is not disabled.
if (!AUTH0_DISABLED) fetchUsers()
// Always load projects to prevent interference with public feeds viewer
// loading of projects.
fetchProjects()
Expand All @@ -71,7 +72,8 @@ class AdminPage extends React.Component<Props> {
const {activeComponent} = this.props
const restricted = <p className='text-center lead'>Restricted access</p>
switch (activeComponent) {
case 'users': return <UserList />
case 'users':
return AUTH0_DISABLED ? restricted : <UserList />
case 'organizations':
if (!isApplicationAdmin || isModuleEnabled('enterprise')) return restricted
else return <OrganizationList />
Expand Down
22 changes: 14 additions & 8 deletions lib/admin/components/ApplicationStatus.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import BootstrapTable from 'react-bootstrap-table/lib/BootstrapTable'
import TableHeaderColumn from 'react-bootstrap-table/lib/TableHeaderColumn'

import * as adminActions from '../actions/admin'
import { AUTH0_DISABLED } from '../../common/constants'
import {getComponentMessages} from '../../common/util/config'
import {formatTimestamp} from '../../common/util/date-time'
import type {ServerJob} from '../../types'
Expand Down Expand Up @@ -114,14 +115,19 @@ class ApplicationStatusView extends Component<Props, {refreshTime: ?Date}> {
return <TableHeaderColumn {...col} key={index} />
})}
</BootstrapTable>
<h3>{this.messages('userLogs')}</h3>
<Button
bsStyle='danger'
bsSize='large'
block
href='https://manage.auth0.com/#/logs'>
<Icon type='star' /> {this.messages('viewUserLogs')}
</Button>
{!AUTH0_DISABLED && (
<>
<h3>{this.messages('userLogs')}</h3>
<Button
block
bsStyle='danger'
bsSize='large'
href='https://manage.auth0.com/#/logs'
>
<Icon type='star' /> {this.messages('viewUserLogs')}
</Button>
</>
)}
</div>
)
}
Expand Down
22 changes: 13 additions & 9 deletions lib/common/components/UserButtons.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { Button, ButtonToolbar } from 'react-bootstrap'
import { LinkContainer } from 'react-router-bootstrap'
import Icon from '@conveyal/woonerf/components/icon'

import {getComponentMessages} from '../../common/util/config'
import type {ManagerUserState} from '../../types/reducers'
import { AUTH0_DISABLED } from '../constants'
import { getComponentMessages } from '../../common/util/config'
import type { ManagerUserState } from '../../types/reducers'

type Props = {
logout: () => any,
Expand Down Expand Up @@ -42,13 +43,16 @@ export default class UserButtons extends Component<Props> {
</Button>
</LinkContainer>
)}
<Button
bsSize='small'
bsStyle='primary'
onClick={logout}
style={buttonStyle}>
<Icon type='sign-out' /> {this.messages('logout')}
</Button>
{/* "Log out" Button (unless auth is disabled) */}
{!AUTH0_DISABLED && (
<Button
bsSize='small'
bsStyle='primary'
onClick={logout}
style={buttonStyle}>
<Icon type='sign-out' /> {this.messages('logout')}
</Button>
)}
</ButtonToolbar>
)
}
Expand Down
1 change: 1 addition & 0 deletions lib/common/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const AUTH0_CLIENT_ID = process.env.AUTH0_CLIENT_ID || ''
export const AUTH0_CONNECTION_NAME = process.env.AUTH0_CONNECTION_NAME || ''
export const AUTH0_DEFAULT_SCOPE = 'app_metadata profile email openid user_metadata'
export const AUTH0_DOMAIN = process.env.AUTH0_DOMAIN || ''
export const AUTH0_DISABLED = Boolean(process.env.DISABLE_AUTH)

export const AUTO_DEPLOY_TYPES = Object.freeze({
ON_FEED_FETCH: 'ON_FEED_FETCH',
Expand Down
38 changes: 24 additions & 14 deletions lib/common/containers/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import MainAlertsViewer from '../../alerts/containers/MainAlertsViewer'
import ActiveAlertEditor from '../../alerts/containers/ActiveAlertEditor'
import Login from '../components/Login'
import PageNotFound from '../components/PageNotFound'
import { AUTH0_CLIENT_ID, AUTH0_DEFAULT_SCOPE, AUTH0_DOMAIN } from '../constants'
import { AUTH0_CLIENT_ID, AUTH0_DEFAULT_SCOPE, AUTH0_DISABLED, AUTH0_DOMAIN } from '../constants'
import ActiveGtfsEditor from '../../editor/containers/ActiveGtfsEditor'
import ActiveFeedSourceViewer from '../../manager/containers/ActiveFeedSourceViewer'
import ActiveProjectsList from '../../manager/containers/ActiveProjectsList'
Expand All @@ -29,6 +29,7 @@ import type { dispatchFn, getStateFn } from '../../types/reducers'

import ActiveUserRetriever from './ActiveUserRetriever'
import AppInfoRetriever from './AppInfoRetriever'
import LocalUserRetriever from './LocalUserRetriever'
import wrapComponentInAuthStrategy from './wrapComponentInAuthStrategy'

function loginOptional (ComponentToWrap) {
Expand Down Expand Up @@ -127,26 +128,35 @@ export default class App extends React.Component<AppProps> {
path: '*'
}
]
const routerWithAuth0 = (
<Auth0Provider
audience=''
// Continue to cache tokens in localstorage (speeds up updating login state when refreshing pages).
cacheLocation='localstorage'
clientId={AUTH0_CLIENT_ID}
domain={AUTH0_DOMAIN}
onRedirectCallback={this.handleRedirect}
redirectUri={window.location.origin}
scope={AUTH0_DEFAULT_SCOPE}
>
<ActiveUserRetriever />
const appContent = (
<>
<AppInfoRetriever />
<Router
history={browserHistory}
onUpdate={logPageView}>
{routes.map((r, i) => (<Route {...r} key={i} />))}
</Router>
</Auth0Provider>
</>
)
const routerWithAuth0 = AUTH0_DISABLED ? <>
<LocalUserRetriever />
{appContent}
</>
: (
<Auth0Provider
audience=''
// Continue to cache tokens in localstorage (speeds up updating login state when refreshing pages).
cacheLocation='localstorage'
clientId={AUTH0_CLIENT_ID}
domain={AUTH0_DOMAIN}
onRedirectCallback={this.handleRedirect}
redirectUri={window.location.origin}
scope={AUTH0_DEFAULT_SCOPE}
>
<ActiveUserRetriever />
{appContent}
</Auth0Provider>
)
// Initialize toast notifications.
toast.configure()
// Configure bugsnag if key is provided.
Expand Down
60 changes: 60 additions & 0 deletions lib/common/containers/LocalUserRetriever.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// @flow
// $FlowFixMe useEffect not recognized by flow.
import { useEffect } from 'react'
import { connect } from 'react-redux'

import * as userActions from '../../manager/actions/user'
import { AUTH0_CLIENT_ID } from '../constants'

type Props = {
receiveTokenAndProfile: typeof userActions.receiveTokenAndProfile
}

const profile = {
app_metadata: {
'datatools': [
{
'permissions': [
{
'type': 'administer-application'
}
],
'projects': [],
'client_id': AUTH0_CLIENT_ID,
'subscriptions': []
}
],
'roles': [
'user'
]
},
// FIXME: pick a better email address for both backend and frontend.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you looking for a real email address here or just a different fake/placeholder one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably a different one. This email address appears in the Notes section of each feed.

email: '[email protected]',
name: 'localuser',
nickname: 'Local User',
picture: 'https://d2tyb7byn1fef9.cloudfront.net/ibi_group_black-512x512.png',
sub: 'localuser',
user_id: 'localuser',
user_metadata: {}
}

const token = 'local-user-token'

/**
* This component provides a user profile for configs without authentication.
*/
const LocalUserRetriever = ({ receiveTokenAndProfile }: Props) => {
// Update the user info in the redux state on initialization.
useEffect(() => {
receiveTokenAndProfile({ profile, token })
}, [])

// Component renders nothing.
return null
}

const mapDispatchToProps = {
receiveTokenAndProfile: userActions.receiveTokenAndProfile
}

export default connect(null, mapDispatchToProps)(LocalUserRetriever)
9 changes: 6 additions & 3 deletions lib/common/containers/WatchButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {connect} from 'react-redux'
import * as userActions from '../../manager/actions/user'
import * as statusActions from '../../manager/actions/status'
import {getComponentMessages, getConfigProperty} from '../util/config'

import type {AppState, ManagerUserState} from '../../types/reducers'
import { AUTH0_DISABLED } from '../constants'

type ContainerProps = {
componentClass?: string,
Expand Down Expand Up @@ -84,9 +84,12 @@ class WatchButton extends Component<Props> {
}

render () {
// Do not render watch button if notifications are not enabled or if auth is disabled.
// (Notifications require an email address verified with Auth0.)
if (AUTH0_DISABLED || !getConfigProperty('application.notifications_enabled')) {
return null
}
const {componentClass} = this.props
// Do not render watch button if notifications are not enabled.
if (!getConfigProperty('application.notifications_enabled')) return null
switch (componentClass) {
case 'menuItem':
return (
Expand Down
3 changes: 2 additions & 1 deletion lib/common/containers/wrapComponentInAuthStrategy.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { browserHistory } from 'react-router'

import {getComponentMessages} from '../util/config'
import type {AppState, ManagerUserState} from '../../types/reducers'
import { AUTH0_DISABLED } from '../constants'

type AuthWrapperProps = {
user: ManagerUserState
Expand Down Expand Up @@ -68,7 +69,7 @@ export default function wrapComponentInAuthStrategy (
(state: AppState) => ({user: state.user})
)(AuthStrategyWrapper)

if (requireAuth || requireAdmin) {
if (!AUTH0_DISABLED && (requireAuth || requireAdmin)) {
return withAuthenticationRequired(connectedComponent)
}

Expand Down
8 changes: 4 additions & 4 deletions lib/manager/components/FeedSourceViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ import * as snapshotActions from '../../editor/actions/snapshots'
import * as gtfsPlusActions from '../../gtfsplus/actions/gtfsplus'
import ManagerPage from '../../common/components/ManagerPage'
import {getComponentMessages, isModuleEnabled} from '../../common/util/config'
import ManagerHeader from './ManagerHeader'
import ActiveFeedVersionNavigator from '../containers/ActiveFeedVersionNavigator'
import FeedSourceSettings from './FeedSourceSettings'
import NotesViewer from './NotesViewer'
import ActiveEditorFeedSourcePanel from '../../editor/containers/ActiveEditorFeedSourcePanel'
import {isEditingDisabled} from '../util'

import type {Props as ContainerProps} from '../containers/ActiveFeedSourceViewer'
import type {Feed, Note, Project} from '../../types'
import type {ManagerUserState} from '../../types/reducers'

import NotesViewer from './NotesViewer'
import FeedSourceSettings from './FeedSourceSettings'
import ManagerHeader from './ManagerHeader'

type Props = ContainerProps & {
activeComponent: string,
activeSubComponent: string,
Expand Down
14 changes: 11 additions & 3 deletions lib/manager/components/UserHomePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import { Auth0ContextInterface } from '@auth0/auth0-react'
import Icon from '@conveyal/woonerf/components/icon'
import React, {Component} from 'react'
import {Grid, Row, Col, Button, ButtonToolbar, Jumbotron} from 'react-bootstrap'
import { Alert, Button, ButtonToolbar, Col, Grid, Jumbotron, Row } from 'react-bootstrap'
import objectPath from 'object-path'

import * as feedsActions from '../actions/feeds'
import * as userActions from '../actions/user'
import * as visibilityFilterActions from '../actions/visibilityFilter'
import ManagerPage from '../../common/components/ManagerPage'
import { DEFAULT_DESCRIPTION, DEFAULT_TITLE } from '../../common/constants'
import { AUTH0_DISABLED, DEFAULT_DESCRIPTION, DEFAULT_TITLE } from '../../common/constants'
import {getConfigProperty, getComponentMessages} from '../../common/util/config'
import {defaultSorter} from '../../common/util/util'
import type {Props as ContainerProps} from '../containers/ActiveUserHomePage'
Expand Down Expand Up @@ -85,6 +85,7 @@ export default class UserHomePage extends Component<Props, State> {
} = this.props
const visibleProjects = projects.sort(defaultSorter)
const activeProject = project
const appTitle = getConfigProperty('application.title') || 'datatools'
return (
<ManagerPage
ref='page'
Expand All @@ -96,7 +97,7 @@ export default class UserHomePage extends Component<Props, State> {
<Col md={8} xs={12}>
{/* Top Welcome Box */}
<Jumbotron style={{ padding: 30 }}>
<h2>{this.messages('welcomeTo')} {getConfigProperty('application.title') || DEFAULT_TITLE}!</h2>
<h2>{this.messages('welcomeTo')} {appTitle || DEFAULT_TITLE}!</h2>
<p>{getConfigProperty('application.description') || DEFAULT_DESCRIPTION}</p>
<ButtonToolbar>
<Button
Expand All @@ -108,6 +109,13 @@ export default class UserHomePage extends Component<Props, State> {
</Button>
</ButtonToolbar>
</Jumbotron>
{/* Info banner shown if auth is disabled. */}
{AUTH0_DISABLED && (
<Alert bsStyle='info'>
<Icon type='info-circle' />
{this.messages('authDisabledInfo').replace('%appTitle%', appTitle)}
</Alert>
)}
{/* Recent Activity List */}
<h3 style={{ borderBottom: '2px solid #ddd', marginTop: 0, paddingBottom: 5 }}>
<Icon type='comments-o' /> {this.messages('recentActivity')}
Expand Down
1 change: 0 additions & 1 deletion lib/manager/containers/FeedSourceTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {connect} from 'react-redux'

import FeedSourceTable from '../components/FeedSourceTable'
import {getFilteredFeeds} from '../util'

import type {Project} from '../../types'
import type {AppState} from '../../types/reducers'

Expand Down
Loading
Loading