Skip to content

Commit d2df691

Browse files
authored
Merge pull request #6994 from FlowFuse/error-sso-role-change
Show error if user roles are managed by SSO
2 parents 4b52948 + 74f939a commit d2df691

File tree

7 files changed

+39
-12
lines changed

7 files changed

+39
-12
lines changed

forge/db/views/User.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ module.exports = function (app) {
8383
allOf: [{ $ref: 'UserSummary' }],
8484
properties: {
8585
role: { type: 'number' },
86-
permissions: { $ref: 'TeamMemberPermissions' }
86+
permissions: { $ref: 'TeamMemberPermissions' },
87+
ssoManaged: { type: 'boolean' }
8788
}
8889
}
8990
})
@@ -97,6 +98,14 @@ module.exports = function (app) {
9798
return result
9899
}
99100

101+
async function ssoManaged (users, team) {
102+
const list = {}
103+
for (const u of users) {
104+
list[u.hashid] = await app.sso.isUserMembershipManaged(u, team)
105+
}
106+
return list
107+
}
108+
100109
app.addSchema({
101110
$id: 'UserList',
102111
type: 'array',
@@ -108,6 +117,7 @@ module.exports = function (app) {
108117
return {
109118
userSummary,
110119
userProfile,
111-
teamMemberList
120+
teamMemberList,
121+
ssoManaged
112122
}
113123
}

forge/routes/api/teamMembers.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ module.exports = async function (app) {
3131
const noPermissions = request.body?.permissions === undefined
3232
if (await app.sso.isUserMembershipManaged(request.user, request.team) && noPermissions) {
3333
// The user's membership for this team is sso managed - do not allow api changes to be applied
34-
reply.code(400).send({ code: 'invalid_request', error: 'Cannot modify team membershipt for an SSO managed user' })
34+
reply.code(400).send({ code: 'invalid_request', error: 'Cannot modify team membership for an SSO managed user' })
3535
// eslint-disable-next-line no-useless-return
3636
return
3737
}
@@ -70,7 +70,14 @@ module.exports = async function (app) {
7070
}
7171
}, async (request, reply) => {
7272
const members = await app.db.models.User.inTeam(request.params.teamId)
73-
const result = app.db.views.User.teamMemberList(members)
73+
let result = app.db.views.User.teamMemberList(members)
74+
if (app.config.features.enabled('sso')) {
75+
const sso = await app.db.views.User.ssoManaged(members, request.team)
76+
result = result.map(r => {
77+
r.ssoManaged = sso[r.id]
78+
return r
79+
})
80+
}
7481
reply.send({
7582
meta: {}, // For future pagination
7683
count: result.length,

frontend/src/components/blueprints/BlueprintTile.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<div class="ff-blueprint-tile--info">
1818
<label>{{ blueprint.name }}</label>
1919
<p v-if="blueprint.description" :title="blueprint.description">
20-
<ff-markdown-viewer :content="blueprint.description"/>
20+
<ff-markdown-viewer :content="blueprint.description" />
2121
</p>
2222
</div>
2323
<div class="ff-blueprint-tile--actions justify-between">

frontend/src/pages/team/Members/General.vue

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,21 @@
1919
</template>
2020
<template v-if="canEditUser" #context-menu="{row}">
2121
<ff-kebab-item
22-
v-if="(hasPermission('team:user:change-role') && !requiresBilling) || isAdminUser"
22+
v-if="((hasPermission('team:user:change-role') && !requiresBilling) || isAdminUser) && !ssoManaged({row})"
2323
data-action="member-change-role"
2424
label="Change Role" @click="changeRoleDialog(row)"
2525
/>
2626
<ff-kebab-item
27-
v-if="hasPermission('team:user:remove') || isAdminUser"
27+
v-if="(hasPermission('team:user:remove') || isAdminUser) && !ssoManaged({row})"
2828
data-action="member-remove-from-team"
2929
label="Remove From Team"
3030
kind="danger"
3131
@click="removeUserDialog(row)"
3232
/>
33+
<ff-kebab-item
34+
v-if="ssoManaged({row})"
35+
label="User role is SSO Managed"
36+
/>
3337
</template>
3438
</ff-data-table>
3539
</form>
@@ -236,6 +240,9 @@ export default {
236240
},
237241
onApplicationRoleClick ({ application, user }) {
238242
this.$refs.editApplicationPermissionsDialog.show(user, application)
243+
},
244+
ssoManaged (row) {
245+
return row.row.ssoManaged
239246
}
240247
}
241248
}

frontend/src/pages/team/dialogs/ChangeTeamRoleDialog.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ export default {
5151
alerts.emit("User's role successfully updated", 'confirmation')
5252
} catch (err) {
5353
console.warn(err)
54+
if (err.response?.status === 400 && err.response?.data.error === 'Cannot modify team membership for an SSO managed user') {
55+
alerts.emit('User\'s roles are managed by SSO Groups', 'warning', 5000)
56+
}
5457
}
5558
}
5659
}

test/unit/forge/ee/lib/sso/index_spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ d
399399
})
400400
it('ignores invalid role in group', async function () {
401401
// Validates that it ignores both unknown roles, but also roles that
402-
// exist but are not valid for a team membershipt (ie admin)
402+
// exist but are not valid for a team membership (ie admin)
403403

404404
// Starting state:
405405
// Alice owner ATeam

test/unit/forge/ee/routes/sso/index_spec.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ describe('SSO managed membership', async function () {
428428
response.statusCode.should.equal(400)
429429
const result = response.json()
430430
result.should.have.property('code', 'invalid_request')
431-
result.should.have.property('error', 'Cannot modify team membershipt for an SSO managed user')
431+
result.should.have.property('error', 'Cannot modify team membership for an SSO managed user')
432432
})
433433
it('cannot modify membership for SSO managed user/team', async function () {
434434
// BTeam is listed as a groupTeam in the SSO config
@@ -443,7 +443,7 @@ describe('SSO managed membership', async function () {
443443
response.statusCode.should.equal(400)
444444
const result = response.json()
445445
result.should.have.property('code', 'invalid_request')
446-
result.should.have.property('error', 'Cannot modify team membershipt for an SSO managed user')
446+
result.should.have.property('error', 'Cannot modify team membership for an SSO managed user')
447447
})
448448

449449
it('can delete membership for non-SSO managed user/team', async function () {
@@ -483,7 +483,7 @@ describe('SSO managed membership', async function () {
483483
response.statusCode.should.equal(400)
484484
const result = response.json()
485485
result.should.have.property('code', 'invalid_request')
486-
result.should.have.property('error', 'Cannot modify team membershipt for an SSO managed user')
486+
result.should.have.property('error', 'Cannot modify team membership for an SSO managed user')
487487
})
488488

489489
it('cannot modify membership for non-SSO managed user/team when groupAllTeams selected', async function () {
@@ -504,6 +504,6 @@ describe('SSO managed membership', async function () {
504504
response.statusCode.should.equal(400)
505505
const result = response.json()
506506
result.should.have.property('code', 'invalid_request')
507-
result.should.have.property('error', 'Cannot modify team membershipt for an SSO managed user')
507+
result.should.have.property('error', 'Cannot modify team membership for an SSO managed user')
508508
})
509509
})

0 commit comments

Comments
 (0)