Index: core/src/main/java/hudson/security/SecurityRealm.java
===================================================================
--- core/src/main/java/hudson/security/SecurityRealm.java (revision 2087)
+++ core/src/main/java/hudson/security/SecurityRealm.java (working copy)
@@ -161,6 +161,22 @@
}
/**
+ * Creates a {@link CliAuthenticator} object that authenticates an invocation of a CLI command.
+ * See {@link CliAuthenticator} for more details.
+ *
+ * @param command
+ * The command about to be executed.
+ *
+ * @param auth Authentication to use; not used in default implementation of this method
+ * @return
+ * never null. By default, this method returns a no-op authenticator that always authenticates
+ * the session as an anonymous user.
+ */
+ public CliAuthenticator createCliAuthenticator(CLICommand command, Authentication auth) {
+ return createCliAuthenticator(command);
+ }
+
+ /**
* {@inheritDoc}
*
*
Index: core/src/main/java/hudson/security/LegacySecurityRealm.java
===================================================================
--- core/src/main/java/hudson/security/LegacySecurityRealm.java (revision 2087)
+++ core/src/main/java/hudson/security/LegacySecurityRealm.java (working copy)
@@ -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 @@
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 @@
}
};
}
+
Index: core/src/main/java/hudson/model/Hudson.java
===================================================================
--- core/src/main/java/hudson/model/Hudson.java (revision 2087)
+++ core/src/main/java/hudson/model/Hudson.java (working copy)
@@ -2910,7 +2910,7 @@
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 {
@@ -3740,3 +3740,4 @@
assert ADMINISTER!=null;
}
}
+
Index: core/src/main/java/hudson/cli/declarative/CLIRegisterer.java
===================================================================
--- core/src/main/java/hudson/cli/declarative/CLIRegisterer.java (revision 2087)
+++ core/src/main/java/hudson/cli/declarative/CLIRegisterer.java (working copy)
@@ -105,7 +105,7 @@
}
@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();
@@ -134,7 +134,7 @@
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
@@ -195,3 +195,4 @@
private static final Logger LOGGER = Logger.getLogger(CLIRegisterer.class.getName());
}
+
Index: core/src/main/java/hudson/cli/CLICommand.java
===================================================================
--- core/src/main/java/hudson/cli/CLICommand.java (revision 2087)
+++ core/src/main/java/hudson/cli/CLICommand.java (working copy)
@@ -60,7 +60,7 @@
*
*
* 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 @@
*
* 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 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 @@
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 @@
private static final Logger LOGGER = Logger.getLogger(CLICommand.class.getName());
}
+
Index: core/src/main/java/hudson/cli/GroovyshCommand.java
===================================================================
--- core/src/main/java/hudson/cli/GroovyshCommand.java (revision 2087)
+++ core/src/main/java/hudson/cli/GroovyshCommand.java (working copy)
@@ -23,27 +23,32 @@
*/
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.io.BufferedInputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
import java.util.List;
import java.util.Locale;
-import java.io.PrintStream;
-import java.io.InputStream;
-import java.io.BufferedInputStream;
-import java.io.PrintWriter;
-import jline.UnsupportedTerminal;
-import jline.Terminal;
-
/**
* Executes Groovy shell.
*
@@ -57,16 +62,40 @@
}
@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);
+ public int main(List args, Locale locale, InputStream stdin, PrintStream stdout, PrintStream stderr, Authentication auth) {
- // this being remote means no jline capability is available
- System.setProperty("jline.terminal", UnsupportedTerminal.class.getName());
- Terminal.resetTerminal();
+ CmdLineParser p = new CmdLineParser(this);
- Groovysh shell = createShell(stdin, stdout, stderr);
- return shell.run(args.toArray(new String[args.size()]));
+ // 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
+ }
+
}
protected Groovysh createShell(InputStream stdin, PrintStream stdout,
Index: core/src/main/java/hudson/cli/CliManagerImpl.java
===================================================================
--- core/src/main/java/hudson/cli/CliManagerImpl.java (revision 2087)
+++ core/src/main/java/hudson/cli/CliManagerImpl.java (working copy)
@@ -23,24 +23,25 @@
*/
package hudson.cli;
+import hudson.model.Hudson;
import hudson.remoting.Channel;
-import hudson.model.Hudson;
+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.jvnet.tiger_types.Types;
+import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.spi.OptionHandler;
-import org.kohsuke.args4j.CmdLineParser;
-import org.jvnet.tiger_types.Types;
-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 @@
* @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 @@
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 @@
}
}
}
+
+