add signed out page

This commit is contained in:
Caleb Doxsey 2023-09-19 17:40:51 -06:00
parent f649d9b1bc
commit dce25e12d5
6 changed files with 77 additions and 18 deletions

View file

@ -89,6 +89,7 @@ func (a *Authenticate) mountDashboard(r *mux.Router) {
// routes that don't need a session: // routes that don't need a session:
sr.Path("/sign_out").Handler(httputil.HandlerFunc(a.SignOut)) sr.Path("/sign_out").Handler(httputil.HandlerFunc(a.SignOut))
sr.Path("/signed_out").Handler(handlers.SignedOut(handlers.SignedOutData{})).Methods(http.MethodGet)
// routes that need a session: // routes that need a session:
sr = sr.NewRoute().Subrouter() sr = sr.NewRoute().Subrouter()
@ -266,16 +267,25 @@ func (a *Authenticate) signOutRedirect(w http.ResponseWriter, r *http.Request) e
rawIDToken := a.revokeSession(ctx, w, r) rawIDToken := a.revokeSession(ctx, w, r)
signOutURL := "" authenticateURL, err := options.GetAuthenticateURL()
if err != nil {
return fmt.Errorf("error getting authenticate url: %w", err)
}
signOutRedirectURL, err := options.GetSignOutRedirectURL() signOutRedirectURL, err := options.GetSignOutRedirectURL()
if err != nil { if err != nil {
return err return err
} }
if signOutRedirectURL != nil {
signOutURL = signOutRedirectURL.String() var signOutURL string
}
if uri := r.FormValue(urlutil.QueryRedirectURI); uri != "" { if uri := r.FormValue(urlutil.QueryRedirectURI); uri != "" {
signOutURL = uri signOutURL = uri
} else if signOutRedirectURL != nil {
signOutURL = signOutRedirectURL.String()
} else {
signOutURL = authenticateURL.ResolveReference(&url.URL{
Path: "/.pomerium/signed_out",
}).String()
} }
if idpSignOutURL, err := authenticator.GetSignOutURL(rawIDToken, signOutURL); err == nil { if idpSignOutURL, err := authenticator.GetSignOutURL(rawIDToken, signOutURL); err == nil {
@ -284,12 +294,9 @@ func (a *Authenticate) signOutRedirect(w http.ResponseWriter, r *http.Request) e
log.Warn(r.Context()).Err(err).Msg("authenticate: failed to get sign out url for authenticator") log.Warn(r.Context()).Err(err).Msg("authenticate: failed to get sign out url for authenticator")
} }
if signOutURL != "" {
httputil.Redirect(w, r, signOutURL, http.StatusFound) httputil.Redirect(w, r, signOutURL, http.StatusFound)
return nil return nil
} }
return httputil.NewError(http.StatusOK, errors.New("user logged out"))
}
// reauthenticateOrFail starts the authenticate process by redirecting the // reauthenticateOrFail starts the authenticate process by redirecting the
// user to their respective identity provider. This function also builds the // user to their respective identity provider. This function also builds the

View file

@ -0,0 +1,23 @@
package handlers
import (
"net/http"
"github.com/pomerium/pomerium/internal/httputil"
"github.com/pomerium/pomerium/ui"
)
// SignedOutData is the data for the SignedOut page.
type SignedOutData struct{}
// ToJSON converts the data into a JSON map.
func (data SignedOutData) ToJSON() map[string]interface{} {
return map[string]interface{}{}
}
// SignedOut returns a handler that renders the signed out page.
func SignedOut(data SignedOutData) http.Handler {
return httputil.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
return ui.ServePage(w, r, "SignedOut", data.ToJSON())
})
}

View file

