mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
dlt-connector use jwt token for authentication at backend
This commit is contained in:
parent
f0edd68619
commit
4255c1fdfa
@ -6,4 +6,5 @@ export const ADMIN_RIGHTS = [
|
||||
RIGHTS.UNDELETE_USER,
|
||||
RIGHTS.COMMUNITY_UPDATE,
|
||||
RIGHTS.COMMUNITY_BY_UUID,
|
||||
RIGHTS.COMMUNITY_BY_IDENTIFIER,
|
||||
]
|
||||
|
||||
3
backend/src/auth/DLT_CONNECTOR_RIGHTS.ts
Normal file
3
backend/src/auth/DLT_CONNECTOR_RIGHTS.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { RIGHTS } from './RIGHTS'
|
||||
|
||||
export const DLT_CONNECTOR_RIGHTS = [RIGHTS.COMMUNITY_BY_IDENTIFIER]
|
||||
@ -59,5 +59,6 @@ export enum RIGHTS {
|
||||
DELETE_USER = 'DELETE_USER',
|
||||
UNDELETE_USER = 'UNDELETE_USER',
|
||||
COMMUNITY_BY_UUID = 'COMMUNITY_BY_UUID',
|
||||
COMMUNITY_BY_IDENTIFIER = 'COMMUNITY_BY_IDENTIFIER',
|
||||
COMMUNITY_UPDATE = 'COMMUNITY_UPDATE',
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { RoleNames } from '@/graphql/enum/RoleNames'
|
||||
|
||||
import { ADMIN_RIGHTS } from './ADMIN_RIGHTS'
|
||||
import { DLT_CONNECTOR_RIGHTS } from './DLT_CONNECTOR_RIGHTS'
|
||||
import { INALIENABLE_RIGHTS } from './INALIENABLE_RIGHTS'
|
||||
import { MODERATOR_RIGHTS } from './MODERATOR_RIGHTS'
|
||||
import { Role } from './Role'
|
||||
@ -20,5 +21,7 @@ export const ROLE_ADMIN = new Role(RoleNames.ADMIN, [
|
||||
...ADMIN_RIGHTS,
|
||||
])
|
||||
|
||||
export const ROLE_DLT_CONNECTOR = new Role(RoleNames.DLT_CONNECTOR_ROLE, DLT_CONNECTOR_RIGHTS)
|
||||
|
||||
// TODO from database
|
||||
export const ROLES = [ROLE_UNAUTHORIZED, ROLE_USER, ROLE_MODERATOR, ROLE_ADMIN]
|
||||
|
||||
@ -6,7 +6,13 @@ import { RoleNames } from '@enum/RoleNames'
|
||||
import { INALIENABLE_RIGHTS } from '@/auth/INALIENABLE_RIGHTS'
|
||||
import { decode, encode } from '@/auth/JWT'
|
||||
import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import { ROLE_UNAUTHORIZED, ROLE_USER, ROLE_ADMIN, ROLE_MODERATOR } from '@/auth/ROLES'
|
||||
import {
|
||||
ROLE_UNAUTHORIZED,
|
||||
ROLE_USER,
|
||||
ROLE_ADMIN,
|
||||
ROLE_MODERATOR,
|
||||
ROLE_DLT_CONNECTOR,
|
||||
} from '@/auth/ROLES'
|
||||
import { Context } from '@/server/context'
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
@ -30,31 +36,35 @@ export const isAuthorized: AuthChecker<Context> = async ({ context }, rights) =>
|
||||
// Set context gradidoID
|
||||
context.gradidoID = decoded.gradidoID
|
||||
|
||||
// TODO - load from database dynamically & admin - maybe encode this in the token to prevent many database requests
|
||||
// TODO this implementation is bullshit - two database queries cause our user identifiers are not aligned and vary between email, id and pubKey
|
||||
try {
|
||||
const user = await User.findOneOrFail({
|
||||
where: { gradidoID: decoded.gradidoID },
|
||||
withDeleted: true,
|
||||
relations: ['emailContact', 'userRoles'],
|
||||
})
|
||||
context.user = user
|
||||
context.role = ROLE_USER
|
||||
if (user.userRoles?.length > 0) {
|
||||
switch (user.userRoles[0].role) {
|
||||
case RoleNames.ADMIN:
|
||||
context.role = ROLE_ADMIN
|
||||
break
|
||||
case RoleNames.MODERATOR:
|
||||
context.role = ROLE_MODERATOR
|
||||
break
|
||||
default:
|
||||
context.role = ROLE_USER
|
||||
if (context.gradidoID === 'dlt-connector') {
|
||||
context.role = ROLE_DLT_CONNECTOR
|
||||
} else {
|
||||
// TODO - load from database dynamically & admin - maybe encode this in the token to prevent many database requests
|
||||
// TODO this implementation is bullshit - two database queries cause our user identifiers are not aligned and vary between email, id and pubKey
|
||||
try {
|
||||
const user = await User.findOneOrFail({
|
||||
where: { gradidoID: decoded.gradidoID },
|
||||
withDeleted: true,
|
||||
relations: ['emailContact', 'userRoles'],
|
||||
})
|
||||
context.user = user
|
||||
context.role = ROLE_USER
|
||||
if (user.userRoles?.length > 0) {
|
||||
switch (user.userRoles[0].role) {
|
||||
case RoleNames.ADMIN:
|
||||
context.role = ROLE_ADMIN
|
||||
break
|
||||
case RoleNames.MODERATOR:
|
||||
context.role = ROLE_MODERATOR
|
||||
break
|
||||
default:
|
||||
context.role = ROLE_USER
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// in case the database query fails (user deleted)
|
||||
throw new LogError('401 Unauthorized')
|
||||
}
|
||||
} catch {
|
||||
// in case the database query fails (user deleted)
|
||||
throw new LogError('401 Unauthorized')
|
||||
}
|
||||
|
||||
// check for correct rights
|
||||
|
||||
@ -5,6 +5,7 @@ export enum RoleNames {
|
||||
USER = 'USER',
|
||||
MODERATOR = 'MODERATOR',
|
||||
ADMIN = 'ADMIN',
|
||||
DLT_CONNECTOR_ROLE = 'DLT_CONNECTOR_ROLE',
|
||||
}
|
||||
|
||||
registerEnumType(RoleNames, {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
CONFIG_VERSION=v4.2023-09-12
|
||||
CONFIG_VERSION=v6.2024-02-20
|
||||
|
||||
# SET LOG LEVEL AS NEEDED IN YOUR .ENV
|
||||
# POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal
|
||||
@ -22,4 +22,5 @@ TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log
|
||||
DLT_CONNECTOR_PORT=6010
|
||||
|
||||
# Route to Backend
|
||||
BACKEND_SERVER_URL=http://localhost:4000
|
||||
BACKEND_SERVER_URL=http://localhost:4000
|
||||
JWT_SECRET=secret123
|
||||
@ -1,5 +1,7 @@
|
||||
CONFIG_VERSION=$DLT_CONNECTOR_CONFIG_VERSION
|
||||
|
||||
JWT_SECRET=$JWT_SECRET
|
||||
|
||||
#IOTA
|
||||
IOTA_API_URL=$IOTA_API_URL
|
||||
IOTA_COMMUNITY_ALIAS=$IOTA_COMMUNITY_ALIAS
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
"graphql-request": "^6.1.0",
|
||||
"graphql-scalars": "^1.22.2",
|
||||
"helmet": "^7.1.0",
|
||||
"jose": "^5.2.2",
|
||||
"log4js": "^6.7.1",
|
||||
"nodemon": "^2.0.20",
|
||||
"protobufjs": "^7.2.5",
|
||||
|
||||
@ -6,6 +6,7 @@ import { CONFIG } from '@/config'
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { logger } from '@/logging/logger'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { SignJWT } from 'jose'
|
||||
|
||||
const communityByForeign = gql`
|
||||
query ($foreign: Boolean) {
|
||||
@ -73,6 +74,7 @@ export class BackendClient {
|
||||
|
||||
public async homeCommunityUUid(): Promise<CommunityDraft> {
|
||||
logger.info('check home community on backend')
|
||||
this.client.setHeader('token', await this.createJWTToken())
|
||||
const { data, errors } = await this.client.rawRequest<Community>(communityByForeign, {
|
||||
foreign: false,
|
||||
})
|
||||
@ -85,4 +87,16 @@ export class BackendClient {
|
||||
communityDraft.createdAt = data.community.creationDate
|
||||
return communityDraft
|
||||
}
|
||||
|
||||
private async createJWTToken(): Promise<string> {
|
||||
const secret = new TextEncoder().encode(CONFIG.JWT_SECRET)
|
||||
const token = await new SignJWT({ gradidoID: 'dlt-connector', 'urn:gradido:claim': true })
|
||||
.setProtectedHeader({ alg: 'HS256' })
|
||||
.setIssuedAt()
|
||||
.setIssuer('urn:gradido:issuer')
|
||||
.setAudience('urn:gradido:audience')
|
||||
.setExpirationTime('1m')
|
||||
.sign(secret)
|
||||
return token
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,13 +9,14 @@ const constants = {
|
||||
LOG_LEVEL: process.env.LOG_LEVEL ?? 'info',
|
||||
CONFIG_VERSION: {
|
||||
DEFAULT: 'DEFAULT',
|
||||
EXPECTED: 'v5.2024-02-24',
|
||||
EXPECTED: 'v6.2024-02-20',
|
||||
CURRENT: '',
|
||||
},
|
||||
}
|
||||
|
||||
const server = {
|
||||
PRODUCTION: process.env.NODE_ENV === 'production' ?? false,
|
||||
JWT_SECRET: process.env.JWT_SECRET ?? 'secret123',
|
||||
}
|
||||
|
||||
const database = {
|
||||
|
||||
@ -10,6 +10,7 @@ import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { TransactionError } from '@/graphql/model/TransactionError'
|
||||
import { CommunityLoggingView } from '@/logging/CommunityLogging.view'
|
||||
import { logger } from '@/logging/logger'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { getDataSource } from '@/typeorm/DataSource'
|
||||
|
||||
import { CreateTransactionRecipeContext } from '../transaction/CreateTransationRecipe.context'
|
||||
@ -22,7 +23,19 @@ export class HomeCommunityRole extends CommunityRole {
|
||||
public async create(communityDraft: CommunityDraft, topic: string): Promise<void> {
|
||||
super.create(communityDraft, topic)
|
||||
// generate key pair for signing transactions and deriving all keys for community
|
||||
const keyPair = new KeyPair(new Mnemonic(CONFIG.IOTA_HOME_COMMUNITY_SEED ?? undefined))
|
||||
let mnemonic: Mnemonic
|
||||
try {
|
||||
mnemonic = new Mnemonic(CONFIG.IOTA_HOME_COMMUNITY_SEED ?? undefined)
|
||||
} catch (e) {
|
||||
throw new LogError(
|
||||
'error creating mnemonic for home community, please fill IOTA_HOME_COMMUNITY_SEED in .env',
|
||||
{
|
||||
IOTA_HOME_COMMUNITY_SEED: CONFIG.IOTA_HOME_COMMUNITY_SEED,
|
||||
error: e,
|
||||
},
|
||||
)
|
||||
}
|
||||
const keyPair = new KeyPair(mnemonic)
|
||||
keyPair.fillInCommunityKeys(this.self)
|
||||
|
||||
// create auf account and gmw account
|
||||
|
||||
@ -4281,6 +4281,11 @@ jiti@^1.19.3:
|
||||
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42"
|
||||
integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==
|
||||
|
||||
jose@^5.2.2:
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/jose/-/jose-5.2.2.tgz#b91170e9ba6dbe609b0c0a86568f9a1fbe4335c0"
|
||||
integrity sha512-/WByRr4jDcsKlvMd1dRJnPfS1GVO3WuKyaurJ/vvXcOaUQO8rnNObCQMlv/5uCceVQIq5Q4WLF44ohsdiTohdg==
|
||||
|
||||
js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user