/* | |
* Copyright 2012 gitblit.com. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package com.gitblit.tests; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.security.PrivateKey; | |
import java.security.cert.X509Certificate; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.zip.ZipEntry; | |
import java.util.zip.ZipInputStream; | |
import org.eclipse.jgit.util.FileUtils; | |
import org.junit.After; | |
import org.junit.Before; | |
import org.junit.Test; | |
import com.gitblit.models.UserModel; | |
import com.gitblit.utils.HttpUtils; | |
import com.gitblit.utils.X509Utils; | |
import com.gitblit.utils.X509Utils.RevocationReason; | |
import com.gitblit.utils.X509Utils.X509Log; | |
import com.gitblit.utils.X509Utils.X509Metadata; | |
/** | |
* Unit tests for X509 certificate generation. | |
* | |
* @author James Moger | |
* | |
*/ | |
public class X509UtilsTest extends GitblitUnitTest { | |
// passwords are case-sensitive and may be length-limited | |
// based on the JCE policy files | |
String caPassword = "aBcDeFg"; | |
File folder = new File(System.getProperty("user.dir"), "x509test"); | |
X509Log log = new X509Log() { | |
@Override | |
public void log(String message) { | |
System.out.println(message); | |
} | |
}; | |
@Before | |
public void prepare() throws Exception { | |
cleanUp(); | |
X509Metadata goMetadata = new X509Metadata("localhost", caPassword); | |
X509Utils.prepareX509Infrastructure(goMetadata, folder, log); | |
} | |
@After | |
public void cleanUp() throws Exception { | |
if (folder.exists()) { | |
FileUtils.delete(folder, FileUtils.RECURSIVE); | |
} | |
} | |
@Test | |
public void testNewCA() throws Exception { | |
File storeFile = new File(folder, X509Utils.CA_KEY_STORE); | |
X509Utils.getPrivateKey(X509Utils.CA_ALIAS, storeFile, caPassword); | |
X509Certificate cert = X509Utils.getCertificate(X509Utils.CA_ALIAS, storeFile, caPassword); | |
assertEquals("O=Gitblit,OU=Gitblit,CN=Gitblit Certificate Authority", cert.getIssuerDN().getName()); | |
} | |
@Test | |
public void testCertificateUserMapping() throws Exception { | |
File storeFile = new File(folder, X509Utils.CA_KEY_STORE); | |
PrivateKey caPrivateKey = X509Utils.getPrivateKey(X509Utils.CA_ALIAS, storeFile, caPassword); | |
X509Certificate caCert = X509Utils.getCertificate(X509Utils.CA_ALIAS, storeFile, caPassword); | |
X509Metadata userMetadata = new X509Metadata("james", "james"); | |
userMetadata.serverHostname = "www.myserver.com"; | |
userMetadata.userDisplayname = "James Moger"; | |
userMetadata.passwordHint = "your name"; | |
userMetadata.oids.put("C", "US"); | |
X509Certificate cert1 = X509Utils.newClientCertificate(userMetadata, caPrivateKey, caCert, storeFile.getParentFile()); | |
UserModel userModel1 = HttpUtils.getUserModelFromCertificate(cert1); | |
assertEquals(userMetadata.commonName, userModel1.username); | |
assertEquals(userMetadata.emailAddress, userModel1.emailAddress); | |
assertEquals("C=US,O=Gitblit,OU=Gitblit,CN=james", cert1.getSubjectDN().getName()); | |
X509Certificate cert2 = X509Utils.newClientCertificate(userMetadata, caPrivateKey, caCert, storeFile.getParentFile()); | |
UserModel userModel2 = HttpUtils.getUserModelFromCertificate(cert2); | |
assertEquals(userMetadata.commonName, userModel2.username); | |
assertEquals(userMetadata.emailAddress, userModel2.emailAddress); | |
assertEquals("C=US,O=Gitblit,OU=Gitblit,CN=james", cert2.getSubjectDN().getName()); | |
assertNotSame("Serial numbers are the same!", cert1.getSerialNumber().longValue(), cert2.getSerialNumber().longValue()); | |
} | |
@Test | |
public void testUserBundle() throws Exception { | |
File storeFile = new File(folder, X509Utils.CA_KEY_STORE); | |
X509Metadata userMetadata = new X509Metadata("james", "james"); | |
userMetadata.serverHostname = "www.myserver.com"; | |
userMetadata.userDisplayname = "James Moger"; | |
userMetadata.passwordHint = "your name"; | |
File zip = X509Utils.newClientBundle(userMetadata, storeFile, caPassword, log); | |
assertTrue(zip.exists()); | |
List<String> expected = Arrays.asList( | |
userMetadata.commonName + ".pem", | |
userMetadata.commonName + ".p12", | |
userMetadata.commonName + ".cer", | |
"ca.cer", | |
"README.TXT"); | |
ZipInputStream zis = new ZipInputStream(new FileInputStream(zip)); | |
ZipEntry entry = null; | |
while ((entry = zis.getNextEntry()) != null) { | |
assertTrue("Unexpected file: " + entry.getName(), expected.contains(entry.getName())); | |
} | |
zis.close(); | |
} | |
@Test | |
public void testCertificateRevocation() throws Exception { | |
File storeFile = new File(folder, X509Utils.CA_KEY_STORE); | |
PrivateKey caPrivateKey = X509Utils.getPrivateKey(X509Utils.CA_ALIAS, storeFile, caPassword); | |
X509Certificate caCert = X509Utils.getCertificate(X509Utils.CA_ALIAS, storeFile, caPassword); | |
X509Metadata userMetadata = new X509Metadata("james", "james"); | |
userMetadata.serverHostname = "www.myserver.com"; | |
userMetadata.userDisplayname = "James Moger"; | |
userMetadata.passwordHint = "your name"; | |
// generate a new client certificate | |
X509Certificate cert1 = X509Utils.newClientCertificate(userMetadata, caPrivateKey, caCert, storeFile.getParentFile()); | |
// confirm this certificate IS NOT revoked | |
File caRevocationList = new File(folder, X509Utils.CA_REVOCATION_LIST); | |
assertFalse(X509Utils.isRevoked(cert1, caRevocationList)); | |
// revoke certificate and then confirm it IS revoked | |
X509Utils.revoke(cert1, RevocationReason.ACompromise, caRevocationList, storeFile, caPassword, log); | |
assertTrue(X509Utils.isRevoked(cert1, caRevocationList)); | |
// generate a second certificate | |
X509Certificate cert2 = X509Utils.newClientCertificate(userMetadata, caPrivateKey, caCert, storeFile.getParentFile()); | |
// confirm second certificate IS NOT revoked | |
assertTrue(X509Utils.isRevoked(cert1, caRevocationList)); | |
assertFalse(X509Utils.isRevoked(cert2, caRevocationList)); | |
// revoke second certificate and then confirm it IS revoked | |
X509Utils.revoke(cert2, RevocationReason.ACompromise, caRevocationList, caPrivateKey, log); | |
assertTrue(X509Utils.isRevoked(cert1, caRevocationList)); | |
assertTrue(X509Utils.isRevoked(cert2, caRevocationList)); | |
// generate a third certificate | |
X509Certificate cert3 = X509Utils.newClientCertificate(userMetadata, caPrivateKey, caCert, storeFile.getParentFile()); | |
// confirm third certificate IS NOT revoked | |
assertTrue(X509Utils.isRevoked(cert1, caRevocationList)); | |
assertTrue(X509Utils.isRevoked(cert2, caRevocationList)); | |
assertFalse(X509Utils.isRevoked(cert3, caRevocationList)); | |
// revoke third certificate and then confirm it IS revoked | |
X509Utils.revoke(cert3, RevocationReason.ACompromise, caRevocationList, caPrivateKey, log); | |
assertTrue(X509Utils.isRevoked(cert1, caRevocationList)); | |
assertTrue(X509Utils.isRevoked(cert2, caRevocationList)); | |
assertTrue(X509Utils.isRevoked(cert3, caRevocationList)); | |
} | |
} |