Skip to content

Commit 731678c

Browse files
authored
[JENKINS-19409] use idstrategy to match role assignments (#332)
The matching of users to roles was so far case sensitive. But as most security realms work case insensitive this means that permissions are not properly matched when someone logs in with capital letters but the role is assigned to the user with small letters. The plugin now falls back to the security realms idstrategy in case the user doesn't match case sensitive. For backward compatibility reasons, this feature can be switched off.
1 parent 6a97d3b commit 731678c

File tree

4 files changed

+61
-4
lines changed

4 files changed

+61
-4
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,16 @@ jenkins.setAuthorizationStrategy(rbas)
123123
124124
jenkins.save()
125125
```
126+
127+
### Case sensitive mode
128+
In previous versions of this plugin, role assignments where always matched case-sensitive, even when the security realm
129+
works case-insensitive (as do most of them). As of version 685 the plugin will use the strategy given by the security realm
130+
to match assigned roles. If for some reason you need the old behaviour, set the property `com.michelin.cio.hudson.plugins.rolestrategy.RoleMap.FORCE_CASE_SENSITIVE`
131+
via command line `jenkins -Dcom.michelin.cio.hudson.plugins.rolestrategy.RoleMap.FORCE_CASE_SENSITIVE=true -war jenkins.war`, set it via the script console or via
132+
an init hook script.
133+
134+
135+
126136
## License
127137

128138
[MIT License](./LICENSE.md)

src/main/java/com/michelin/cio/hudson/plugins/rolestrategy/RoleMap.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import hudson.security.AccessControlled;
4242
import hudson.security.AuthorizationStrategy;
4343
import hudson.security.Permission;
44+
import hudson.security.SecurityRealm;
4445
import hudson.security.SidACL;
4546
import java.util.ArrayList;
4647
import java.util.Collections;
@@ -60,6 +61,7 @@
6061
import java.util.regex.Matcher;
6162
import java.util.regex.Pattern;
6263
import java.util.stream.Collectors;
64+
import jenkins.model.IdStrategy;
6365
import jenkins.model.Jenkins;
6466
import jenkins.model.ProjectNamingStrategy;
6567
import org.acegisecurity.acls.sid.PrincipalSid;
@@ -83,6 +85,10 @@
8385
*/
8486
public class RoleMap {
8587

88+
@SuppressFBWarnings("MS_SHOULD_BE_FINAL") // Used to allow old behaviour
89+
@Restricted(NoExternalUse.class)
90+
public static boolean FORCE_CASE_SENSITIVE = Boolean.getBoolean(RoleMap.class.getName() + ".FORCE_CASE_SENSITIVE");
91+
8692
/**
8793
* Map associating each {@link Role} with the concerned {@link User}s/groups.
8894
*/
@@ -133,6 +139,9 @@ public RoleMap(@NonNull SortedMap<Role, Set<PermissionEntry>> grantedRoles) {
133139
public boolean hasPermission(PermissionEntry sid, Permission permission, RoleType roleType, AccessControlled controlledItem) {
134140
final Set<Permission> permissions = getImplyingPermissions(permission);
135141
final boolean[] hasPermission = { false };
142+
final SecurityRealm securityRealm = Jenkins.get().getSecurityRealm();
143+
final boolean principal = sid.getType() == AuthorizationType.USER;
144+
final IdStrategy strategy = principal ? securityRealm.getUserIdStrategy() : securityRealm.getGroupIdStrategy();
136145

137146
// Walk through the roles, and only add the roles having the given permission,
138147
// or a permission implying the given permission
@@ -149,12 +158,20 @@ public boolean hasPermission(PermissionEntry sid, Permission permission, RoleTyp
149158
*/
150159
@CheckForNull
151160
private PermissionEntry hasPermission(Role current, PermissionEntry entry) {
152-
if (grantedRoles.get(current).contains(entry)) {
161+
Set<PermissionEntry> entries = grantedRoles.get(current);
162+
if (entries.contains(entry)) {
153163
return entry;
154164
}
155-
entry = new PermissionEntry(AuthorizationType.EITHER, entry.getSid());
156-
if (grantedRoles.get(current).contains(entry)) {
157-
return entry;
165+
PermissionEntry eitherEntry = new PermissionEntry(AuthorizationType.EITHER, entry.getSid());
166+
if (entries.contains(eitherEntry)) {
167+
return eitherEntry;
168+
}
169+
if (!FORCE_CASE_SENSITIVE) {
170+
for (PermissionEntry pe : entries) {
171+
if (pe.isApplicable(principal) && strategy.equals(pe.getSid(), entry.getSid())) {
172+
return pe;
173+
}
174+
}
158175
}
159176
return null;
160177
}

src/test/java/org/jenkinsci/plugins/rolestrategy/RoleStrategyTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
import static org.hamcrest.MatcherAssert.assertThat;
44
import static org.hamcrest.Matchers.is;
5+
import static org.junit.Assert.assertFalse;
56
import static org.junit.Assert.assertTrue;
67

78
import com.michelin.cio.hudson.plugins.rolestrategy.RoleBasedAuthorizationStrategy;
9+
import com.michelin.cio.hudson.plugins.rolestrategy.RoleMap;
810
import com.synopsys.arc.jenkins.plugins.rolestrategy.RoleType;
911
import hudson.PluginManager;
1012
import hudson.model.User;
@@ -31,11 +33,39 @@ public void initSecurityRealm() {
3133
@LocalData
3234
@Test
3335
public void testRoleAssignment() {
36+
RoleMap.FORCE_CASE_SENSITIVE = false;
3437
try (ACLContext c = ACL.as(User.getById("alice", true))) {
3538
assertTrue(jenkinsRule.jenkins.hasPermission(Permission.READ));
3639
}
3740
}
3841

42+
@LocalData
43+
@Test
44+
public void testRoleAssignmentCaseInsensitiveNoMatchSucceeds() {
45+
RoleMap.FORCE_CASE_SENSITIVE = false;
46+
try (ACLContext c = ACL.as(User.getById("Alice", true))) {
47+
assertTrue(jenkinsRule.jenkins.hasPermission(Permission.READ));
48+
}
49+
}
50+
51+
@LocalData
52+
@Test
53+
public void testRoleAssignmentCaseSensitiveMatch() {
54+
RoleMap.FORCE_CASE_SENSITIVE = true;
55+
try (ACLContext c = ACL.as(User.getById("alice", true))) {
56+
assertTrue(jenkinsRule.jenkins.hasPermission(Permission.READ));
57+
}
58+
}
59+
60+
@LocalData
61+
@Test
62+
public void testRoleAssignmentCaseSensitiveNoMatchFails() {
63+
RoleMap.FORCE_CASE_SENSITIVE = true;
64+
try (ACLContext c = ACL.as(User.getById("Alice", true))) {
65+
assertFalse(jenkinsRule.jenkins.hasPermission(Permission.READ));
66+
}
67+
}
68+
3969
@LocalData
4070
@Test
4171
public void dangerousPermissionsAreIgnored() {

src/test/resources/org/jenkinsci/plugins/rolestrategy/RoleStrategyTest/testRoleAssignment/config.xml renamed to src/test/resources/org/jenkinsci/plugins/rolestrategy/RoleStrategyTest/config.xml

File renamed without changes.

0 commit comments

Comments
 (0)