mirror of
https://github.com/pomerium/pomerium.git
synced 2025-07-05 10:58:11 +02:00
add signed out page
This commit is contained in:
parent
f649d9b1bc
commit
dce25e12d5
6 changed files with 77 additions and 18 deletions
|
@ -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,11 +294,8 @@ 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
|
||||||
|
|
23
internal/handlers/signedout.go
Normal file
23
internal/handlers/signedout.go
Normal 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())
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import CssBaseline from "@mui/material/CssBaseline";
|
import CssBaseline from "@mui/material/CssBaseline";
|
||||||
import { ThemeProvider } from "@mui/material/styles";
|
import { ThemeProvider } from "@mui/material/styles";
|
||||||
import React, {FC, useLayoutEffect} from "react";
|
import React, { FC, useLayoutEffect } from "react";
|
||||||
|
|
||||||
import ErrorPage from "./components/ErrorPage";
|
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}>
|
||||||
|
|
|
@ -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} />
|
||||||
<IconButton color="inherit" onClick={handleMenuOpen}>
|
{showAvatar && (
|
||||||
<Avatar name={userName} url={userPictureUrl} />
|
<IconButton color="inherit" onClick={handleMenuOpen}>
|
||||||
</IconButton>
|
<Avatar name={userName} url={userPictureUrl} />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
<Menu
|
<Menu
|
||||||
onClose={handleMenuClose}
|
onClose={handleMenuClose}
|
||||||
anchorOrigin={{
|
anchorOrigin={{
|
||||||
|
|
16
ui/src/components/SignedOutPage.tsx
Normal file
16
ui/src/components/SignedOutPage.tsx
Normal 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;
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue