mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-11-15 04:52:20 +00:00
Merge branch 'security-rc' into SECURITY-144-rc
Conflicts: core/src/main/java/hudson/FilePath.java
This commit is contained in:
commit
f0658e233d
33 files changed
+461
-99
No files matched your search
@@ -89,6 +89,7 @@ import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.io.Serializable;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -1760,6 +1761,77 @@ public final class FilePath implements Serializable {
|
||||
return p.getIn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads this file from the specific offset.
|
||||
*/
|
||||
public InputStream readFromOffset(final long offset) throws IOException {
|
||||
if(channel ==null) {
|
||||
final RandomAccessFile raf = new RandomAccessFile(new File(remote), "r");
|
||||
try {
|
||||
raf.seek(offset);
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException e1) {
|
||||
// ignore
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return new InputStream() {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return raf.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
raf.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
return raf.read(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
return raf.read(b);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
final Pipe p = Pipe.createRemoteToLocal();
|
||||
channel.callAsync(new Callable<Void, IOException>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public Void call() throws IOException {
|
||||
final OutputStream out = new java.util.zip.GZIPOutputStream(p.getOut(), 8192);
|
||||
RandomAccessFile raf = null;
|
||||
try {
|
||||
raf = new RandomAccessFile(new File(remote), "r");
|
||||
raf.seek(offset);
|
||||
byte[] buf = new byte[8192];
|
||||
int len;
|
||||
while ((len = raf.read(buf)) >= 0) {
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(out);
|
||||
if (raf != null) {
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return new java.util.zip.GZIPInputStream(p.getIn());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads this file into a string, by using the current system encoding.
|
||||
*/
|
||||
|
||||
@@ -56,6 +56,7 @@ import javax.xml.transform.TransformerFactoryConfigurationError;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Date;
|
||||
@@ -116,6 +117,8 @@ public class WebAppMain implements ServletContextListener {
|
||||
|
||||
installLogger();
|
||||
|
||||
markCookieAsHttpOnly(context);
|
||||
|
||||
final FileAndDescription describedHomeDir = getHomeDir(event);
|
||||
home = describedHomeDir.file.getAbsoluteFile();
|
||||
home.mkdirs();
|
||||
@@ -251,6 +254,31 @@ public class WebAppMain implements ServletContextListener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the session cookie as HTTP only.
|
||||
*
|
||||
* @see <a href="https://www.owasp.org/index.php/HttpOnly">discussion of this topic in OWASP</a>
|
||||
*/
|
||||
private void markCookieAsHttpOnly(ServletContext context) {
|
||||
try {
|
||||
Method m;
|
||||
try {
|
||||
m = context.getClass().getMethod("getSessionCookieConfig");
|
||||
} catch (NoSuchMethodException x) { // 3.0+
|
||||
LOGGER.log(Level.FINE, "Failed to set secure cookie flag", x);
|
||||
return;
|
||||
}
|
||||
Object sessionCookieConfig = m.invoke(context);
|
||||
|
||||
// not exposing session cookie to JavaScript to mitigate damage caused by XSS
|
||||
Class scc = Class.forName("javax.servlet.SessionCookieConfig");
|
||||
Method setHttpOnly = scc.getMethod("setHttpOnly",boolean.class);
|
||||
setHttpOnly.invoke(sessionCookieConfig,true);
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.WARNING, "Failed to set HTTP-only cookie flag", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void joinInit() throws InterruptedException {
|
||||
initThread.join();
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
*/
|
||||
package hudson.model;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.OverrideMustInvoke;
|
||||
import edu.umd.cs.findbugs.annotations.When;
|
||||
import hudson.EnvVars;
|
||||
import hudson.Launcher.ProcStarter;
|
||||
import hudson.Util;
|
||||
@@ -108,14 +110,14 @@ import static javax.servlet.http.HttpServletResponse.*;
|
||||
*
|
||||
* <p>
|
||||
* {@link Executor}s on one {@link Computer} are transparently interchangeable
|
||||
* (that is the definition of {@link Computer}.)
|
||||
* (that is the definition of {@link Computer}).
|
||||
*
|
||||
* <p>
|
||||
* This object is related to {@link Node} but they have some significant difference.
|
||||
* This object is related to {@link Node} but they have some significant differences.
|
||||
* {@link Computer} primarily works as a holder of {@link Executor}s, so
|
||||
* if a {@link Node} is configured (probably temporarily) with 0 executors,
|
||||
* you won't have a {@link Computer} object for it (except for the master node,
|
||||
* which always get its {@link Computer} in case we have no static executors and
|
||||
* which always gets its {@link Computer} in case we have no static executors and
|
||||
* we need to run a {@link FlyweightTask} - see JENKINS-7291 for more discussion.)
|
||||
*
|
||||
* Also, even if you remove a {@link Node}, it takes time for the corresponding
|
||||
@@ -124,8 +126,8 @@ import static javax.servlet.http.HttpServletResponse.*;
|
||||
* remains intact, while all the {@link Node} objects will go away.
|
||||
*
|
||||
* <p>
|
||||
* This object also serves UI (since {@link Node} is an interface and can't have
|
||||
* related side pages.)
|
||||
* This object also serves UI (unlike {@link Node}), and can be used along with
|
||||
* {@link TransientComputerActionFactory} to add {@link Action}s to {@link Computer}s.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
@@ -207,7 +209,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces
|
||||
* The method also creates a log directory if required.
|
||||
* @see #relocateOldLogs()
|
||||
*/
|
||||
protected File getLogFile() {
|
||||
public File getLogFile() {
|
||||
File dir = new File(Jenkins.getInstance().getRootDir(),"logs/slaves/"+nodeName);
|
||||
dir.mkdirs();
|
||||
return new File(dir,"slave.log");
|
||||
@@ -1318,9 +1320,13 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces
|
||||
* scheduling that does not overlap with being offline.
|
||||
*
|
||||
* @return {@code true} if the computer is accepting tasks
|
||||
* @see hudson.slaves.RetentionStrategy#isAcceptingTasks(Computer)
|
||||
* @see hudson.model.Node#isAcceptingTasks()
|
||||
*/
|
||||
@OverrideMustInvoke(When.ANYTIME)
|
||||
public boolean isAcceptingTasks() {
|
||||
return true;
|
||||
final Node node = getNode();
|
||||
return getRetentionStrategy().isAcceptingTasks(this) && (node == null || node.isAcceptingTasks());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -140,7 +140,7 @@ public class FileParameterValue extends ParameterValue {
|
||||
return new BuildWrapper() {
|
||||
@Override
|
||||
public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
|
||||
if (!StringUtils.isEmpty(location)) {
|
||||
if (!StringUtils.isEmpty(location) && !StringUtils.isEmpty(file.getName())) {
|
||||
listener.getLogger().println("Copying file to "+location);
|
||||
FilePath locationFilePath = build.getWorkspace().child(location);
|
||||
locationFilePath.getParent().mkdirs();
|
||||
@@ -162,7 +162,8 @@ public class FileParameterValue extends ParameterValue {
|
||||
}
|
||||
|
||||
/**
|
||||
* In practice this will always be false, since location should be unique.
|
||||
* Compares file parameters (existing files will be considered as different).
|
||||
* @since 1.586 Function has been modified in order to avoid <a href="https://issues.jenkins-ci.org/browse/JENKINS-19017">JENKINS-19017</a> issue (wrong merge of builds in the queue).
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
@@ -173,12 +174,13 @@ public class FileParameterValue extends ParameterValue {
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
FileParameterValue other = (FileParameterValue) obj;
|
||||
if (location == null) {
|
||||
if (other.location != null)
|
||||
return false;
|
||||
} else if (!location.equals(other.location))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
if (location == null && other.location == null)
|
||||
return true; // Consider null parameters as equal
|
||||
|
||||
//TODO: check fingerprints or checksums to improve the behavior (JENKINS-25211)
|
||||
// Return false even if files are equal
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -69,7 +69,7 @@ import org.kohsuke.stapler.export.ExportedBean;
|
||||
import org.kohsuke.stapler.export.Exported;
|
||||
|
||||
/**
|
||||
* Base type of Jenkins slaves (although in practice, you probably extend {@link Slave} to define a new slave type.)
|
||||
* Base type of Jenkins slaves (although in practice, you probably extend {@link Slave} to define a new slave type).
|
||||
*
|
||||
* <p>
|
||||
* As a special case, {@link Jenkins} extends from here.
|
||||
@@ -77,6 +77,10 @@ import org.kohsuke.stapler.export.Exported;
|
||||
* <p>
|
||||
* Nodes are persisted objects that capture user configurations, and instances get thrown away and recreated whenever
|
||||
* the configuration changes. Running state of nodes are captured by {@link Computer}s.
|
||||
*
|
||||
* <p>
|
||||
* There is no URL binding for {@link Node}. {@link Computer} and {@link TransientComputerActionFactory} must
|
||||
* be used to associate new {@link Action}s to slaves.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see NodeMonitor
|
||||
@@ -190,6 +194,20 @@ public abstract class Node extends AbstractModelObject implements Reconfigurable
|
||||
*/
|
||||
protected abstract Computer createComputer();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the node is accepting tasks. Needed to allow slaves programmatic suspension of task
|
||||
* scheduling that does not overlap with being offline. Called by {@link Computer#isAcceptingTasks()}.
|
||||
* This method is distinct from {@link Computer#isAcceptingTasks()} as sometimes the {@link Node} concrete
|
||||
* class may not have control over the {@link hudson.model.Computer} concrete class associated with it.
|
||||
*
|
||||
* @return {@code true} if the node is accepting tasks.
|
||||
* @see Computer#isAcceptingTasks()
|
||||
* @since 1.586
|
||||
*/
|
||||
public boolean isAcceptingTasks() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Let Nodes be aware of the lifecycle of their own {@link Computer}.
|
||||
*/
|
||||
|
||||
@@ -81,6 +81,7 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.CheckForNull;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a user.
|
||||
@@ -191,11 +192,11 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
public @Nonnull String getUrl() {
|
||||
return "user/"+Util.rawEncode(idStrategy().keyFor(id));
|
||||
}
|
||||
|
||||
public String getSearchUrl() {
|
||||
public @Nonnull String getSearchUrl() {
|
||||
return "/user/"+Util.rawEncode(idStrategy().keyFor(id));
|
||||
}
|
||||
|
||||
@@ -203,24 +204,22 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
|
||||
* The URL of the user page.
|
||||
*/
|
||||
@Exported(visibility=999)
|
||||
public String getAbsoluteUrl() {
|
||||
public @Nonnull String getAbsoluteUrl() {
|
||||
return Jenkins.getInstance().getRootUrl()+getUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the human readable name of this user.
|
||||
* This is configurable by the user.
|
||||
*
|
||||
* @return
|
||||
* never null.
|
||||
*/
|
||||
@Exported(visibility=999)
|
||||
public String getFullName() {
|
||||
public @Nonnull String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the human readable name of thie user.
|
||||
* Sets the human readable name of the user.
|
||||
* If the input parameter is empty, the user's ID will be set.
|
||||
*/
|
||||
public void setFullName(String name) {
|
||||
if(Util.fixEmptyAndTrim(name)==null) name=id;
|
||||
@@ -228,7 +227,7 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
|
||||
}
|
||||
|
||||
@Exported
|
||||
public String getDescription() {
|
||||
public @CheckForNull String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@@ -242,7 +241,7 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
|
||||
/**
|
||||
* Updates the user object by adding a property.
|
||||
*/
|
||||
public synchronized void addProperty(UserProperty p) throws IOException {
|
||||
public synchronized void addProperty(@Nonnull UserProperty p) throws IOException {
|
||||
UserProperty old = getProperty(p.getClass());
|
||||
List<UserProperty> ps = new ArrayList<UserProperty>(properties);
|
||||
if(old!=null)
|
||||
@@ -284,7 +283,7 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
|
||||
* If this user is not a valid user in the backend {@link SecurityRealm}.
|
||||
* @since 1.419
|
||||
*/
|
||||
public Authentication impersonate() throws UsernameNotFoundException {
|
||||
public @Nonnull Authentication impersonate() throws UsernameNotFoundException {
|
||||
try {
|
||||
UserDetails u = new ImpersonatingUserDetailsService(
|
||||
Jenkins.getInstance().getSecurityRealm().getSecurityComponents().userDetails).loadUserByUsername(id);
|
||||
@@ -332,9 +331,11 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
|
||||
* (by creating a new {@link User} object if none exists.)
|
||||
* If false, this method will return null if {@link User} object
|
||||
* with the given name doesn't exist.
|
||||
* @return Requested user. May be {@code null} if a user does not exist and
|
||||
* {@code create} is false.
|
||||
* @deprecated use {@link User#get(String, boolean, java.util.Map)}
|
||||
*/
|
||||
public static User get(String idOrFullName, boolean create) {
|
||||
public static @Nullable User get(String idOrFullName, boolean create) {
|
||||
return get(idOrFullName, create, Collections.emptyMap());
|
||||
}
|
||||
|
||||
@@ -350,8 +351,12 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
|
||||
* @param context
|
||||
* contextual environment this user idOfFullName was retrieved from,
|
||||
* that can help resolve the user ID
|
||||
*
|
||||
* @return
|
||||
* An existing or created user. May be {@code null} if a user does not exist and
|
||||
* {@code create} is false.
|
||||
*/
|
||||
public static User get(String idOrFullName, boolean create, Map context) {
|
||||
public static @Nullable User get(String idOrFullName, boolean create, Map context) {
|
||||
|
||||
if(idOrFullName==null)
|
||||
return null;
|
||||
@@ -369,14 +374,19 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
|
||||
}
|
||||
}
|
||||
// DefaultUserCanonicalIdResolver will always return a non-null id if all other CanonicalIdResolver failed
|
||||
|
||||
if (id == null) {
|
||||
throw new IllegalStateException("The user id should be always non-null thanks to DefaultUserCanonicalIdResolver");
|
||||
}
|
||||
return getOrCreate(id, idOrFullName, create);
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve a user by its ID, and create a new one if requested
|
||||
* Retrieve a user by its ID, and create a new one if requested.
|
||||
* @return
|
||||
* An existing or created user. May be {@code null} if a user does not exist and
|
||||
* {@code create} is false.
|
||||
*/
|
||||
private static User getOrCreate(String id, String fullName, boolean create) {
|
||||
private static @Nullable User getOrCreate(@Nonnull String id, @Nonnull String fullName, boolean create) {
|
||||
String idkey = idStrategy().keyFor(id);
|
||||
|
||||
byNameLock.readLock().lock();
|
||||
@@ -468,7 +478,7 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
|
||||
/**
|
||||
* Gets all the users.
|
||||
*/
|
||||
public static Collection<User> getAll() {
|
||||
public static @Nonnull Collection<User> getAll() {
|
||||
final IdStrategy strategy = idStrategy();
|
||||
if(System.currentTimeMillis() -lastScanned>10000) {
|
||||
// occasionally scan the file system to check new users
|
||||
@@ -555,12 +565,12 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
|
||||
/**
|
||||
* Returns the user name.
|
||||
*/
|
||||
public String getDisplayName() {
|
||||
public @Nonnull String getDisplayName() {
|
||||
return getFullName();
|
||||
}
|
||||
|
||||
/** true if {@link AbstractBuild#hasParticipant} or {@link hudson.model.Cause.UserIdCause} */
|
||||
private boolean relatedTo(AbstractBuild<?,?> b) {
|
||||
private boolean relatedTo(@Nonnull AbstractBuild<?,?> b) {
|
||||
if (b.hasParticipant(this)) {
|
||||
return true;
|
||||
}
|
||||
@@ -580,7 +590,7 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
|
||||
* by the timestamp order.
|
||||
*/
|
||||
@WithBridgeMethods(List.class)
|
||||
public RunList getBuilds() {
|
||||
public @Nonnull RunList getBuilds() {
|
||||
return new RunList<Run<?,?>>(Jenkins.getInstance().getAllItems(Job.class)).filter(new Predicate<Run<?,?>>() {
|
||||
@Override public boolean apply(Run<?,?> r) {
|
||||
return r instanceof AbstractBuild && relatedTo((AbstractBuild<?,?>) r);
|
||||
@@ -592,7 +602,7 @@ public class User extends AbstractModelObject implements AccessControlled, Descr
|
||||
* Gets all the {@link AbstractProject}s that this user has committed to.
|
||||
* @since 1.191
|
||||
*/
|
||||
public Set<AbstractProject<?,?>> getProjects() {
|
||||
public @Nonnull Set<AbstractProject<?,?>> getProjects() {
|
||||
Set<AbstractProject<?,?>> r = new HashSet<AbstractProject<?,?>>();
|
||||
for (AbstractProject<?,?> p : Jenkins.getInstance().getAllItems(AbstractProject.class))
|
||||
if(p.hasParticipant(this))
|
||||
|
||||
@@ -54,8 +54,11 @@ import javax.annotation.Nonnull;
|
||||
* Extensible property of {@link Node}.
|
||||
*
|
||||
* <p>
|
||||
* Plugins can contribute this extension point to add additional data or UI actions to {@link Node}.
|
||||
* Plugins can contribute this extension point to add additional data to {@link Node}.
|
||||
* {@link NodeProperty}s show up in the configuration screen of a node, and they are persisted with the {@link Node} object.
|
||||
*
|
||||
* <p>
|
||||
* To add UI action to {@link Node}s, i.e. a new link shown in the left side menu on a node page (<code>./computer/<a node></code>), see instead {@link hudson.model.TransientComputerActionFactory}.
|
||||
*
|
||||
*
|
||||
* <h2>Views</h2>
|
||||
|
||||
@@ -182,7 +182,7 @@ public class NodeProvisioner {
|
||||
cl.onComplete(f,node);
|
||||
|
||||
hudson.addNode(node);
|
||||
LOGGER.info(f.displayName+" provisioningE successfully completed. We have now "+hudson.getComputers().length+" computer(s)");
|
||||
LOGGER.info(f.displayName+" provisioning successfully completed. We have now "+hudson.getComputers().length+" computer(s)");
|
||||
} catch (InterruptedException e) {
|
||||
throw new AssertionError(e); // since we confirmed that the future is already done
|
||||
} catch (ExecutionException e) {
|
||||
|
||||
@@ -67,6 +67,20 @@ public abstract class RetentionStrategy<T extends Computer> extends AbstractDesc
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the computer is accepting tasks. Needed to allow retention strategies programmatic
|
||||
* suspension of task scheduling that in preparation for going offline. Called by
|
||||
* {@link hudson.model.Computer#isAcceptingTasks()}
|
||||
*
|
||||
* @param c the computer.
|
||||
* @return {@code true} if the computer is accepting tasks
|
||||
* @see hudson.model.Computer#isAcceptingTasks()
|
||||
* @since 1.586
|
||||
*/
|
||||
public boolean isAcceptingTasks(T c) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a new {@link Computer} object is introduced (such as when Hudson started, or when
|
||||
* a new slave is added.)
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
*/
|
||||
package hudson.slaves;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.OverrideMustInvoke;
|
||||
import edu.umd.cs.findbugs.annotations.When;
|
||||
import hudson.AbortException;
|
||||
import hudson.remoting.ChannelBuilder;
|
||||
import hudson.util.IOUtils;
|
||||
@@ -141,8 +143,11 @@ public class SlaveComputer extends Computer {
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@OverrideMustInvoke(When.ANYTIME)
|
||||
public boolean isAcceptingTasks() {
|
||||
return acceptingTasks;
|
||||
// our boolean flag is an override on any additional programmatic reasons why this slave might not be
|
||||
// accepting tasks.
|
||||
return acceptingTasks && super.isAcceptingTasks();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,8 +158,11 @@ public class SlaveComputer extends Computer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows a {@linkplain hudson.slaves.ComputerLauncher} or a {@linkplain hudson.slaves.RetentionStrategy} to
|
||||
* suspend tasks being accepted by the slave computer.
|
||||
* Allows suspension of tasks being accepted by the slave computer. While this could be called by a
|
||||
* {@linkplain hudson.slaves.ComputerLauncher} or a {@linkplain hudson.slaves.RetentionStrategy}, such usage
|
||||
* can result in fights between multiple actors calling setting differential values. A better approach
|
||||
* is to override {@link hudson.slaves.RetentionStrategy#isAcceptingTasks(hudson.model.Computer)} if the
|
||||
* {@link hudson.slaves.RetentionStrategy} needs to control availability.
|
||||
*
|
||||
* @param acceptingTasks {@code true} if the slave can accept tasks.
|
||||
*/
|
||||
|
||||
@@ -297,6 +297,9 @@ public class ArtifactArchiver extends Recorder implements SimpleBuildStep {
|
||||
* Performs on-the-fly validation on the file mask wildcard.
|
||||
*/
|
||||
public FormValidation doCheckArtifacts(@AncestorInPath AbstractProject project, @QueryParameter String value) throws IOException {
|
||||
if (project == null) {
|
||||
return FormValidation.ok();
|
||||
}
|
||||
return FilePath.validateFileMask(project.getSomeWorkspace(),value);
|
||||
}
|
||||
|
||||
|
||||
@@ -260,6 +260,9 @@ public class Fingerprinter extends Recorder implements Serializable, DependencyD
|
||||
}
|
||||
|
||||
public FormValidation doCheckTargets(@AncestorInPath AbstractProject<?,?> project, @QueryParameter String value) throws IOException {
|
||||
if (project == null) {
|
||||
return FormValidation.ok();
|
||||
}
|
||||
return FilePath.validateFileMask(project.getSomeWorkspace(),value);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import javax.mail.internet.InternetAddress;
|
||||
import javax.servlet.ServletContext;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -117,14 +118,17 @@ public class JenkinsLocationConfiguration extends GlobalConfiguration {
|
||||
}
|
||||
Object sessionCookieConfig = m.invoke(context);
|
||||
|
||||
// not exposing session cookie to JavaScript to mitigate damage caused by XSS
|
||||
Class scc = Class.forName("javax.servlet.SessionCookieConfig");
|
||||
Method setHttpOnly = scc.getMethod("setHttpOnly",boolean.class);
|
||||
setHttpOnly.invoke(sessionCookieConfig,true);
|
||||
|
||||
Method setSecure = scc.getMethod("setSecure",boolean.class);
|
||||
Method setSecure = scc.getMethod("setSecure", boolean.class);
|
||||
boolean v = fixNull(jenkinsUrl).startsWith("https");
|
||||
setSecure.invoke(sessionCookieConfig,v);
|
||||
setSecure.invoke(sessionCookieConfig, v);
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getTargetException() instanceof IllegalStateException) {
|
||||
// servlet 3.0 spec seems to prohibit this from getting set at runtime,
|
||||
// though Winstone is happy to accept i. see JENKINS-25019
|
||||
return;
|
||||
}
|
||||
LOGGER.log(Level.WARNING, "Failed to set secure cookie flag", e);
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.WARNING, "Failed to set secure cookie flag", e);
|
||||
}
|
||||
|
||||
@@ -13,11 +13,14 @@ import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.security.DigestOutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.Signature;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateExpiredException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CertificateNotYetValidException;
|
||||
@@ -74,19 +77,61 @@ public class JSONSignatureValidator {
|
||||
Set<TrustAnchor> anchors = new HashSet<TrustAnchor>(); // CertificateUtil.getDefaultRootCAs();
|
||||
Jenkins j = Jenkins.getInstance();
|
||||
for (String cert : (Set<String>) j.servletContext.getResourcePaths("/WEB-INF/update-center-rootCAs")) {
|
||||
if (cert.endsWith(".txt")) continue; // skip text files that are meant to be documentation
|
||||
anchors.add(new TrustAnchor((X509Certificate)cf.generateCertificate(j.servletContext.getResourceAsStream(cert)),null));
|
||||
if (cert.endsWith("/") || cert.endsWith(".txt")) {
|
||||
continue; // skip directories also any text files that are meant to be documentation
|
||||
}
|
||||
InputStream in = j.servletContext.getResourceAsStream(cert);
|
||||
if (in == null) continue; // our test for paths ending in / should prevent this from happening
|
||||
Certificate certificate;
|
||||
try {
|
||||
certificate = cf.generateCertificate(in);
|
||||
} catch (CertificateException e) {
|
||||
LOGGER.log(Level.WARNING, String.format("Webapp resources in /WEB-INF/update-center-rootCAs are "
|
||||
+ "expected to be either certificates or .txt files documenting the "
|
||||
+ "certificates, but %s did not parse as a certificate. Skipping this "
|
||||
+ "resource for now.",
|
||||
cert), e);
|
||||
continue;
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
try {
|
||||
anchors.add(new TrustAnchor((X509Certificate) certificate, null));
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
String.format("The name constraints in the certificate resource %s could not be "
|
||||
+ "decoded. Skipping this resource for now.",
|
||||
cert), e);
|
||||
}
|
||||
}
|
||||
File[] cas = new File(j.root, "update-center-rootCAs").listFiles();
|
||||
if (cas!=null) {
|
||||
for (File cert : cas) {
|
||||
if (cert.getName().endsWith(".txt")) continue; // skip text files that are meant to be documentation
|
||||
if (cert.isDirectory() || cert.getName().endsWith(".txt")) {
|
||||
continue; // skip directories also any text files that are meant to be documentation
|
||||
}
|
||||
FileInputStream in = new FileInputStream(cert);
|
||||
Certificate certificate;
|
||||
try {
|
||||
anchors.add(new TrustAnchor((X509Certificate)cf.generateCertificate(in),null));
|
||||
certificate = cf.generateCertificate(in);
|
||||
} catch (CertificateException e) {
|
||||
LOGGER.log(Level.WARNING, String.format("Files in %s are expected to be either "
|
||||
+ "certificates or .txt files documenting the certificates, "
|
||||
+ "but %s did not parse as a certificate. Skipping this file for now.",
|
||||
cert.getParentFile().getAbsolutePath(),
|
||||
cert.getAbsolutePath()), e);
|
||||
continue;
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
try {
|
||||
anchors.add(new TrustAnchor((X509Certificate) certificate, null));
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
String.format("The name constraints in the certificate file %s could not be "
|
||||
+ "decoded. Skipping this file for now.",
|
||||
cert.getAbsolutePath()), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
CertificateUtil.validatePath(certs, anchors);
|
||||
|
||||
Reference in new issue
Block a user