mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
added auth strategies form + add ability to disable strategies
This commit is contained in:
@@ -56,7 +56,6 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
|
||||
// register roles
|
||||
const roles = transformObject(this.config.roles ?? {}, (role, name) => {
|
||||
//console.log("role", role, name);
|
||||
return Role.create({ name, ...role });
|
||||
});
|
||||
this.ctx.guard.setRoles(Object.values(roles));
|
||||
@@ -88,6 +87,11 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
this.ctx.guard.registerPermissions(Object.values(AuthPermissions));
|
||||
}
|
||||
|
||||
isStrategyEnabled(strategy: Strategy | string) {
|
||||
const name = typeof strategy === "string" ? strategy : strategy.getName();
|
||||
return this.config.strategies?.[name]?.enabled ?? false;
|
||||
}
|
||||
|
||||
get controller(): AuthController {
|
||||
if (!this.isBuilt()) {
|
||||
throw new Error("Can't access controller, AppAuth not built yet");
|
||||
@@ -115,12 +119,6 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
identifier: string,
|
||||
profile: ProfileExchange
|
||||
): Promise<any> {
|
||||
/*console.log("***** AppAuth:resolveUser", {
|
||||
action,
|
||||
strategy: strategy.getName(),
|
||||
identifier,
|
||||
profile
|
||||
});*/
|
||||
if (!this.config.allow_register && action === "register") {
|
||||
throw new Exception("Registration is not allowed", 403);
|
||||
}
|
||||
@@ -141,21 +139,10 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
}
|
||||
|
||||
private filterUserData(user: any) {
|
||||
/*console.log(
|
||||
"--filterUserData",
|
||||
user,
|
||||
this.config.jwt.fields,
|
||||
pick(user, this.config.jwt.fields)
|
||||
);*/
|
||||
return pick(user, this.config.jwt.fields);
|
||||
}
|
||||
|
||||
private async login(strategy: Strategy, identifier: string, profile: ProfileExchange) {
|
||||
/*console.log("--- trying to login", {
|
||||
strategy: strategy.getName(),
|
||||
identifier,
|
||||
profile
|
||||
});*/
|
||||
if (!("email" in profile)) {
|
||||
throw new Exception("Profile must have email");
|
||||
}
|
||||
@@ -172,18 +159,14 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
if (!result.data) {
|
||||
throw new Exception("User not found", 404);
|
||||
}
|
||||
//console.log("---login data", result.data, result);
|
||||
|
||||
// compare strategy and identifier
|
||||
//console.log("strategy comparison", result.data.strategy, strategy.getName());
|
||||
if (result.data.strategy !== strategy.getName()) {
|
||||
//console.log("!!! User registered with different strategy");
|
||||
throw new Exception("User registered with different strategy");
|
||||
}
|
||||
|
||||
//console.log("identifier comparison", result.data.strategy_value, identifier);
|
||||
if (result.data.strategy_value !== identifier) {
|
||||
//console.log("!!! Invalid credentials");
|
||||
throw new Exception("Invalid credentials");
|
||||
}
|
||||
|
||||
@@ -285,6 +268,7 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
// also keep disabled strategies as a choice
|
||||
const strategies = Object.keys(this.config.strategies ?? {});
|
||||
this.replaceEntityField(users, "strategy", enumm({ enum: strategies }));
|
||||
} catch (e) {}
|
||||
@@ -315,9 +299,16 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
||||
return this.configDefault;
|
||||
}
|
||||
|
||||
const strategies = this.authenticator.getStrategies();
|
||||
|
||||
return {
|
||||
...this.config,
|
||||
...this.authenticator.toJSON(secrets)
|
||||
...this.authenticator.toJSON(secrets),
|
||||
strategies: transformObject(strategies, (strategy) => ({
|
||||
enabled: this.isStrategyEnabled(strategy),
|
||||
type: strategy.getType(),
|
||||
config: strategy.toJSON(secrets)
|
||||
}))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type AppAuth, AuthPermissions, type SafeUser, type Strategy } from "auth";
|
||||
import { TypeInvalidError, parse } from "core/utils";
|
||||
import { tbValidator as tb } from "core";
|
||||
import { Type, TypeInvalidError, parse, transformObject } from "core/utils";
|
||||
import { DataPermissions } from "data";
|
||||
import type { Hono } from "hono";
|
||||
import { Controller } from "modules/Controller";
|
||||
@@ -12,6 +13,10 @@ export type AuthActionResponse = {
|
||||
errors?: any;
|
||||
};
|
||||
|
||||
const booleanLike = Type.Transform(Type.String())
|
||||
.Decode((v) => v === "1")
|
||||
.Encode((v) => (v ? "1" : "0"));
|
||||
|
||||
export class AuthController extends Controller {
|
||||
constructor(private auth: AppAuth) {
|
||||
super();
|
||||
@@ -31,6 +36,9 @@ export class AuthController extends Controller {
|
||||
}
|
||||
|
||||
private registerStrategyActions(strategy: Strategy, mainHono: Hono<ServerEnv>) {
|
||||
if (!this.auth.isStrategyEnabled(strategy)) {
|
||||
return;
|
||||
}
|
||||
const actions = strategy.getActions?.();
|
||||
if (!actions) {
|
||||
return;
|
||||
@@ -98,7 +106,8 @@ export class AuthController extends Controller {
|
||||
const strategies = this.auth.authenticator.getStrategies();
|
||||
|
||||
for (const [name, strategy] of Object.entries(strategies)) {
|
||||
//console.log("registering", name, "at", `/${name}`);
|
||||
if (!this.auth.isStrategyEnabled(strategy)) continue;
|
||||
|
||||
hono.route(`/${name}`, strategy.getController(this.auth.authenticator));
|
||||
this.registerStrategyActions(strategy, hono);
|
||||
}
|
||||
@@ -127,10 +136,25 @@ export class AuthController extends Controller {
|
||||
return c.redirect("/");
|
||||
});
|
||||
|
||||
hono.get("/strategies", async (c) => {
|
||||
const { strategies, basepath } = this.auth.toJSON(false);
|
||||
return c.json({ strategies, basepath });
|
||||
});
|
||||
hono.get(
|
||||
"/strategies",
|
||||
tb("query", Type.Object({ include_disabled: Type.Optional(booleanLike) })),
|
||||
async (c) => {
|
||||
const { include_disabled } = c.req.valid("query");
|
||||
const { strategies, basepath } = this.auth.toJSON(false);
|
||||
|
||||
if (!include_disabled) {
|
||||
return c.json({
|
||||
strategies: transformObject(strategies ?? {}, (strategy, name) => {
|
||||
return this.auth.isStrategyEnabled(name) ? strategy : undefined;
|
||||
}),
|
||||
basepath
|
||||
});
|
||||
}
|
||||
|
||||
return c.json({ strategies, basepath });
|
||||
}
|
||||
);
|
||||
|
||||
return hono.all("*", (c) => c.notFound());
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export const STRATEGIES = Strategies;
|
||||
const strategiesSchemaObject = objectTransform(STRATEGIES, (strategy, name) => {
|
||||
return Type.Object(
|
||||
{
|
||||
enabled: Type.Optional(Type.Boolean({ default: true })),
|
||||
type: Type.Const(name, { default: name, readOnly: true }),
|
||||
config: strategy.schema
|
||||
},
|
||||
@@ -61,6 +62,7 @@ export const authConfigSchema = Type.Object(
|
||||
default: {
|
||||
password: {
|
||||
type: "password",
|
||||
enabled: true,
|
||||
config: {
|
||||
hashing: "sha256"
|
||||
}
|
||||
|
||||
@@ -342,8 +342,7 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
||||
toJSON(secrets?: boolean) {
|
||||
return {
|
||||
...this.config,
|
||||
jwt: secrets ? this.config.jwt : undefined,
|
||||
strategies: transformObject(this.getStrategies(), (s) => s.toJSON(secrets))
|
||||
jwt: secrets ? this.config.jwt : undefined
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,9 +147,6 @@ export class PasswordStrategy implements Strategy {
|
||||
}
|
||||
|
||||
toJSON(secrets?: boolean) {
|
||||
return {
|
||||
type: this.getType(),
|
||||
config: secrets ? this.options : undefined
|
||||
};
|
||||
return secrets ? this.options : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,11 +476,8 @@ export class OAuthStrategy implements Strategy {
|
||||
const config = secrets ? this.config : filterKeys(this.config, ["secret", "client_id"]);
|
||||
|
||||
return {
|
||||
type: this.getType(),
|
||||
config: {
|
||||
type: this.getIssuerConfig().type,
|
||||
...config
|
||||
}
|
||||
type: this.getIssuerConfig().type,
|
||||
...config
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user