Skip to content

Commit dad6a0d

Browse files
Merge pull request #2406 from benjaminapetersen/bugzilla/1507730/serviceaccount-rolebinding-double-delete
Automatic merge from submit-queue. Fix bugzilla 15077030 rolebindings for serviceaccounts Fix bugzilla 15077030 where deleting a rolebinding for a serviceaccount can delete additional rolebindings for serviceaccounts from another namespace. Hopefully will follow-up with some tests soon. Time elapse is def showing some subtle bugs here.
2 parents 685f44d + b54162a commit dad6a0d

File tree

6 files changed

+86
-25
lines changed

6 files changed

+86
-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
}));
@@ -5218,20 +5220,20 @@ f = r, P(), k(f), angular.extend(a, {
52185220
project: n,
52195221
subjectKinds: E,
52205222
canUpdateRolebindings: y("rolebindings", "update", g),
5221-
confirmRemove: function(n, r, i) {
5222-
var c = null, l = T(n, r, i, a.user.metadata.name);
5223-
_.isEqual(n, a.user.metadata.name) && u.isLastRole(a.user.metadata.name, a.roleBindings) && (c = !0), o.open({
5223+
confirmRemove: function(n, r, i, c) {
5224+
var l = null, d = T(n, r, i, a.user.metadata.name);
5225+
_.isEqual(n, a.user.metadata.name) && u.isLastRole(a.user.metadata.name, a.roleBindings) && (l = !0), o.open({
52245226
animation: !0,
52255227
templateUrl: "views/modals/confirm.html",
52265228
controller: "ConfirmModalController",
52275229
resolve: {
52285230
modalConfig: function() {
5229-
return l;
5231+
return d;
52305232
}
52315233
}
52325234
}).result.then(function() {
5233-
m.removeSubject(n, i, a.roleBindings, f).then(function(e) {
5234-
c ? t.url("./") : (s.getProjectRules(g, !0).then(function() {
5235+
m.removeSubject(n, i, c, a.roleBindings, f).then(function(e) {
5236+
l ? t.url("./") : (s.getProjectRules(g, !0).then(function() {
52355237
P(e[0]);
52365238
var t = y("rolebindings", "update", g);
52375239
angular.extend(a, {

dist/scripts/templates.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10703,7 +10703,7 @@ angular.module('openshiftConsoleTemplates', []).run(['$templateCache', function(
1070310703
"</div>\n" +
1070410704
"<div class=\"action-set\">\n" +
1070510705
"<div class=\"col-roles\">\n" +
10706-
"<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" +
10706+
"<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" +
1070710707
"</div>\n" +
1070810708
"<div ng-if=\"mode.edit\" class=\"col-add-role\">\n" +
1070910709
"<div row>\n" +

test/spec/services/membership/roleBindingsSpec.js

+56-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,61 @@ describe('RoleBindingsService', function() {
102105
$rootScope.$digest();
103106
});
104107

108+
it('should honor the namespace of a subject if provided', function() {
109+
var bindings = [{
110+
roleRef: { name: 'admin'},
111+
subjects: [
112+
// multiple jim, only one should be removed in test 1
113+
{name: 'jim', kind: 'user'},
114+
{name: 'jim', kind: 'user', namespace: 'yourproject'},
115+
{name: 'jim', kind: 'user', namespace: 'myproject'},
116+
{name: 'jack', kind: 'user'}
117+
]
118+
}, {
119+
roleRef: { name: 'view'},
120+
subjects: [
121+
// multiple jane, only one should be removed in test 2
122+
{name: 'jane', kind: 'user', namespace: 'myproject'},
123+
{name: 'jack', kind: 'user', namespace: 'yourproject'},
124+
{name: 'jane', kind: 'user', namespace: 'herproject'},
125+
{name: 'jack', kind: 'user', namespace: 'hisproject'}
126+
]
127+
}];
128+
129+
// test 1
130+
RoleBindingsService
131+
.removeSubject('jim', 'admin', 'myproject', bindings)
132+
.then(function(resp) {
133+
expect(resp[0].subjects).toEqual([
134+
{name: 'jim', kind: 'user'},
135+
{name: 'jim', kind: 'user', namespace: 'yourproject'},
136+
{name: 'jack', kind: 'user'}
137+
]);
138+
139+
});
140+
141+
// test 2
142+
RoleBindingsService
143+
.removeSubject('jane', 'view', 'herproject', bindings)
144+
.then(function(resp) {
145+
expect(resp[0].subjects).toEqual([
146+
{name: 'jane', kind: 'user', namespace: 'myproject'},
147+
{name: 'jack', kind: 'user', namespace: 'yourproject'},
148+
{name: 'jack', kind: 'user', namespace: 'hisproject'}
149+
]);
150+
});
151+
// resolve $q.all() via digest loop
152+
$rootScope.$digest();
153+
154+
});
155+
105156
it('should delete the rolebinding if the removed subject was the only subject', function() {
106157
var bindings = [{
107158
roleRef: { name: 'admin'},
108159
subjects: [{name: 'jane', kind: 'user'}]
109160
}];
110161
RoleBindingsService
111-
.removeSubject('jane', 'admin', bindings)
162+
.removeSubject('jane', 'admin', null, bindings)
112163
.then(function(resp) {
113164
expect(resp[0]).toBe(undefined);
114165
});
@@ -130,7 +181,7 @@ describe('RoleBindingsService', function() {
130181
subjects: [{name: 'jane', kind: 'user'}, {name: 'jack', kind: 'user'}]
131182
}];
132183
RoleBindingsService
133-
.removeSubject('jane', 'admin', bindings)
184+
.removeSubject('jane', 'admin', null, bindings)
134185
.then(function(resp) {
135186
_.each(resp, function(roleBinding) {
136187
expect(roleBinding.subjects).toEqual([ {name: 'jack', kind: 'user'}]);
@@ -154,7 +205,7 @@ describe('RoleBindingsService', function() {
154205
subjects: [{name: 'jane', kind: 'user'}]
155206
}];
156207
RoleBindingsService
157-
.removeSubject('jane', 'admin', bindings)
208+
.removeSubject('jane', 'admin', null, bindings)
158209
.then(function(resp) {
159210
expect(resp[0]).toBe(undefined);
160211
expect(resp[1].subjects).toEqual([ {name: 'jack', kind: 'user'}]);

0 commit comments

Comments
 (0)