permissions, connection data reader
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Timo Hocker
2022-09-12 12:29:43 +02:00
parent 910099285b
commit ba9608829d
8 changed files with 164 additions and 24 deletions

View File

@ -20,6 +20,7 @@ interface AccessSettings {
redirect_to?: string
data?: unknown,
leave_open?: boolean
permissions?: string[]
}
interface AccessResult {
@ -95,7 +96,8 @@ class AuthRequest {
refresh_token_expires_in,
redirect_to,
data,
leave_open
leave_open,
permissions
}: AccessSettings): Promise<AccessResult> {
const log = logger.extend ('allow_access');
log ('allowed access');
@ -104,7 +106,7 @@ class AuthRequest {
const at = await auth.sign (
'access_token',
access_token_expires_in,
{ data }
{ data, permissions }
);
const result: AccessResult = { access_token_id: at.id };

View File

@ -25,6 +25,7 @@ interface VerificationResult {
type: TokenType;
id: string;
next_module?: string;
permissions?: string[];
data?: unknown;
error?: string;
}
@ -37,7 +38,8 @@ interface SignatureResult {
interface SignatureOptions
{
data?: unknown
next_module?: string
next_module?: string,
permissions?: string[]
}
class Authority {
@ -45,10 +47,11 @@ class Authority {
const log = logger.extend ('verify');
log ('verifying token');
const result: VerificationResult = {
authorized: false,
valid: false,
type: 'none',
id: ''
authorized: false,
valid: false,
type: 'none',
permissions: [],
id: ''
};
const data = await verify_signature_get_info (
key,
@ -83,6 +86,7 @@ class Authority {
result.valid = true;
result.authorized = result.type === 'access_token';
result.next_module = data.next_module;
result.permissions = data.permissions;
result.data = data.obj;
log (
@ -90,6 +94,7 @@ class Authority {
result.type,
result.next_module
);
log ('permissions %o', result.permissions);
return result;
}
@ -111,7 +116,8 @@ class Authority {
type,
valid_for,
valid_until,
next_module: options?.next_module
next_module: options?.next_module,
permissions: options?.permissions
};
const signature = sign_object (options?.data, key, attributes);
log ('created token %s', attributes.id);

View File

@ -32,6 +32,13 @@ interface GatewayOptions {
cookie?: CookieSettings;
refresh_cookie?: CookieSettings;
refresh_settings?: RefreshSettings;
require_permissions?: string[];
}
interface ConnectionInfo {
token_id: string
token_data: unknown
permissions: string[]
}
class GatewayClass {
@ -97,7 +104,11 @@ class GatewayClass {
log ('setting connection info');
const con = req.connection as unknown as Record<string, unknown>;
con.auth = { token_id: ver.id, token_data: ver.data };
con.auth = {
token_id: ver.id,
token_data: ver.data,
permissions: ver.permissions
};
log ('token valid: %s', ver.authorized);
return ver.authorized;
@ -144,8 +155,9 @@ class GatewayClass {
log ('setting connection info');
const con = req.connection as unknown as Record<string, unknown>;
con.auth = {
token_id: refresh_result.access_token_id,
token_data: ver.data
token_id: refresh_result.access_token_id,
token_data: ver.data,
permissions: ver.permissions
};
log ('tokens refreshed');
@ -175,6 +187,22 @@ class GatewayClass {
return false;
}
public check_permissions (
req: IncomingMessage,
permissions = this._options.require_permissions || []
): boolean {
for (const perm of permissions) {
if (!this.has_permission (req, perm))
return false;
}
return true;
}
public has_permission (req: IncomingMessage, permission: string) {
const info = this.get_info (req);
return info.permissions.includes (permission);
}
public async process_request (
req: IncomingMessage,
res: ServerResponse,
@ -183,7 +211,13 @@ class GatewayClass {
const log = logger.extend ('process_request');
log ('processing incoming http request');
if (await this.authenticate (req, res)) {
log ('authentification successful, calling next handler');
log ('authentification successful');
log ('checking permissions');
if (!this.check_permissions (req))
return this.redirect (res);
log ('authorization successful. calling next handler');
return next ();
}
@ -216,6 +250,16 @@ class GatewayClass {
log ('complete');
}
public get_info (req: IncomingMessage): ConnectionInfo {
const conn = req.connection as unknown as Record<string, unknown>;
const auth = conn.auth as Record<string, unknown>;
return {
token_id: auth.token_id as string,
token_data: auth.token_data,
permissions: (auth.permissions as string[]) || []
};
}
}
export default function create_gateway (options: GatewayOptions): Gateway {