mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
Merge pull request #3306 from gradido/3305-feature-gms-user-search-backend-authentication-handshake
feat(backend): gms user-search - backend authentication-handshake
This commit is contained in:
commit
b4986d7b3a
@ -7,7 +7,7 @@ module.exports = {
|
||||
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
lines: 84,
|
||||
lines: 83,
|
||||
},
|
||||
},
|
||||
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
||||
|
||||
@ -183,3 +183,40 @@ export async function updateGmsUser(apiKey: string, user: GmsUser): Promise<bool
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export async function verifyAuthToken(
|
||||
// apiKey: string,
|
||||
communityUuid: string,
|
||||
token: string,
|
||||
): Promise<string> {
|
||||
const baseUrl = CONFIG.GMS_URL.endsWith('/') ? CONFIG.GMS_URL : CONFIG.GMS_URL.concat('/')
|
||||
const service = 'verify-auth-token?token='.concat(token).concat('&uuid=').concat(communityUuid)
|
||||
const config = {
|
||||
headers: {
|
||||
accept: 'application/json',
|
||||
language: 'en',
|
||||
timezone: 'UTC',
|
||||
connection: 'keep-alive',
|
||||
// authorization: apiKey,
|
||||
},
|
||||
}
|
||||
try {
|
||||
const result = await axios.get(baseUrl.concat(service), config)
|
||||
logger.debug('GET-Response of verify-auth-token:', result)
|
||||
if (result.status !== 200) {
|
||||
throw new LogError(
|
||||
'HTTP Status Error in verify-auth-token:',
|
||||
result.status,
|
||||
result.statusText,
|
||||
)
|
||||
}
|
||||
logger.debug('responseData:', result.data.responseData)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
const token: string = result.data.responseData.token
|
||||
logger.debug('verifyAuthToken=', token)
|
||||
return token
|
||||
} catch (error: any) {
|
||||
logger.error('Error in verifyAuthToken:', error)
|
||||
throw new LogError(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@ export enum RIGHTS {
|
||||
LIST_ALL_CONTRIBUTION_MESSAGES = 'LIST_ALL_CONTRIBUTION_MESSAGES',
|
||||
OPEN_CREATIONS = 'OPEN_CREATIONS',
|
||||
USER = 'USER',
|
||||
GMS_USER_PLAYGROUND = 'GMS_USER_PLAYGROUND',
|
||||
// Moderator
|
||||
SEARCH_USERS = 'SEARCH_USERS',
|
||||
ADMIN_CREATE_CONTRIBUTION = 'ADMIN_CREATE_CONTRIBUTION',
|
||||
|
||||
@ -29,4 +29,5 @@ export const USER_RIGHTS = [
|
||||
RIGHTS.LIST_ALL_CONTRIBUTION_MESSAGES,
|
||||
RIGHTS.OPEN_CREATIONS,
|
||||
RIGHTS.USER,
|
||||
RIGHTS.GMS_USER_PLAYGROUND,
|
||||
]
|
||||
|
||||
@ -19,7 +19,7 @@ const constants = {
|
||||
LOG_LEVEL: process.env.LOG_LEVEL ?? 'info',
|
||||
CONFIG_VERSION: {
|
||||
DEFAULT: 'DEFAULT',
|
||||
EXPECTED: 'v21.2024-01-06',
|
||||
EXPECTED: 'v22.2024-03-14',
|
||||
CURRENT: '',
|
||||
},
|
||||
}
|
||||
@ -146,6 +146,8 @@ const gms = {
|
||||
GMS_CREATE_USER_THROW_ERRORS: process.env.GMS_CREATE_USER_THROW_ERRORS === 'true' || false,
|
||||
// koordinates of Illuminz-instance of GMS
|
||||
GMS_URL: process.env.GMS_HOST ?? 'http://localhost:4044/',
|
||||
// used as secret postfix attached at the gms community-auth-url endpoint ('/hook/gms/' + 'secret')
|
||||
GMS_WEBHOOK_SECRET: process.env.GMS_WEBHOOK_SECRET ?? 'secret',
|
||||
}
|
||||
|
||||
export const CONFIG = {
|
||||
|
||||
10
backend/src/graphql/model/GmsUserAuthenticationResult.ts
Normal file
10
backend/src/graphql/model/GmsUserAuthenticationResult.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Field, ObjectType } from 'type-graphql'
|
||||
|
||||
@ObjectType()
|
||||
export class GmsUserAuthenticationResult {
|
||||
@Field(() => String)
|
||||
url: string
|
||||
|
||||
@Field(() => String)
|
||||
token: string
|
||||
}
|
||||
@ -25,6 +25,7 @@ import { PasswordEncryptionType } from '@enum/PasswordEncryptionType'
|
||||
import { UserContactType } from '@enum/UserContactType'
|
||||
import { SearchAdminUsersResult } from '@model/AdminUser'
|
||||
// import { Location } from '@model/Location'
|
||||
import { GmsUserAuthenticationResult } from '@model/GmsUserAuthenticationResult'
|
||||
import { User } from '@model/User'
|
||||
import { UserAdmin, SearchUsersResult } from '@model/UserAdmin'
|
||||
|
||||
@ -68,6 +69,7 @@ import random from 'random-bigint'
|
||||
import { randombytes_random } from 'sodium-native'
|
||||
|
||||
import { FULL_CREATION_AVAILABLE } from './const/const'
|
||||
import { authenticateGmsUserPlayground } from './util/authenticateGmsUserPlayground'
|
||||
import { getHomeCommunity } from './util/communities'
|
||||
import { compareGmsRelevantUserSettings } from './util/compareGmsRelevantUserSettings'
|
||||
import { getUserCreations } from './util/creations'
|
||||
@ -674,6 +676,21 @@ export class UserResolver {
|
||||
return elopageBuys
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.GMS_USER_PLAYGROUND])
|
||||
@Query(() => GmsUserAuthenticationResult)
|
||||
async authenticateGmsUserSearch(@Ctx() context: Context): Promise<GmsUserAuthenticationResult> {
|
||||
logger.info(`authUserForGmsUserSearch()...`)
|
||||
const dbUser = getUser(context)
|
||||
let result: GmsUserAuthenticationResult
|
||||
if (context.token) {
|
||||
result = await authenticateGmsUserPlayground(context.token, dbUser)
|
||||
logger.info('authUserForGmsUserSearch=', result)
|
||||
} else {
|
||||
throw new LogError('authUserForGmsUserSearch without token')
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.SEARCH_ADMIN_USERS])
|
||||
@Query(() => SearchAdminUsersResult)
|
||||
async searchAdminUsers(
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
import { User as DbUser } from '@entity/User'
|
||||
|
||||
import { verifyAuthToken } from '@/apis/gms/GmsClient'
|
||||
import { CONFIG } from '@/config'
|
||||
import { GmsUserAuthenticationResult } from '@/graphql/model/GmsUserAuthenticationResult'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
|
||||
export async function authenticateGmsUserPlayground(
|
||||
token: string,
|
||||
dbUser: DbUser,
|
||||
): Promise<GmsUserAuthenticationResult> {
|
||||
const result = new GmsUserAuthenticationResult()
|
||||
result.url = CONFIG.GMS_URL.concat('/playground')
|
||||
result.token = await verifyAuthToken(dbUser.communityUuid, token)
|
||||
logger.info('GmsUserAuthenticationResult:', result)
|
||||
return result
|
||||
}
|
||||
@ -15,6 +15,14 @@ export const verifyLogin = gql`
|
||||
}
|
||||
}
|
||||
`
|
||||
export const authenticateGmsUserSearch = gql`
|
||||
query {
|
||||
authenticateGmsUserSearch {
|
||||
url
|
||||
token
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const queryOptIn = gql`
|
||||
query ($optIn: String!) {
|
||||
|
||||
@ -13,6 +13,7 @@ import { schema } from '@/graphql/schema'
|
||||
import { Connection } from '@/typeorm/connection'
|
||||
import { checkDBVersion } from '@/typeorm/DBVersion'
|
||||
import { elopageWebhook } from '@/webhook/elopage'
|
||||
import { gmsWebhook } from '@/webhook/gms'
|
||||
|
||||
import { context as serverContext } from './context'
|
||||
import { cors } from './cors'
|
||||
@ -94,6 +95,10 @@ export const createServer = async (
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
app.post('/hook/elopage/' + CONFIG.WEBHOOK_ELOPAGE_SECRET, elopageWebhook)
|
||||
|
||||
// GMS Webhook
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
app.get('/hook/gms/' + CONFIG.GMS_WEBHOOK_SECRET, gmsWebhook)
|
||||
|
||||
// Apollo Server
|
||||
const apollo = new ApolloServer({
|
||||
schema: await schema(),
|
||||
|
||||
@ -37,6 +37,7 @@ const logPlugin = {
|
||||
const { logger } = requestContext
|
||||
const { query, mutation, variables, operationName } = requestContext.request
|
||||
if (operationName !== 'IntrospectionQuery') {
|
||||
logger.debug('requestDidStart:', requestContext)
|
||||
logger.info(`Request:
|
||||
${mutation || query}variables: ${JSON.stringify(filterVariables(variables), null, 2)}`)
|
||||
}
|
||||
|
||||
36
backend/src/webhook/gms.ts
Normal file
36
backend/src/webhook/gms.ts
Normal file
@ -0,0 +1,36 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
import { User as DbUser } from '@entity/User'
|
||||
|
||||
import { decode } from '@/auth/JWT'
|
||||
|
||||
export const gmsWebhook = async (req: any, res: any): Promise<void> => {
|
||||
console.log('GMS Hook received', req.query)
|
||||
const { token } = req.query
|
||||
|
||||
if (!token) {
|
||||
console.log('gmsWebhook: missing token')
|
||||
res.status(400).json({ message: 'false' })
|
||||
return
|
||||
}
|
||||
const payload = await decode(token)
|
||||
console.log('gmsWebhook: decoded token=', payload)
|
||||
if (!payload) {
|
||||
console.log('gmsWebhook: invalid token')
|
||||
res.status(400).json({ message: 'false' })
|
||||
return
|
||||
}
|
||||
const user = await DbUser.findOne({ where: { gradidoID: payload.gradidoID } })
|
||||
if (!user) {
|
||||
console.log('gmsWebhook: missing user')
|
||||
res.status(400).json({ message: 'false' })
|
||||
return
|
||||
}
|
||||
console.log('gmsWebhook: authenticate user=', user.gradidoID, user.firstName, user.lastName)
|
||||
console.log('gmsWebhook: authentication successful')
|
||||
res.status(200).json({ userUuid: user.gradidoID })
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user