Skip to content

Commit

Permalink
ServiceAccount Member Dashboard Access (gardener#871)
Browse files Browse the repository at this point in the history
* allow all kind of members to access the dashboard (including ServiceAccount members)

* keep old logic to allow serviceaccountusers to login

* added tests

* rm roles

* Apply suggestions from code review

Co-authored-by: Holger Koser <[email protected]>

Co-authored-by: Holger Koser <[email protected]>
  • Loading branch information
grolu and holgerkoser authored Nov 6, 2020
1 parent 3e634a3 commit fec8875
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 2 deletions.
13 changes: 11 additions & 2 deletions backend/lib/services/projects.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ const {
dashboardClient,
Resources
} = require('@gardener-dashboard/kube-client')

const { PreconditionFailed } = require('http-errors')
const shoots = require('./shoots')
const authorization = require('./authorization')
const cache = require('../cache')

const Member = require('./members/Member')
const PROJECT_INITIALIZATION_TIMEOUT = 30 * 1000

function fromResource ({ metadata, spec = {}, status = {} }) {
Expand Down Expand Up @@ -137,7 +138,15 @@ exports.list = async function ({ user, qs = {} }) {
.includes(user.id)
.value()

return hasGroupMembership || hasUserMembership
const member = Member.parseUsername(user.id)
const hasServiceAccountMembership = _
.chain(project)
.get('spec.members')
.filter(['kind', 'ServiceAccount'])
.find(member)
.value()

return hasGroupMembership || hasUserMembership || hasServiceAccountMembership
}

const phases = _
Expand Down
128 changes: 128 additions & 0 deletions backend/test/services.projects.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
//
// SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors
//
// SPDX-License-Identifier: Apache-2.0
//

'use strict'

const projects = require('../lib/services/projects')
const cache = require('../lib/cache')
const authorization = require('../lib/services/authorization')
const nextTick = () => new Promise(process.nextTick)

describe('services', function () {
/* eslint no-unused-expressions: 0 */
const sandbox = sinon.createSandbox()

afterEach(function () {
sandbox.restore()
})

describe('projects', function () {
const projectList = [
{
spec: {
members: [
{
kind: 'User',
name: '[email protected]'
},
{
kind: 'User',
name: 'system:serviceaccount:garden-foo:robot-user'
},
{
kind: 'ServiceAccount',
name: 'robot-sa',
namespace: 'garden-foo'
}
]
},
metadata: {
name: 'foo'
},
status: {
phase: 'Ready'
}
},
{
spec: {
members: [
{
kind: 'User',
name: '[email protected]'
}
]
},
metadata: {
name: 'bar'
},
status: {
phase: 'Ready'
}
},
{
spec: {
members: [
{
apiGroup: 'rbac.authorization.k8s.io',
kind: 'User',
name: '[email protected]'
}
]
},
metadata: {
name: 'notReady'
}
}
]

const createUser = (username) => {
return {
id: username
}
}

beforeEach(function () {
sandbox.stub(cache, 'getProjects').returns(projectList)
sandbox.stub(authorization, 'isAdmin').callsFake(async (user) => {
await nextTick()
if (user.id === '[email protected]') {
return true
}
return false
})
})

describe('#list', function () {
it('should return all ready projects if user is admin', async function () {
const userProjects = await projects.list({ user: createUser('[email protected]') })
expect(userProjects).to.have.length(2)
})

it('should return project for user member', async function () {
const userProjects = await projects.list({ user: createUser('system:serviceaccount:garden-foo:robot-user') })
expect(userProjects).to.have.length(1)
expect(userProjects[0].metadata.name).to.eql('foo')
})

it('should return project for serviceaccount user member', async function () {
const userProjects = await projects.list({ user: createUser('system:serviceaccount:garden-foo:robot-user') })
expect(userProjects).to.have.length(1)
expect(userProjects[0].metadata.name).to.eql('foo')
})

it('should return project for serviceaccount member', async function () {
const userProjects = await projects.list({ user: createUser('system:serviceaccount:garden-foo:robot-sa') })
expect(userProjects).to.have.length(1)
expect(userProjects[0].metadata.name).to.eql('foo')
})

it('should not return project if not in member list', async function () {
const userProjects = await projects.list({ user: createUser('[email protected]') })
expect(userProjects).to.have.length(0)
})
})
})
})

0 comments on commit fec8875

Please sign in to comment.