feat: add cache (#2)
* ci: remove main workflow ci: add pr workflow to branch next * docs: correct readme ci: add docker build on release ci: add lint and test to release flow * feat: add cache for both memory and redis refactor: cleanup getAccountability nested promise refactor: import path for get-auth-providers.ts docs: document cache options ci: add redis file to gitignore * ci: use test:coverage for testing to update pr --------- Co-authored-by: Krise <krise86@users.noreply.github.com>
This commit is contained in:
47
.github/workflows/docker-release.yml
vendored
Normal file
47
.github/workflows/docker-release.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
name: Create and publish a Docker image
|
||||
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
- prereleased
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build-and-push-image:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.release.tag_name }}
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
27
.github/workflows/main.yml
vendored
27
.github/workflows/main.yml
vendored
@@ -1,27 +0,0 @@
|
||||
name: Merge to Main
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
jobs:
|
||||
build:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node: [ 18, 20 ]
|
||||
|
||||
name: Node ${{ matrix.node }} Release
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8
|
||||
- name: Use Node.js ${{ matrix.node }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
cache: 'pnpm'
|
||||
- run: pnpm install
|
||||
- run: pnpm lint
|
||||
- run: pnpm test
|
||||
8
.github/workflows/pr.yml
vendored
8
.github/workflows/pr.yml
vendored
@@ -2,7 +2,9 @@ name: Pull Request
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
branches:
|
||||
- main
|
||||
- next
|
||||
|
||||
jobs:
|
||||
check:
|
||||
@@ -27,8 +29,10 @@ jobs:
|
||||
name: install dependencies
|
||||
- run: pnpm lint
|
||||
name: linting
|
||||
- run: pnpm test
|
||||
- run: pnpm test:coverage
|
||||
name: testing
|
||||
- run: pnpm build
|
||||
name: build package
|
||||
- name: 'Report Coverage'
|
||||
if: always() # Also generate the report if tests are failing
|
||||
uses: davelosert/vitest-coverage-report-action@v2
|
||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -34,6 +34,10 @@ jobs:
|
||||
cache: 'pnpm'
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- run: pnpm lint
|
||||
name: linting
|
||||
- run: pnpm test
|
||||
name: testing
|
||||
- name: Verify the integrity of provenance attestations and registry signatures for installed dependencies
|
||||
run: pnpm audit signatures
|
||||
- name: Release
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -9,6 +9,9 @@ extensions/
|
||||
uploads/
|
||||
.env
|
||||
|
||||
# Redis files
|
||||
./*.rdb
|
||||
|
||||
# Code editor files
|
||||
.vscode
|
||||
|
||||
|
||||
16
README.md
16
README.md
@@ -5,9 +5,15 @@ The plugin expects to resolve the following new configuration option
|
||||
|
||||
The provider must issues Access tokens as JWT since this is used for verification right now. Might add support for general tokens later.
|
||||
|
||||
## Configuration
|
||||
all configuration options listed here are an extension to directus default config.
|
||||
|
||||
|
||||
|AUTH_PROVIDER_TRUSTED| True | Must be true for the provider to be considered as trusted. Note, do not trust public providers as these can generate tokens that you cannot control.
|
||||
|AUTH_PROVIDER_JWT_ROLE_KEY | String | What key in the JWT payload contains the role
|
||||
|AUTH_PROVIDER_JWT_ADMIN_KEY | Boolean | What key in the JWT payload contains a bool to grant admin rights
|
||||
|AUTH_PROVIDER_JWT_APP_KEY | Boolean | What key in the JWT payload contains a bool to allow app access
|
||||
| ENV Variable | Supported values | Description |
|
||||
|------------------------------|-------------------|--------------|
|
||||
| AUTH_PROVIDER_TRUSTED | True/False | Must be true for the provider to be considered as trusted. Note, do not trust public providers as these can generate tokens that you cannot control.
|
||||
| AUTH_PROVIDER_JWT_ROLE_KEY | String | What key in the JWT payload contains the role |
|
||||
| AUTH_PROVIDER_JWT_ADMIN_KEY | String | What key in the JWT payload contains a bool to grant admin rights |
|
||||
| AUTH_PROVIDER_JWT_APP_KEY | String | What key in the JWT payload contains a bool to allow app access
|
||||
| AUTH_PROVIDER_JWT_USEDB | Bool | If enabled/true the plugin will resolve the user and roles from the directus database using the token. For OIDC the sub is used. Should not be used without a Redis Cache enabled.
|
||||
| CACHE_JWT_NAMESPACE | String | What namespace to use in cache store.
|
||||
| CACHE_JWT_TTL | Number | Time to live for the cached user entry, default 5000 (5 seconds)
|
||||
|
||||
@@ -103,8 +103,10 @@
|
||||
"vitest": "^0.34.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@keyv/redis": "^2.7.0",
|
||||
"jsonwebtoken": "^9.0.1",
|
||||
"jwks-rsa": "^3.0.1",
|
||||
"keyv": "^4.5.3",
|
||||
"openid-client": "^5.4.3"
|
||||
}
|
||||
}
|
||||
80
pnpm-lock.yaml
generated
80
pnpm-lock.yaml
generated
@@ -5,12 +5,18 @@ settings:
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
'@keyv/redis':
|
||||
specifier: ^2.7.0
|
||||
version: 2.7.0
|
||||
jsonwebtoken:
|
||||
specifier: ^9.0.1
|
||||
version: 9.0.1
|
||||
jwks-rsa:
|
||||
specifier: ^3.0.1
|
||||
version: 3.0.1
|
||||
keyv:
|
||||
specifier: ^4.5.3
|
||||
version: 4.5.3
|
||||
openid-client:
|
||||
specifier: ^5.4.3
|
||||
version: 5.4.3
|
||||
@@ -892,6 +898,10 @@ packages:
|
||||
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
|
||||
dev: true
|
||||
|
||||
/@ioredis/commands@1.2.0:
|
||||
resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
|
||||
dev: false
|
||||
|
||||
/@istanbuljs/load-nyc-config@1.1.0:
|
||||
resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -997,6 +1007,15 @@ packages:
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
dev: true
|
||||
|
||||
/@keyv/redis@2.7.0:
|
||||
resolution: {integrity: sha512-GYqCT+iEP93+gVVPzhW4kmkr/9KTmwb88wkglX6aUMSP50JIhUhNF/yXH0aQTZRPsWfPKO10NJjUZzEh7YW6yw==}
|
||||
engines: {node: '>= 14'}
|
||||
dependencies:
|
||||
ioredis: 5.3.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@mapbox/node-pre-gyp@1.0.11:
|
||||
resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==}
|
||||
hasBin: true
|
||||
@@ -2303,6 +2322,11 @@ packages:
|
||||
engines: {node: '>=0.8'}
|
||||
dev: true
|
||||
|
||||
/cluster-key-slot@1.1.2:
|
||||
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/color-convert@1.9.3:
|
||||
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||
dependencies:
|
||||
@@ -2624,6 +2648,11 @@ packages:
|
||||
resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
|
||||
dev: true
|
||||
|
||||
/denque@2.1.0:
|
||||
resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
|
||||
engines: {node: '>=0.10'}
|
||||
dev: false
|
||||
|
||||
/depd@2.0.0:
|
||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@@ -3856,6 +3885,23 @@ packages:
|
||||
engines: {node: '>= 0.10'}
|
||||
dev: true
|
||||
|
||||
/ioredis@5.3.2:
|
||||
resolution: {integrity: sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==}
|
||||
engines: {node: '>=12.22.0'}
|
||||
dependencies:
|
||||
'@ioredis/commands': 1.2.0
|
||||
cluster-key-slot: 1.1.2
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
denque: 2.1.0
|
||||
lodash.defaults: 4.2.0
|
||||
lodash.isarguments: 3.1.0
|
||||
redis-errors: 1.2.0
|
||||
redis-parser: 3.0.0
|
||||
standard-as-callback: 2.1.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/ip@2.0.0:
|
||||
resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==}
|
||||
requiresBuild: true
|
||||
@@ -4241,6 +4287,10 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/json-buffer@3.0.1:
|
||||
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
|
||||
dev: false
|
||||
|
||||
/json-parse-even-better-errors@2.3.1:
|
||||
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
|
||||
dev: true
|
||||
@@ -4318,6 +4368,12 @@ packages:
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/keyv@4.5.3:
|
||||
resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==}
|
||||
dependencies:
|
||||
json-buffer: 3.0.1
|
||||
dev: false
|
||||
|
||||
/knex@2.5.1(sqlite3@5.1.6):
|
||||
resolution: {integrity: sha512-z78DgGKUr4SE/6cm7ku+jHvFT0X97aERh/f0MUKAKgFnwCYBEW4TFBqtHWFYiJFid7fMrtpZ/gxJthvz5mEByA==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -4413,10 +4469,18 @@ packages:
|
||||
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
|
||||
dev: false
|
||||
|
||||
/lodash.defaults@4.2.0:
|
||||
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
|
||||
dev: false
|
||||
|
||||
/lodash.flattendeep@4.4.0:
|
||||
resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==}
|
||||
dev: true
|
||||
|
||||
/lodash.isarguments@3.1.0:
|
||||
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
|
||||
dev: false
|
||||
|
||||
/lodash.memoize@4.1.2:
|
||||
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
|
||||
dev: true
|
||||
@@ -5644,6 +5708,18 @@ packages:
|
||||
resolve: 1.22.2
|
||||
dev: true
|
||||
|
||||
/redis-errors@1.2.0:
|
||||
resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
|
||||
engines: {node: '>=4'}
|
||||
dev: false
|
||||
|
||||
/redis-parser@3.0.0:
|
||||
resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
redis-errors: 1.2.0
|
||||
dev: false
|
||||
|
||||
/regenerator-runtime@0.13.11:
|
||||
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
|
||||
dev: true
|
||||
@@ -6027,6 +6103,10 @@ packages:
|
||||
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
|
||||
dev: true
|
||||
|
||||
/standard-as-callback@2.1.0:
|
||||
resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
|
||||
dev: false
|
||||
|
||||
/std-env@3.3.3:
|
||||
resolution: {integrity: sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==}
|
||||
dev: true
|
||||
|
||||
@@ -3,7 +3,7 @@ import {JwksClient} from 'jwks-rsa';
|
||||
|
||||
import { Issuer } from 'openid-client';
|
||||
|
||||
import env from '../config/config.js';
|
||||
import env from '../config/config';
|
||||
import { createError } from '@directus/errors';
|
||||
|
||||
const InvalidJWKIssuerMetadata = createError('INVALID_JWKS_ISSUER_ERROR', 'No JWKS_URL or JWKS_KEYS and could not discover JWKS_URL from openid metadata', 500);
|
||||
|
||||
54
src/external-jwt/cache.ts
Normal file
54
src/external-jwt/cache.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import {default as Keyv, Store} from 'keyv';
|
||||
import env from './config/config';
|
||||
import {default as KeyvRedis} from '@keyv/redis';
|
||||
// check if redis is defined
|
||||
|
||||
const cache: Keyv | null = getCache();
|
||||
|
||||
function getCache(): Keyv | null {
|
||||
if(env['CACHE_ENABLED'] !== true) return null;
|
||||
|
||||
// check namespace
|
||||
let namespace = env['CACHE_JWT_NAMESPACE'];
|
||||
if(namespace == null || namespace === '') {
|
||||
namespace = 'exjwt';
|
||||
}
|
||||
|
||||
let ttl = env['CACHE_JWT_TTL'];
|
||||
if (ttl == null || ttl === '') {
|
||||
ttl = 5000
|
||||
}
|
||||
|
||||
let uri = '';
|
||||
let store: Store<string | undefined> | undefined = undefined;
|
||||
if(env['CACHE_STORE'] === 'redis') {
|
||||
uri = env['REDIS']
|
||||
|
||||
if(uri == null || uri === '') {
|
||||
uri = `redis://${env['REDIS_USERNAME']}:${env['REDIS_PASSWORD']}@${env['REDIS_HOST']}:${env['REDIS_PORT']}`;
|
||||
}
|
||||
|
||||
store = new KeyvRedis(uri);
|
||||
|
||||
}
|
||||
|
||||
return new Keyv(uri, {
|
||||
namespace: namespace,
|
||||
ttl,
|
||||
store: store
|
||||
});
|
||||
}
|
||||
|
||||
export function CacheEnabled(): boolean {
|
||||
return cache !== null;
|
||||
}
|
||||
|
||||
export async function CacheSet(key: string, value: any) {
|
||||
if(cache === null) return false;
|
||||
return cache.set(key, value);
|
||||
}
|
||||
|
||||
export async function CacheGet(key: string) {
|
||||
if(cache === null) return null;
|
||||
return cache.get(key);
|
||||
}
|
||||
@@ -25,13 +25,14 @@ const allowedEnvironmentVars = [
|
||||
'CACHE_VALUE_MAX_SIZE',
|
||||
'CACHE_SKIP_ALLOWED',
|
||||
'CACHE_HEALTHCHECK_THRESHOLD',
|
||||
// Externl JWT Cache
|
||||
'CACHE_JWT_NAMESPACE',
|
||||
// redis
|
||||
'REDIS',
|
||||
'REDIS_HOST',
|
||||
'REDIS_PORT',
|
||||
'REDIS_USERNAME',
|
||||
'REDIS_PASSWORD',
|
||||
'REDIS_JWT_DB',
|
||||
// auth
|
||||
'AUTH_PROVIDERS',
|
||||
'AUTH_.+_DRIVER',
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { Accountability } from '@directus/types';
|
||||
import { getAuthProviders } from './authProvider/get-auth-providers.js';
|
||||
import type { Knex } from 'knex';
|
||||
import { verify_token } from './verify-token.js';
|
||||
import { CacheEnabled, CacheGet, CacheSet } from './cache.js';
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +23,7 @@ export async function getAccountabilityForToken(
|
||||
accountability: Accountability | null,
|
||||
database: Knex
|
||||
): Promise<Accountability> {
|
||||
if (!accountability) {
|
||||
if (accountability == null) {
|
||||
accountability = {
|
||||
user: null,
|
||||
role: null,
|
||||
@@ -32,80 +33,92 @@ export async function getAccountabilityForToken(
|
||||
}
|
||||
|
||||
if (token == null || iss == null) {
|
||||
|
||||
return accountability
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const providers = authProviders.filter((provider) => provider && iss.includes(provider.client_id));
|
||||
if(providers.length === 0) return accountability;
|
||||
if(providers.length > 1) {
|
||||
console.log("to many matching providers");
|
||||
const providers = authProviders.filter((provider) => provider.issuer_url && iss.includes(provider.issuer_url));
|
||||
|
||||
if(providers.length === 0) return accountability;
|
||||
if(providers.length > 1) {
|
||||
return accountability;
|
||||
}
|
||||
|
||||
|
||||
const provider = providers[0];
|
||||
|
||||
|
||||
|
||||
try {
|
||||
|
||||
|
||||
const result = await verify_token(provider, token)
|
||||
|
||||
|
||||
|
||||
if(provider.use_database) { // use database to get user
|
||||
// TODO: Add caching to this function
|
||||
if (CacheEnabled() && result.sub) {
|
||||
|
||||
const cachedAccountability = await CacheGet(result.sub);
|
||||
if (cachedAccountability) {
|
||||
return cachedAccountability;
|
||||
}
|
||||
}
|
||||
|
||||
const user = await database
|
||||
.select('directus_users.id', 'directus_users.role', 'directus_roles.admin_access', 'directus_roles.app_access')
|
||||
.from('directus_users')
|
||||
.leftJoin('directus_roles', 'directus_users.role', 'directus_roles.id')
|
||||
.where({
|
||||
'directus_users.external_identifier': result.sub,
|
||||
'directus_users.provider': provider.name,
|
||||
})
|
||||
.first();
|
||||
|
||||
if(!user) {
|
||||
return accountability;
|
||||
}
|
||||
|
||||
accountability.user = user.id;
|
||||
accountability.role = user.role;
|
||||
accountability.admin = user.admin_access === true || user.admin_access == 1;
|
||||
accountability.app = user.app_access === true || user.app_access == 1;
|
||||
|
||||
if (CacheEnabled() && result.sub) {
|
||||
CacheSet(result.sub, accountability);
|
||||
}
|
||||
|
||||
|
||||
return accountability;
|
||||
}
|
||||
|
||||
const provider = providers[0];
|
||||
|
||||
|
||||
|
||||
verify_token(provider, token).then(async (result) => {
|
||||
if(accountability) {
|
||||
// check if role key is set else try role key
|
||||
|
||||
if(provider.role_key != null) {
|
||||
accountability.role = typeof result[provider.role_key] === 'string' ? result[provider.role_key] : result[provider.role_key][0];
|
||||
} else {
|
||||
if (result.role) {
|
||||
accountability.role = result.role;
|
||||
}
|
||||
}
|
||||
|
||||
if(provider.use_database) { // use database to get user
|
||||
// TODO: Add caching to this function
|
||||
|
||||
const user = await database
|
||||
.select('directus_users.id', 'directus_users.role', 'directus_roles.admin_access', 'directus_roles.app_access')
|
||||
.from('directus_users')
|
||||
.leftJoin('directus_roles', 'directus_users.role', 'directus_roles.id')
|
||||
.where({
|
||||
'directus_users.external_identifier': result.sub,
|
||||
'directus_users.provider': provider.name,
|
||||
})
|
||||
.first();
|
||||
|
||||
if(!user) {
|
||||
reject("invalid user credentials");
|
||||
}
|
||||
|
||||
accountability.user = user.id;
|
||||
accountability.role = user.role;
|
||||
accountability.admin = user.admin_access === true || user.admin_access == 1;
|
||||
accountability.app = user.app_access === true || user.app_access == 1;
|
||||
} else {
|
||||
if(provider.admin_key != null) {
|
||||
accountability.admin = result[provider.admin_key];
|
||||
}
|
||||
if(provider.app_key != null) {
|
||||
accountability.app = result[provider.app_key];
|
||||
}
|
||||
accountability.user = result.sub;
|
||||
|
||||
|
||||
}
|
||||
|
||||
console.log(accountability);
|
||||
|
||||
resolve(accountability);
|
||||
// check if role key is set else try role key
|
||||
if(provider.role_key != null) {
|
||||
if(typeof result[provider.role_key] === 'string') {
|
||||
accountability.role = result[provider.role_key];
|
||||
}
|
||||
if(typeof result[provider.role_key] === 'object') {
|
||||
accountability.role = ''
|
||||
}
|
||||
if(result[provider.role_key].instanceOf(Array)) {
|
||||
accountability.role = result[provider.role_key][0];
|
||||
}
|
||||
}
|
||||
|
||||
reject("no accountability");
|
||||
if(provider.admin_key != null) {
|
||||
accountability.admin = result[provider.admin_key];
|
||||
}
|
||||
if(provider.app_key != null) {
|
||||
accountability.app = result[provider.app_key];
|
||||
}
|
||||
accountability.user = result.sub;
|
||||
|
||||
} catch (error) {
|
||||
return accountability;
|
||||
}
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
return accountability;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user