/* * 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)); } }