From 7ffbd444b3ce2905bf9f1cd06b55134355fa5f55 Mon Sep 17 00:00:00 2001 From: miles-grant-ibigroup Date: Thu, 15 Jun 2023 11:28:13 -0400 Subject: [PATCH 01/19] support disabling `AUTH0_DISABLED` --- lib/common/constants/index.js | 1 + lib/common/containers/App.js | 51 +++++++++++-------- .../containers/wrapComponentInAuthStrategy.js | 9 ++-- lib/editor/util/ui.js | 23 +++++---- lib/manager/actions/user.js | 18 +++++-- lib/manager/actions/versions.js | 4 +- lib/manager/components/FeedSourceViewer.js | 13 ++--- lib/manager/components/ProjectsList.js | 2 + lib/manager/containers/FeedSourceTable.js | 6 +-- lib/manager/util/index.js | 3 ++ 10 files changed, 80 insertions(+), 50 deletions(-) diff --git a/lib/common/constants/index.js b/lib/common/constants/index.js index 44d714301..bf1ea8f15 100644 --- a/lib/common/constants/index.js +++ b/lib/common/constants/index.js @@ -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', diff --git a/lib/common/containers/App.js b/lib/common/containers/App.js index b3859a7ad..8445b2da1 100644 --- a/lib/common/containers/App.js +++ b/lib/common/containers/App.js @@ -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_DOMAIN, AUTH0_DISABLED } from '../constants' import ActiveGtfsEditor from '../../editor/containers/ActiveGtfsEditor' import ActiveFeedSourceViewer from '../../manager/containers/ActiveFeedSourceViewer' import ActiveProjectsList from '../../manager/containers/ActiveProjectsList' @@ -127,26 +127,35 @@ export default class App extends React.Component { path: '*' } ] - const routerWithAuth0 = ( - - - - - {routes.map((r, i) => ())} - - - ) + const routerWithAuth0 = AUTH0_DISABLED ? <> + + + + {routes.map((r, i) => ())} + + + : ( + + + + + {routes.map((r, i) => ())} + + + ) // Initialize toast notifications. toast.configure() // Configure bugsnag if key is provided. diff --git a/lib/common/containers/wrapComponentInAuthStrategy.js b/lib/common/containers/wrapComponentInAuthStrategy.js index 20f72ea89..09dede9f6 100644 --- a/lib/common/containers/wrapComponentInAuthStrategy.js +++ b/lib/common/containers/wrapComponentInAuthStrategy.js @@ -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 @@ -28,8 +29,8 @@ export default function wrapComponentInAuthStrategy ( ): React.Component { const AuthStrategyWrapper = (props: AuthWrapperProps) => { const { user } = props - const userIsLoggedIn: boolean = !!user.token - const adminTestFailed = requireAdmin && !user.isCheckingLogin && !userHasAdminViewPrivileges(user) + const userIsLoggedIn: boolean = AUTH0_DISABLED || !!user.token + const adminTestFailed = !AUTH0_DISABLED && (requireAdmin && !user.isCheckingLogin && !userHasAdminViewPrivileges(user)) const messages = getComponentMessages('WrapComponentInAuthStrategy') useEffect(() => { @@ -39,7 +40,7 @@ export default function wrapComponentInAuthStrategy ( } }, [userIsLoggedIn, adminTestFailed]) - if (requireAuth && !user.token) { + if (!AUTH0_DISABLED && (requireAuth && !user.token)) { // Don't render anything while the login info is being fetched (i.e. token is null). return null } else if (adminTestFailed) { @@ -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) } diff --git a/lib/editor/util/ui.js b/lib/editor/util/ui.js index 55615ff95..e22dae1db 100644 --- a/lib/editor/util/ui.js +++ b/lib/editor/util/ui.js @@ -3,6 +3,7 @@ import {getComponentMessages} from '../../common/util/config' import type { Feed } from '../../types' import type { ManagerUserState } from '../../types/reducers' +import { AUTH0_DISABLED } from '../../common/constants' export type GtfsIcon = { addable: boolean, @@ -81,22 +82,24 @@ export const GTFS_ICONS = [ * @param {*} feedSource */ export function getEditorEnabledState (feedSource: Feed, user: ManagerUserState, feedIsLocked: boolean) { - let editingIsDisabled = true + let editingIsDisabled = !AUTH0_DISABLED let permissionProblem = 'no feed source' if (feedSource) { // FIXME: warn user if they don't have edit privileges const {id, name, projectId, organizationId} = feedSource // check if editing is forbidden - if (!user.permissions) { - permissionProblem = 'undefined user privileges' - } else if (!user.permissions.hasFeedPermission(organizationId, projectId, id, 'edit-gtfs')) { - permissionProblem = 'insufficient user privileges' - } else if (feedIsLocked) { - permissionProblem = 'feed is locked' - } else { - permissionProblem = 'none' - editingIsDisabled = false + if (!AUTH0_DISABLED) { + if (!user.permissions) { + permissionProblem = 'undefined user privileges' + } else if (!user.permissions.hasFeedPermission(organizationId, projectId, id, 'edit-gtfs')) { + permissionProblem = 'insufficient user privileges' + } else if (feedIsLocked) { + permissionProblem = 'feed is locked' + } else { + permissionProblem = 'none' + editingIsDisabled = false + } } if (editingIsDisabled) { diff --git a/lib/manager/actions/user.js b/lib/manager/actions/user.js index 655017e4f..f03182830 100644 --- a/lib/manager/actions/user.js +++ b/lib/manager/actions/user.js @@ -7,7 +7,12 @@ import type { Auth0ContextInterface } from '@auth0/auth0-react' import { fetchUsers } from '../../admin/actions/admin' import { createVoidPayloadAction, secureFetch } from '../../common/actions' -import { AUTH0_CLIENT_ID, AUTH0_CONNECTION_NAME, AUTH0_DOMAIN } from '../../common/constants' +import { + AUTH0_CLIENT_ID, + AUTH0_CONNECTION_NAME, + AUTH0_DISABLED, + AUTH0_DOMAIN +} from '../../common/constants' import { getSettingsFromProfile, isSettingForThisClient } from '../../common/util/user' import UserPermissions from '../../common/user/UserPermissions' import type { RecentActivity, UserProfile } from '../../types' @@ -67,9 +72,14 @@ export function createPublicUser (credentials: any) { */ export function getRecentActivity (user: ManagerUserState) { return function (dispatch: dispatchFn, getState: getStateFn) { - if (!user.profile) throw new Error('Profile does not exist in user state') - const {user_id: userId} = user.profile - const url = `/api/manager/secure/user/${userId}/recentactivity` + let url + if (!AUTH0_DISABLED) { + if (!user.profile) throw new Error('Profile does not exist in user state') + const {user_id: userId} = user.profile + url = `/api/manager/secure/user/${userId}/recentactivity` + } else { + url = `/api/manager/secure/user/userId/recentactivity` + } return dispatch(secureFetch(url)) .then(response => response.json()) .then(activity => dispatch(receiveRecentActivity(activity))) diff --git a/lib/manager/actions/versions.js b/lib/manager/actions/versions.js index a89fdb7df..b8e775d60 100644 --- a/lib/manager/actions/versions.js +++ b/lib/manager/actions/versions.js @@ -5,7 +5,7 @@ import {createAction, type ActionType} from 'redux-actions' import {browserHistory} from 'react-router' import {createVoidPayloadAction, fetchGraphQL, secureFetch} from '../../common/actions' -import {SECURE_API_PREFIX} from '../../common/constants' +import {AUTH0_DISABLED, SECURE_API_PREFIX} from '../../common/constants' import {getConfigProperty, isModuleEnabled} from '../../common/util/config' import {uploadFile} from '../../common/util/upload-file' import {ENTITY} from '../../editor/constants' @@ -188,7 +188,7 @@ export function uploadFeed (feedSource: Feed, file: File) { const lastModified = file.lastModified const url = `${SECURE_API_PREFIX}feedversion?feedSourceId=${feedSource.id}&lastModified=${lastModified}` const {token} = getState().user - if (!token) { + if (!AUTH0_DISABLED && !token) { return dispatch(setErrorMessage({ title: `Unathorized`, message: 'You must be logged in to perform this action.' diff --git a/lib/manager/components/FeedSourceViewer.js b/lib/manager/components/FeedSourceViewer.js index c7fdfaf96..cf7d5af00 100644 --- a/lib/manager/components/FeedSourceViewer.js +++ b/lib/manager/components/FeedSourceViewer.js @@ -14,16 +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 { AUTH0_DISABLED } from '../../common/constants' + +import NotesViewer from './NotesViewer' +import FeedSourceSettings from './FeedSourceSettings' +import ManagerHeader from './ManagerHeader' type Props = ContainerProps & { activeComponent: string, @@ -128,11 +129,11 @@ export default class FeedSourceViewer extends Component { ) } const {editorSnapshots, id: feedSourceId, name, noteCount, notes} = feedSource - const disabled = !user.permissions || !user.permissions.hasFeedPermission( + const disabled = !AUTH0_DISABLED && (!user.permissions || !user.permissions.hasFeedPermission( project.organizationId, project.id, feedSourceId, 'manage-feed' - ) + )) const editDisabled = isEditingDisabled(user, feedSource, project) const activeTab = ['settings', 'comments', 'snapshots'].indexOf(activeComponent) === -1 || typeof routeParams.feedVersionIndex !== 'undefined' ? '' diff --git a/lib/manager/components/ProjectsList.js b/lib/manager/components/ProjectsList.js index efa83d003..206449aa5 100644 --- a/lib/manager/components/ProjectsList.js +++ b/lib/manager/components/ProjectsList.js @@ -24,6 +24,7 @@ import {defaultSorter} from '../../common/util/util' import type {Props as ContainerProps} from '../containers/ActiveProjectsList' import type {Project} from '../../types' import type {ManagerUserState} from '../../types/reducers' +import { AUTH0_DISABLED } from '../../common/constants' type Props = ContainerProps & { createProject: typeof projectsActions.createProject, @@ -36,6 +37,7 @@ type Props = ContainerProps & { } const userCanCreateProject = (user: ManagerUserState) => { + if (AUTH0_DISABLED) return true const {permissions} = user if (!permissions) return false else return permissions.isApplicationAdmin() || permissions.canAdministerAnOrganization() diff --git a/lib/manager/containers/FeedSourceTable.js b/lib/manager/containers/FeedSourceTable.js index b796346cd..de269e463 100644 --- a/lib/manager/containers/FeedSourceTable.js +++ b/lib/manager/containers/FeedSourceTable.js @@ -4,9 +4,9 @@ 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' +import { AUTH0_DISABLED } from '../../common/constants' export type Props = { onNewFeedSourceClick: () => void, @@ -17,8 +17,8 @@ const mapStateToProps = (state: AppState, ownProps: Props) => { const {user} = state const {filter, isFetching, sort} = state.projects const {project} = ownProps - const isNotAdmin = !user.permissions || - !user.permissions.isProjectAdmin(project.id, project.organizationId) + const isNotAdmin = !AUTH0_DISABLED && (!user.permissions || + !user.permissions.isProjectAdmin(project.id, project.organizationId)) const feedSources = project.feedSources ? project.feedSources : [] return { diff --git a/lib/manager/util/index.js b/lib/manager/util/index.js index 28c1309a5..42fa4168f 100644 --- a/lib/manager/util/index.js +++ b/lib/manager/util/index.js @@ -17,6 +17,7 @@ import type { ProjectFilter, ProjectsState } from '../../types/reducers' +import { AUTH0_DISABLED } from '../../common/constants' import {getVersionValidationSummaryByFilterStrategy} from './version' @@ -246,6 +247,8 @@ export function isEditingDisabled ( project: ?Project ): boolean { // If any of the args or null, + if (AUTH0_DISABLED) return false + return ( !user || !feedSource || From fd85a0e18b12b31e3298fd546f12d38762fcd320 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Tue, 11 Jul 2023 14:09:49 -0400 Subject: [PATCH 02/19] refactor(LocalUserRetriever): Provide local user info for non-auth configs --- lib/common/containers/App.js | 27 +++++----- lib/common/containers/LocalUserRetriever.js | 59 +++++++++++++++++++++ 2 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 lib/common/containers/LocalUserRetriever.js diff --git a/lib/common/containers/App.js b/lib/common/containers/App.js index 8445b2da1..595267d6f 100644 --- a/lib/common/containers/App.js +++ b/lib/common/containers/App.js @@ -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) { @@ -127,14 +128,19 @@ export default class App extends React.Component { path: '*' } ] + const appContent = ( + <> + + + {routes.map((r, i) => ())} + + + ) const routerWithAuth0 = AUTH0_DISABLED ? <> - - - - {routes.map((r, i) => ())} - + + {appContent} : ( { scope={AUTH0_DEFAULT_SCOPE} > - - - {routes.map((r, i) => ())} - + {appContent} ) // Initialize toast notifications. diff --git a/lib/common/containers/LocalUserRetriever.js b/lib/common/containers/LocalUserRetriever.js new file mode 100644 index 000000000..553cf7208 --- /dev/null +++ b/lib/common/containers/LocalUserRetriever.js @@ -0,0 +1,59 @@ +// @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' + ] + }, + email: 'user@example.com', + 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) From dee0615ef647c3bf56bc2bb31ba3706a37431a41 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Tue, 11 Jul 2023 14:27:57 -0400 Subject: [PATCH 03/19] refactor(PublicHeader): Hide logout button on non-auth configs --- lib/public/components/PublicHeader.js | 39 +++++++++------------------ 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/lib/public/components/PublicHeader.js b/lib/public/components/PublicHeader.js index d4474e13b..e7611956e 100644 --- a/lib/public/components/PublicHeader.js +++ b/lib/public/components/PublicHeader.js @@ -2,12 +2,13 @@ import type { Auth0ContextInterface } from '@auth0/auth0-react' import Icon from '@conveyal/woonerf/components/icon' -import React, {Component} from 'react' -import {Grid, Row, Col, Button, Glyphicon, ButtonToolbar} from 'react-bootstrap' -import {LinkContainer} from 'react-router-bootstrap' +import React, { Component } from 'react' +import { Grid, Row, Col, Button, Glyphicon, ButtonToolbar } from 'react-bootstrap' +import { LinkContainer } from 'react-router-bootstrap' import * as userActions from '../../manager/actions/user' -import type {Props as ContainerProps} from '../containers/ActivePublicHeader' +import type { Props as ContainerProps } from '../containers/ActivePublicHeader' +import { AUTH0_DISABLED } from '../../common/constants' type Props = ContainerProps & { auth0: Auth0ContextInterface, @@ -17,21 +18,7 @@ type Props = ContainerProps & { username: ?string } -type State = { - showLogin: boolean -} - -export default class PublicHeader extends Component { - state = { showLogin: false } - - _onLoginClick = () => { - this.setState({ showLogin: true }) - } - - _onLoginHide = () => { - this.setState({ showLogin: false }) - } - +export default class PublicHeader extends Component { _onLogoutClick = () => { this.props.logout(this.props.auth0) } @@ -73,14 +60,12 @@ export default class PublicHeader extends Component { ) } - {/* "Log out" Button */} - {username - ? ( - - ) - : null} + {/* "Log out" Button (if auth is enabled) */} + {username && !AUTH0_DISABLED && ( + + )} From 617833a0009400fdf3bf63bb8d8cd599392f76cc Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:09:46 -0400 Subject: [PATCH 04/19] refactor(UserButtons): Hide logout button on non-auth configs --- lib/common/components/UserButtons.js | 22 +++++++++++++--------- lib/public/components/PublicHeader.js | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/common/components/UserButtons.js b/lib/common/components/UserButtons.js index 2749e129e..b0f4a28ba 100644 --- a/lib/common/components/UserButtons.js +++ b/lib/common/components/UserButtons.js @@ -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, @@ -42,13 +43,16 @@ export default class UserButtons extends Component { )} - + {/* "Log out" Button (unless auth is disabled) */} + {!AUTH0_DISABLED && ( + + )} ) } diff --git a/lib/public/components/PublicHeader.js b/lib/public/components/PublicHeader.js index e7611956e..b8701ad1d 100644 --- a/lib/public/components/PublicHeader.js +++ b/lib/public/components/PublicHeader.js @@ -60,7 +60,7 @@ export default class PublicHeader extends Component { ) } - {/* "Log out" Button (if auth is enabled) */} + {/* "Log out" Button (unless auth is disabled) */} {username && !AUTH0_DISABLED && ( - - + {/* Display account type if two or more are configured and if the relevant text is available. + (or the account type from the user profile does not match the one(s) configured). */} + {((Object.keys(accountTypes).length > 1 && displayedAccountType) || accountTypeIsUnknown) && ( + + Account type +
+ {displayedAccountType} + {/* Show account terms URL only if one has been configured. */} + {accountTermsUrl && ( + + {' - '} + Terms and conditions + + )} +
+
+ )} + +

Avatar

+ + Profile + Change on gravatar.com + +
+ +

Password

+ +
+ + )} ) From a895298d42eadb6ed4239280106fc7f6e4bc359f Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:34:28 -0400 Subject: [PATCH 06/19] refactor(LocalUserRetriever): Use same email as backend. --- lib/common/containers/LocalUserRetriever.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/common/containers/LocalUserRetriever.js b/lib/common/containers/LocalUserRetriever.js index 553cf7208..9a21b83a7 100644 --- a/lib/common/containers/LocalUserRetriever.js +++ b/lib/common/containers/LocalUserRetriever.js @@ -28,7 +28,8 @@ const profile = { 'user' ] }, - email: 'user@example.com', + // FIXME: pick a better email address for both backend and frontend. + email: 'mock@example.com', name: 'localuser', nickname: 'Local User', picture: 'https://d2tyb7byn1fef9.cloudfront.net/ibi_group_black-512x512.png', From 398d8f97c5bf47ec83f5dde7cbfc2f4cd5a3ca2e Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Tue, 11 Jul 2023 17:58:53 -0400 Subject: [PATCH 07/19] refactor(AdminPage): Hide user list on non-auth configs --- lib/admin/components/AdminPage.js | 8 +++++--- lib/common/components/UserButtons.js | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/admin/components/AdminPage.js b/lib/admin/components/AdminPage.js index 0206fd9b7..ce27c9c15 100644 --- a/lib/admin/components/AdminPage.js +++ b/lib/admin/components/AdminPage.js @@ -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' @@ -51,8 +52,8 @@ class AdminPage extends React.Component { } = 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() @@ -71,7 +72,8 @@ class AdminPage extends React.Component { const {activeComponent} = this.props const restricted =

