Skip to content

Commit

Permalink
Fix controllerregistrations permission issue
Browse files Browse the repository at this point in the history
  • Loading branch information
grolu committed Aug 6, 2021
1 parent eb0fde0 commit 67a4ac0
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 30 deletions.
24 changes: 22 additions & 2 deletions backend/__fixtures__/controllerregistrations.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function getControllerRegistration ({ uid, name, version, resources }) {
const controllerRegistrationList = [
getControllerRegistration({
uid: 1,
name: 'foo',
name: 'OS Registration',
version: 'v1.0.0',
resources: [{
kind: 'OperatingSystemConfig',
Expand All @@ -43,11 +43,31 @@ const controllerRegistrationList = [
}),
getControllerRegistration({
uid: 2,
name: 'bar',
name: 'Network Registration',
resources: [{
kind: 'Network',
type: 'gardium'
}]
}),
getControllerRegistration({
uid: 2,
name: 'Network Registration 2',
resources: [{
kind: 'Network',
type: 'foobium'
},
{
kind: 'Foo',
type: 'bar'
}]
}),
getControllerRegistration({
uid: 2,
name: 'DNS Registration',
resources: [{
kind: 'DNSProvider',
type: 'gardenland'
}]
})
]

Expand Down
30 changes: 18 additions & 12 deletions backend/lib/services/controllerregistrations.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,29 @@

'use strict'

const { Forbidden } = require('http-errors')
const { getControllerRegistrations } = require('../cache')
const authorization = require('./authorization')
const _ = require('lodash')

const REQUIRED_RESOURCE_KINDS = ['Network', 'DNSProvider']
exports.listExtensions = async function ({ user }) {
const allowed = await authorization.canListControllerRegistrations(user)
if (!allowed) {
throw new Forbidden('You are not allowed to list controllerregistrations')
}

const controllerregistrations = getControllerRegistrations()
return _.map(controllerregistrations, ({ metadata, spec }) => {
return {
name: metadata.name,
version: _.get(spec, 'deployment.providerConfig.values.image.tag'),
resources: _.get(spec, 'resources')
const allowed = await authorization.canListControllerRegistrations(user)
const extensions = []
for (const { metadata, spec = {} } of controllerregistrations) {
const name = metadata.name
if (allowed) {
const version = _.get(spec, 'deployment.providerConfig.values.image.tag')
const resources = spec.resources
extensions.push({ name, version, resources })
} else {
// required resoure kinds are essential for the frontend and need to be returned even if the user has not the permission to read controllerregistrations
const resources = _.filter(spec.resources, ({ kind }) => REQUIRED_RESOURCE_KINDS.includes(kind))
// only expose the extension if it contains one of the required resources
if (!_.isEmpty(resources)) {
extensions.push({ name, resources })
}
}
})
}
return extensions
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`api controllerregistrations should return all gardener extensions 1`] = `
exports[`api controllerregistrations should return all gardener extensions (admin) 1`] = `
Array [
Array [
Object {
Expand All @@ -26,10 +26,10 @@ Array [
]
`;

exports[`api controllerregistrations should return all gardener extensions 2`] = `
exports[`api controllerregistrations should return all gardener extensions (admin) 2`] = `
Array [
Object {
"name": "foo",
"name": "OS Registration",
"resources": Array [
Object {
"kind": "OperatingSystemConfig",
Expand All @@ -39,13 +39,93 @@ Array [
"version": "v1.0.0",
},
Object {
"name": "bar",
"name": "Network Registration",
"resources": Array [
Object {
"kind": "Network",
"type": "gardium",
},
],
},
Object {
"name": "Network Registration 2",
"resources": Array [
Object {
"kind": "Network",
"type": "foobium",
},
Object {
"kind": "Foo",
"type": "bar",
},
],
},
Object {
"name": "DNS Registration",
"resources": Array [
Object {
"kind": "DNSProvider",
"type": "gardenland",
},
],
},
]
`;

exports[`api controllerregistrations should return only required registrations and information (admin) 1`] = `
Array [
Array [
Object {
":authority": "kubernetes:6443",
":method": "post",
":path": "/apis/authorization.k8s.io/v1/selfsubjectaccessreviews",
":scheme": "https",
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImpvaG4uZG9lQGV4YW1wbGUub3JnIiwiaWF0IjoxNTc3ODM2ODAwLCJhdWQiOlsiZ2FyZGVuZXIiXSwiZXhwIjozMTU1NzE2ODAwLCJqdGkiOiJqdGkifQ.LkQ9PEN893UNTsZZn2Ux_CAYNOoQ2ISboWuHiAc5HHU",
},
Object {
"apiVersion": "authorization.k8s.io/v1",
"kind": "SelfSubjectAccessReview",
"spec": Object {
"nonResourceAttributes": undefined,
"resourceAttributes": Object {
"group": "core.gardener.cloud",
"resource": "controllerregistrations",
"verb": "list",
},
},
},
],
]
`;

exports[`api controllerregistrations should return only required registrations and information (admin) 2`] = `
Array [
Object {
"name": "Network Registration",
"resources": Array [
Object {
"kind": "Network",
"type": "gardium",
},
],
},
Object {
"name": "Network Registration 2",
"resources": Array [
Object {
"kind": "Network",
"type": "foobium",
},
],
},
Object {
"name": "DNS Registration",
"resources": Array [
Object {
"kind": "DNSProvider",
"type": "gardenland",
},
],
},
]
`;
17 changes: 16 additions & 1 deletion backend/test/acceptance/api.controllerregistrations.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('api', function () {
describe('controllerregistrations', function () {
const user = fixtures.auth.createUser({ id: 'john.doe@example.org' })

it('should return all gardener extensions', async function () {
it('should return all gardener extensions (admin)', async function () {
mockRequest.mockImplementationOnce(fixtures.auth.mocks.reviewSelfSubjectAccess())

const res = await agent
Expand All @@ -40,5 +40,20 @@ describe('api', function () {

expect(res.body).toMatchSnapshot()
})

it('should return only required registrations and information (admin)', async function () {
mockRequest.mockImplementationOnce(fixtures.auth.mocks.reviewSelfSubjectAccess({ allowed: false }))

const res = await agent
.get('/api/gardener-extensions')
.set('cookie', await user.cookie)
.expect('content-type', /json/)
.expect(200)

expect(mockRequest).toBeCalledTimes(1)
expect(mockRequest.mock.calls).toMatchSnapshot()

expect(res.body).toMatchSnapshot()
})
})
})
24 changes: 13 additions & 11 deletions frontend/src/components/dialogs/InfoDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,19 @@ SPDX-License-Identifier: Apache-2.0
<div class="grey--text text--darken-1">
<div class="font-weight-bold">Version Information</div>
<div v-if="!!dashboardVersion">Dashboard<span class="ml-1 font-weight-bold">{{dashboardVersion}}</span></div>
<div v-if="!!gardenerVersion">API<span class="ml-1 font-weight-bold">{{gardenerVersion}}</span></div>
<v-divider v-if="extensionsList.length" class="my-3"></v-divider>
<div v-if="extensionsList.length" class="font-weight-bold">Extensions ({{extensionsList.length}} deployed)</div>
<div
v-for="extension in extensionsList"
:key="extension.id"
class="extension-item">
<span>{{extension.name}}</span>
<span v-if="!!extension.version"><span class="ml-1 font-weight-bold">{{extension.version}}</span></span>
<span v-if="!!extension.kind"> (Kind: {{extension.kind}})</span>
</div>
<template v-if="isAdmin">
<div v-if="!!gardenerVersion">API<span class="ml-1 font-weight-bold">{{gardenerVersion}}</span></div>
<v-divider v-if="extensionsList.length" class="my-3"></v-divider>
<div v-if="extensionsList.length" class="font-weight-bold">Extensions ({{extensionsList.length}} deployed)</div>
<div
v-for="extension in extensionsList"
:key="extension.id"
class="extension-item">
<span>{{extension.name}}</span>
<span v-if="!!extension.version"><span class="ml-1 font-weight-bold">{{extension.version}}</span></span>
<span v-if="!!extension.kind"> (Kind: {{extension.kind}})</span>
</div>
</template>
</div>
</template>
</g-dialog>
Expand Down

0 comments on commit 67a4ac0

Please sign in to comment.