From a7a7ec8f5e388fdeaadbd2868aaba5326f27f93a Mon Sep 17 00:00:00 2001 From: jpederzolli Date: Wed, 9 Jun 2010 22:07:05 +0000 Subject: [PATCH] Issue: HUDSON-6587 restore container based SLI authentication git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@31878 71c3de6d-444a-0410-be80-ed276b4c234a --- core/src/main/java/hudson/cli/CLICommand.java | 17 ++--- .../main/java/hudson/cli/CliManagerImpl.java | 31 ++++++--- .../main/java/hudson/cli/GroovyshCommand.java | 65 ++++++++++++++----- .../hudson/cli/declarative/CLIRegisterer.java | 5 +- core/src/main/java/hudson/model/Hudson.java | 3 +- .../hudson/security/LegacySecurityRealm.java | 27 ++++++-- .../java/hudson/security/SecurityRealm.java | 16 +++++ .../model/listeners/ItemListenerTest.java | 2 +- 8 files changed, 120 insertions(+), 46 deletions(-) diff --git a/core/src/main/java/hudson/cli/CLICommand.java b/core/src/main/java/hudson/cli/CLICommand.java index 2503ccd082..c02fae0b8e 100644 --- a/core/src/main/java/hudson/cli/CLICommand.java +++ b/core/src/main/java/hudson/cli/CLICommand.java @@ -60,7 +60,7 @@ import java.util.logging.Logger; * *