@ -7,6 +7,7 @@ import ErrorPage from "./components/ErrorPage";
import Footer from "./components/Footer"; import Footer from "./components/Footer";
import Header from "./components/Header"; import Header from "./components/Header";
import SignOutConfirmPage from "./components/SignOutConfirmPage"; import SignOutConfirmPage from "./components/SignOutConfirmPage";
import SignedOutPage from "./components/SignedOutPage";
import { ToolbarOffset } from "./components/ToolbarOffset"; import { ToolbarOffset } from "./components/ToolbarOffset";
import UserInfoPage from "./components/UserInfoPage"; import UserInfoPage from "./components/UserInfoPage";
import WebAuthnRegistrationPage from "./components/WebAuthnRegistrationPage"; import WebAuthnRegistrationPage from "./components/WebAuthnRegistrationPage";
@ -27,6 +28,9 @@ const App: FC = () => {
case "SignOutConfirm": case "SignOutConfirm":
body = <SignOutConfirmPage data={data} />; body = <SignOutConfirmPage data={data} />;
break; break;
case "SignedOut":
body = <SignedOutPage data={data} />;
break;
case "DeviceEnrolled": case "DeviceEnrolled":
case "UserInfo": case "UserInfo":
body = <UserInfoPage data={data} />; body = <UserInfoPage data={data} />;
@ -38,18 +42,18 @@ const App: FC = () => {
useLayoutEffect(() => { useLayoutEffect(() => {
const favicon = document.getElementById( const favicon = document.getElementById(
'favicon' "favicon"
) as HTMLAnchorElement | null; ) as HTMLAnchorElement | null;
if (favicon) { if (favicon) {
favicon.href = data?.faviconUrl || '/.pomerium/favicon.ico'; favicon.href = data?.faviconUrl || "/.pomerium/favicon.ico";
} }
const extraFaviconLinks = document.getElementsByClassName( const extraFaviconLinks = document.getElementsByClassName(
'pomerium_favicon' "pomerium_favicon"
) as HTMLCollectionOf<HTMLAnchorElement> | null; ) as HTMLCollectionOf<HTMLAnchorElement> | null;
for (const link of extraFaviconLinks) { for (const link of extraFaviconLinks) {
link.style.display = data?.faviconUrl ? 'none' : ''; link.style.display = data?.faviconUrl ? "none" : "";
} }
}, []) }, []);
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>

View file

@ -57,6 +57,8 @@ const Header: FC<HeaderProps> = ({ includeSidebar, data }) => {
get(data, "user.claims.picture") || get(data, "user.claims.picture") ||
get(data, "profile.claims.picture") || get(data, "profile.claims.picture") ||
null; null;
const showAvatar =
data?.page !== "SignOutConfirm" && data?.page !== "SignedOut";
const handleDrawerOpen = () => { const handleDrawerOpen = () => {
setDrawerOpen(true); setDrawerOpen(true);
@ -122,9 +124,11 @@ const Header: FC<HeaderProps> = ({ includeSidebar, data }) => {
</a> </a>
)} )}
<Box flexGrow={1} /> <Box flexGrow={1} />
{showAvatar && (
<IconButton color="inherit" onClick={handleMenuOpen}> <IconButton color="inherit" onClick={handleMenuOpen}>
<Avatar name={userName} url={userPictureUrl} /> <Avatar name={userName} url={userPictureUrl} />
</IconButton> </IconButton>
)}
<Menu <Menu
onClose={handleMenuClose} onClose={handleMenuClose}
anchorOrigin={{ anchorOrigin={{

View file

@ -0,0 +1,16 @@
import { Alert } from "@mui/material";
import Container from "@mui/material/Container";
import React, { FC } from "react";
import { SignedOutPageData } from "src/types";
type SignedOutPageProps = {
data: SignedOutPageData;
};
const SignedOutPage: FC<SignedOutPageProps> = ({ data }) => {
return (
<Container>
<Alert color="info">User has been Logged Out</Alert>
</Container>
);
};
export default SignedOutPage;

View file

@ -132,6 +132,10 @@ export type SignOutConfirmPageData = BasePageData & {
url: string; url: string;
}; };
export type SignedOutPageData = BasePageData & {
page: "SignedOut";
};
export type UserInfoPageData = BasePageData & export type UserInfoPageData = BasePageData &
UserInfoData & { UserInfoData & {
page: "UserInfo"; page: "UserInfo";
@ -150,6 +154,7 @@ export type PageData =
| ErrorPageData | ErrorPageData
| DeviceEnrolledPageData | DeviceEnrolledPageData
| SignOutConfirmPageData | SignOutConfirmPageData
| SignedOutPageData
| UserInfoPageData | UserInfoPageData
| WebAuthnRegistrationPageData; | WebAuthnRegistrationPageData;