Skip to content

Commit 4d6fad0

Browse files
Fix bugzilla 15077030 where deleting a rolebinding for a serviceaccount can delete additional rolebindings for serviceaccounts from another namespace
1 parent 9b48a7b commit 4d6fad0

File tree

6 files changed

+87
-25
lines changed

6 files changed

+87
-25
lines changed

app/scripts/controllers/membership.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,8 @@ angular
274274
project: project,
275275
subjectKinds: subjectKinds,
276276
canUpdateRolebindings: canI('rolebindings', 'update', projectName),
277-
confirmRemove: function(subjectName, kindName, roleName) {
277+
confirmRemove: function(subjectName, kindName, roleName, namespace) {
278+
278279
var redirectToProjectList = null;
279280
var modalScope = createModalScope(subjectName, kindName, roleName, $scope.user.metadata.name);
280281
if(_.isEqual(subjectName, $scope.user.metadata.name)) {
@@ -294,7 +295,7 @@ angular
294295
})
295296
.result.then(function() {
296297
RoleBindingsService
297-
.removeSubject(subjectName, roleName, $scope.roleBindings, requestContext)
298+
.removeSubject(subjectName, roleName, namespace, $scope.roleBindings, requestContext)
298299
.then(function(updateRolebinding) {
299300
if(redirectToProjectList) {
300301
$location.url("./");

app/scripts/services/membership/roleBindings.js

+12-5
Original file line numberDiff line numberDiff line change
@@ -87,20 +87,27 @@ angular
8787
};
8888

8989
// has to handle multiple bindings or multiple reference to a subject within a single binding
90-
var removeSubject = function(subjectName, role, roleBindings, context) {
91-
var matches = _.filter(roleBindings, {roleRef: {name: role}});
90+
var removeSubject = function(subjectName, role, namespace, roleBindings, context) {
91+
var matchingBindings = _.filter(roleBindings, {roleRef: {name: role}});
92+
9293
return $q.all(
93-
_.map(matches, function(binding) {
94+
_.map(matchingBindings, function(binding) {
9495
var tpl = bindingTPL();
9596
binding = _.extend(tpl, binding);
9697
cleanBinding(binding);
97-
binding.subjects = _.reject(binding.subjects, {name: subjectName});
98+
var toMatch = { name: subjectName };
99+
if(namespace) {
100+
toMatch.namespace = namespace;
101+
}
102+
103+
binding.subjects = _.reject(binding.subjects, toMatch);
104+
98105
return binding.subjects.length ?
99106
DataService.update('rolebindings', binding.metadata.name, binding, context) :
100107
DataService.delete('rolebindings', binding.metadata.name, context)
101108
// For a delete, resp is simply a 201 or less useful object.
102109
// Instead, this intercepts the response & returns the binding object
103-
// with the empty .subjects[] list.
110+
// with the empty .subjects[] list.
104111
.then(function() {
105112
return binding;
106113
});

app/views/membership.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ <h3>
113113
key="role.metadata.name"
114114
key-help="roleHelp(role)"
115115
show-action="mode.edit"
116-
action="confirmRemove(subject.name, subjectKind.name, role.metadata.name)"
116+
action="confirmRemove(subject.name, subjectKind.name, role.metadata.name, subject.namespace)"
117117
action-title="Remove role {{role.metadata.name}} from {{subject.name}}"></action-chip>
118118
</div>
119119
<div

dist/scripts/scripts.js

+13-11
Original file line numberDiff line numberDiff line change
@@ -2514,17 +2514,19 @@ l.subjects.push(n);
25142514
} else l.subjects = [ n ];
25152515
return i(l), t.update("rolebindings", l.metadata.name, l, s);
25162516
},
2517-
removeSubject: function(n, a, o, s) {
2518-
var c = _.filter(o, {
2517+
removeSubject: function(n, a, o, s, c) {
2518+
var l = _.filter(s, {
25192519
roleRef: {
25202520
name: a
25212521
}
25222522
});
2523-
return e.all(_.map(c, function(e) {
2523+
return e.all(_.map(l, function(e) {
25242524
var a = r();
2525-
return e = _.extend(a, e), i(e), e.subjects = _.reject(e.subjects, {
2525+
e = _.extend(a, e), i(e);
2526+
var s = {
25262527
name: n
2527-
}), e.subjects.length ? t.update("rolebindings", e.metadata.name, e, s) : t.delete("rolebindings", e.metadata.name, s).then(function() {
2528+
};
2529+
return o && (s.namespace = o), e.subjects = _.reject(e.subjects, s), e.subjects.length ? t.update("rolebindings", e.metadata.name, e, c) : t.delete("rolebindings", e.metadata.name, c).then(function() {
25282530
return e;
25292531
});
25302532
}));
@@ -5222,20 +5224,20 @@ f = r, P(), k(f), angular.extend(a, {
52225224
project: n,
52235225
subjectKinds: E,
52245226
canUpdateRolebindings: y("rolebindings", "update", g),
5225-
confirmRemove: function(n, r, i) {
5226-
var c = null, l = T(n, r, i, a.user.metadata.name);
5227-
_.isEqual(n, a.user.metadata.name) && u.isLastRole(a.user.metadata.name, a.roleBindings) && (c = !0), o.open({
5227+
confirmRemove: function(n, r, i, c) {
5228+
var l = null, d = T(n, r, i, a.user.metadata.name);
5229+
_.isEqual(n, a.user.metadata.name) && u.isLastRole(a.user.metadata.name, a.roleBindings) && (l = !0), o.open({
52285230
animation: !0,
52295231
templateUrl: "views/modals/confirm.html",
52305232
controller: "ConfirmModalController",
52315233
resolve: {
52325234
modalConfig: function() {
5233-
return l;
5235+
return d;
52345236
}
52355237
}
52365238
}).result.then(function() {
5237-
m.removeSubject(n, i, a.roleBindings, f).then(function(e) {
5238-
c ? t.url("./") : (s.getProjectRules(g, !0).then(function() {
5239+
m.removeSubject(n, i, c, a.roleBindings, f).then(function(e) {
5240+
l ? t.url("./") : (s.getProjectRules(g, !0).then(function() {
52395241
P(e[0]);
52405242
var t = y("rolebindings", "update", g);
52415243
angular.extend(a, {

dist/scripts/templates.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10702,7 +10702,7 @@ angular.module('openshiftConsoleTemplates', []).run(['$templateCache', function(
1070210702
"</div>\n" +
1070310703
"<div class=\"action-set\">\n" +
1070410704
"<div class=\"col-roles\">\n" +
10705-
"<action-chip ng-repeat=\"role in subject.roles\" key=\"role.metadata.name\" key-help=\"roleHelp(role)\" show-action=\"mode.edit\" action=\"confirmRemove(subject.name, subjectKind.name, role.metadata.name)\" action-title=\"Remove role {{role.metadata.name}} from {{subject.name}}\"></action-chip>\n" +
10705+
"<action-chip ng-repeat=\"role in subject.roles\" key=\"role.metadata.name\" key-help=\"roleHelp(role)\" show-action=\"mode.edit\" action=\"confirmRemove(subject.name, subjectKind.name, role.metadata.name, subject.namespace)\" action-title=\"Remove role {{role.metadata.name}} from {{subject.name}}\"></action-chip>\n" +
1070610706
"</div>\n" +
1070710707
"<div ng-if=\"mode.edit\" class=\"col-add-role\">\n" +
1070810708
"<div row>\n" +

test/spec/services/membership/roleBindingsSpec.js

+57-5
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,13 @@ describe('RoleBindingsService', function() {
8888
it('should update the rolebinding by removing the subject from the subject list', function() {
8989
var bindings = [{
9090
roleRef: { name: 'admin'},
91-
subjects: [{name: 'jane', kind: 'user'}, {name: 'jack', kind: 'user'}]
91+
subjects: [
92+
{name: 'jane', kind: 'user'},
93+
{name: 'jack', kind: 'user'}
94+
]
9295
}];
9396
RoleBindingsService
94-
.removeSubject('jane', 'admin', bindings)
97+
.removeSubject('jane', 'admin', null, bindings)
9598
.then(function(resp) {
9699
expect(resp[0].subjects).toEqual([{
97100
name: 'jack',
@@ -102,13 +105,62 @@ describe('RoleBindingsService', function() {
102105
$rootScope.$digest();
103106
});
104107

108+
// TODO: cover this case
109+
it('should honor the namespace of a subject if provided', function() {
110+
var bindings = [{
111+
roleRef: { name: 'admin'},
112+
subjects: [
113+
// multiple jim, only one should be removed in test 1
114+
{name: 'jim', kind: 'user'},
115+
{name: 'jim', kind: 'user', namespace: 'yourproject'},
116+
{name: 'jim', kind: 'user', namespace: 'myproject'},
117+
{name: 'jack', kind: 'user'}
118+
]
119+
}, {
120+
roleRef: { name: 'view'},
121+
subjects: [
122+
// multiple jane, only one should be removed in test 2
123+
{name: 'jane', kind: 'user', namespace: 'myproject'},
124+
{name: 'jack', kind: 'user', namespace: 'yourproject'},
125+
{name: 'jane', kind: 'user', namespace: 'herproject'},
126+
{name: 'jack', kind: 'user', namespace: 'hisproject'}
127+
]
128+
}];
129+
130+
// test 1
131+
RoleBindingsService
132+
.removeSubject('jim', 'admin', 'myproject', bindings)
133+
.then(function(resp) {
134+
expect(resp[0].subjects).toEqual([
135+
{name: 'jim', kind: 'user'},
136+
{name: 'jim', kind: 'user', namespace: 'yourproject'},
137+
{name: 'jack', kind: 'user'}
138+
]);
139+
140+
});
141+
142+
// test 2
143+
RoleBindingsService
144+
.removeSubject('jane', 'view', 'herproject', bindings)
145+
.then(function(resp) {
146+
expect(resp[0].subjects).toEqual([
147+
{name: 'jane', kind: 'user', namespace: 'myproject'},
148+
{name: 'jack', kind: 'user', namespace: 'yourproject'},
149+
{name: 'jack', kind: 'user', namespace: 'hisproject'}
150+
]);
151+
});
152+
// resolve $q.all() via digest loop
153+
$rootScope.$digest();
154+
155+
});
156+
105157
it('should delete the rolebinding if the removed subject was the only subject', function() {
106158
var bindings = [{
107159
roleRef: { name: 'admin'},
108160
subjects: [{name: 'jane', kind: 'user'}]
109161
}];
110162
RoleBindingsService
111-
.removeSubject('jane', 'admin', bindings)
163+
.removeSubject('jane', 'admin', null, bindings)
112164
.then(function(resp) {
113165
expect(resp[0]).toBe(undefined);
114166
});
@@ -130,7 +182,7 @@ describe('RoleBindingsService', function() {
130182
subjects: [{name: 'jane', kind: 'user'}, {name: 'jack', kind: 'user'}]
131183
}];
132184
RoleBindingsService
133-
.removeSubject('jane', 'admin', bindings)
185+
.removeSubject('jane', 'admin', null, bindings)
134186
.then(function(resp) {
135187
_.each(resp, function(roleBinding) {
136188
expect(roleBinding.subjects).toEqual([ {name: 'jack', kind: 'user'}]);
@@ -154,7 +206,7 @@ describe('RoleBindingsService', function() {
154206
subjects: [{name: 'jane', kind: 'user'}]
155207
}];
156208
RoleBindingsService
157-
.removeSubject('jane', 'admin', bindings)
209+
.removeSubject('jane', 'admin', null, bindings)
158210
.then(function(resp) {
159211
expect(resp[0]).toBe(undefined);
160212
expect(resp[1].subjects).toEqual([ {name: 'jack', kind: 'user'}]);

0 commit comments

Comments
 (0)