Skip to content

Commit 8aae4bd

Browse files
Remove dependency to matrix-auth plugin (#172)
* remove dependency to matrix-auth the only thing used from matrix-auth was the validation of user names Since matrix auth added a separation between users and groups the UI was broken when matrix-auth 3.0 or newer was installed. * fix icon * Update src/main/java/com/michelin/cio/hudson/plugins/rolestrategy/RoleBasedAuthorizationStrategy.java Co-authored-by: Alexander Stohr <[email protected]> * dedup code for image * require a post to for checking name * use POST to check the names need to align with the RequirePOST on the doCheckName method in the descriptor * use iconset and icon classes avoids the differentiation of jenkins version * use the qualified url of the icon Co-authored-by: Alexander Stohr <[email protected]>
1 parent 1728196 commit 8aae4bd

File tree

7 files changed

+116
-17
lines changed

7 files changed

+116
-17
lines changed

pom.xml

+4-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>org.jenkins-ci.plugins</groupId>
66
<artifactId>plugin</artifactId>
7-
<version>4.18</version>
7+
<version>4.40</version>
88
<relativePath />
99
</parent>
1010

@@ -41,8 +41,7 @@
4141

4242
<properties>
4343
<changelist>999999-SNAPSHOT</changelist>
44-
<jenkins.version>2.222.4</jenkins.version>
45-
<java.level>8</java.level>
44+
<jenkins.version>2.303.1</jenkins.version>
4645
<useBeta>true</useBeta>
4746
</properties>
4847

@@ -72,19 +71,15 @@
7271
<dependencies>
7372
<dependency>
7473
<groupId>io.jenkins.tools.bom</groupId>
75-
<artifactId>bom-2.222.x</artifactId>
76-
<version>887.vae9c8ac09ff7</version>
74+
<artifactId>bom-2.303.x</artifactId>
75+
<version>1362.v59f2f3db_80ee</version>
7776
<scope>import</scope>
7877
<type>pom</type>
7978
</dependency>
8079
</dependencies>
8180
</dependencyManagement>
8281

8382
<dependencies>
84-
<dependency>
85-
<groupId>org.jenkins-ci.plugins</groupId>
86-
<artifactId>matrix-auth</artifactId>
87-
</dependency>
8883
<dependency>
8984
<groupId>io.jenkins.plugins</groupId>
9085
<artifactId>caffeine-api</artifactId>

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

+73-4
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,33 @@
3030
import com.thoughtworks.xstream.converters.Converter;
3131
import com.thoughtworks.xstream.converters.MarshallingContext;
3232
import com.thoughtworks.xstream.converters.UnmarshallingContext;
33+
import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamReader;
3334
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
3435
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
3536
import edu.umd.cs.findbugs.annotations.CheckForNull;
3637
import edu.umd.cs.findbugs.annotations.NonNull;
3738
import edu.umd.cs.findbugs.annotations.Nullable;
3839
import hudson.Extension;
40+
import hudson.Functions;
41+
import hudson.Util;
3942
import hudson.model.AbstractItem;
4043
import hudson.model.Computer;
44+
import hudson.model.Descriptor;
4145
import hudson.model.Hudson;
4246
import hudson.model.Item;
4347
import hudson.model.Job;
4448
import hudson.model.Run;
49+
import hudson.model.User;
4550
import hudson.model.View;
4651
import hudson.scm.SCM;
4752
import hudson.security.ACL;
53+
import hudson.security.AccessControlled;
4854
import hudson.security.AuthorizationStrategy;
49-
import hudson.security.GlobalMatrixAuthorizationStrategy;
5055
import hudson.security.Permission;
5156
import hudson.security.PermissionGroup;
57+
import hudson.security.SecurityRealm;
5258
import hudson.security.SidACL;
59+
import hudson.security.UserMayOrMayNotExistException2;
5360
import java.io.IOException;
5461
import javax.servlet.ServletException;
5562

@@ -64,12 +71,15 @@
6471
import java.util.Map;
6572
import java.util.Set;
6673
import java.util.SortedMap;
74+
import java.util.logging.Level;
75+
import java.util.logging.Logger;
6776
import java.util.regex.Pattern;
6877

6978
import hudson.util.FormValidation;
7079
import jenkins.model.Jenkins;
7180
import net.sf.json.JSONObject;
7281
import org.acegisecurity.acls.sid.PrincipalSid;
82+
import org.apache.commons.lang.StringUtils;
7383
import org.jenkinsci.plugins.rolestrategy.permissions.PermissionHelper;
7484
import org.kohsuke.accmod.Restricted;
7585
import org.kohsuke.accmod.restrictions.NoExternalUse;
@@ -78,6 +88,8 @@
7888
import org.kohsuke.stapler.StaplerRequest;
7989
import org.kohsuke.stapler.StaplerResponse;
8090
import org.kohsuke.stapler.interceptor.RequirePOST;
91+
import org.springframework.security.core.AuthenticationException;
92+
import org.springframework.security.core.userdetails.UsernameNotFoundException;
8193

8294
/**
8395
* Role-based authorization strategy.
@@ -517,10 +529,12 @@ public void doGetMatchingJobs(@QueryParameter(required = true) String pattern,
517529
* update the getRoleMaps() method.</p>
518530
*/
519531
public static class ConverterImpl implements Converter {
532+
@Override
520533
public boolean canConvert(Class type) {
521534
return type==RoleBasedAuthorizationStrategy.class;
522535
}
523536

537+
@Override
524538
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
525539
RoleBasedAuthorizationStrategy strategy = (RoleBasedAuthorizationStrategy)source;
526540

@@ -561,6 +575,7 @@ public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingC
561575
}
562576
}
563577

