Skip to content

Commit 777804f

Browse files
committed
fix: remove ABAC
1 parent 2ae72af commit 777804f

File tree

3 files changed

+4
-127
lines changed

3 files changed

+4
-127
lines changed

src/authz.ts

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Ability, Subject, subject } from '@casl/ability'
22
import Debug from 'debug'
3-
import { each, forIn, get, isEmpty, isEqual, omit, set } from 'lodash'
3+
import { each, forIn, get, isEmpty } from 'lodash'
44
import { Acl, AclAction, OpenAPIDoc, Schema, SessionUser, TeamAuthz, UserAuthz } from 'src/otomi-models'
55
import OtomiStack from 'src/otomi-stack'
66
import { extract, flattenObject } from 'src/utils'
@@ -197,50 +197,6 @@ export default class Authz {
197197
return iCan
198198
}
199199

200-
validateWithAbac = (action: string, schemaName: string, teamId: string, body?: any, dataOrig?: any): string[] => {
201-
const violatedAttributes: string[] = []
202-
if (this.user.roles.includes('platformAdmin')) return violatedAttributes
203-
204-
if (!['create', 'update'].includes(action))
205-
throw new Error('validateWithAbac should only be used for mutating actions')
206-
const deniedRoleAttributes = this.getAbacDenied(action, schemaName, teamId)
207-
// check if we are denied any attributes by role
208-
// also check if we are denied by lack of self service
209-
const deniedSelfServiceAttributes = get(
210-
this.user.authz,
211-
`${teamId}.deniedAttributes.teamMembers`,
212-
[],
213-
) as Array<string>
214-
// merge denied attributes from both role-based and self-service restrictions
215-
const deniedAttributes = [...deniedRoleAttributes, ...deniedSelfServiceAttributes]
216-
217-
deniedAttributes.forEach((path) => {
218-
const val = get(body, path)
219-
const origVal = get(dataOrig, path)
220-
// undefined value expected for forbidden props, so put back original before save
221-
if (val === undefined) set(body, path, origVal)
222-
// if a value is provided which is not allowed, mark it as violated
223-
else if (!isEqual(val, origVal)) violatedAttributes.push(path)
224-
})
225-
return violatedAttributes
226-
}
227-
228-
getAbacDenied = (action: string, schemaName: string, teamId: string): string[] => {
229-
const schema = this.specRules[schemaName]
230-
const aclProps = getAclProps(schema)
231-
const violatedAttributes: Array<string> = aclProps.filter(
232-
(prop) => !this.validateWithCasl(action, `${schemaName}.${prop}`, teamId),
233-
)
234-
return violatedAttributes
235-
}
236-
237-
filterWithAbac = (schemaName: string, teamId: string, body: Record<string, any>): any => {
238-
if (typeof body !== 'object') return body
239-
const deniedRoleAttributes = this.getAbacDenied('read', schemaName, teamId)
240-
const ret = (body.length !== undefined ? body : [body]).map((obj) => omit(obj, deniedRoleAttributes))
241-
return body.length !== undefined ? ret : ret[0]
242-
}
243-
244200
hasSelfService = (teamId: string, attribute: string): boolean => {
245201
const deniedAttributes = get(this.user.authz, `${teamId}.deniedAttributes.teamMembers`, []) as Array<string>
246202
return !deniedAttributes.includes(attribute)

src/middleware/authz.ts

Lines changed: 1 addition & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
1-
/* eslint-disable no-param-reassign */
2-
import { getSpec } from 'src/app'
3-
import { debug } from 'console'
4-
import { find } from 'lodash'
5-
import get from 'lodash/get'
61
import Authz from 'src/authz'
72
import { HttpError } from 'src/error'
83
import { OpenApiRequestExt } from 'src/otomi-models'
9-
import { RepoService } from '../services/RepoService'
104

115
const HttpMethodMapping: Record<string, string> = {
126
DELETE: 'delete',
@@ -16,34 +10,12 @@ const HttpMethodMapping: Record<string, string> = {
1610
PUT: 'update',
1711
}
1812

19-
function renameKeys(obj: Record<string, any>) {
20-
const newKeys = {
21-
serviceId: 'id',
22-
secretId: 'id',
23-
}
24-
if (Object.keys(obj).length === 1 && 'teamId' in obj) return { id: obj.teamId }
25-
const keyValues = Object.keys(obj).map((key) => {
26-
const newKey = newKeys[key] || key
27-
return { [newKey]: obj[key] }
28-
})
29-
return Object.assign({}, ...keyValues)
30-
}
31-
32-
// const badCode = (code) => code >= 300 || code < 200
33-
// const wrapResponse = (filter, orig) => {
34-
// return function (obj) {
35-
// if (badCode(this.statusCode)) return orig(obj)
36-
// const ret = filter(obj)
37-
// return orig(ret)
38-
// }
39-
// }
40-
4113
/**
4214
* Authorize a request based on RBAC and ABAC rules.
4315
* Called by the security handler.
4416
* Throws HttpError if authorization fails.
4517
*/
46-
export function authorize(req: OpenApiRequestExt, authz: Authz, repoService: RepoService): void {
18+
export function authorize(req: OpenApiRequestExt, authz: Authz): void {
4719
const { body, user } = req
4820
// express-openapi-validator stores path params in req.openapi.pathParams
4921
const teamId = req.openapi?.pathParams?.teamId ?? req.params?.teamId ?? req.query?.teamId ?? body?.teamId
@@ -55,8 +27,6 @@ export function authorize(req: OpenApiRequestExt, authz: Authz, repoService: Rep
5527
// If there is no RBAC then we allow the request
5628
if (!schemaName) return
5729

58-
const apiSpec = getSpec().spec
59-
6030
// Initialize rules for the user
6131
authz.init(user)
6232

@@ -80,53 +50,4 @@ export function authorize(req: OpenApiRequestExt, authz: Authz, repoService: Rep
8050
if (!valid) {
8151
throw new HttpError(403, `User not allowed to perform "${action}" on "${schemaName}" resource`)
8252
}
83-
84-
// Check ABAC permissions for create/update operations
85-
const schemaToRepoMap: Record<string, string> = {
86-
Service: 'services',
87-
Team: 'teamConfig',
88-
App: 'apps',
89-
Build: 'builds',
90-
Workload: 'workloads',
91-
Settings: 'otomi',
92-
Netpol: 'netpols',
93-
Policy: 'policies',
94-
SealedSecret: 'sealedSecrets',
95-
}
96-
const teamSpecificCollections = ['builds', 'services', 'workloads', 'netpols', 'policies', 'sealedSecrets']
97-
98-
//TODO lookup if we can remove this
99-
const collectionId = schemaToRepoMap[schemaName]
100-
if (collectionId && ['create', 'update'].includes(action)) {
101-
// Look up x-allow-values from the API spec for ABAC validation
102-
let dataOrig = get(
103-
apiSpec,
104-
`components.schemas.TeamSelfService.properties.${schemaName.toLowerCase()}.x-allow-values`,
105-
{},
106-
)
107-
108-
if (action === 'update') {
109-
try {
110-
const pathParams = req.openapi?.pathParams ?? req.params
111-
const selector = renameKeys(pathParams)
112-
let collection
113-
if (teamSpecificCollections.includes(collectionId)) {
114-
collection = repoService.getTeamConfigService(teamId).getCollection(collectionId)
115-
} else {
116-
collection = repoService.getCollection(collectionId)
117-
}
118-
dataOrig = find(collection, selector) || {}
119-
} catch (error) {
120-
debug('Error in authorize', error)
121-
}
122-
}
123-
124-
const violatedAttributes = authz.validateWithAbac(action, schemaName, teamId, req.body, dataOrig)
125-
if (violatedAttributes.length > 0) {
126-
throw new HttpError(
127-
403,
128-
`User not allowed to modify the following attributes: ${violatedAttributes.join(', ')} of ${schemaName} resource`,
129-
)
130-
}
131-
}
13253
}

src/middleware/security-handlers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Request, Response } from 'express'
1+
import { Request } from 'express'
22
import { getSpec } from 'src/app'
33
import Authz, { getTeamSelfServiceAuthz } from 'src/authz'
44
import { OpenApiRequestExt } from 'src/otomi-models'
@@ -38,7 +38,7 @@ export async function groupAuthzSecurityHandler(req: Request, scopes: string[],
3838
// Perform authorization check
3939
try {
4040
const authz = new Authz(getSpec().spec)
41-
authorize(extReq, authz, otomiStack.repoService)
41+
authorize(extReq, authz)
4242
return true
4343
} catch (error: any) {
4444
// authorize threw an error (e.g., HttpError for 403)

0 commit comments

Comments
 (0)