Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions src/api/crm/v1/resources/openApi.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { FastifyInstance, FastifyRequest } from 'fastify'
import { FastifyInstance } from 'fastify'
import { OpenAPIV3 } from 'openapi-types'
import { globalTenantIdToLocalTenantIdMapping } from '../../../../data/user/tenantMapping.js'
import { getTenantIdsFromHeader } from '../../../shared/validateUserAuthorization.js'
import { getCrmV1ApiDefinition } from '../config.js'
import { CustomRequest } from '../../../../types/types.js'

export const openApiResourceName = 'openapi'

Expand All @@ -12,11 +13,11 @@
*
* This will later be referenced through ORD.
*/
export async function openApiResource(fastify: FastifyInstance): Promise<void> {

Check warning on line 16 in src/api/crm/v1/resources/openApi.ts

View workflow job for this annotation

GitHub Actions / Build

Async function 'openApiResource' has no 'await' expression
fastify.get('/oas3.json', {}, getOpenApiDefinitionHandler)
}

async function getOpenApiDefinitionHandler(req: FastifyRequest): Promise<OpenAPIV3.Document> {
async function getOpenApiDefinitionHandler(req: CustomRequest): Promise<OpenAPIV3.Document> {

Check warning on line 20 in src/api/crm/v1/resources/openApi.ts

View workflow job for this annotation

GitHub Actions / Build

Async function 'getOpenApiDefinitionHandler' has no 'await' expression
const tenantIds = getTenantIdsFromHeader(req)
if (tenantIds.localTenantId) {
// This is the `sap.foo.bar:open-local-tenant-id:v1` access strategy
Expand Down
5 changes: 3 additions & 2 deletions src/api/open-resource-discovery/v1/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { FastifyInstance, FastifyRequest } from 'fastify'
import { FastifyInstance } from 'fastify'
import fastifyETag from '@fastify/etag'
import { globalTenantIdToLocalTenantIdMapping } from '../../../data/user/tenantMapping.js'
import { getTenantIdsFromHeader } from '../../shared/validateUserAuthorization.js'
import { ordDocumentApiV1Config } from './config.js'
import { ordConfiguration } from './data/configuration.js'
import { getOrdDocumentForTenant, ordDocument } from './data/document.js'
import { CustomRequest } from '../../../types/types.js'

export async function ordDocumentV1Api(fastify: FastifyInstance): Promise<void> {
fastify.log.info(`Registering ${ordDocumentApiV1Config.apiName}...`)
Expand All @@ -31,7 +32,7 @@ export async function ordDocumentV1Api(fastify: FastifyInstance): Promise<void>
// The result of this request will differ, depending on the tenant chosen
// We'll implement this as an ORD access strategy, where the tenant ID is passed via Header
// To show multiple options, we can offer both local tenant ID and global tenant ID for correlations
fastify.get(`/${ordDocumentApiV1Config.apiEntryPoint}/documents/system-instance`, (req: FastifyRequest) => {
fastify.get(`/${ordDocumentApiV1Config.apiEntryPoint}/documents/system-instance`, (req: CustomRequest) => {
const tenantIds = getTenantIdsFromHeader(req)

if (tenantIds.localTenantId) {
Expand Down
24 changes: 16 additions & 8 deletions src/api/shared/validateUserAuthorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import _ from 'lodash'
import { TenantConfiguration, tenants } from '../../data/user/tenants.js'
import { apiUsersAndPasswords } from '../../data/user/users.js'
import { UnauthorizedError } from '../../error/UnauthorizedError.js'
import { globalTenantIdToLocalTenantIdMapping } from '../../data/user/tenantMapping.js'
import { CustomRequest } from '../../types/types.js'

export interface UserInfo {
userName: string
Expand All @@ -12,6 +14,8 @@ export interface UserInfo {

export const basicAuthConfig = { validate: validateUserAuthorization, authenticate: true }

const localTenants = Object.values(globalTenantIdToLocalTenantIdMapping)

/**
* Validates a request for a valid BasicAuth login
*
Expand All @@ -20,11 +24,7 @@ export const basicAuthConfig = { validate: validateUserAuthorization, authentica
*
* @throws UnauthorizedError
*/
export async function validateUserAuthorization(
username: string,
password: string,
req: FastifyRequest,
): Promise<void> {
export function validateUserAuthorization(username: string, password: string, req: FastifyRequest): void {
if (apiUsersAndPasswords[username] && apiUsersAndPasswords[username].password === password) {
const tenantId = apiUsersAndPasswords[username].tenantId
// Add user info to the request that we've validated
Expand All @@ -34,23 +34,31 @@ export async function validateUserAuthorization(
tenantConfiguration: tenants[tenantId],
}
req.log.info(`User "${username}" of tenant "${tenantId}" authenticated successfully.`)
return
} else {
throw new UnauthorizedError(`Unknown username "${username}" and password combination`)
}
}

export function getTenantIdsFromHeader(req: FastifyRequest): {
export function getTenantIdsFromHeader(req: CustomRequest): {
localTenantId: string | undefined
sapGlobalTenantId: string | undefined
} {
const localTenantId = _.isArray(req.headers['sap-local-tenant-id'])
let localTenantId = _.isArray(req.headers['sap-local-tenant-id'])
? req.headers['sap-local-tenant-id'].join()
: req.headers['sap-local-tenant-id']

if (req.query['local-tenant-id'] && localTenants.includes(req.query['local-tenant-id'])) {
localTenantId = req.query['local-tenant-id']
}

const sapGlobalTenantId = _.isArray(req.headers['sap-global-tenant-id'])
? req.headers['sap-global-tenant-id'].join()
: req.headers['sap-global-tenant-id']

if (req.query['global-tenant-id'] && req.query['global-tenant-id'] in globalTenantIdToLocalTenantIdMapping) {
localTenantId = req.query['global-tenant-id']
}

return {
localTenantId,
sapGlobalTenantId,
Expand Down
5 changes: 3 additions & 2 deletions src/event/odm-finance-costobject/v1/eventCatalogDefinition.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { FastifyInstance, FastifyRequest } from 'fastify'
import { FastifyInstance } from 'fastify'
import { getTenantIdsFromHeader } from '../../../api/shared/validateUserAuthorization.js'
import { globalTenantIdToLocalTenantIdMapping } from '../../../data/user/tenantMapping.js'
import { SapEventCatalog } from '../../shared/SapEventCatalog.js'
import { getOdmCostObjectSapEventCatalogDefinition } from './config.js'
import { CustomRequest } from '../../../types/types.js'

export const openApiResourceName = 'openapi'

Expand All @@ -16,7 +17,7 @@ export async function sapEventCatalogDefinition(fastify: FastifyInstance): Promi
fastify.get('/odm-finance-costobject.asyncapi2.json', {}, getSapEventCatalogDefinitionHandler)
}

async function getSapEventCatalogDefinitionHandler(req: FastifyRequest): Promise<SapEventCatalog> {
async function getSapEventCatalogDefinitionHandler(req: CustomRequest): Promise<SapEventCatalog> {
const tenantIds = getTenantIdsFromHeader(req)
if (tenantIds.localTenantId) {
// This is the `sap.foo.bar:open-local-tenant-id:v1` access strategy
Expand Down
3 changes: 3 additions & 0 deletions src/types/fastify.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ declare module 'fastify' {
tenantConfiguration: TenantConfiguration
}
}
export interface FastifyQueryParameters {
[key: string]: string
}
}
8 changes: 8 additions & 0 deletions src/types/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { FastifyRequest } from 'fastify'

export type CustomRequest = FastifyRequest<{
Querystring: {
'local-tenant-id': string
'global-tenant-id': string
}
}>
Loading