* The Hudson master then picks the right {@link CLICommand} to execute, clone it, and - * calls {@link #main(List, Locale, InputStream, PrintStream, PrintStream)} method. + * calls {@link #main(List, Locale, InputStream, PrintStream, PrintStream, Authentication)} method. * *

Note for CLI command implementor

* Start with this document @@ -73,7 +73,7 @@ import java.util.logging.Logger; *
  • * Use args4j annotation on your implementation to define * options and arguments (however, if you don't like that, you could override - * the {@link #main(List, Locale, InputStream, PrintStream, PrintStream)} method directly. + * the {@link #main(List, Locale, InputStream, PrintStream, PrintStream, Authentication)} method directly. * *
  • * stdin, stdout, stderr are remoted, so proper buffering is necessary for good user experience. @@ -150,7 +150,7 @@ public abstract class CLICommand implements ExtensionPoint, Cloneable { */ public abstract String getShortDescription(); - public int main(List args, Locale locale, InputStream stdin, PrintStream stdout, PrintStream stderr) { + public int main(List args, Locale locale, InputStream stdin, PrintStream stdout, PrintStream stderr, Authentication auth) { this.stdin = new BufferedInputStream(stdin); this.stdout = stdout; this.stderr = stderr; @@ -162,15 +162,15 @@ public abstract class CLICommand implements ExtensionPoint, Cloneable { SecurityContext sc = SecurityContextHolder.getContext(); Authentication old = sc.getAuthentication(); - CliAuthenticator authenticator = Hudson.getInstance().getSecurityRealm().createCliAuthenticator(this); + CliAuthenticator authenticator = Hudson.getInstance().getSecurityRealm().createCliAuthenticator(this, auth); new ClassParser().parse(authenticator,p); try { p.parseArgument(args.toArray(new String[args.size()])); - Authentication auth = authenticator.authenticate(); - if (auth==Hudson.ANONYMOUS) - auth = loadStoredAuthentication(); - sc.setAuthentication(auth); // run the CLI with the right credential + Authentication a = authenticator.authenticate(); + if (a == Hudson.ANONYMOUS) + a = loadStoredAuthentication(); + sc.setAuthentication(a); // run the CLI with the right credential return run(); } catch (CmdLineException e) { stderr.println(e.getMessage()); @@ -305,3 +305,4 @@ public abstract class CLICommand implements ExtensionPoint, Cloneable { private static final Logger LOGGER = Logger.getLogger(CLICommand.class.getName()); } + diff --git a/core/src/main/java/hudson/cli/CliManagerImpl.java b/core/src/main/java/hudson/cli/CliManagerImpl.java index 17f2d73fd4..f2fd739665 100644 --- a/core/src/main/java/hudson/cli/CliManagerImpl.java +++ b/core/src/main/java/hudson/cli/CliManagerImpl.java @@ -23,24 +23,25 @@ */ package hudson.cli; -import hudson.remoting.Channel; import hudson.model.Hudson; +import hudson.remoting.Channel; +import org.acegisecurity.Authentication; +import org.apache.commons.discovery.ResourceClassIterator; +import org.apache.commons.discovery.ResourceNameIterator; import org.apache.commons.discovery.resource.ClassLoaders; import org.apache.commons.discovery.resource.classes.DiscoverClasses; import org.apache.commons.discovery.resource.names.DiscoverServiceNames; -import org.apache.commons.discovery.ResourceNameIterator; -import org.apache.commons.discovery.ResourceClassIterator; -import org.kohsuke.args4j.spi.OptionHandler; -import org.kohsuke.args4j.CmdLineParser; import org.jvnet.tiger_types.Types; +import org.kohsuke.args4j.CmdLineParser; +import org.kohsuke.args4j.spi.OptionHandler; -import java.util.List; -import java.util.Locale; -import java.util.Collections; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.Serializable; +import java.util.Collections; +import java.util.List; +import java.util.Locale; /** * {@link CliEntryPoint} implementation exposed to the remote CLI. @@ -48,7 +49,15 @@ import java.io.Serializable; * @author Kohsuke Kawaguchi */ public class CliManagerImpl implements CliEntryPoint, Serializable { + + private final Authentication auth; + + public CliManagerImpl(Authentication auth) { + this.auth = auth!=null ? auth : Hudson.ANONYMOUS; + } + public CliManagerImpl() { + this(null); } public int main(List args, Locale locale, InputStream stdin, OutputStream stdout, OutputStream stderr) { @@ -64,11 +73,11 @@ public class CliManagerImpl implements CliEntryPoint, Serializable { CLICommand cmd = CLICommand.clone(subCmd); if(cmd!=null) { // execute the command, do so with the originator of the request as the principal - return cmd.main(args.subList(1,args.size()),locale, stdin, out, err); + return cmd.main(args.subList(1,args.size()),locale, stdin, out, err, auth); } err.println("No such command: "+subCmd); - new HelpCommand().main(Collections.emptyList(), locale, stdin, out, err); + new HelpCommand().main(Collections.emptyList(), locale, stdin, out, err, auth); return -1; } @@ -101,3 +110,5 @@ public class CliManagerImpl implements CliEntryPoint, Serializable { } } } + + diff --git a/core/src/main/java/hudson/cli/GroovyshCommand.java b/core/src/main/java/hudson/cli/GroovyshCommand.java index fab488013b..886f9a17bb 100644 --- a/core/src/main/java/hudson/cli/GroovyshCommand.java +++ b/core/src/main/java/hudson/cli/GroovyshCommand.java @@ -23,26 +23,31 @@ */ package hudson.cli; +import groovy.lang.Binding; +import groovy.lang.Closure; +import hudson.AbortException; import hudson.Extension; import hudson.model.Hudson; import hudson.remoting.ChannelClosedException; -import groovy.lang.Binding; -import groovy.lang.Closure; +import hudson.security.CliAuthenticator; +import jline.Terminal; +import jline.UnsupportedTerminal; import org.acegisecurity.Authentication; +import org.acegisecurity.context.SecurityContext; +import org.acegisecurity.context.SecurityContextHolder; import org.codehaus.groovy.tools.shell.Groovysh; import org.codehaus.groovy.tools.shell.IO; import org.codehaus.groovy.tools.shell.Shell; import org.codehaus.groovy.tools.shell.util.XmlCommandRegistrar; +import org.kohsuke.args4j.ClassParser; +import org.kohsuke.args4j.CmdLineParser; -import java.util.List; -import java.util.Locale; -import java.io.PrintStream; -import java.io.InputStream; import java.io.BufferedInputStream; +import java.io.InputStream; +import java.io.PrintStream; import java.io.PrintWriter; - -import jline.UnsupportedTerminal; -import jline.Terminal; +import java.util.List; +import java.util.Locale; /** * Executes Groovy shell. @@ -57,16 +62,40 @@ public class GroovyshCommand extends CLICommand { } @Override - public int main(List args, Locale locale, InputStream stdin, PrintStream stdout, PrintStream stderr) { - // this allows the caller to manipulate the JVM state, so require the admin privilege. - Hudson.getInstance().checkPermission(Hudson.ADMINISTER); - - // this being remote means no jline capability is available - System.setProperty("jline.terminal", UnsupportedTerminal.class.getName()); - Terminal.resetTerminal(); + public int main(List args, Locale locale, InputStream stdin, PrintStream stdout, PrintStream stderr, Authentication auth) { + + CmdLineParser p = new CmdLineParser(this); + + // add options from the authenticator + SecurityContext sc = SecurityContextHolder.getContext(); + Authentication old = sc.getAuthentication(); + CliAuthenticator authenticator = Hudson.getInstance().getSecurityRealm().createCliAuthenticator(this, auth); + new ClassParser().parse(authenticator, p); + + try { + + sc.setAuthentication(authenticator.authenticate()); + + // this allows the caller to manipulate the JVM state, so require the admin privilege. + Hudson.getInstance().checkPermission(Hudson.ADMINISTER); + + // this being remote means no jline capability is available + System.setProperty("jline.terminal", UnsupportedTerminal.class.getName()); + Terminal.resetTerminal(); + + Groovysh shell = createShell(stdin, stdout, stderr); + return shell.run(args.toArray(new String[args.size()])); + } catch (AbortException e) { + // signals an error without stack trace + stderr.println(e.getMessage()); + return -1; + } catch (Exception e) { + e.printStackTrace(stderr); + return -1; + } finally { + sc.setAuthentication(old); // restore + } - Groovysh shell = createShell(stdin, stdout, stderr); - return shell.run(args.toArray(new String[args.size()])); } protected Groovysh createShell(InputStream stdin, PrintStream stdout, diff --git a/core/src/main/java/hudson/cli/declarative/CLIRegisterer.java b/core/src/main/java/hudson/cli/declarative/CLIRegisterer.java index db6f32ba99..5af1e3341b 100644 --- a/core/src/main/java/hudson/cli/declarative/CLIRegisterer.java +++ b/core/src/main/java/hudson/cli/declarative/CLIRegisterer.java @@ -106,7 +106,7 @@ public class CLIRegisterer extends ExtensionFinder { } @Override - public int main(List args, Locale locale, InputStream stdin, PrintStream stdout, PrintStream stderr) { + public int main(List args, Locale locale, InputStream stdin, PrintStream stdout, PrintStream stderr, Authentication auth) { CmdLineParser parser = new CmdLineParser(null); try { SecurityContext sc = SecurityContextHolder.getContext(); @@ -135,7 +135,7 @@ public class CLIRegisterer extends ExtensionFinder { binders.add(new MethodBinder(chains.pop(),parser)); // authentication - CliAuthenticator authenticator = Hudson.getInstance().getSecurityRealm().createCliAuthenticator(this); + CliAuthenticator authenticator = Hudson.getInstance().getSecurityRealm().createCliAuthenticator(this, auth); new ClassParser().parse(authenticator,parser); // fill up all the binders @@ -196,3 +196,4 @@ public class CLIRegisterer extends ExtensionFinder { private static final Logger LOGGER = Logger.getLogger(CLIRegisterer.class.getName()); } + diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java index 36b7e32fb9..2dd8890b6d 100644 --- a/core/src/main/java/hudson/model/Hudson.java +++ b/core/src/main/java/hudson/model/Hudson.java @@ -2864,7 +2864,7 @@ public final class Hudson extends Node implements ItemGroup, Stapl if(req.getHeader("Side").equals("download")) { duplexChannels.put(uuid,server=new FullDuplexHttpChannel(uuid, !hasPermission(ADMINISTER)) { protected void main(Channel channel) throws IOException, InterruptedException { - channel.setProperty(CliEntryPoint.class.getName(),new CliManagerImpl()); + channel.setProperty(CliEntryPoint.class.getName(),new CliManagerImpl(getAuthentication())); } }); try { @@ -3692,3 +3692,4 @@ public final class Hudson extends Node implements ItemGroup, Stapl assert ADMINISTER!=null; } } + diff --git a/core/src/main/java/hudson/security/LegacySecurityRealm.java b/core/src/main/java/hudson/security/LegacySecurityRealm.java index ce4f8e75e2..2356948919 100644 --- a/core/src/main/java/hudson/security/LegacySecurityRealm.java +++ b/core/src/main/java/hudson/security/LegacySecurityRealm.java @@ -23,16 +23,17 @@ */ package hudson.security; -import org.acegisecurity.AuthenticationManager; -import org.acegisecurity.Authentication; -import org.acegisecurity.AuthenticationException; -import org.springframework.web.context.WebApplicationContext; -import org.kohsuke.stapler.StaplerRequest; import groovy.lang.Binding; +import hudson.Extension; +import hudson.cli.CLICommand; import hudson.model.Descriptor; import hudson.util.spring.BeanBuilder; -import hudson.Extension; import net.sf.json.JSONObject; +import org.acegisecurity.Authentication; +import org.acegisecurity.AuthenticationException; +import org.acegisecurity.AuthenticationManager; +import org.kohsuke.stapler.StaplerRequest; +import org.springframework.web.context.WebApplicationContext; import javax.servlet.Filter; import javax.servlet.FilterConfig; @@ -70,6 +71,19 @@ public final class LegacySecurityRealm extends SecurityRealm implements Authenti return "loginEntry"; } + @Override + public CliAuthenticator createCliAuthenticator(CLICommand command, final Authentication auth) { + if (auth == null) { + return createCliAuthenticator(command); + } else { + return new CliAuthenticator() { + public Authentication authenticate() { + return auth; + } + }; + } + } + /** * Filter to run for the LegacySecurityRealm is the * ChainServletFilter legacy from /WEB-INF/security/SecurityFilters.groovy. @@ -102,3 +116,4 @@ public final class LegacySecurityRealm extends SecurityRealm implements Authenti } }; } + diff --git a/core/src/main/java/hudson/security/SecurityRealm.java b/core/src/main/java/hudson/security/SecurityRealm.java index a985bad00d..c4c9ca36f0 100644 --- a/core/src/main/java/hudson/security/SecurityRealm.java +++ b/core/src/main/java/hudson/security/SecurityRealm.java @@ -160,6 +160,22 @@ public abstract class SecurityRealm extends AbstractDescribableImpl" + "").getBytes()), - out, out); + out, out, null); out.flush(); assertNotNull("job should be created: " + buf, hudson.getItem("testJob")); assertEquals("onCreated event should be triggered: " + buf, "C", events.toString()); -- GitLab