Skip to content

Commit

Permalink
Merge pull request #1776 from carbon-design-system/fix/readd-authenti…
Browse files Browse the repository at this point in the history
…cation

fix: re-add authentication to web-app

Co-authored-by: Joe Harvey <jdharvey-ibm@users.noreply.github.com>
  • Loading branch information
jdharvey-ibm and jdharvey-ibm committed Mar 1, 2024
2 parents 24e9185 + fed8f65 commit c96dea0
Show file tree
Hide file tree
Showing 303 changed files with 410 additions and 319 deletions.
9 changes: 4 additions & 5 deletions services/web-app/components/footer/footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import { Column, Grid, Theme } from '@carbon/react'
import { IbmLogo } from '@carbon-platform/icons'
import clsx from 'clsx'
import Link from 'next/link'
import PropTypes from 'prop-types'

import { currentYear } from '@/utils/date'
Expand Down Expand Up @@ -43,11 +42,11 @@ const Footer = ({ hasSideNav }) => {
]

const getColList = (col) =>
col.map((item, i) => (
col.map((item) => (
<li key={item.text}>
<Link href={item.link} key={i}>
<a className={clsx(styles.text, styles.link, styles['list-link'])}>{item.text}</a>
</Link>
<a href={item.link} className={clsx(styles.text, styles.link, styles['list-link'])}>
{item.text}
</a>
</li>
))

Expand Down
37 changes: 30 additions & 7 deletions services/web-app/components/page-not-found/page-not-found.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,44 @@
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
import { Column, Grid } from '@carbon/react'
import { H1 } from '@carbon-platform/mdx-components'
import { Button, Column, Grid } from '@carbon/react'
import { ArrowRight } from '@carbon/react/icons'
import { useEffect, useState } from 'react'

import { useAuth } from '@/contexts/auth'
import { isValidIbmEmail } from '@/utils/string'

import styles from './page-not-found.module.scss'

export const PageNotFound = () => {
const [isAuthorized, setIsAuthorized] = useState(false)
const { isAuthenticated, loading, user } = useAuth()

useEffect(() => {
if (!loading && isAuthenticated && isValidIbmEmail(user?.email ?? '')) {
setIsAuthorized(true)
}
}, [loading, isAuthenticated, user])

return (
<Grid>
<Grid className={styles.grid}>
<Column className={styles.column} sm={4} md={8} lg={6}>
<H1 headingClassName={styles.title} className={styles['h1-container']}>
Page not found.
</H1>
<h1 className={styles.title}>Page not found.</h1>
{!isAuthorized && (
<>
<h2 className={styles.title}>Log in to view all pages.</h2>
<Grid>
<Column sm={4}>
<Button className={styles.button} as="a" href="/api/login">
Log in
<ArrowRight size={16} />
</Button>
</Column>
</Grid>
</>
)}
</Column>
</Grid>
)
}

export default PageNotFound
5 changes: 3 additions & 2 deletions services/web-app/contexts/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ const AuthProvider = ({ children }) => {
const [loading, setLoading] = useState(true)

useEffect(() => {
setImmediate(async function loadUser() {
async function loadUser() {
const userResponse = await fetch('/api/user')
if (userResponse.ok) {
setUser(await userResponse.json())
}
setLoading(false)
})
}
loadUser()
}, [])

const login = async (next) => {
Expand Down
8 changes: 4 additions & 4 deletions services/web-app/layouts/layout/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
Theme
} from '@carbon/react'
import clsx from 'clsx'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { createContext, useContext, useEffect, useState } from 'react'

Expand Down Expand Up @@ -185,9 +184,10 @@ const Layout = ({ children }) => {
</div>
)}
<div className={styles['header-name']}>
<Link href="/">
<a className="cds--header__name">Carbon Design System</a>
</Link>
{/* eslint-disable-next-line @next/next/no-html-link-for-pages -- no prefetching */}
<a href="/" className="cds--header__name">
Carbon Design System
</a>
</div>
<Grid narrow className={styles['header-grid']}>
<Column sm={0} lg={{ span: 8, offset: 4 }}>
Expand Down
65 changes: 65 additions & 0 deletions services/web-app/middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright IBM Corp. 2022, 2023
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import { NextResponse } from 'next/server'

import sendLocalRequest from '@/utils/sendLocalRequest'
import { isValidIbmEmail } from '@/utils/string'

class NotAuthorizedException extends Error {}

function exitWith404(req) {
const url = req.nextUrl.clone()
url.pathname = '/404'
return NextResponse.rewrite(url)
}

async function applyAuthMiddleware(req) {
if (
req.nextUrl.pathname === '/404' ||
req.nextUrl.pathname.startsWith('/api/') ||
req.nextUrl.pathname.startsWith('/_next/') ||
req.nextUrl.pathname.startsWith('/vendor/') ||
req.nextUrl.pathname === 'favicon.ico'
) {
return NextResponse.next()
}

const userResponse = await sendLocalRequest(req, '/api/user', true)

// Guard - non-200 user api response
if (!userResponse.ok) {
throw new NotAuthorizedException()
}

const user = await userResponse.json()

// Guard - no valid user
if (!user?.email) {
throw new NotAuthorizedException()
}

// Guard - not a valid IBMer
if (!isValidIbmEmail(user.email)) {
throw new NotAuthorizedException()
}

return NextResponse.next()
}

export default async function middleware(req) {
try {
await applyAuthMiddleware(req)
} catch (err) {
if (err instanceof NotAuthorizedException) {
return exitWith404(req)
}
throw err
}

return NextResponse.next()
}
19 changes: 11 additions & 8 deletions services/web-app/pages/_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useEffect } from 'react'

import components from '@/components/mdx'
import defaultSeo from '@/config/seo.json'
import { AuthProvider } from '@/contexts/auth'
import Layout, { LayoutProvider } from '@/layouts/layout'

function useNormalScrollRoutes() {
Expand Down Expand Up @@ -67,14 +68,16 @@ function App({ Component, pageProps }) {
async="async"
></Script>
<Script src="/vendor/prismjs/prism.min.js" type="text/javascript" async="async"></Script>
<LayoutProvider>
<Layout>
<DefaultSeo {...defaultSeo} />
<MDXProvider components={components}>
<Component {...pageProps} />
</MDXProvider>
</Layout>
</LayoutProvider>
<AuthProvider>
<LayoutProvider>
<Layout>
<DefaultSeo {...defaultSeo} />
<MDXProvider components={components}>
<Component {...pageProps} />
</MDXProvider>
</Layout>
</LayoutProvider>
</AuthProvider>
</>
)
}
Expand Down
Loading

0 comments on commit c96dea0

Please sign in to comment.