mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
full code of encrypted authentication process, tests open
This commit is contained in:
parent
ee16e540cf
commit
4ca94b189c
@ -1,4 +1,4 @@
|
||||
import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity } from 'database'
|
||||
import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity, getHomeCommunity } from 'database'
|
||||
import { validate as validateUUID, version as versionUUID } from 'uuid'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
@ -18,45 +18,45 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.federation.authenticateCo
|
||||
export async function startCommunityAuthentication(
|
||||
foreignFedCom: DbFederatedCommunity,
|
||||
): Promise<void> {
|
||||
const homeCom = await DbCommunity.findOneByOrFail({ foreign: false })
|
||||
const homeFedCom = await DbFederatedCommunity.findOneByOrFail({
|
||||
const homeComA = await getHomeCommunity()
|
||||
const homeFedComA = await DbFederatedCommunity.findOneByOrFail({
|
||||
foreign: false,
|
||||
apiVersion: CONFIG.FEDERATION_BACKEND_SEND_ON_API,
|
||||
})
|
||||
const foreignCom = await DbCommunity.findOneByOrFail({ publicKey: foreignFedCom.publicKey })
|
||||
const foreignComB = await DbCommunity.findOneByOrFail({ publicKey: foreignFedCom.publicKey })
|
||||
logger.debug(
|
||||
'started with foreignFedCom:',
|
||||
foreignFedCom.endPoint,
|
||||
foreignFedCom.publicKey.toString('hex'),
|
||||
foreignCom.publicJwtKey,
|
||||
foreignComB.publicJwtKey,
|
||||
)
|
||||
// check if communityUuid is a valid v4Uuid and not still a temporary onetimecode
|
||||
if (
|
||||
foreignCom &&
|
||||
((foreignCom.communityUuid === null && foreignCom.authenticatedAt === null) ||
|
||||
(foreignCom.communityUuid !== null &&
|
||||
!validateUUID(foreignCom.communityUuid) &&
|
||||
versionUUID(foreignCom.communityUuid) !== 4))
|
||||
foreignComB &&
|
||||
((foreignComB.communityUuid === null && foreignComB.authenticatedAt === null) ||
|
||||
(foreignComB.communityUuid !== null &&
|
||||
!validateUUID(foreignComB.communityUuid) &&
|
||||
versionUUID(foreignComB.communityUuid) !== 4))
|
||||
) {
|
||||
try {
|
||||
const client = AuthenticationClientFactory.getInstance(foreignFedCom)
|
||||
|
||||
if (client instanceof V1_0_AuthenticationClient) {
|
||||
if (!foreignCom.publicJwtKey) {
|
||||
if (!foreignComB.publicJwtKey) {
|
||||
throw new Error('Public JWT key still not exist for foreign community')
|
||||
}
|
||||
//create JWT with url in payload encrypted by foreignCom.publicJwtKey and signed with homeCom.privateJwtKey
|
||||
const payload = new OpenConnectionJwtPayloadType(
|
||||
ensureUrlEndsWithSlash(homeFedCom.endPoint).concat(homeFedCom.apiVersion),
|
||||
ensureUrlEndsWithSlash(homeFedComA.endPoint).concat(homeFedComA.apiVersion),
|
||||
)
|
||||
const jws = await encryptAndSign(payload, homeCom.privateJwtKey!, foreignCom.publicJwtKey)
|
||||
const jws = await encryptAndSign(payload, homeComA!.privateJwtKey!, foreignComB.publicJwtKey)
|
||||
// prepare the args for the client invocation
|
||||
const args = new EncryptedTransferArgs()
|
||||
args.publicKey = homeCom.publicKey.toString('hex')
|
||||
args.publicKey = homeComA!.publicKey.toString('hex')
|
||||
args.jwt = jws
|
||||
logger.debug(
|
||||
'before client.openConnection() args:',
|
||||
homeCom.publicKey.toString('hex'),
|
||||
homeComA!.publicKey.toString('hex'),
|
||||
args.jwt,
|
||||
)
|
||||
if (await client.openConnection(args)) {
|
||||
@ -69,6 +69,6 @@ export async function startCommunityAuthentication(
|
||||
logger.error(`Error:`, err)
|
||||
}
|
||||
} else {
|
||||
logger.debug(`foreignCom.communityUuid is not a valid v4Uuid or still a temporary onetimecode`)
|
||||
logger.debug(`foreignComB.communityUuid is not a valid v4Uuid or still a temporary onetimecode`)
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
import { JwtPayloadType } from './JwtPayloadType'
|
||||
|
||||
export class AuthenticationResponseJwtPayloadType extends JwtPayloadType {
|
||||
static AUTHENTICATION_RESPONSE_TYPE = 'authenticationResponse'
|
||||
|
||||
uuid: string
|
||||
|
||||
constructor(
|
||||
uuid: string,
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
super()
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
this.tokentype = AuthenticationResponseJwtPayloadType.AUTHENTICATION_RESPONSE_TYPE
|
||||
this.uuid = uuid
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
import { CONFIG } from '@/config'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import {
|
||||
CommunityLoggingView,
|
||||
Community as DbCommunity,
|
||||
@ -16,6 +15,8 @@ import { OpenConnectionJwtPayloadType } from 'core/src/auth/jwt/payloadtypes/Ope
|
||||
import { interpretEncryptedTransferArgs } from 'core/src/graphql/logic/interpretEncryptedTransferArgs'
|
||||
import { OpenConnectionCallbackJwtPayloadType } from 'core/src/auth/jwt/payloadtypes/OpenConnectionCallbackJwtPayloadType'
|
||||
import { AuthenticationJwtPayloadType } from 'core/src/auth/jwt/payloadtypes/AuthenticationJwtPayloadType'
|
||||
import { AuthenticationResponseJwtPayloadType } from 'core/src/auth/jwt/payloadtypes/AuthenticationResponseJwtPayloadType'
|
||||
import { encryptAndSign } from 'core/src/auth/jwt/JWT'
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.api.1_0.resolver.AuthenticationResolver`)
|
||||
|
||||
@ -29,17 +30,25 @@ export class AuthenticationResolver {
|
||||
logger.debug(`openConnection() via apiVersion=1_0:`, args)
|
||||
const openConnectionJwtPayload = await interpretEncryptedTransferArgs(args) as OpenConnectionJwtPayloadType
|
||||
if (!openConnectionJwtPayload) {
|
||||
throw new LogError(`invalid OpenConnection payload of requesting community with publicKey`, args.publicKey)
|
||||
const errmsg = `invalid OpenConnection payload of requesting community with publicKey` + args.publicKey
|
||||
logger.error(errmsg)
|
||||
throw new Error(errmsg)
|
||||
}
|
||||
if (openConnectionJwtPayload.tokentype !== OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE) {
|
||||
throw new LogError(`invalid tokentype of community with publicKey`, args.publicKey)
|
||||
const errmsg = `invalid tokentype of community with publicKey` + args.publicKey
|
||||
logger.error(errmsg)
|
||||
throw new Error(errmsg)
|
||||
}
|
||||
if (!openConnectionJwtPayload.url) {
|
||||
throw new LogError(`invalid url of community with publicKey`, args.publicKey)
|
||||
const errmsg = `invalid url of community with publicKey` + args.publicKey
|
||||
logger.error(errmsg)
|
||||
throw new Error(errmsg)
|
||||
}
|
||||
const fedComA = await DbFedCommunity.findOneByOrFail({ publicKey: Buffer.from(args.publicKey, 'hex') })
|
||||
if (!openConnectionJwtPayload.url.startsWith(fedComA.endPoint)) {
|
||||
throw new LogError(`invalid url of community with publicKey`, args.publicKey)
|
||||
const errmsg = `invalid url of community with publicKey` + args.publicKey
|
||||
logger.error(errmsg)
|
||||
throw new Error(errmsg)
|
||||
}
|
||||
|
||||
// biome-ignore lint/complexity/noVoid: no await to respond immediately and invoke callback-request asynchronously
|
||||
@ -53,18 +62,22 @@ export class AuthenticationResolver {
|
||||
args: EncryptedTransferArgs,
|
||||
): Promise<boolean> {
|
||||
logger.debug(`openConnectionCallback() via apiVersion=1_0 ...`, args)
|
||||
// decrypt args.url with homeCom.privateJwtKey and verify signing with callbackFedCom.publicKey
|
||||
const openConnectionCallbackJwtPayload = await interpretEncryptedTransferArgs(args) as OpenConnectionCallbackJwtPayloadType
|
||||
if (!openConnectionCallbackJwtPayload) {
|
||||
throw new LogError(`invalid OpenConnectionCallback payload of requesting community with publicKey`, args.publicKey)
|
||||
const errmsg = `invalid OpenConnectionCallback payload of requesting community with publicKey` + args.publicKey
|
||||
logger.error(errmsg)
|
||||
throw new Error(errmsg)
|
||||
}
|
||||
|
||||
// TODO decrypt args.url with homeCom.privateJwtKey and verify signing with callbackFedCom.publicKey
|
||||
const endPoint = openConnectionCallbackJwtPayload.url.slice(0, openConnectionCallbackJwtPayload.url.lastIndexOf('/') + 1)
|
||||
const apiVersion = openConnectionCallbackJwtPayload.url.slice(openConnectionCallbackJwtPayload.url.lastIndexOf('/') + 1, openConnectionCallbackJwtPayload.url.length)
|
||||
logger.debug(`search fedComB per:`, endPoint, apiVersion)
|
||||
const fedComB = await DbFedCommunity.findOneBy({ endPoint, apiVersion })
|
||||
if (!fedComB) {
|
||||
throw new LogError(`unknown callback community with url`, openConnectionCallbackJwtPayload.url)
|
||||
const errmsg = `unknown callback community with url` + openConnectionCallbackJwtPayload.url
|
||||
logger.error(errmsg)
|
||||
throw new Error(errmsg)
|
||||
}
|
||||
logger.debug(
|
||||
`found fedComB and start authentication:`,
|
||||
@ -83,7 +96,9 @@ export class AuthenticationResolver {
|
||||
logger.debug(`authenticate() via apiVersion=1_0 ...`, args)
|
||||
const authArgs = await interpretEncryptedTransferArgs(args) as AuthenticationJwtPayloadType
|
||||
if (!authArgs) {
|
||||
throw new LogError(`invalid authentication payload of requesting community with publicKey`, args.publicKey)
|
||||
const errmsg = `invalid authentication payload of requesting community with publicKey` + args.publicKey
|
||||
logger.error(errmsg)
|
||||
throw new Error(errmsg)
|
||||
}
|
||||
const authCom = await DbCommunity.findOneByOrFail({ communityUuid: authArgs.oneTimeCode })
|
||||
logger.debug('found authCom:', new CommunityLoggingView(authCom))
|
||||
@ -92,9 +107,11 @@ export class AuthenticationResolver {
|
||||
authCom.authenticatedAt = new Date()
|
||||
await DbCommunity.save(authCom)
|
||||
logger.debug('store authCom.uuid successfully:', new CommunityLoggingView(authCom))
|
||||
const homeCom = await getHomeCommunity()
|
||||
if (homeCom?.communityUuid) {
|
||||
return homeCom.communityUuid
|
||||
const homeComB = await getHomeCommunity()
|
||||
if (homeComB?.communityUuid) {
|
||||
const responseArgs = new AuthenticationResponseJwtPayloadType(homeComB.communityUuid)
|
||||
const responseJwt = await encryptAndSign(responseArgs, homeComB.privateJwtKey!, authCom.publicJwtKey!)
|
||||
return responseJwt
|
||||
}
|
||||
}
|
||||
return null
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
getHomeCommunity,
|
||||
} from 'database'
|
||||
import { getLogger } from 'log4js'
|
||||
import { validate as validateUUID, version as versionUUID } from 'uuid'
|
||||
import { EncryptedTransferArgs } from 'core/src/graphql/model/EncryptedTransferArgs'
|
||||
|
||||
import { AuthenticationClientFactory } from '@/client/AuthenticationClientFactory'
|
||||
@ -13,9 +14,10 @@ import { randombytes_random } from 'sodium-native'
|
||||
|
||||
import { AuthenticationClient as V1_0_AuthenticationClient } from '@/client/1_0/AuthenticationClient'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import { encryptAndSign } from 'core/src/auth/jwt/JWT'
|
||||
import { encryptAndSign, verifyAndDecrypt } from 'core/src/auth/jwt/JWT'
|
||||
import { OpenConnectionCallbackJwtPayloadType } from 'core/src/auth/jwt/payloadtypes/OpenConnectionCallbackJwtPayloadType'
|
||||
import { AuthenticationJwtPayloadType } from 'core/src/auth/jwt/payloadtypes/AuthenticationJwtPayloadType'
|
||||
import { AuthenticationResponseJwtPayloadType } from 'core/src/auth/jwt/payloadtypes/AuthenticationResponseJwtPayloadType'
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.api.1_0.util.authenticateCommunity`)
|
||||
|
||||
@ -27,8 +29,8 @@ export async function startOpenConnectionCallback(
|
||||
publicKey,
|
||||
})
|
||||
try {
|
||||
const homeCom = await getHomeCommunity()
|
||||
const homeFedCom = await DbFedCommunity.findOneByOrFail({
|
||||
const homeComB = await getHomeCommunity()
|
||||
const homeFedComB = await DbFedCommunity.findOneByOrFail({
|
||||
foreign: false,
|
||||
apiVersion: api,
|
||||
})
|
||||
@ -50,14 +52,14 @@ export async function startOpenConnectionCallback(
|
||||
const client = AuthenticationClientFactory.getInstance(fedComA)
|
||||
|
||||
if (client instanceof V1_0_AuthenticationClient) {
|
||||
const url = homeFedCom.endPoint.endsWith('/')
|
||||
? homeFedCom.endPoint + homeFedCom.apiVersion
|
||||
: homeFedCom.endPoint + '/' + homeFedCom.apiVersion
|
||||
const url = homeFedComB.endPoint.endsWith('/')
|
||||
? homeFedComB.endPoint + homeFedComB.apiVersion
|
||||
: homeFedComB.endPoint + '/' + homeFedComB.apiVersion
|
||||
|
||||
const callbackArgs = new OpenConnectionCallbackJwtPayloadType(oneTimeCode, url)
|
||||
logger.debug(`Authentication: start openConnectionCallback with args:`, callbackArgs)
|
||||
// encrypt callbackArgs with requestedCom.publicJwtKey and sign it with homeCom.privateJwtKey
|
||||
const jwt = await encryptAndSign(callbackArgs, homeCom!.privateJwtKey!, comA.publicJwtKey!)
|
||||
const jwt = await encryptAndSign(callbackArgs, homeComB!.privateJwtKey!, comA.publicJwtKey!)
|
||||
const args = new EncryptedTransferArgs()
|
||||
args.publicKey = comA.publicKey.toString('hex')
|
||||
args.jwt = jwt
|
||||
@ -81,7 +83,7 @@ export async function startAuthentication(
|
||||
fedComB: new FederatedCommunityLoggingView(fedComB),
|
||||
})
|
||||
try {
|
||||
const homeCom = await getHomeCommunity()
|
||||
const homeComA = await getHomeCommunity()
|
||||
const comB = await DbCommunity.findOneByOrFail({
|
||||
foreign: true,
|
||||
publicKey: fedComB.publicKey,
|
||||
@ -93,30 +95,36 @@ export async function startAuthentication(
|
||||
const client = AuthenticationClientFactory.getInstance(fedComB)
|
||||
|
||||
if (client instanceof V1_0_AuthenticationClient) {
|
||||
const authenticationArgs = new AuthenticationJwtPayloadType(oneTimeCode, homeCom!.communityUuid!)
|
||||
const authenticationArgs = new AuthenticationJwtPayloadType(oneTimeCode, homeComA!.communityUuid!)
|
||||
// encrypt authenticationArgs.uuid with fedComB.publicJwtKey and sign it with homeCom.privateJwtKey
|
||||
const jwt = await encryptAndSign(authenticationArgs, homeCom!.privateJwtKey!, comB.publicJwtKey!)
|
||||
const jwt = await encryptAndSign(authenticationArgs, homeComA!.privateJwtKey!, comB.publicJwtKey!)
|
||||
const args = new EncryptedTransferArgs()
|
||||
args.publicKey = comB.publicKey.toString('hex')
|
||||
args.jwt = jwt
|
||||
logger.debug(`invoke authenticate() with:`, args)
|
||||
const fedComUuid = await client.authenticate(args)
|
||||
logger.debug(`response of authenticate():`, fedComUuid)
|
||||
if (fedComUuid !== null) {
|
||||
const responseJwt = await client.authenticate(args)
|
||||
logger.debug(`response of authenticate():`, responseJwt)
|
||||
if (responseJwt !== null) {
|
||||
const payload = await verifyAndDecrypt(responseJwt, homeComA!.privateJwtKey!, comB.publicJwtKey!) as AuthenticationResponseJwtPayloadType
|
||||
logger.debug(
|
||||
`received communityUUid for callbackFedCom:`,
|
||||
fedComUuid,
|
||||
`received payload from authenticate ComB:`,
|
||||
payload,
|
||||
new FederatedCommunityLoggingView(fedComB),
|
||||
)
|
||||
const callbackCom = await DbCommunity.findOneByOrFail({
|
||||
foreign: true,
|
||||
publicKey: fedComB.publicKey,
|
||||
})
|
||||
// TODO decrypt fedComUuid with callbackFedCom.publicKey
|
||||
callbackCom.communityUuid = fedComUuid
|
||||
callbackCom.authenticatedAt = new Date()
|
||||
await DbCommunity.save(callbackCom)
|
||||
logger.debug('Community Authentication successful:', new CommunityLoggingView(callbackCom))
|
||||
if (payload.tokentype !== AuthenticationResponseJwtPayloadType.AUTHENTICATION_RESPONSE_TYPE) {
|
||||
const errmsg = `Invalid tokentype in authenticate-response of community with publicKey` + comB.publicKey
|
||||
logger.error(errmsg)
|
||||
throw new Error(errmsg)
|
||||
}
|
||||
if (!payload.uuid || !validateUUID(payload.uuid) || versionUUID(payload.uuid) !== 4) {
|
||||
const errmsg = `Invalid uuid in authenticate-response of community with publicKey` + comB.publicKey
|
||||
logger.error(errmsg)
|
||||
throw new Error(errmsg)
|
||||
}
|
||||
comB.communityUuid = payload.uuid
|
||||
comB.authenticatedAt = new Date()
|
||||
await DbCommunity.save(comB)
|
||||
logger.debug('Community Authentication successful:', new CommunityLoggingView(comB))
|
||||
} else {
|
||||
logger.error('Community Authentication failed:', authenticationArgs)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user