feat: update AuthProvider interface and improve user role handling
Some checks failed
Release / Release (push) Has been cancelled
Some checks failed
Release / Release (push) Has been cancelled
This commit is contained in:
172
extensions/directus-extension-external-jwt/package.json
Normal file
172
extensions/directus-extension-external-jwt/package.json
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
{
|
||||||
|
"name": "directus-extension-external-jwt",
|
||||||
|
"description": "External JWT Directus Extension allow directus to trust tokens issued by an oauth2 or OIDC provider",
|
||||||
|
"icon": "extension",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"keywords": [
|
||||||
|
"directus",
|
||||||
|
"directus-extension",
|
||||||
|
"directus-custom-hook",
|
||||||
|
"directus-external-jwt"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/Zerosubnet/directus-extension-external-jwt",
|
||||||
|
"license": "LGPL-3.0-only",
|
||||||
|
"author": {
|
||||||
|
"name": "zerosubnet"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Zerosubnet/directus-extension-external-jwt.git"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"release": {
|
||||||
|
"branches": [
|
||||||
|
"main",
|
||||||
|
"next",
|
||||||
|
{
|
||||||
|
"name": "beta",
|
||||||
|
"prerelease": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
"@semantic-release/commit-analyzer",
|
||||||
|
"@semantic-release/release-notes-generator",
|
||||||
|
"@semantic-release/changelog",
|
||||||
|
"@semantic-release/npm",
|
||||||
|
[
|
||||||
|
"@semantic-release/github",
|
||||||
|
{
|
||||||
|
"assets": [
|
||||||
|
"dist/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/exec",
|
||||||
|
{
|
||||||
|
"tagImage": "docker tag ${SRCIMAGE} ${DSTIMAGE}:${nextRelease.version}",
|
||||||
|
"publishImage": "docker push ${DSTIMAGE}:${nextRelease.version}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"preset": "angular"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"directus:extension": {
|
||||||
|
"type": "hook",
|
||||||
|
"path": "dist/index.js",
|
||||||
|
"source": "src/index.ts",
|
||||||
|
"host": "^10.1.7"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "directus-extension build && npm run sync",
|
||||||
|
"dev": "directus-extension build -w --no-minify",
|
||||||
|
"link": "directus-extension link",
|
||||||
|
"sync": "rm -rf ./extensions/directus-extension-external-jwt && mkdir -p ./extensions/directus-extension-external-jwt/dist && ln ./package.json ./extensions/directus-extension-external-jwt/package.json && ln ./dist/index.js ./extensions/directus-extension-external-jwt/dist/index.js",
|
||||||
|
"directus": "pnpm dlx directus start",
|
||||||
|
"lint": "eslint . --ext .ts",
|
||||||
|
"test": "vitest",
|
||||||
|
"test:coverage": "vitest run --coverage"
|
||||||
|
},
|
||||||
|
"nyc": {
|
||||||
|
"extension": [
|
||||||
|
".ts",
|
||||||
|
".tsx"
|
||||||
|
],
|
||||||
|
"reporter": [
|
||||||
|
"text",
|
||||||
|
"lcov"
|
||||||
|
],
|
||||||
|
"report-dir": "coverage",
|
||||||
|
"all": true,
|
||||||
|
"extends": "@istanbuljs/nyc-config-typescript",
|
||||||
|
"check-coverage": true,
|
||||||
|
"include": [
|
||||||
|
"src/**/*.[tj]s?(x)"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"src/_tests_/**/*.*",
|
||||||
|
"src/**/*.test.[tj]s?(x)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@directus/errors": "^0.3.2",
|
||||||
|
"@directus/extensions-sdk": "^13.0.1",
|
||||||
|
"@directus/tsconfig": "^1.0.1",
|
||||||
|
"@directus/types": "^11.1.2",
|
||||||
|
"@directus/utils": "^11.0.9",
|
||||||
|
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
||||||
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
|
"@semantic-release/commit-analyzer": "^10.0.4",
|
||||||
|
"@semantic-release/exec": "^6.0.3",
|
||||||
|
"@semantic-release/github": "^9.2.6",
|
||||||
|
"@semantic-release/npm": "^10.0.6",
|
||||||
|
"@types/chai": "^4.3.16",
|
||||||
|
"@types/chai-as-promised": "^7.1.8",
|
||||||
|
"@types/config": "^3.3.4",
|
||||||
|
"@types/express": "^4.17.21",
|
||||||
|
"@types/fs-extra": "^11.0.4",
|
||||||
|
"@types/js-yaml": "^4.0.9",
|
||||||
|
"@types/jsonwebtoken": "^9.0.6",
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@types/mocha": "^10.0.6",
|
||||||
|
"@types/node": "^20.14.2",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||||
|
"@vitest/coverage-istanbul": "^0.34.6",
|
||||||
|
"axios": "^1.7.2",
|
||||||
|
"config": "^3.3.11",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"eslint": "^8.57.0",
|
||||||
|
"eslint-config-standard-with-typescript": "^37.0.0",
|
||||||
|
"eslint-plugin-import": "^2.29.1",
|
||||||
|
"eslint-plugin-n": "^15.7.0",
|
||||||
|
"eslint-plugin-no-loops": "^0.3.0",
|
||||||
|
"eslint-plugin-promise": "^6.2.0",
|
||||||
|
"fs-extra": "^11.2.0",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"nyc": "^15.1.0",
|
||||||
|
"semantic-release": "^21.1.2",
|
||||||
|
"sqlite3": "^5.1.7",
|
||||||
|
"ts-mocha": "^10.0.0",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "^5.4.5",
|
||||||
|
"vitest": "^0.34.6"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@directus/extensions": "^3.0.5",
|
||||||
|
"@keyv/redis": "^2.8.5",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"jwks-rsa": "^3.1.0",
|
||||||
|
"keyv": "^4.5.4",
|
||||||
|
"openid-client": "^5.6.5",
|
||||||
|
"uuid": "^11.1.0"
|
||||||
|
},
|
||||||
|
"pnpm": {
|
||||||
|
"overrides": {
|
||||||
|
"vite@<4.3.9": "^4.3.9",
|
||||||
|
"vite@>4.3.9": "^4.5.3",
|
||||||
|
"zod@<=3.22.2": ">=3.22.3",
|
||||||
|
"axios@<=1.4.0": ">=1.4.1",
|
||||||
|
"axios@>=1.3.2 <=1.7.3": ">=1.7.4",
|
||||||
|
"micromatch@<4.0.8": ">=4.0.8",
|
||||||
|
"vite@>=4.0.0 <4.5.4": ">=4.5.4",
|
||||||
|
"vite@>=4.0.0 <=4.5.3": ">=4.5.4",
|
||||||
|
"rollup@>=3.0.0 <3.29.5": ">=3.29.5",
|
||||||
|
"cross-spawn@>=7.0.0 <7.0.5": ">=7.0.5",
|
||||||
|
"nanoid@<3.3.8": ">=3.3.8",
|
||||||
|
"@octokit/request-error@>=1.0.0 <5.1.1": ">=5.1.1",
|
||||||
|
"@octokit/endpoint@>=9.0.5 <9.0.6": ">=9.0.6",
|
||||||
|
"@octokit/request@>=1.0.0 <9.2.1": ">=9.2.1",
|
||||||
|
"@octokit/plugin-paginate-rest@>=1.0.0 <11.4.1": ">=11.4.1",
|
||||||
|
"serialize-javascript@<6.0.2": ">=6.0.2",
|
||||||
|
"esbuild@<=0.24.2": ">=0.25.0",
|
||||||
|
"vite@<=4.5.5": ">=4.5.6"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@ export interface AuthProvider {
|
|||||||
JWKSClient?: JwksClient;
|
JWKSClient?: JwksClient;
|
||||||
use_database?: boolean;
|
use_database?: boolean;
|
||||||
|
|
||||||
initial_role?: string;
|
default_role_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -37,26 +37,31 @@ export interface AuthProvider {
|
|||||||
export async function getAuthProviders(): Promise<AuthProvider[]> {
|
export async function getAuthProviders(): Promise<AuthProvider[]> {
|
||||||
console.log("calling auth providers _")
|
console.log("calling auth providers _")
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const authProviders: AuthProvider[] = toArray(env['AUTH_PROVIDERS'])
|
const authProviders: AuthProvider[] = toArray(env["AUTH_PROVIDERS"])
|
||||||
.filter((provider) => provider && env[`AUTH_${provider.toUpperCase()}_DRIVER`] === ('openid' || 'oauth2'))
|
.filter(
|
||||||
.map((provider) => ({
|
(provider) =>
|
||||||
name: provider,
|
provider &&
|
||||||
label: env[`AUTH_${provider.toUpperCase()}_LABEL`],
|
env[`AUTH_${provider.toUpperCase()}_DRIVER`] ===
|
||||||
driver: env[`AUTH_${provider.toUpperCase()}_DRIVER`],
|
("openid" || "oauth2")
|
||||||
icon: env[`AUTH_${provider.toUpperCase()}_ICON`],
|
)
|
||||||
trusted: env[`AUTH_${provider.toUpperCase()}_TRUSTED`],
|
.map((provider) => ({
|
||||||
jwks_url: env[`AUTH_${provider.toUpperCase()}_JWKS_URL`],
|
name: provider,
|
||||||
jwks_keys: env[`AUTH_${provider.toUpperCase()}_JWKS_KEYS`],
|
label: env[`AUTH_${provider.toUpperCase()}_LABEL`],
|
||||||
issuer_url: env[`AUTH_${provider.toUpperCase()}_ISSUER_URL`],
|
driver: env[`AUTH_${provider.toUpperCase()}_DRIVER`],
|
||||||
admin_key: env[`AUTH_${provider.toUpperCase()}_JWT_ADMIN_KEY`],
|
icon: env[`AUTH_${provider.toUpperCase()}_ICON`],
|
||||||
app_key: env[`AUTH_${provider.toUpperCase()}_JWT_APP_KEY`],
|
trusted: env[`AUTH_${provider.toUpperCase()}_TRUSTED`],
|
||||||
role_key: env[`AUTH_${provider.toUpperCase()}_JWT_ROLE_KEY`],
|
jwks_url: env[`AUTH_${provider.toUpperCase()}_JWKS_URL`],
|
||||||
client_id: env[`AUTH_${provider.toUpperCase()}_CLIENT_ID`],
|
jwks_keys: env[`AUTH_${provider.toUpperCase()}_JWKS_KEYS`],
|
||||||
client_secret: env[`AUTH_${provider.toUpperCase()}_CLIENT_SECRET`],
|
issuer_url: env[`AUTH_${provider.toUpperCase()}_ISSUER_URL`],
|
||||||
use_database: env[`AUTH_${provider.toUpperCase()}_JWT_USEDB`],
|
admin_key: env[`AUTH_${provider.toUpperCase()}_JWT_ADMIN_KEY`],
|
||||||
|
app_key: env[`AUTH_${provider.toUpperCase()}_JWT_APP_KEY`],
|
||||||
|
role_key: env[`AUTH_${provider.toUpperCase()}_JWT_ROLE_KEY`],
|
||||||
|
client_id: env[`AUTH_${provider.toUpperCase()}_CLIENT_ID`],
|
||||||
|
client_secret: env[`AUTH_${provider.toUpperCase()}_CLIENT_SECRET`],
|
||||||
|
use_database: env[`AUTH_${provider.toUpperCase()}_JWT_USEDB`],
|
||||||
|
|
||||||
initial_role: env[`AUTH_${provider.toUpperCase()}_INITIAL_ROLE`]
|
default_role_id: env[`AUTH_${provider.toUpperCase()}_DEFAULT_ROLE_ID`],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
if(authProviders.length === 0) return resolve([]);
|
if(authProviders.length === 0) return resolve([]);
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ const getUser = async (
|
|||||||
.first();
|
.first();
|
||||||
};
|
};
|
||||||
|
|
||||||
const insertUser = async (database: Knex, user: Record<string, any>) => {
|
const insertUser = async (database: Knex, user: Record<string, any>): Promise<any> => {
|
||||||
return database("directus_users").insert(user).returning("*");
|
return database("directus_users").insert(user);
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: optimize this function, reduce the amount of loops
|
// TODO: optimize this function, reduce the amount of loops
|
||||||
@@ -51,14 +51,6 @@ export async function getAccountabilityForToken(
|
|||||||
accountability: Accountability | null,
|
accountability: Accountability | null,
|
||||||
database: Knex
|
database: Knex
|
||||||
): Promise<Accountability> {
|
): Promise<Accountability> {
|
||||||
console.log(
|
|
||||||
"getAccountabilityForToken called with token",
|
|
||||||
token,
|
|
||||||
"and iss",
|
|
||||||
iss,
|
|
||||||
"and accountability",
|
|
||||||
accountability
|
|
||||||
);
|
|
||||||
if (accountability == null) {
|
if (accountability == null) {
|
||||||
accountability = {
|
accountability = {
|
||||||
user: null,
|
user: null,
|
||||||
@@ -103,10 +95,9 @@ export async function getAccountabilityForToken(
|
|||||||
console.debug("User found in database:", user);
|
console.debug("User found in database:", user);
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
const role = provider.initial_role
|
|
||||||
user = await insertUser(database, {
|
user = await insertUser(database, {
|
||||||
id: uuid.v4(),
|
id: uuid.v4(),
|
||||||
role: role,
|
role: provider.default_role_id,
|
||||||
provider: provider.name,
|
provider: provider.name,
|
||||||
external_identifier: result.sub,
|
external_identifier: result.sub,
|
||||||
});
|
});
|
||||||
@@ -126,11 +117,6 @@ export async function getAccountabilityForToken(
|
|||||||
CacheSet(result.sub, accountability);
|
CacheSet(result.sub, accountability);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(
|
|
||||||
"Returning accountability from database:",
|
|
||||||
accountability
|
|
||||||
);
|
|
||||||
|
|
||||||
return accountability;
|
return accountability;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user