generated from bcgov/quickstart-openshift
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ORV2-1749 Tighten up user navigation in frontend (#1006)
- Loading branch information
1 parent
ef3808b
commit 41cd734
Showing
19 changed files
with
502 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
frontend/src/common/authentication/auth-walls/IDIRAuthWall.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { useContext, useEffect } from "react"; | ||
import { useAuth } from "react-oidc-context"; | ||
import { Navigate, Outlet, useLocation, useNavigate } from "react-router-dom"; | ||
|
||
import { LoadIDIRUserContext } from "../LoadIDIRUserContext"; | ||
import { LoadIDIRUserRoles } from "../LoadIDIRUserRoles"; | ||
import OnRouteBCContext from "../OnRouteBCContext"; | ||
import { IDIRUserAuthGroupType, UserRolesType } from "../types"; | ||
import { DoesUserHaveAuthGroup, DoesUserHaveRole } from "../util"; | ||
import { Loading } from "../../pages/Loading"; | ||
import { IDPS } from "../../types/idp"; | ||
import { ERROR_ROUTES, HOME } from "../../../routes/constants"; | ||
|
||
const isIDIR = (identityProvider: string) => identityProvider === IDPS.IDIR; | ||
|
||
/** | ||
* This component ensures that a page is only available to IDIR users | ||
* with necessary roles and auth groups (as applicable). | ||
* | ||
*/ | ||
export const IDIRAuthWall = ({ | ||
requiredRole, | ||
allowedAuthGroups, | ||
}: { | ||
requiredRole?: UserRolesType; | ||
/** | ||
* The collection of auth groups allowed to have access to a page or action. | ||
* IDIR System Admin is assumed to be allowed regardless of it being passed. | ||
* If not provided, only a System Admin will be allowed to access. | ||
*/ | ||
allowedAuthGroups?: IDIRUserAuthGroupType[]; | ||
}) => { | ||
const { | ||
isAuthenticated, | ||
isLoading: isAuthLoading, | ||
user: userFromToken, | ||
} = useAuth(); | ||
|
||
const { userRoles, idirUserDetails } = useContext(OnRouteBCContext); | ||
|
||
const userIDP = userFromToken?.profile?.identity_provider as string; | ||
|
||
const location = useLocation(); | ||
const navigate = useNavigate(); | ||
|
||
useEffect(() => { | ||
if (!isAuthLoading && !isAuthenticated) { | ||
/** | ||
* Redirect the user back to login page if they are trying to directly access | ||
* a protected page but are unauthenticated. | ||
*/ | ||
navigate(HOME); | ||
} | ||
}, [isAuthLoading, isAuthenticated]); | ||
|
||
if (isAuthLoading) { | ||
return <Loading />; | ||
} | ||
|
||
if (isAuthenticated) { | ||
if (isIDIR(userIDP)) { | ||
if (!idirUserDetails?.userAuthGroup) { | ||
return ( | ||
<> | ||
<LoadIDIRUserContext /> | ||
<Loading /> | ||
</> | ||
); | ||
} | ||
if (!userRoles) { | ||
return ( | ||
<> | ||
<LoadIDIRUserRoles /> | ||
<Loading /> | ||
</> | ||
); | ||
} | ||
} else { | ||
return ( | ||
<Navigate | ||
to={ERROR_ROUTES.UNAUTHORIZED} | ||
state={{ from: location }} | ||
replace | ||
/> | ||
); | ||
} | ||
|
||
const doesUserHaveAccess = | ||
DoesUserHaveAuthGroup<IDIRUserAuthGroupType>({ | ||
userAuthGroup: idirUserDetails?.userAuthGroup, | ||
allowedAuthGroups, | ||
}) && DoesUserHaveRole(userRoles, requiredRole); | ||
|
||
if (doesUserHaveAccess) { | ||
return <Outlet />; | ||
} | ||
// The user does not have access. They should be disallowed. | ||
return ( | ||
<Navigate | ||
to={ERROR_ROUTES.UNAUTHORIZED} | ||
state={{ from: location }} | ||
replace | ||
/> | ||
); | ||
} else { | ||
return <Navigate to={HOME} state={{ from: location }} replace />; | ||
} | ||
}; | ||
|
||
IDIRAuthWall.displayName = "IDIRAuthWall"; |
85 changes: 85 additions & 0 deletions
85
frontend/src/common/authentication/auth-walls/NewBCeIDAuthWall.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { useContext } from "react"; | ||
import { useAuth } from "react-oidc-context"; | ||
import { Navigate, Outlet, useLocation } from "react-router-dom"; | ||
import { | ||
ERROR_ROUTES, | ||
HOME | ||
} from "../../../routes/constants"; | ||
import { Loading } from "../../pages/Loading"; | ||
import { IDPS } from "../../types/idp"; | ||
import { LoadBCeIDUserContext } from "../LoadBCeIDUserContext"; | ||
import OnRouteBCContext from "../OnRouteBCContext"; | ||
|
||
const isBCeID = (identityProvider: string) => identityProvider === IDPS.BCEID; | ||
|
||
/** | ||
* This component ensures that a page is only available to new BCeID users. | ||
*/ | ||
export const NewBCeIDAuthWall = () => { | ||
const { | ||
isAuthenticated, | ||
isLoading: isAuthLoading, | ||
user: userFromToken, | ||
} = useAuth(); | ||
|
||
const { isNewBCeIDUser, companyId, userDetails } = | ||
useContext(OnRouteBCContext); | ||
|
||
const userIDP = userFromToken?.profile?.identity_provider as string; | ||
const location = useLocation(); | ||
|
||
if (isAuthLoading) { | ||
return <Loading />; | ||
} | ||
|
||
if (isAuthenticated) { | ||
if (isBCeID(userIDP)) { | ||
// Condition to check if the user context must be loaded. | ||
if ( | ||
!companyId && | ||
isNewBCeIDUser === undefined && | ||
!userDetails?.userAuthGroup | ||
) { | ||
return ( | ||
<> | ||
<LoadBCeIDUserContext /> | ||
<Loading /> | ||
</> | ||
); | ||
} | ||
if (isNewBCeIDUser) { | ||
// The user is now authenticated and confirmed to be a new user | ||
return <Outlet />; | ||
} | ||
/** | ||
* Implementation Note: | ||
* There is no need to load up the user roles. | ||
* User context is sufficient enough to determine whether the user | ||
* already has a profile in the system. | ||
*/ | ||
} else { | ||
/** | ||
* This is a placeholder to navigate an IDIR user to the unexpected error page | ||
* since a companyId is necessary for them to do anything and | ||
* that feature is yet to be built. | ||
* | ||
* Once we set up idir user acting as a company, there will be appropriate | ||
* handlers here. | ||
*/ | ||
return ( | ||
<Navigate | ||
to={ERROR_ROUTES.UNEXPECTED} | ||
state={{ from: location }} | ||
replace | ||
/> | ||
); | ||
} | ||
} | ||
/** | ||
* The user is either a) unauthenticated or b) set up their profile already. | ||
* Redirect them to home page either way. | ||
*/ | ||
return <Navigate to={HOME} state={{ from: location }} replace />; | ||
}; | ||
|
||
NewBCeIDAuthWall.displayName = "NewBCeIDAuthWall"; |
Oops, something went wrong.