Restricted access

switch (activeComponent) { - case 'users': return + case 'users': + return AUTH0_DISABLED ? restricted : case 'organizations': if (!isApplicationAdmin || isModuleEnabled('enterprise')) return restricted else return diff --git a/lib/common/components/UserButtons.js b/lib/common/components/UserButtons.js index b0f4a28ba..735393187 100644 --- a/lib/common/components/UserButtons.js +++ b/lib/common/components/UserButtons.js @@ -28,13 +28,13 @@ export default class UserButtons extends Component { user.permissions.canAdministerAnOrganization() return ( - + {isSiteAdmin && ( - + + {!AUTH0_DISABLED && ( + <> +

{this.messages('userLogs')}

+ + + )} ) } From 184dbbf48fa507da51cf3a8901da1c1ba6d2b1e0 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Wed, 12 Jul 2023 14:53:05 -0400 Subject: [PATCH 09/19] refactor(WatchButton): Hide watch button on no-auth configs --- lib/common/containers/WatchButton.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/common/containers/WatchButton.js b/lib/common/containers/WatchButton.js index 86702dcfa..50801d7c4 100644 --- a/lib/common/containers/WatchButton.js +++ b/lib/common/containers/WatchButton.js @@ -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, @@ -84,9 +84,12 @@ class WatchButton extends Component { } render () { + // Do not render watch button if notifications are not enabled or if auth is disabled. + // (Notifications require an email addressed 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 ( From 6ad320a749a21447b74a16577ecdecd47e74ea31 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Wed, 12 Jul 2023 14:57:31 -0400 Subject: [PATCH 10/19] refactor(wrapComponentInAuthStrategy): Relax some admin checks. --- lib/common/containers/wrapComponentInAuthStrategy.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/common/containers/wrapComponentInAuthStrategy.js b/lib/common/containers/wrapComponentInAuthStrategy.js index 09dede9f6..ca1007f39 100644 --- a/lib/common/containers/wrapComponentInAuthStrategy.js +++ b/lib/common/containers/wrapComponentInAuthStrategy.js @@ -29,8 +29,8 @@ export default function wrapComponentInAuthStrategy ( ): React.Component { const AuthStrategyWrapper = (props: AuthWrapperProps) => { const { user } = props - const userIsLoggedIn: boolean = AUTH0_DISABLED || !!user.token - const adminTestFailed = !AUTH0_DISABLED && (requireAdmin && !user.isCheckingLogin && !userHasAdminViewPrivileges(user)) + const userIsLoggedIn: boolean = !!user.token + const adminTestFailed = requireAdmin && !user.isCheckingLogin && !userHasAdminViewPrivileges(user) const messages = getComponentMessages('WrapComponentInAuthStrategy') useEffect(() => { @@ -40,7 +40,7 @@ export default function wrapComponentInAuthStrategy ( } }, [userIsLoggedIn, adminTestFailed]) - if (!AUTH0_DISABLED && (requireAuth && !user.token)) { + if (requireAuth && !user.token) { // Don't render anything while the login info is being fetched (i.e. token is null). return null } else if (adminTestFailed) { From 8b56c67bccbae81b015be67b7fda8b44837ed764 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:37:32 -0400 Subject: [PATCH 11/19] refactor(editor/util/ui.js): Revert unneeded changes. --- lib/editor/util/ui.js | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/lib/editor/util/ui.js b/lib/editor/util/ui.js index e22dae1db..55615ff95 100644 --- a/lib/editor/util/ui.js +++ b/lib/editor/util/ui.js @@ -3,7 +3,6 @@ import {getComponentMessages} from '../../common/util/config' import type { Feed } from '../../types' import type { ManagerUserState } from '../../types/reducers' -import { AUTH0_DISABLED } from '../../common/constants' export type GtfsIcon = { addable: boolean, @@ -82,24 +81,22 @@ export const GTFS_ICONS = [ * @param {*} feedSource */ export function getEditorEnabledState (feedSource: Feed, user: ManagerUserState, feedIsLocked: boolean) { - let editingIsDisabled = !AUTH0_DISABLED + let editingIsDisabled = true let permissionProblem = 'no feed source' if (feedSource) { // FIXME: warn user if they don't have edit privileges const {id, name, projectId, organizationId} = feedSource // check if editing is forbidden - if (!AUTH0_DISABLED) { - if (!user.permissions) { - permissionProblem = 'undefined user privileges' - } else if (!user.permissions.hasFeedPermission(organizationId, projectId, id, 'edit-gtfs')) { - permissionProblem = 'insufficient user privileges' - } else if (feedIsLocked) { - permissionProblem = 'feed is locked' - } else { - permissionProblem = 'none' - editingIsDisabled = false - } + if (!user.permissions) { + permissionProblem = 'undefined user privileges' + } else if (!user.permissions.hasFeedPermission(organizationId, projectId, id, 'edit-gtfs')) { + permissionProblem = 'insufficient user privileges' + } else if (feedIsLocked) { + permissionProblem = 'feed is locked' + } else { + permissionProblem = 'none' + editingIsDisabled = false } if (editingIsDisabled) { From cf1471de528508384aaf57f01e2ebd10347db41f Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Wed, 12 Jul 2023 16:46:16 -0400 Subject: [PATCH 12/19] refactor(manager/util/index): Only check user perms for enabling editing. --- lib/manager/util/index.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/manager/util/index.js b/lib/manager/util/index.js index 42fa4168f..f43b1ca22 100644 --- a/lib/manager/util/index.js +++ b/lib/manager/util/index.js @@ -17,7 +17,6 @@ import type { ProjectFilter, ProjectsState } from '../../types/reducers' -import { AUTH0_DISABLED } from '../../common/constants' import {getVersionValidationSummaryByFilterStrategy} from './version' @@ -246,14 +245,12 @@ export function isEditingDisabled ( feedSource: Feed, project: ?Project ): boolean { - // If any of the args or null, - if (AUTH0_DISABLED) return false - return ( + // If any of the args are null... !user || !feedSource || !project || - // or the user does not have permission, editing is disabled. + // ...or the user does not have permission, editing is disabled. !user.permissions || !user.permissions.hasFeedPermission( project.organizationId, From 62d2dadd6c2b897aba2e824e621d20a8e9552aec Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Wed, 12 Jul 2023 16:58:11 -0400 Subject: [PATCH 13/19] refactor(FeedSourceTable): Evaluate admin only using user perms. --- lib/manager/containers/FeedSourceTable.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/manager/containers/FeedSourceTable.js b/lib/manager/containers/FeedSourceTable.js index de269e463..872c515f7 100644 --- a/lib/manager/containers/FeedSourceTable.js +++ b/lib/manager/containers/FeedSourceTable.js @@ -6,7 +6,6 @@ import FeedSourceTable from '../components/FeedSourceTable' import {getFilteredFeeds} from '../util' import type {Project} from '../../types' import type {AppState} from '../../types/reducers' -import { AUTH0_DISABLED } from '../../common/constants' export type Props = { onNewFeedSourceClick: () => void, @@ -17,8 +16,8 @@ const mapStateToProps = (state: AppState, ownProps: Props) => { const {user} = state const {filter, isFetching, sort} = state.projects const {project} = ownProps - const isNotAdmin = !AUTH0_DISABLED && (!user.permissions || - !user.permissions.isProjectAdmin(project.id, project.organizationId)) + const isNotAdmin = !user.permissions || + !user.permissions.isProjectAdmin(project.id, project.organizationId) const feedSources = project.feedSources ? project.feedSources : [] return { From 6ff7aa35ac3e993669f84444d4ac190e515202fe Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Wed, 12 Jul 2023 17:06:17 -0400 Subject: [PATCH 14/19] refactor(manager/components): Use user perms for enabling features. --- lib/manager/components/FeedSourceViewer.js | 5 ++--- lib/manager/components/ProjectsList.js | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/manager/components/FeedSourceViewer.js b/lib/manager/components/FeedSourceViewer.js index cf7d5af00..707db7dde 100644 --- a/lib/manager/components/FeedSourceViewer.js +++ b/lib/manager/components/FeedSourceViewer.js @@ -20,7 +20,6 @@ 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 { AUTH0_DISABLED } from '../../common/constants' import NotesViewer from './NotesViewer' import FeedSourceSettings from './FeedSourceSettings' @@ -129,11 +128,11 @@ export default class FeedSourceViewer extends Component { ) } const {editorSnapshots, id: feedSourceId, name, noteCount, notes} = feedSource - const disabled = !AUTH0_DISABLED && (!user.permissions || !user.permissions.hasFeedPermission( + const disabled = !user.permissions || !user.permissions.hasFeedPermission( project.organizationId, project.id, feedSourceId, 'manage-feed' - )) + ) const editDisabled = isEditingDisabled(user, feedSource, project) const activeTab = ['settings', 'comments', 'snapshots'].indexOf(activeComponent) === -1 || typeof routeParams.feedVersionIndex !== 'undefined' ? '' diff --git a/lib/manager/components/ProjectsList.js b/lib/manager/components/ProjectsList.js index 206449aa5..efa83d003 100644 --- a/lib/manager/components/ProjectsList.js +++ b/lib/manager/components/ProjectsList.js @@ -24,7 +24,6 @@ import {defaultSorter} from '../../common/util/util' import type {Props as ContainerProps} from '../containers/ActiveProjectsList' import type {Project} from '../../types' import type {ManagerUserState} from '../../types/reducers' -import { AUTH0_DISABLED } from '../../common/constants' type Props = ContainerProps & { createProject: typeof projectsActions.createProject, @@ -37,7 +36,6 @@ type Props = ContainerProps & { } const userCanCreateProject = (user: ManagerUserState) => { - if (AUTH0_DISABLED) return true const {permissions} = user if (!permissions) return false else return permissions.isApplicationAdmin() || permissions.canAdministerAnOrganization() From 6f9c15673bd0b004ee0d9e310f911f9c2887c07c Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Wed, 12 Jul 2023 17:18:14 -0400 Subject: [PATCH 15/19] refactor(manager/actions): Enable features using users perms only. --- lib/manager/actions/user.js | 18 ++++-------------- lib/manager/actions/versions.js | 4 ++-- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/lib/manager/actions/user.js b/lib/manager/actions/user.js index f03182830..655017e4f 100644 --- a/lib/manager/actions/user.js +++ b/lib/manager/actions/user.js @@ -7,12 +7,7 @@ import type { Auth0ContextInterface } from '@auth0/auth0-react' import { fetchUsers } from '../../admin/actions/admin' import { createVoidPayloadAction, secureFetch } from '../../common/actions' -import { - AUTH0_CLIENT_ID, - AUTH0_CONNECTION_NAME, - AUTH0_DISABLED, - AUTH0_DOMAIN -} from '../../common/constants' +import { AUTH0_CLIENT_ID, AUTH0_CONNECTION_NAME, AUTH0_DOMAIN } from '../../common/constants' import { getSettingsFromProfile, isSettingForThisClient } from '../../common/util/user' import UserPermissions from '../../common/user/UserPermissions' import type { RecentActivity, UserProfile } from '../../types' @@ -72,14 +67,9 @@ export function createPublicUser (credentials: any) { */ export function getRecentActivity (user: ManagerUserState) { return function (dispatch: dispatchFn, getState: getStateFn) { - let url - if (!AUTH0_DISABLED) { - if (!user.profile) throw new Error('Profile does not exist in user state') - const {user_id: userId} = user.profile - url = `/api/manager/secure/user/${userId}/recentactivity` - } else { - url = `/api/manager/secure/user/userId/recentactivity` - } + if (!user.profile) throw new Error('Profile does not exist in user state') + const {user_id: userId} = user.profile + const url = `/api/manager/secure/user/${userId}/recentactivity` return dispatch(secureFetch(url)) .then(response => response.json()) .then(activity => dispatch(receiveRecentActivity(activity))) diff --git a/lib/manager/actions/versions.js b/lib/manager/actions/versions.js index b8e775d60..a89fdb7df 100644 --- a/lib/manager/actions/versions.js +++ b/lib/manager/actions/versions.js @@ -5,7 +5,7 @@ import {createAction, type ActionType} from 'redux-actions' import {browserHistory} from 'react-router' import {createVoidPayloadAction, fetchGraphQL, secureFetch} from '../../common/actions' -import {AUTH0_DISABLED, SECURE_API_PREFIX} from '../../common/constants' +import {SECURE_API_PREFIX} from '../../common/constants' import {getConfigProperty, isModuleEnabled} from '../../common/util/config' import {uploadFile} from '../../common/util/upload-file' import {ENTITY} from '../../editor/constants' @@ -188,7 +188,7 @@ export function uploadFeed (feedSource: Feed, file: File) { const lastModified = file.lastModified const url = `${SECURE_API_PREFIX}feedversion?feedSourceId=${feedSource.id}&lastModified=${lastModified}` const {token} = getState().user - if (!AUTH0_DISABLED && !token) { + if (!token) { return dispatch(setErrorMessage({ title: `Unathorized`, message: 'You must be logged in to perform this action.' From 46f2f90e5942788057d5278377a61479ae6778ac Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Wed, 12 Jul 2023 17:53:57 -0400 Subject: [PATCH 16/19] test(ActiveProjectViewer): Update snapshots --- .../__tests__/__snapshots__/ActiveProjectViewer.js.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/manager/containers/__tests__/__snapshots__/ActiveProjectViewer.js.snap b/lib/manager/containers/__tests__/__snapshots__/ActiveProjectViewer.js.snap index 2463f87d1..f9b5bd4df 100644 --- a/lib/manager/containers/__tests__/__snapshots__/ActiveProjectViewer.js.snap +++ b/lib/manager/containers/__tests__/__snapshots__/ActiveProjectViewer.js.snap @@ -1328,7 +1328,7 @@ exports[`lib > manager > ActiveProjectViewer should render with newly created pr {isSiteAdmin && ( - +
+ {/* Info banner shown if auth is disabled. */} + {AUTH0_DISABLED && ( + + + {this.messages('authDisabledInfo').replace('%appTitle%', appTitle)} + + )} {/* Recent Activity List */}

{this.messages('recentActivity')} From 9fac32381e587a581bd89f82ca578c46a401595d Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Tue, 25 Jul 2023 10:59:58 -0400 Subject: [PATCH 19/19] style: Sort imports and fix typos. --- lib/common/containers/WatchButton.js | 2 +- lib/public/components/PublicHeader.js | 2 +- lib/public/components/UserAccount.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/common/containers/WatchButton.js b/lib/common/containers/WatchButton.js index 50801d7c4..99c899b59 100644 --- a/lib/common/containers/WatchButton.js +++ b/lib/common/containers/WatchButton.js @@ -85,7 +85,7 @@ class WatchButton extends Component { render () { // Do not render watch button if notifications are not enabled or if auth is disabled. - // (Notifications require an email addressed verified with Auth0.) + // (Notifications require an email address verified with Auth0.) if (AUTH0_DISABLED || !getConfigProperty('application.notifications_enabled')) { return null } diff --git a/lib/public/components/PublicHeader.js b/lib/public/components/PublicHeader.js index b8701ad1d..92605155c 100644 --- a/lib/public/components/PublicHeader.js +++ b/lib/public/components/PublicHeader.js @@ -3,7 +3,7 @@ import type { Auth0ContextInterface } from '@auth0/auth0-react' import Icon from '@conveyal/woonerf/components/icon' import React, { Component } from 'react' -import { Grid, Row, Col, Button, Glyphicon, ButtonToolbar } from 'react-bootstrap' +import { Button, ButtonToolbar, Col, Glyphicon, Grid, Row } from 'react-bootstrap' import { LinkContainer } from 'react-router-bootstrap' import * as userActions from '../../manager/actions/user' diff --git a/lib/public/components/UserAccount.js b/lib/public/components/UserAccount.js index 1d536e786..8cd472350 100644 --- a/lib/public/components/UserAccount.js +++ b/lib/public/components/UserAccount.js @@ -109,7 +109,7 @@ export default class UserAccount extends Component { Email address
{profile.email}
- {/* Display account type if two or more are configured and if the relevant text is available. + {/* Display account type if two or more are configured and if the relevant text is available (or the account type from the user profile does not match the one(s) configured). */} {((Object.keys(accountTypes).length > 1 && displayedAccountType) || accountTypeIsUnknown) && (