feat: add admin auth provider

This commit is contained in:
Morten Olsen
2025-10-16 16:49:28 +02:00
parent 9ba5788d20
commit 5cf0a3612a
6 changed files with 50 additions and 9 deletions

32
src/auth/auth.admin.ts Normal file
View File

@@ -0,0 +1,32 @@
import type { Services } from '#root/utils/services.ts';
import { Config } from '#root/config/config.ts';
import type { Statement } from './auth.schemas.ts';
import type { AuthProvider } from './auth.provider.ts';
const adminStatements: Statement[] = [
{
effect: 'allow',
resources: ['**'],
actions: ['**'],
},
];
class AdminAuth implements AuthProvider {
#services: Services;
constructor(services: Services) {
this.#services = services;
}
public getAccess = async (token: string) => {
const config = this.#services.get(Config);
if (!config.adminToken || token !== config.adminToken) {
throw new Error('Invalid admin token');
}
return {
statements: adminStatements,
};
};
}
export { AdminAuth };

View File

@@ -22,7 +22,7 @@ class JwtAuth implements AuthProvider {
public generate = (options: TokenBody) => {
const config = this.#services.get(Config);
const { tokenSecret } = config;
const { jwtSecret: tokenSecret } = config;
if (!tokenSecret) {
throw new Error('Token secret does not exist');
}
@@ -32,7 +32,7 @@ class JwtAuth implements AuthProvider {
public getAccess = async (token: string) => {
const config = this.#services.get(Config);
const { tokenSecret } = config;
const { jwtSecret: tokenSecret } = config;
if (!tokenSecret) {
throw new Error('Token secret does not exist');
}

View File

@@ -1,3 +1,4 @@
import { AdminAuth } from './auth/auth.admin.ts';
import { JwtAuth } from './auth/auth.jwt.ts';
import { K8sAuth } from './auth/auth.k8s.ts';
import { OidcAuth } from './auth/auth.oidc.ts';
@@ -56,8 +57,11 @@ class Backbone {
if (this.config.oidc.enabled) {
this.sessionProvider.register('oidc', this.#services.get(OidcAuth));
}
if (this.config.tokenSecret) {
this.sessionProvider.register('token', this.#services.get(JwtAuth));
if (this.config.jwtSecret) {
this.sessionProvider.register('jwt', this.#services.get(JwtAuth));
}
if (this.config.adminToken) {
this.sessionProvider.register('admin', this.#services.get(AdminAuth));
}
};

View File

@@ -1,5 +1,5 @@
class Config {
public get tokenSecret() {
public get jwtSecret() {
return process.env.TOKEN_SECRET;
}

View File

@@ -13,12 +13,12 @@ import fastify, { type FastifyInstance } from 'fastify';
import fastifyWebSocket from '@fastify/websocket';
import { createWebSocketStream } from 'ws';
import { Session } from '../access/access.session.ts';
import { api } from '../api/api.ts';
import { AccessHandler } from '#root/access/access.handler.ts';
import { TopicsHandler } from '#root/topics/topics.handler.ts';
import type { Services } from '#root/utils/services.ts';
import { Session } from '#root/services/sessions/sessions.session.ts';
import { SessionProvider } from '#root/services/sessions/sessions.provider.ts';
type Aedes = ReturnType<typeof aedes.createBroker>;
@@ -57,8 +57,8 @@ class MqttServer {
if (!username || !password) {
throw new Error('unauthorized');
}
const accessHandler = this.#services.get(AccessHandler);
const auth = await accessHandler.validate(username, password.toString('utf8'));
const sessionProvider = this.#services.get(SessionProvider);
const auth = await sessionProvider.validate(username, password.toString('utf8'));
client.session = new Session(auth);
callback(null, true);
} catch {

View File

@@ -6,6 +6,7 @@ import { TopicsStore } from '#root/topics/topics.store.ts';
import { Backbone } from '#root/backbone.ts';
import { JwtAuth } from '#root/auth/auth.jwt.ts';
import type { Statement } from '#root/auth/auth.schemas.ts';
import { Config } from '#root/config/config.ts';
type CreateSocketOptions = {
port: number;
@@ -29,6 +30,10 @@ type WorldOptions = {
const createWorld = async (options: WorldOptions) => {
const { topics = [] } = options;
const backbone = new Backbone();
backbone.services.set(Config, {
jwtSecret: 'test',
adminToken: 'test',
});
const accessTokens = backbone.services.get(JwtAuth);
backbone.sessionProvider.register('token', accessTokens);
const topicsStore = new TopicsStore();