add support for specifying a logout url

This commit is contained in:
Blake Blackshear 2024-05-18 09:41:21 -05:00
parent dd730bf6c7
commit 6cd88dfef3
3 changed files with 20 additions and 23 deletions

View File

@ -12,12 +12,12 @@ import time
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from flask import Blueprint, current_app, jsonify, make_response, request from flask import Blueprint, current_app, jsonify, make_response, redirect, request
from flask_limiter import Limiter from flask_limiter import Limiter
from joserfc import jwt from joserfc import jwt
from peewee import DoesNotExist from peewee import DoesNotExist
from frigate.config import AuthModeEnum from frigate.config import AuthConfig, AuthModeEnum
from frigate.const import CONFIG_DIR, JWT_SECRET_ENV_VAR, PASSWORD_HASH_ALGORITHM from frigate.const import CONFIG_DIR, JWT_SECRET_ENV_VAR, PASSWORD_HASH_ALGORITHM
from frigate.models import User from frigate.models import User
@ -167,6 +167,7 @@ def set_jwt_cookie(response, cookie_name, encoded_jwt, expiration):
) )
# Endpoint for use with nginx auth_request
@AuthBp.route("/auth") @AuthBp.route("/auth")
def auth(): def auth():
success_response = make_response({}, 202) success_response = make_response({}, 202)
@ -271,11 +272,11 @@ def profile():
return jsonify({"username": username}) return jsonify({"username": username})
@AuthBp.route("/logout", methods=["POST"]) @AuthBp.route("/logout")
def logout(): def logout():
JWT_COOKIE_NAME = current_app.frigate_config.auth.cookie_name auth_config: AuthConfig = current_app.frigate_config.auth
response = make_response({}, 200) response = make_response(redirect("/login", code=303))
response.delete_cookie(JWT_COOKIE_NAME) response.delete_cookie(auth_config.cookie_name)
return response return response

View File

@ -143,18 +143,21 @@ class AuthConfig(FrigateBaseModel):
title="Refresh the session if it is going to expire in this many seconds", title="Refresh the session if it is going to expire in this many seconds",
ge=30, ge=30,
) )
header_map: Optional[HeaderMappingConfig] = Field( header_map: HeaderMappingConfig = Field(
default_factory=HeaderMappingConfig, default_factory=HeaderMappingConfig,
title="Header mapping definitions for proxy auth mode.", title="Header mapping definitions for proxy auth mode.",
) )
failed_login_rate_limit: Optional[str] = Field( failed_login_rate_limit: str = Field(
default="1/second;5/minute;20/hour", default="1/second;5/minute;20/hour",
title="Rate limits for failed login attempts.", title="Rate limits for failed login attempts.",
) )
trusted_proxies: Optional[List[str]] = Field( trusted_proxies: List[str] = Field(
default=[], default=[],
title="Trusted proxies for determining IP address to rate limit", title="Trusted proxies for determining IP address to rate limit",
) )
logout_url: Optional[str] = Field(
default=None, title="Redirect url for logging out in proxy mode."
)
# As of Feb 2023, OWASP recommends 600000 iterations for PBKDF2-SHA256 # As of Feb 2023, OWASP recommends 600000 iterations for PBKDF2-SHA256
hash_iterations: int = Field(default=600000, title="Password hash iterations") hash_iterations: int = Field(default=600000, title="Password hash iterations")

View File

@ -18,8 +18,6 @@ import {
import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer"; import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer";
import { DialogClose } from "../ui/dialog"; import { DialogClose } from "../ui/dialog";
import { LuLogOut } from "react-icons/lu"; import { LuLogOut } from "react-icons/lu";
import { useCallback } from "react";
import axios from "axios";
import useSWR from "swr"; import useSWR from "swr";
type AccountSettingsProps = { type AccountSettingsProps = {
@ -27,14 +25,8 @@ type AccountSettingsProps = {
}; };
export default function AccountSettings({ className }: AccountSettingsProps) { export default function AccountSettings({ className }: AccountSettingsProps) {
const { data: profile } = useSWR("profile"); const { data: profile } = useSWR("profile");
const { data: config } = useSWR("config");
const handleLogout = useCallback(() => { const logoutUrl = config?.auth.logout_url || "/api/logout";
axios.post(`logout`).then((response) => {
if (response.status == 200) {
window.location.href = "/";
}
});
}, []);
const Container = isDesktop ? DropdownMenu : Drawer; const Container = isDesktop ? DropdownMenu : Drawer;
const Trigger = isDesktop ? DropdownMenuTrigger : DrawerTrigger; const Trigger = isDesktop ? DropdownMenuTrigger : DrawerTrigger;
@ -75,17 +67,18 @@ export default function AccountSettings({ className }: AccountSettingsProps) {
> >
<div className="w-full flex-col overflow-y-auto overflow-x-hidden"> <div className="w-full flex-col overflow-y-auto overflow-x-hidden">
<DropdownMenuLabel> <DropdownMenuLabel>
Current User: {profile?.username} Current User: {profile?.username || "anonymous"}
</DropdownMenuLabel> </DropdownMenuLabel>
<DropdownMenuSeparator className={isDesktop ? "mt-3" : "mt-1"} /> <DropdownMenuSeparator className={isDesktop ? "mt-3" : "mt-1"} />
<MenuItem <MenuItem
className={ className={
isDesktop ? "cursor-pointer" : "flex items-center p-2 text-sm" isDesktop ? "cursor-pointer" : "flex items-center p-2 text-sm"
} }
onClick={() => handleLogout()}
> >
<LuLogOut className="mr-2 size-4" /> <a className="flex" href={logoutUrl}>
<span>Logout</span> <LuLogOut className="mr-2 size-4" />
<span>Logout</span>
</a>
</MenuItem> </MenuItem>
</div> </div>
</Content> </Content>