Skip to content

Commit

Permalink
Merge pull request #5 from ikedam/feature/JENKIS-32376_ServerBasedDow…
Browse files Browse the repository at this point in the history
…nloading

[FIXED JENKINS-32376] Supports server-based downloading
  • Loading branch information
ikedam committed Jan 16, 2016
2 parents b8bfa33 + cf71b46 commit 45819d1
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 134 deletions.
14 changes: 1 addition & 13 deletions pom.xml
Expand Up @@ -3,7 +3,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>1.466</version><!-- which version of Jenkins is this plugin built against? -->
<version>1.609</version><!-- which version of Jenkins is this plugin built against? -->
</parent>

<groupId>jp.ikedam.jenkins.plugins</groupId>
Expand Down Expand Up @@ -55,16 +55,4 @@
<url>http://repo.jenkins-ci.org/public/</url>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>[2.3,]</version>
</dependency>
</dependencies>
</project>
Expand Up @@ -24,25 +24,22 @@
package jp.ikedam.jenkins.plugins.updatesitesmanager;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.logging.Level;
import java.util.logging.Logger;

import jenkins.model.Jenkins;

import hudson.Extension;
import hudson.util.FormValidation;

import org.apache.commons.io.FileUtils;
import jenkins.util.JSONSignatureValidator;
import jp.ikedam.jenkins.plugins.updatesitesmanager.internal.ExtendedCertJsonSignValidator;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

import javax.annotation.Nonnull;

/**
* Extended UpdateSite to be managed in UpdateSitesManager.
Expand All @@ -54,10 +51,7 @@
* <li>can set a CA certificate for the signature of the site.</li>
* </ul>
*
* The CA certificate is written to a temporary file under ${JENKINS_HOME}/update-center-rootCAs/ .
* I think it is a better implementation to override UpdateSite#verifySignature,
* but it is private method.
* Re-implementing doPostBack results to re-implement whole the UpdateSite.
* The CA certificate is written as additional trust anchor dynamically
*/
public class ManagedUpdateSite extends DescribedUpdateSite
{
Expand Down Expand Up @@ -129,24 +123,6 @@ public String getNote()
return note;
}

/**
* Returns the path to the CA certificate file.
*
* The file to store the CA certificate temporary.
*
* @return the path to the CA certificate file
*/
protected File getCaCertificateFile()
{
File caCertificateDir = new File(Jenkins.getInstance().getRootDir(), "update-center-rootCAs");
if(!caCertificateDir.exists())
{
assert(caCertificateDir.mkdir());
}

return new File(caCertificateDir, String.format("tmp-ManageUpdateSite-%s.crt", getId()));
}

/**
* Create a new instance
*
Expand Down Expand Up @@ -174,98 +150,18 @@ public ManagedUpdateSite(
}

/**
* Process update-center.json.
*
* If a CA certificate is set, write it to file and make it ready to verify the signature.
*
* @param req
* @return FormValidation object
* @throws IOException
* @throws GeneralSecurityException
* @see hudson.model.UpdateSite#doPostBack(org.kohsuke.stapler.StaplerRequest)
* Verifier for the signature of downloaded update-center.json.
*
* @return JSONSignatureValidator object with additional cert as anchor if enabled
*/
@Nonnull
@Override
public FormValidation doPostBack(StaplerRequest req) throws IOException,
GeneralSecurityException
protected JSONSignatureValidator getJsonSignatureValidator()
{
if(isUseCaCertificate())
{
return doPostBackWithCaCertificate(req);
}

return super.doPostBack(req);
}

/**
* Uses custom CA certificate to process update-center.json.
*
* To avoid having the certificate file overwritten by another thread,
* this method is synchronized.
*
* @param req
* @return FormValidation object
* @throws IOException
* @throws GeneralSecurityException
*/
private synchronized FormValidation doPostBackWithCaCertificate(StaplerRequest req)
throws IOException, GeneralSecurityException
{
File caFile = getCaCertificateFile();
try
{
FileUtils.writeStringToFile(getCaCertificateFile(), getCaCertificate());
return super.doPostBack(req);
}
finally
{
if(caFile.exists())
{
caFile.delete();
}
}
}

/**
* Verify the signature of downloaded update-center.json.
*
* @return FormValidation object.
* @throws IOException
* @see hudson.model.UpdateSite#doVerifySignature()
*/
@Override
public FormValidation doVerifySignature() throws IOException
{
if(isUseCaCertificate())
{
return doVerifySignatureWithCaCertificate();
}

return super.doVerifySignature();
}

/**
* Verify the signature with custom CA certificate.
*
* To avoid having the certificate file overwritten by another thread,
* this method is synchronized.
*
* @return FormValidation object.
* @throws IOException
*/
private synchronized FormValidation doVerifySignatureWithCaCertificate() throws IOException
{
File caFile = getCaCertificateFile();
try
{
FileUtils.writeStringToFile(getCaCertificateFile(), getCaCertificate());
return super.doVerifySignature();
}
finally
{
if(caFile.exists())
{
caFile.delete();
}
if (isUseCaCertificate()) {
return new ExtendedCertJsonSignValidator(getId(), getCaCertificate());
} else {
return super.getJsonSignatureValidator();
}
}

Expand Down Expand Up @@ -352,5 +248,5 @@ public FormValidation doCheckCaCertificate(
return FormValidation.ok();
}

};
}
}
@@ -0,0 +1,52 @@
package jp.ikedam.jenkins.plugins.updatesitesmanager.internal;

import jenkins.util.JSONSignatureValidator;
import org.apache.tools.ant.filters.StringInputStream;

import java.io.IOException;
import java.io.InputStream;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import static java.lang.String.format;

/**
* Adds provided cert to trust anchors when validating update center json
*
* @author lanwen (Merkushev Kirill)
*/
public class ExtendedCertJsonSignValidator extends JSONSignatureValidator {
private static final Logger LOGGER = Logger.getLogger(ExtendedCertJsonSignValidator.class.getName());

private String cert;

public ExtendedCertJsonSignValidator(String id, String cert) {
super(format("Update site with own cert for %s", id));
this.cert = cert;
}

@Override
protected Set<TrustAnchor> loadTrustAnchors(CertificateFactory cf) throws IOException {
Set<TrustAnchor> trustAnchors = super.loadTrustAnchors(cf);
InputStream stream = null;
try {
stream = new StringInputStream(cert);
Certificate certificate = cf.generateCertificate(stream);
trustAnchors.add(new TrustAnchor((X509Certificate) certificate, null));
} catch (CertificateException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
} finally {
if (stream != null) {
stream.close();
stream = null;
}
}
return trustAnchors;
}
}

0 comments on commit 45819d1

Please sign in to comment.