578+
@Override
564579
public Object unmarshal(HierarchicalStreamReader reader, final UnmarshallingContext context) {
565580
final Map<String, RoleMap> roleMaps = new HashMap<>();
566581
while(reader.hasMoreChildren()) {
@@ -576,7 +591,7 @@ public Object unmarshal(HierarchicalStreamReader reader, final UnmarshallingCont
576591
String pattern = reader.getAttribute("pattern");
577592
Set<Permission> permissions = new HashSet<>();
578593

579-
String next = reader.peekNextChild();
594+
String next = ((ExtendedHierarchicalStreamReader) reader).peekNextChild();
580595
if (next != null && next.equals("permissions")) {
581596
reader.moveDown();
582597
while(reader.hasMoreChildren()) {
@@ -593,7 +608,7 @@ public Object unmarshal(HierarchicalStreamReader reader, final UnmarshallingCont
593608
Role role = new Role(name, pattern, permissions);
594609
map.addRole(role);
595610

596-
next = reader.peekNextChild();
611+
next = ((ExtendedHierarchicalStreamReader) reader).peekNextChild();
597612
if (next != null && next.equals("assignedSIDs")) {
598613
reader.moveDown();
599614
while(reader.hasMoreChildren()) {
@@ -665,7 +680,7 @@ public static boolean isCreateAllowed(){
665680
/**
666681
* Descriptor used to bind the strategy to the Web forms.
667682
*/
668-
public static final class DescriptorImpl extends GlobalMatrixAuthorizationStrategy.DescriptorImpl {
683+
public static final class DescriptorImpl extends Descriptor<AuthorizationStrategy> {
669684

670685
@Override
671686
@NonNull
@@ -924,5 +939,59 @@ public boolean showPermission(String type, Permission p) {
924939
return false;
925940
}
926941
}
942+
943+
@RequirePOST
944+
public FormValidation doCheckName(@QueryParameter String value) {
945+
final String v = value.substring(1,value.length()-1);
946+
String ev = Functions.escape(v);
947+
948+
if (!Jenkins.get().hasPermission(Jenkins.ADMINISTER)) return FormValidation.ok(ev); // can't check
949+
950+
SecurityRealm sr = Jenkins.get().getSecurityRealm();
951+
952+
if (v.equals("authenticated")) {
953+
// system reserved group
954+
return FormValidation.respond(FormValidation.Kind.OK, ValidationUtil.formatUserGroupValidationResponse("user", ev, "Group"));
955+
}
956+
957+
try {
958+
try {
959+
sr.loadUserByUsername2(v);
960+
User u = User.getById(v, true);
961+
if (v.equals(u.getFullName())) {
962+
return FormValidation.respond(FormValidation.Kind.OK, ValidationUtil.formatUserGroupValidationResponse("person", ev, "User"));
963+
}
964+
return FormValidation.respond(FormValidation.Kind.OK, ValidationUtil.formatUserGroupValidationResponse("person", Util.escape(StringUtils.abbreviate(u.getFullName(), 50)), "User " + ev));
965+
} catch (UserMayOrMayNotExistException2 e) {
966+
// undecidable, meaning the user may exist
967+
return FormValidation.respond(FormValidation.Kind.OK, ev);
968+
} catch (UsernameNotFoundException e) {
969+
// fall through next
970+
} catch (AuthenticationException e) {
971+
// other seemingly unexpected error.
972+
return FormValidation.error(e,"Failed to test the validity of the user name "+v);
973+
}
974+
975+
try {
976+
sr.loadGroupByGroupname2(v, false);
977+
return FormValidation.respond(FormValidation.Kind.OK, ValidationUtil.formatUserGroupValidationResponse("user", ev, "Group"));
978+
} catch (UserMayOrMayNotExistException2 e) {
979+
// undecidable, meaning the group may exist
980+
return FormValidation.respond(FormValidation.Kind.WARNING, v);
981+
} catch (UsernameNotFoundException e) {
982+
// fall through next
983+
} catch (AuthenticationException e) {
984+
// other seemingly unexpected error.
985+
return FormValidation.error(e,"Failed to test the validity of the group name "+v);
986+
}
987+
988+
// couldn't find it. it doesn't exist
989+
return FormValidation.respond(FormValidation.Kind.ERROR, ValidationUtil.formatNonExistentUserGroupValidationResponse(ev, "User or group not found")); // TODO i18n
990+
} catch (Exception e) {
991+
// if the check fails miserably, we still want the user to be able to see the name of the user,
992+
// so use 'ev' as the message
993+
return FormValidation.error(e,ev);
994+
}
995+
}
927996
}
928997
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.michelin.cio.hudson.plugins.rolestrategy;
2+
3+
import org.apache.commons.jelly.JellyContext;
4+
import org.jenkins.ui.icon.Icon;
5+
import org.jenkins.ui.icon.IconSet;
6+
import org.kohsuke.accmod.Restricted;
7+
import org.kohsuke.accmod.restrictions.NoExternalUse;
8+
import org.kohsuke.stapler.Stapler;
9+
10+
import jenkins.model.Jenkins;
11+
12+
@Restricted(NoExternalUse.class)
13+
class ValidationUtil {
14+
private ValidationUtil() {
15+
// do not use
16+
}
17+
18+
static String formatNonExistentUserGroupValidationResponse(String user, String tooltip) {
19+
return formatUserGroupValidationResponse(null, "<span style='text-decoration: line-through; color: grey;'>" + user + "</span>", tooltip);
20+
}
21+
22+
static String formatUserGroupValidationResponse(String img, String user, String tooltip) {
23+
if (img == null) {
24+
return String.format("<span title='%s'>%s</span>", tooltip, user);
25+
}
26+
27+
String imageFormat = String.format("icon-%s icon-sm", img);
28+
Icon icon = IconSet.icons.getIconByClassSpec(imageFormat);
29+
JellyContext ctx = new JellyContext();
30+
ctx.setVariable("resURL", Stapler.getCurrentRequest().getContextPath() + Jenkins.RESOURCE_PATH);
31+
String url = icon.getQualifiedUrl(ctx);
32+
return String.format("<span title='%s'><img src='%s' style='%s margin-right:0.2em'>%s</span>",
33+
tooltip, url, icon.getStyle(), user);
34+
}
35+
}

src/main/resources/com/michelin/cio/hudson/plugins/rolestrategy/RoleStrategyConfig/assign-global-roles.jelly

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@
149149
"#globalRoles TD.start A" : deleteAssignedGlobalRole,
150150
"#globalRoles TD.stop A" : deleteAssignedGlobalRole,
151151
"#globalRoles TR.permission-row" : function(e) {
152-
FormChecker.delayedCheck("${descriptorPath}/checkName?value="+encodeURIComponent(e.getAttribute("name")),"GET",e.childNodes[1]);
152+
FormChecker.delayedCheck("${descriptorPath}/checkName?value="+encodeURIComponent(e.getAttribute("name")),"POST",e.childNodes[1]);
153153
}
154154
});
155155
</script>

src/main/resources/com/michelin/cio/hudson/plugins/rolestrategy/RoleStrategyConfig/assign-project-roles.jelly

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@
150150
"#projectRoles TD.start A" : deleteAssignedProjectRole,
151151
"#projectRoles TD.stop A" : deleteAssignedProjectRole,
152152
"#projectRoles TR.permission-row" : function(e) {
153-
FormChecker.delayedCheck("${descriptorPath}/checkName?value="+encodeURIComponent(e.getAttribute("name")),"GET",e.childNodes[1]);
153+
FormChecker.delayedCheck("${descriptorPath}/checkName?value="+encodeURIComponent(e.getAttribute("name")),"POST",e.childNodes[1]);
154154
}
155155
});
156156
</script>

src/main/resources/com/michelin/cio/hudson/plugins/rolestrategy/RoleStrategyConfig/assign-slave-roles.jelly

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@
151151
"#slaveRoles TD.start A" : deleteAssignedSlaveRole,
152152
"#slaveRoles TD.stop A" : deleteAssignedSlaveRole,
153153
"#slaveRoles TR.permission-row" : function(e) {
154-
FormChecker.delayedCheck("${descriptorPath}/checkName?value="+encodeURIComponent(e.getAttribute("name")),"GET",e.childNodes[1]);
154+
FormChecker.delayedCheck("${descriptorPath}/checkName?value="+encodeURIComponent(e.getAttribute("name")),"POST",e.childNodes[1]);
155155
}
156156
});
157157
</script>

src/main/resources/com/michelin/cio/hudson/plugins/rolestrategy/RoleStrategyConfig/manage-roles.jelly

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191

9292
<f:form method="post" name="config" action="rolesSubmit">
9393
<h1>
94-
<l:icon src="icon-fingerprint icon-xlg" alt="${it.displayName}" />
94+
<l:icon class="icon-fingerprint icon-xlg" alt="${it.displayName}" />
9595
${it.manageRolesName}
9696
</h1>
9797

0 commit comments

Comments
 (0)