Invert privilege check logic

This commit is contained in:
Evert Prants 2024-06-09 11:42:01 +03:00
parent 8dd6ccc58c
commit 46351fb17d
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
9 changed files with 23 additions and 10 deletions

View File

@ -15,7 +15,7 @@
{ {
href: '/ssoadmin/oauth2', href: '/ssoadmin/oauth2',
title: $t('admin.menu.oauth2'), title: $t('admin.menu.oauth2'),
privileges: [['admin:oauth2', 'self:oauth2']] privileges: ['admin:oauth2', 'self:oauth2']
}, },
{ {
href: '/ssoadmin/audit', href: '/ssoadmin/audit',

View File

@ -3,6 +3,12 @@ import { Users, type UserSession } from './users';
import { hasPrivileges, type RequiredPrivileges } from '$lib/utils'; import { hasPrivileges, type RequiredPrivileges } from '$lib/utils';
export class AdminUtils { export class AdminUtils {
/**
* Check a session privileges against a list of required privileges.
* @param session User session with privileges loaded
* @param privileges OR logic, AND's arrays
* @throws 403 error if privileges are not met
*/
static checkPrivileges(session: UserSession, privileges: RequiredPrivileges): void { static checkPrivileges(session: UserSession, privileges: RequiredPrivileges): void {
if (!session.privileges?.length || !hasPrivileges(session.privileges, privileges)) { if (!session.privileges?.length || !hasPrivileges(session.privileges, privileges)) {
error(403, 'Forbidden resource'); error(403, 'Forbidden resource');

View File

@ -1,9 +1,15 @@
export type RequiredPrivileges = (string | string[])[]; export type RequiredPrivileges = (string | string[])[];
/**
* Check a list of privileges against a list of required privileges.
* @param list List of privileges
* @param privileges OR logic, AND's arrays
* @returns Satisfies privileges
*/
export const hasPrivileges = (list: string[], privileges: RequiredPrivileges) => export const hasPrivileges = (list: string[], privileges: RequiredPrivileges) =>
privileges.every((item) => { privileges.some((item) => {
if (Array.isArray(item)) { if (Array.isArray(item)) {
return item.some((sub) => list.includes(sub)); return item.every((sub) => list.includes(sub));
} }
return list.includes(item); return list.includes(item);
}); });

View File

@ -28,7 +28,7 @@
let internalErrors: string[] = []; let internalErrors: string[] = [];
$: errors = [...internalErrors, ...(form?.errors?.length ? form.errors : [])]; $: errors = [...internalErrors, ...(form?.errors?.length ? form.errors : [])];
$: adminButton = hasPrivileges(data.privileges, [['admin', 'self:oauth2']]); $: adminButton = hasPrivileges(data.privileges, ['admin', 'self:oauth2']);
let usernameRef: HTMLInputElement; let usernameRef: HTMLInputElement;
let displayRef: HTMLInputElement; let displayRef: HTMLInputElement;

View File

@ -1,4 +1,5 @@
import { Users } from '$lib/server/users/index.js'; import { Users } from '$lib/server/users/index.js';
import { hasPrivileges } from '$lib/utils.js';
import { error, redirect } from '@sveltejs/kit'; import { error, redirect } from '@sveltejs/kit';
export const load = async ({ url, locals }) => { export const load = async ({ url, locals }) => {
@ -11,7 +12,7 @@ export const load = async ({ url, locals }) => {
// Only users with 'admin' privilege can access // Only users with 'admin' privilege can access
const privileges = await Users.getUserPrivileges(currentUser); const privileges = await Users.getUserPrivileges(currentUser);
if (!privileges.includes('admin')) { if (!hasPrivileges(privileges, ['admin', 'self:oauth2'])) {
return error(404, 'Not Found'); return error(404, 'Not Found');
} }

View File

@ -9,7 +9,7 @@ const PAGE_SIZE = 20;
export const load = async ({ parent, url }) => { export const load = async ({ parent, url }) => {
const { user } = await parent(); const { user } = await parent();
const currentUser = await Users.getBySession(user); const currentUser = await Users.getBySession(user);
AdminUtils.checkPrivileges(user, [['admin:oauth2', 'self:oauth2']]); AdminUtils.checkPrivileges(user, ['admin:oauth2', 'self:oauth2']);
let limit = PAGE_SIZE; let limit = PAGE_SIZE;
let page = 1; let page = 1;
@ -28,7 +28,7 @@ export const load = async ({ parent, url }) => {
const offset = (page - 1) * limit; const offset = (page - 1) * limit;
const fullPrivileges = hasPrivileges(user.privileges, ['admin:oauth2']); const fullPrivileges = hasPrivileges(user.privileges, ['admin:oauth2']);
const createPrivileges = hasPrivileges(user.privileges, [['admin:oauth2', 'self:oauth2:create']]); const createPrivileges = hasPrivileges(user.privileges, ['admin:oauth2', 'self:oauth2:create']);
const data = await OAuth2Clients.getClientByAdminUser(currentUser as User, { const data = await OAuth2Clients.getClientByAdminUser(currentUser as User, {
filter, filter,

View File

@ -375,7 +375,7 @@ export const actions = {
export const load = async ({ params: { uuid }, parent }) => { export const load = async ({ params: { uuid }, parent }) => {
const { user } = await parent(); const { user } = await parent();
const currentUser = await Users.getBySession(user); const currentUser = await Users.getBySession(user);
AdminUtils.checkPrivileges(user, [['admin:oauth2', 'self:oauth2']]); AdminUtils.checkPrivileges(user, ['admin:oauth2', 'self:oauth2']);
const fullPrivileges = hasPrivileges(user.privileges, ['admin:oauth2']); const fullPrivileges = hasPrivileges(user.privileges, ['admin:oauth2']);

View File

@ -67,7 +67,7 @@ export const actions = {
export const load = async ({ params: { uuid, user: userId }, parent }) => { export const load = async ({ params: { uuid, user: userId }, parent }) => {
const { user } = await parent(); const { user } = await parent();
const currentUser = await Users.getBySession(user); const currentUser = await Users.getBySession(user);
AdminUtils.checkPrivileges(user, [['admin:oauth2', 'self:oauth2']]); AdminUtils.checkPrivileges(user, ['admin:oauth2', 'self:oauth2']);
const fullPrivileges = hasPrivileges(user.privileges || [], ['admin:oauth2']); const fullPrivileges = hasPrivileges(user.privileges || [], ['admin:oauth2']);

View File

@ -48,7 +48,7 @@ export const actions = {
export const load = async ({ parent }) => { export const load = async ({ parent }) => {
const { user } = await parent(); const { user } = await parent();
AdminUtils.checkPrivileges(user, [['admin:oauth2', 'self:oauth2:create']]); AdminUtils.checkPrivileges(user, ['admin:oauth2', 'self:oauth2:create']);
return {}; return {};
}; };