summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Moger <james.moger@gitblit.com>2012-11-25 11:35:31 -0500
committerJames Moger <james.moger@gitblit.com>2012-11-25 11:35:31 -0500
commitc8b26c51aa67fc9345b624e36aab6f819e7eed74 (patch)
tree80f69598db8d26e028544440512a069091c0e1b0
parentca12058bbf0f2aa391254cbc6a5915323cdd611b (diff)
downloadgitblit-c8b26c51aa67fc9345b624e36aab6f819e7eed74.tar.gz
gitblit-c8b26c51aa67fc9345b624e36aab6f819e7eed74.zip
Gitblit Certificate Authority revisions. Eliminate certificate scripts.
-rw-r--r--build.xml19
-rw-r--r--distrib/makeclientcertificate.cmd1
-rw-r--r--distrib/makeclientcertificate.sh2
-rw-r--r--distrib/makekeystore.cmd6
-rw-r--r--distrib/makekeystore.sh5
-rw-r--r--distrib/makekeystore_jdk.cmd6
-rw-r--r--distrib/makekeystore_jdk.sh7
-rw-r--r--resources/rosette_32x32.pngbin0 -> 1695 bytes
-rw-r--r--resources/settings_32x32.pngbin0 -> 1038 bytes
-rw-r--r--src/com/gitblit/GitBlitServer.java28
-rw-r--r--src/com/gitblit/MakeCertificate.java130
-rw-r--r--src/com/gitblit/authority/DefaultOidsPanel.java80
-rw-r--r--src/com/gitblit/authority/GitblitAuthority.java185
-rw-r--r--src/com/gitblit/authority/MakeClientCertificate.java230
-rw-r--r--src/com/gitblit/authority/NewCertificateConfig.java33
-rw-r--r--src/com/gitblit/authority/NewClientCertificateDialog.java14
-rw-r--r--src/com/gitblit/authority/NewWebCertificateDialog.java131
-rw-r--r--src/com/gitblit/authority/UserCertificatePanel.java88
-rw-r--r--src/com/gitblit/authority/UserOidsPanel.java95
-rw-r--r--src/com/gitblit/authority/Utils.java22
-rw-r--r--src/com/gitblit/authority/X509CertificateViewer.java6
-rw-r--r--src/com/gitblit/utils/X509Utils.java114
-rw-r--r--src/com/gitblit/wicket/GitBlitWebApp.properties7
-rw-r--r--tests/com/gitblit/tests/X509UtilsTest.java29
24 files changed, 665 insertions, 573 deletions
diff --git a/build.xml b/build.xml
index 8a7fd54b..aa247d39 100644
--- a/build.xml
+++ b/build.xml
@@ -190,9 +190,9 @@
<fileset dir="${basedir}">
<include name="LICENSE" />
<include name="NOTICE" />
- <include name="authority*.jar" />
- </fileset>
+ </fileset>
</copy>
+ <copy tofile="${project.deploy.dir}/authority.jar" file="${basedir}/authority-${gb.version}.jar" />
<!-- Certificate templates -->
<mkdir dir="${project.deploy.dir}/certs"/>
@@ -461,7 +461,6 @@
<exclude name="com/gitblit/AddIndexedBranch*.class" />
<exclude name="com/gitblit/GitBlitServer*.class" />
<exclude name="com/gitblit/Launcher*.class" />
- <exclude name="com/gitblit/MakeCertificate*.class" />
<exclude name="com/gitblit/authority/**" />
</fileset>
</copy>
@@ -494,7 +493,6 @@
<exclude name="com/gitblit/AddIndexedBranch*.class" />
<exclude name="com/gitblit/GitBlitServer*.class" />
<exclude name="com/gitblit/Launcher*.class" />
- <exclude name="com/gitblit/MakeCertificate*.class" />
</fileset>
</copy>
@@ -671,7 +669,6 @@
<exclude name="com/gitblit/client/**" />
<exclude name="com/gitblit/GitBlitServer*.class" />
<exclude name="com/gitblit/Launcher*.class" />
- <exclude name="com/gitblit/MakeCertificate*.class" />
<exclude name="com/gitblit/authority/**" />
</fileset>
</jar>
@@ -767,6 +764,7 @@
<resource file="${basedir}/resources/rosette_16x16.png" />
<resource file="${basedir}/resources/vcard_16x16.png" />
<resource file="${basedir}/resources/settings_16x16.png" />
+ <resource file="${basedir}/resources/settings_32x32.png" />
<resource file="${basedir}/resources/search-icon.png" />
<resource file="${basedir}/resources/blank.png" />
<resource file="${basedir}/resources/bullet_green.png" />
@@ -775,6 +773,7 @@
<resource file="${basedir}/resources/bullet_white.png" />
<resource file="${basedir}/resources/bullet_delete.png" />
<resource file="${basedir}/resources/bullet_key.png" />
+ <resource file="${basedir}/src/log4j.properties" />
<resource file="${basedir}/src/com/gitblit/wicket/GitBlitWebApp.properties" />
<resource file="${basedir}/src/com/gitblit/wicket/GitBlitWebApp_es.properties" />
<resource file="${basedir}/src/com/gitblit/wicket/GitBlitWebApp_ja.properties" />
@@ -1116,16 +1115,6 @@
summary="Gitblit Manager v${gb.version} (Swing tool to remotely administer a Gitblit server)"
labels="Featured, Type-Package, OpSys-All" />
- <!-- Upload Gitblit Authority -->
- <gcupload
- username="${googlecode.user}"
- password="${googlecode.password}"
- projectname="gitblit"
- filename="${authority.zipfile}"
- targetfilename="authority-${gb.version}.zip"
- summary="Gitblit Authority v${gb.version} (Swing tool to manage client SSL certificates)"
- labels="Featured, Type-Package, OpSys-All" />
-
<!-- Upload Gitblit API Library -->
<gcupload
username="${googlecode.user}"
diff --git a/distrib/makeclientcertificate.cmd b/distrib/makeclientcertificate.cmd
deleted file mode 100644
index 72941421..00000000
--- a/distrib/makeclientcertificate.cmd
+++ /dev/null
@@ -1 +0,0 @@
-@java -cp gitblit.jar;"%CD%\ext\*" com.gitblit.authority.MakeClientCertificate
diff --git a/distrib/makeclientcertificate.sh b/distrib/makeclientcertificate.sh
deleted file mode 100644
index 76a195ee..00000000
--- a/distrib/makeclientcertificate.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-java -cp gitblit.jar:$PWD/ext/* com.gitblit.authority.MakeClientCertificate
diff --git a/distrib/makekeystore.cmd b/distrib/makekeystore.cmd
deleted file mode 100644
index 8a72e03b..00000000
--- a/distrib/makekeystore.cmd
+++ /dev/null
@@ -1,6 +0,0 @@
-@REM --------------------------------------------------------------------------
-@REM Set HOSTNAME to the server's hostname
-@REM --------------------------------------------------------------------------
-@SET HOSTNAME=localhost
-@del serverKeyStore.jks
-@java -cp gitblit.jar;"%CD%\ext\*" com.gitblit.MakeCertificate --hostname %HOSTNAME% --subject "CN=%HOSTNAME%, OU=Gitblit, O=Gitblit, L=Some Town, ST=Some State, C=US"
diff --git a/distrib/makekeystore.sh b/distrib/makekeystore.sh
deleted file mode 100644
index 59bba90d..00000000
--- a/distrib/makekeystore.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-# SET HOSTNAME to the server's hostname
-HOSTNAME=localhost
-rm keystore
-java -cp gitblit.jar:$PWD/ext/* com.gitblit.MakeCertificate --hostname $HOSTNAME --subject "CN=$HOSTNAME, OU=Gitblit, O=Gitblit, L=Some Town, ST=Some State, C=US"
diff --git a/distrib/makekeystore_jdk.cmd b/distrib/makekeystore_jdk.cmd
deleted file mode 100644
index 121c6718..00000000
--- a/distrib/makekeystore_jdk.cmd
+++ /dev/null
@@ -1,6 +0,0 @@
-@REM --------------------------------------------------------------------------
-@REM Set HOSTNAME to the server's hostname
-@REM --------------------------------------------------------------------------
-@SET HOSTNAME=localhost
-@del serverKeyStore.jks
-@keytool -keystore serverKeyStore.jks -alias %HOSTNAME% -genkey -keyalg RSA -dname "CN=%HOSTNAME%, OU=Gitblit, O=Gitblit, L=Some Town, ST=Some State, C=US" \ No newline at end of file
diff --git a/distrib/makekeystore_jdk.sh b/distrib/makekeystore_jdk.sh
deleted file mode 100644
index 97e5dc90..00000000
--- a/distrib/makekeystore_jdk.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-# --------------------------------------------------------------------------
-# SET HOSTNAME to the server's hostname
-# --------------------------------------------------------------------------
-HOSTNAME=localhost
-rm keystore
-keytool -keystore keystore -alias $HOSTNAME -genkey -keyalg RSA -dname "CN=$HOSTNAME, OU=Gitblit, O=Gitblit, L=Some Town, ST=Some State, C=US" \ No newline at end of file
diff --git a/resources/rosette_32x32.png b/resources/rosette_32x32.png
new file mode 100644
index 00000000..ecbcc0a6
--- /dev/null
+++ b/resources/rosette_32x32.png
Binary files differ
diff --git a/resources/settings_32x32.png b/resources/settings_32x32.png
new file mode 100644
index 00000000..39af4be9
--- /dev/null
+++ b/resources/settings_32x32.png
Binary files differ
diff --git a/src/com/gitblit/GitBlitServer.java b/src/com/gitblit/GitBlitServer.java
index 52afb54b..d98f8916 100644
--- a/src/com/gitblit/GitBlitServer.java
+++ b/src/com/gitblit/GitBlitServer.java
@@ -16,7 +16,9 @@
package com.gitblit;
import java.io.BufferedReader;
+import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
@@ -55,10 +57,12 @@ import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParameterException;
import com.beust.jcommander.Parameters;
+import com.gitblit.authority.GitblitAuthority;
import com.gitblit.authority.NewCertificateConfig;
import com.gitblit.utils.StringUtils;
import com.gitblit.utils.TimeUtils;
import com.gitblit.utils.X509Utils;
+import com.gitblit.utils.X509Utils.X509Log;
import com.gitblit.utils.X509Utils.X509Metadata;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
@@ -194,7 +198,7 @@ public class GitBlitServer {
// conditionally configure the https connector
if (params.securePort > 0) {
- File folder = new File(System.getProperty("user.dir"));
+ final File folder = new File(System.getProperty("user.dir"));
File certificatesConf = new File(folder, X509Utils.CA_CONFIG);
File serverKeyStore = new File(folder, X509Utils.SERVER_KEY_STORE);
File serverTrustStore = new File(folder, X509Utils.SERVER_TRUST_STORE);
@@ -215,7 +219,27 @@ public class GitBlitServer {
}
metadata.notAfter = new Date(System.currentTimeMillis() + 10*TimeUtils.ONEYEAR);
- X509Utils.prepareX509Infrastructure(metadata, folder);
+ X509Utils.prepareX509Infrastructure(metadata, folder, new X509Log() {
+ @Override
+ public void log(String message) {
+ BufferedWriter writer = null;
+ try {
+ writer = new BufferedWriter(new FileWriter(new File(folder, X509Utils.CERTS + File.separator + "log.txt"), true));
+ writer.write(MessageFormat.format("{0,date,yyyy-MM-dd HH:mm}: {1}", new Date(), message));
+ writer.newLine();
+ writer.flush();
+ } catch (Exception e) {
+ LoggerFactory.getLogger(GitblitAuthority.class).error("Failed to append log entry!", e);
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+ });
if (serverKeyStore.exists()) {
Connector secureConnector = createSSLConnector(serverKeyStore, serverTrustStore, params.storePassword,
diff --git a/src/com/gitblit/MakeCertificate.java b/src/com/gitblit/MakeCertificate.java
deleted file mode 100644
index e3c39ff7..00000000
--- a/src/com/gitblit/MakeCertificate.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2011 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;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.math.BigInteger;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.SecureRandom;
-import java.security.Security;
-import java.security.cert.X509Certificate;
-import java.util.Date;
-
-import javax.security.auth.x500.X500Principal;
-
-import org.bouncycastle.cert.X509v3CertificateBuilder;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
-import com.beust.jcommander.ParameterException;
-import com.beust.jcommander.Parameters;
-import com.gitblit.utils.TimeUtils;
-
-/**
- * Utility class to generate self-signed certificates.
- *
- * @author James Moger
- *
- */
-public class MakeCertificate {
-
- private static final String BC = org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
-
- public static void main(String... args) {
- Params params = new Params();
- JCommander jc = new JCommander(params);
- try {
- jc.parse(args);
- } catch (ParameterException t) {
- System.err.println(t.getMessage());
- jc.usage();
- }
- File keystore = new File("serverKeyStore.jks");
- generateSelfSignedCertificate(params.hostname, keystore, params.storePassword,
- params.subject);
- }
-
- public static void generateSelfSignedCertificate(String hostname, File keystore,
- String keystorePassword, String info) {
- try {
- Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
-
- KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
- kpGen.initialize(1024, new SecureRandom());
- KeyPair pair = kpGen.generateKeyPair();
-
- // Generate self-signed certificate
- X500Principal principal = new X500Principal(info);
-
- Date notBefore = new Date(System.currentTimeMillis() - TimeUtils.ONEDAY);
- Date notAfter = new Date(System.currentTimeMillis() + 10 * TimeUtils.ONEYEAR);
- BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
-
- X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(principal, serial,
- notBefore, notAfter, principal, pair.getPublic());
- ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
- .setProvider(BC).build(pair.getPrivate());
- X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC)
- .getCertificate(certGen.build(sigGen));
- cert.checkValidity(new Date());
- cert.verify(cert.getPublicKey());
-
- // Save to keystore
- KeyStore store = KeyStore.getInstance("JKS");
- if (keystore.exists()) {
- FileInputStream fis = new FileInputStream(keystore);
- store.load(fis, keystorePassword.toCharArray());
- fis.close();
- } else {
- store.load(null);
- }
- store.setKeyEntry(hostname, pair.getPrivate(), keystorePassword.toCharArray(),
- new java.security.cert.Certificate[] { cert });
- FileOutputStream fos = new FileOutputStream(keystore);
- store.store(fos, keystorePassword.toCharArray());
- fos.close();
- } catch (Throwable t) {
- t.printStackTrace();
- throw new RuntimeException("Failed to generate self-signed certificate!", t);
- }
- }
-
- /**
- * JCommander Parameters class for MakeCertificate.
- */
- @Parameters(separators = " ")
- private static class Params {
-
- private static final FileSettings FILESETTINGS = new FileSettings(Constants.PROPERTIES_FILE);
-
- @Parameter(names = { "--hostname" }, description = "Server Hostname", required = true)
- public String hostname;
-
- @Parameter(names = { "--subject" }, description = "Certificate subject", required = true)
- public String subject;
-
- @Parameter(names = "--storePassword", description = "Password for SSL (https) keystore.")
- public String storePassword = FILESETTINGS.getString(Keys.server.storePassword, "");
- }
-}
diff --git a/src/com/gitblit/authority/DefaultOidsPanel.java b/src/com/gitblit/authority/DefaultOidsPanel.java
new file mode 100644
index 00000000..12b919fa
--- /dev/null
+++ b/src/com/gitblit/authority/DefaultOidsPanel.java
@@ -0,0 +1,80 @@
+/*
+ * 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.authority;
+
+import java.awt.GridLayout;
+
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import com.gitblit.client.Translation;
+import com.gitblit.utils.X509Utils.X509Metadata;
+
+public class DefaultOidsPanel extends JPanel {
+
+ private static final long serialVersionUID = 1L;
+
+ private JTextField organizationalUnit;
+ private JTextField organization;
+ private JTextField locality;
+ private JTextField stateProvince;
+ private JTextField countryCode;
+
+ public DefaultOidsPanel(X509Metadata metadata) {
+ super();
+
+ organizationalUnit = new JTextField(metadata.getOID("OU", ""), 20);
+ organization = new JTextField(metadata.getOID("O", ""), 20);
+ locality = new JTextField(metadata.getOID("L", ""), 20);
+ stateProvince = new JTextField(metadata.getOID("ST", ""), 20);
+ countryCode = new JTextField(metadata.getOID("C", ""), 20);
+
+ setLayout(new GridLayout(0, 1, Utils.MARGIN, Utils.MARGIN));
+ add(Utils.newFieldPanel(Translation.get("gb.organizationalUnit") + " (OU)", organizationalUnit));
+ add(Utils.newFieldPanel(Translation.get("gb.organization") + " (O)", organization));
+ add(Utils.newFieldPanel(Translation.get("gb.locality") + " (L)", locality));
+ add(Utils.newFieldPanel(Translation.get("gb.stateProvince") + " (ST)", stateProvince));
+ add(Utils.newFieldPanel(Translation.get("gb.countryCode") + " (C)", countryCode));
+ }
+
+ public void update(X509Metadata metadata) {
+ metadata.setOID("OU", organizationalUnit.getText());
+ metadata.setOID("O", organization.getText());
+ metadata.setOID("L", locality.getText());
+ metadata.setOID("ST", stateProvince.getText());
+ metadata.setOID("C", countryCode.getText());
+ }
+
+ public String getOrganizationalUnit() {
+ return organizationalUnit.getText();
+ }
+
+ public String getOrganization() {
+ return organization.getText();
+ }
+
+ public String getLocality() {
+ return locality.getText();
+ }
+
+ public String getStateProvince() {
+ return stateProvince.getText();
+ }
+
+ public String getCountryCode() {
+ return countryCode.getText();
+ }
+}
diff --git a/src/com/gitblit/authority/GitblitAuthority.java b/src/com/gitblit/authority/GitblitAuthority.java
index 5e8b30ec..7734a151 100644
--- a/src/com/gitblit/authority/GitblitAuthority.java
+++ b/src/com/gitblit/authority/GitblitAuthority.java
@@ -29,10 +29,13 @@ import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedInputStream;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
+import java.security.PrivateKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
@@ -51,6 +54,9 @@ import javax.mail.Multipart;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import javax.swing.ImageIcon;
+import javax.swing.InputVerifier;
+import javax.swing.JButton;
+import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
@@ -60,6 +66,7 @@ import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.RowFilter;
+import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
@@ -69,6 +76,7 @@ import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
+import org.slf4j.LoggerFactory;
import com.gitblit.ConfigUserService;
import com.gitblit.Constants;
@@ -81,8 +89,10 @@ import com.gitblit.client.HeaderPanel;
import com.gitblit.client.Translation;
import com.gitblit.models.UserModel;
import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.TimeUtils;
import com.gitblit.utils.X509Utils;
import com.gitblit.utils.X509Utils.RevocationReason;
+import com.gitblit.utils.X509Utils.X509Log;
import com.gitblit.utils.X509Utils.X509Metadata;
/**
@@ -91,7 +101,7 @@ import com.gitblit.utils.X509Utils.X509Metadata;
* @author James Moger
*
*/
-public class GitblitAuthority extends JFrame {
+public class GitblitAuthority extends JFrame implements X509Log {
private static final long serialVersionUID = 1L;
@@ -112,6 +122,10 @@ public class GitblitAuthority extends JFrame {
private int defaultDuration;
private TableRowSorter<UserCertificateTableModel> defaultSorter;
+
+ private MailExecutor mail;
+
+ private JButton certificateDefaultsButton;
public static void main(String... args) {
EventQueue.invokeLater(new Runnable() {
@@ -170,7 +184,7 @@ public class GitblitAuthority extends JFrame {
// try to restore saved window size
if (StringUtils.isEmpty(sz)) {
- setSize(850, 500);
+ setSize(900, 600);
} else {
String[] chunks = sz.split("x");
int width = Integer.parseInt(chunks[0]);
@@ -218,6 +232,7 @@ public class GitblitAuthority extends JFrame {
return null;
}
gitblitSettings = new FileSettings(file.getAbsolutePath());
+ mail = new MailExecutor(gitblitSettings);
caKeystorePassword = gitblitSettings.getString(Keys.server.storePassword, null);
String us = gitblitSettings.getString(Keys.realm.userService, "users.conf");
String ext = us.substring(us.lastIndexOf(".") + 1).toLowerCase();
@@ -243,7 +258,9 @@ public class GitblitAuthority extends JFrame {
private void load(File folder) {
this.folder = folder;
this.userService = loadUsers(folder);
- if (userService != null) {
+ if (userService == null) {
+ JOptionPane.showMessageDialog(this, MessageFormat.format("Sorry, {0} doesn't look like a Gitblit GO installation.", folder));
+ } else {
// build empty certificate model for all users
Map<String, UserCertificateModel> map = new HashMap<String, UserCertificateModel>();
for (String user : userService.getAllUsernames()) {
@@ -273,9 +290,20 @@ public class GitblitAuthority extends JFrame {
Collections.sort(tableModel.list);
tableModel.fireTableDataChanged();
Utils.packColumns(table, Utils.MARGIN);
+
+ File caKeystore = new File(folder, X509Utils.CA_KEY_STORE);
+ if (!caKeystore.exists()) {
+ // show certificate defaults dialog
+ certificateDefaultsButton.doClick();
+ }
}
}
+ private void prepareX509Infrastructure() {
+ X509Metadata metadata = new X509Metadata("localhost", caKeystorePassword);
+ X509Utils.prepareX509Infrastructure(metadata, folder, this);
+ }
+
private List<X509Certificate> findCerts(File folder, String username) {
List<X509Certificate> list = new ArrayList<X509Certificate>();
File userFolder = new File(folder, X509Utils.CERTS + File.separator + username);
@@ -310,6 +338,11 @@ public class GitblitAuthority extends JFrame {
public Insets getInsets() {
return Utils.INSETS;
}
+
+ @Override
+ public boolean isAllowEmail() {
+ return mail.isReady();
+ }
@Override
public Date getDefaultExpiration() {
@@ -329,6 +362,7 @@ public class GitblitAuthority extends JFrame {
@Override
public void newCertificate(UserCertificateModel ucm, X509Metadata metadata, boolean sendEmail) {
+ prepareX509Infrastructure();
Date notAfter = metadata.notAfter;
metadata.serverHostname = gitblitSettings.getString(Keys.web.siteName, "localhost");
UserModel user = ucm.user;
@@ -367,8 +401,8 @@ public class GitblitAuthority extends JFrame {
}
File caKeystoreFile = new File(folder, X509Utils.CA_KEY_STORE);
- File zip = X509Utils.newClientBundle(metadata, caKeystoreFile, caKeystorePassword);
-
+ File zip = X509Utils.newClientBundle(metadata, caKeystoreFile, caKeystorePassword, GitblitAuthority.this);
+
// save latest expiration date
if (ucm.expires == null || metadata.notAfter.after(ucm.expires)) {
ucm.expires = metadata.notAfter;
@@ -389,7 +423,6 @@ public class GitblitAuthority extends JFrame {
if (sendEmail) {
// send email
try {
- MailExecutor mail = new MailExecutor(gitblitSettings);
if (mail.isReady()) {
Message message = mail.createMessage(user.emailAddress);
message.setSubject("Your Gitblit client certificate for " + metadata.serverHostname);
@@ -427,7 +460,7 @@ public class GitblitAuthority extends JFrame {
public void revoke(UserCertificateModel ucm, X509Certificate cert, RevocationReason reason) {
File caRevocationList = new File(folder, X509Utils.CA_REVOCATION_LIST);
File caKeystoreFile = new File(folder, X509Utils.CA_KEY_STORE);
- if (X509Utils.revoke(cert, reason, caRevocationList, caKeystoreFile, caKeystorePassword)) {
+ if (X509Utils.revoke(cert, reason, caRevocationList, caKeystoreFile, caKeystorePassword, GitblitAuthority.this)) {
File certificatesConfigFile = new File(folder, X509Utils.CA_CONFIG);
FileBasedConfig config = new FileBasedConfig(certificatesConfigFile, FS.detect());
if (certificatesConfigFile.exists()) {
@@ -451,6 +484,7 @@ public class GitblitAuthority extends JFrame {
int modelIndex = table.convertRowIndexToModel(table.getSelectedRow());
tableModel.fireTableDataChanged();
table.getSelectionModel().setSelectionInterval(modelIndex, modelIndex);
+
}
}
};
@@ -491,7 +525,99 @@ public class GitblitAuthority extends JFrame {
usersPanel.add(new JScrollPane(table), BorderLayout.CENTER);
usersPanel.setMinimumSize(new Dimension(400, 10));
- final JTextField filterTextfield = new JTextField(20);
+ certificateDefaultsButton = new JButton(new ImageIcon(getClass().getResource("/settings_16x16.png")));
+ certificateDefaultsButton.setFocusable(false);
+ certificateDefaultsButton.setToolTipText(Translation.get("gb.certificateDefaults"));
+ certificateDefaultsButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ X509Metadata metadata = new X509Metadata("whocares", "whocares");
+ File certificatesConfigFile = new File(folder, X509Utils.CA_CONFIG);
+ FileBasedConfig config = new FileBasedConfig(certificatesConfigFile, FS.detect());
+ NewCertificateConfig certificateConfig = null;
+ if (certificatesConfigFile.exists()) {
+ try {
+ config.load();
+ } catch (Exception x) {
+ Utils.showException(GitblitAuthority.this, x);
+ }
+ certificateConfig = NewCertificateConfig.KEY.parse(config);
+ certificateConfig.update(metadata);
+ }
+ InputVerifier verifier = new InputVerifier() {
+ public boolean verify(JComponent comp) {
+ boolean returnValue;
+ JTextField textField = (JTextField) comp;
+ try {
+ Integer.parseInt(textField.getText());
+ returnValue = true;
+ } catch (NumberFormatException e) {
+ returnValue = false;
+ }
+ return returnValue;
+ }
+ };
+
+ JTextField durationTF = new JTextField(4);
+ durationTF.setInputVerifier(verifier);
+ durationTF.setVerifyInputWhenFocusTarget(true);
+ durationTF.setText("" + certificateConfig.duration);
+ JPanel durationPanel = Utils.newFieldPanel(Translation.get("gb.duration"), durationTF, Translation.get("gb.duration.days").replace("{0}", "").trim());
+ DefaultOidsPanel oids = new DefaultOidsPanel(metadata);
+
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.add(durationPanel, BorderLayout.NORTH);
+ panel.add(oids, BorderLayout.CENTER);
+
+ int result = JOptionPane.showConfirmDialog(GitblitAuthority.this,
+ panel, Translation.get("gb.certificateDefaults"), JOptionPane.OK_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE, new ImageIcon(getClass().getResource("/settings_32x32.png")));
+ if (result == JOptionPane.OK_OPTION) {
+ try {
+ oids.update(metadata);
+ certificateConfig.duration = Integer.parseInt(durationTF.getText());
+ certificateConfig.store(config, metadata);
+ config.save();
+
+ prepareX509Infrastructure();
+ } catch (Exception e1) {
+ Utils.showException(GitblitAuthority.this, e1);
+ }
+ }
+ }
+ });
+
+ JButton newWebCertificate = new JButton(new ImageIcon(getClass().getResource("/rosette_16x16.png")));
+ newWebCertificate.setFocusable(false);
+ newWebCertificate.setToolTipText(Translation.get("gb.newWebCertificate"));
+ newWebCertificate.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Date defaultExpiration = new Date(System.currentTimeMillis() + 10*TimeUtils.ONEYEAR);
+ NewWebCertificateDialog dialog = new NewWebCertificateDialog(GitblitAuthority.this, defaultExpiration);
+ dialog.setModal(true);
+ dialog.setVisible(true);
+ if (dialog.isCanceled()) {
+ return;
+ }
+ prepareX509Infrastructure();
+ Date expires = dialog.getExpiration();
+ String hostname = dialog.getHostname();
+
+ // read CA private key and certificate
+ File caKeystoreFile = new File(folder, X509Utils.CA_KEY_STORE);
+ PrivateKey caPrivateKey = X509Utils.getPrivateKey(X509Utils.CA_ALIAS, caKeystoreFile, caKeystorePassword);
+ X509Certificate caCert = X509Utils.getCertificate(X509Utils.CA_ALIAS, caKeystoreFile, caKeystorePassword);
+
+ // generate new SSL certificate
+ X509Metadata metadata = new X509Metadata(hostname, caKeystorePassword);
+ metadata.notAfter = expires;
+ File serverKeystoreFile = new File(folder, X509Utils.SERVER_KEY_STORE);
+ X509Utils.newSSLCertificate(metadata, caPrivateKey, caCert, serverKeystoreFile, GitblitAuthority.this);
+ }
+ });
+
+ final JTextField filterTextfield = new JTextField(15);
filterTextfield.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
filterUsers(filterTextfield.getText());
@@ -502,17 +628,33 @@ public class GitblitAuthority extends JFrame {
filterUsers(filterTextfield.getText());
}
});
+
+ JPanel buttonControls = new JPanel(new FlowLayout(FlowLayout.LEFT, Utils.MARGIN, Utils.MARGIN));
+ buttonControls.add(certificateDefaultsButton);
+ buttonControls.add(newWebCertificate);
- JPanel userControls = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 5));
+ JPanel userControls = new JPanel(new FlowLayout(FlowLayout.RIGHT, Utils.MARGIN, Utils.MARGIN));
userControls.add(new JLabel(Translation.get("gb.filter")));
userControls.add(filterTextfield);
+ JPanel topPanel = new JPanel(new BorderLayout(0, 0));
+ topPanel.add(buttonControls, BorderLayout.WEST);
+ topPanel.add(userControls, BorderLayout.EAST);
+
JPanel leftPanel = new JPanel(new BorderLayout());
- leftPanel.add(userControls, BorderLayout.NORTH);
+ leftPanel.add(topPanel, BorderLayout.NORTH);
leftPanel.add(usersPanel, BorderLayout.CENTER);
userCertificatePanel.setMinimumSize(new Dimension(375, 10));
+ JLabel statusLabel = new JLabel();
+ statusLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+ if (X509Utils.unlimitedStrength) {
+ statusLabel.setText("JCE Unlimited Strength Jurisdiction Policy");
+ } else {
+ statusLabel.setText("JCE Standard Encryption Policy");
+ }
+
JPanel root = new JPanel(new BorderLayout()) {
private static final long serialVersionUID = 1L;
public Insets getInsets() {
@@ -521,7 +663,8 @@ public class GitblitAuthority extends JFrame {
};
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, userCertificatePanel);
splitPane.setDividerLocation(1d);
- root.add(splitPane);
+ root.add(splitPane, BorderLayout.CENTER);
+ root.add(statusLabel, BorderLayout.SOUTH);
return root;
}
@@ -545,4 +688,24 @@ public class GitblitAuthority extends JFrame {
sorter.setRowFilter(containsFilter);
table.setRowSorter(sorter);
}
+
+ @Override
+ public void log(String message) {
+ BufferedWriter writer = null;
+ try {
+ writer = new BufferedWriter(new FileWriter(new File(folder, X509Utils.CERTS + File.separator + "log.txt"), true));
+ writer.write(MessageFormat.format("{0,date,yyyy-MM-dd HH:mm}: {1}", new Date(), message));
+ writer.newLine();
+ writer.flush();
+ } catch (Exception e) {
+ LoggerFactory.getLogger(GitblitAuthority.class).error("Failed to append log entry!", e);
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
}
diff --git a/src/com/gitblit/authority/MakeClientCertificate.java b/src/com/gitblit/authority/MakeClientCertificate.java
deleted file mode 100644
index 5829fc11..00000000
--- a/src/com/gitblit/authority/MakeClientCertificate.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * 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.authority;
-
-import java.io.File;
-import java.text.MessageFormat;
-import java.util.Date;
-
-import javax.activation.DataHandler;
-import javax.activation.FileDataSource;
-import javax.mail.Message;
-import javax.mail.Multipart;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.internet.MimeMultipart;
-
-import org.eclipse.jgit.storage.file.FileBasedConfig;
-import org.eclipse.jgit.util.FS;
-
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
-import com.beust.jcommander.ParameterException;
-import com.beust.jcommander.Parameters;
-import com.gitblit.ConfigUserService;
-import com.gitblit.Constants;
-import com.gitblit.FileSettings;
-import com.gitblit.IUserService;
-import com.gitblit.Keys;
-import com.gitblit.MailExecutor;
-import com.gitblit.models.UserModel;
-import com.gitblit.utils.StringUtils;
-import com.gitblit.utils.TimeUtils;
-import com.gitblit.utils.X509Utils;
-import com.gitblit.utils.X509Utils.X509Metadata;
-
-/**
- * Utility class to generate self-signed certificates.
- *
- * @author James Moger
- *
- */
-public class MakeClientCertificate {
-
- public static void main(String... args) throws Exception {
- Params params = new Params();
- JCommander jc = new JCommander(params);
- try {
- jc.parse(args);
- } catch (ParameterException t) {
- System.err.println(t.getMessage());
- jc.usage();
- System.exit(-1);
- }
-
- // Load the user list
- String us = Params.FILESETTINGS.getString(Keys.realm.userService, "users.conf");
- String ext = us.substring(us.lastIndexOf(".") + 1).toLowerCase();
- IUserService service = null;
- if (!ext.equals("conf") && !ext.equals("properties")) {
- if (us.equals("com.gitblit.LdapUserService")) {
- us = Params.FILESETTINGS.getString(Keys.realm.ldap.backingUserService, "users.conf");
- } else if (us.equals("com.gitblit.LdapUserService")) {
- us = Params.FILESETTINGS.getString(Keys.realm.redmine.backingUserService, "users.conf");
- }
- }
-
- if (us.endsWith(".conf")) {
- service = new ConfigUserService(new File(us));
- } else {
- throw new RuntimeException("Unsupported user service: " + us);
- }
-
- // Confirm the user exists
- UserModel user = service.getUserModel(params.username);
- if (user == null) {
- System.out.println(MessageFormat.format("Failed to find user \"{0}\" in {1}", params.username, us));
- System.exit(-1);
- }
-
- File folder = new File(System.getProperty("user.dir"));
- X509Metadata serverMetadata = new X509Metadata("localhost", params.storePassword);
- X509Utils.prepareX509Infrastructure(serverMetadata, folder);
-
- File caStore = new File(folder, X509Utils.CA_KEY_STORE);
-
- X509Metadata clientMetadata = new X509Metadata(params.username, params.password);
- clientMetadata.userDisplayname = user.getDisplayName();
- clientMetadata.emailAddress = user.emailAddress;
- clientMetadata.serverHostname = params.serverHostname;
- clientMetadata.passwordHint = params.hint;
-
- UserCertificateModel ucm = null;
-
- // set default values from config file
- File certificatesConfigFile = new File(folder, X509Utils.CA_CONFIG);
- FileBasedConfig config = new FileBasedConfig(certificatesConfigFile, FS.detect());
- if (certificatesConfigFile.exists()) {
- config.load();
- NewCertificateConfig certificateConfig = NewCertificateConfig.KEY.parse(config);
- certificateConfig.update(clientMetadata);
-
- ucm = UserCertificateConfig.KEY.parse(config).getUserCertificateModel(params.username);
- }
-
- // set user's specified OID values
- if (!StringUtils.isEmpty(user.organizationalUnit)) {
- clientMetadata.oids.put("OU", user.organizationalUnit);
- }
- if (!StringUtils.isEmpty(user.organization)) {
- clientMetadata.oids.put("O", user.organization);
- }
- if (!StringUtils.isEmpty(user.locality)) {
- clientMetadata.oids.put("L", user.locality);
- }
- if (!StringUtils.isEmpty(user.stateProvince)) {
- clientMetadata.oids.put("ST", user.stateProvince);
- }
- if (!StringUtils.isEmpty(user.countryCode)) {
- clientMetadata.oids.put("C", user.countryCode);
- }
-
- if (params.duration > 0) {
- // overriding duration from command-line parameter
- clientMetadata.notAfter = new Date(System.currentTimeMillis() + TimeUtils.ONEDAY * params.duration);
- }
-
- // generate zip bundle
- File zip = X509Utils.newClientBundle(clientMetadata, caStore, params.storePassword);
-
- String indent = " ";
- System.out.println(MessageFormat.format("Client certificate bundle generated for {0}", params.username));
- System.out.print(indent);
- System.out.println(zip);
-
- // update certificates.conf
- if (ucm == null) {
- ucm = new UserCertificateModel(new UserModel(params.username));
- }
-
- // save latest expiration date
- if (ucm.expires == null || clientMetadata.notAfter.after(ucm.expires)) {
- ucm.expires = clientMetadata.notAfter;
- }
- ucm.update(config);
- config.save();
-
- if (params.sendEmail) {
- if (StringUtils.isEmpty(user.emailAddress)) {
- System.out.print(indent);
- System.out.println(MessageFormat.format("User \"{0}\" does not have an email address.", user.username));
- } else {
- // send email
- MailExecutor mail = new MailExecutor(Params.FILESETTINGS);
- if (mail.isReady()) {
- Message message = mail.createMessage(user.emailAddress);
- message.setSubject("Your Gitblit client certificate for " + clientMetadata.serverHostname);
-
- // body of email
- String body = X509Utils.processTemplate(new File(caStore.getParentFile(), "mail.tmpl"), clientMetadata);
- if (StringUtils.isEmpty(body)) {
- body = MessageFormat.format("Hi {0}\n\nHere is your client certificate bundle.\nInside the zip file are installation instructions.", user.getDisplayName());
- }
- Multipart mp = new MimeMultipart();
- MimeBodyPart messagePart = new MimeBodyPart();
- messagePart.setText(body);
- mp.addBodyPart(messagePart);
-
- // attach zip
- MimeBodyPart filePart = new MimeBodyPart();
- FileDataSource fds = new FileDataSource(zip);
- filePart.setDataHandler(new DataHandler(fds));
- filePart.setFileName(fds.getName());
- mp.addBodyPart(filePart);
-
- message.setContent(mp);
-
- mail.sendNow(message);
- System.out.println();
- System.out.println("Mail sent.");
- } else {
- System.out.print(indent);
- System.out.println("Mail server is not properly configured. Can not send email.");
- }
- }
- }
- }
-
- /**
- * JCommander Parameters class for MakeClientCertificate.
- */
- @Parameters(separators = " ")
- private static class Params {
-
- private static final FileSettings FILESETTINGS = new FileSettings(Constants.PROPERTIES_FILE);
-
- @Parameter(names = { "--username" }, description = "Username for certificate (CN)", required = true)
- public String username;
-
- @Parameter(names = { "--password" }, description = "Password to secure user's certificate (<=7 chars unless JCE Unlimited Strength installed)", required = true)
- public String password;
-
- @Parameter(names = { "--hint" }, description = "Hint for password", required = true)
- public String hint;
-
- @Parameter(names = "--duration", description = "Number of days from now until the certificate expires")
- public int duration = 0;
-
- @Parameter(names = "--storePassword", description = "Password for CA keystore.")
- public String storePassword = FILESETTINGS.getString(Keys.server.storePassword, "");
-
- @Parameter(names = "--server", description = "Hostname or server identity")
- public String serverHostname = Params.FILESETTINGS.getString(Keys.web.siteName, "localhost");
-
- @Parameter(names = "--sendEmail", description = "Send an email to the user with their bundle")
- public boolean sendEmail;
-
- }
-}
diff --git a/src/com/gitblit/authority/NewCertificateConfig.java b/src/com/gitblit/authority/NewCertificateConfig.java
index e4db130e..ca047c82 100644
--- a/src/com/gitblit/authority/NewCertificateConfig.java
+++ b/src/com/gitblit/authority/NewCertificateConfig.java
@@ -36,13 +36,13 @@ public class NewCertificateConfig {
}
};
- public final String OU;
- public final String O;
- public final String L;
- public final String ST;
- public final String C;
+ public String OU;
+ public String O;
+ public String L;
+ public String ST;
+ public String C;
- public final int duration;
+ public int duration;
private NewCertificateConfig(final Config c) {
duration = c.getInt("new", null, "duration", 0);
@@ -69,4 +69,25 @@ public class NewCertificateConfig {
metadata.oids.put(oid, value);
}
}
+
+ public void store(Config c, X509Metadata metadata) {
+ store(c, "new", "organizationalUnit", metadata.getOID("OU", null));
+ store(c, "new", "organization", metadata.getOID("O", null));
+ store(c, "new", "locality", metadata.getOID("L", null));
+ store(c, "new", "stateProvince", metadata.getOID("ST", null));
+ store(c, "new", "countryCode", metadata.getOID("C", null));
+ if (duration <= 0) {
+ c.unset("new", null, "duration");
+ } else {
+ c.setInt("new", null, "duration", duration);
+ }
+ }
+
+ private void store(Config c, String section, String name, String value) {
+ if (StringUtils.isEmpty(value)) {
+ c.unset(section, null, name);
+ } else {
+ c.setString(section, null, name, value);
+ }
+ }
} \ No newline at end of file
diff --git a/src/com/gitblit/authority/NewClientCertificateDialog.java b/src/com/gitblit/authority/NewClientCertificateDialog.java
index ad4fe9aa..b04ae73c 100644
--- a/src/com/gitblit/authority/NewClientCertificateDialog.java
+++ b/src/com/gitblit/authority/NewClientCertificateDialog.java
@@ -50,12 +50,12 @@ public class NewClientCertificateDialog extends JDialog {
JCheckBox sendEmail;
boolean isCanceled = true;
- public NewClientCertificateDialog(Frame owner, String displayname, Date defaultExpiration) {
+ public NewClientCertificateDialog(Frame owner, String displayname, Date defaultExpiration, boolean allowEmail) {
super(owner);
setTitle(Translation.get("gb.newCertificate"));
- JPanel content = new JPanel(new BorderLayout(5, 5)) {
+ JPanel content = new JPanel(new BorderLayout(Utils.MARGIN, Utils.MARGIN)) {
private static final long serialVersionUID = 1L;
@Override
@@ -72,7 +72,7 @@ public class NewClientCertificateDialog extends JDialog {
hint = new JTextField(20);
sendEmail = new JCheckBox(Translation.get("gb.sendEmail"));
- JPanel panel = new JPanel(new GridLayout(0, 2, 5, 5));
+ JPanel panel = new JPanel(new GridLayout(0, 2, Utils.MARGIN, Utils.MARGIN));
panel.add(new JLabel(Translation.get("gb.expires")));
panel.add(expirationDate);
@@ -86,8 +86,10 @@ public class NewClientCertificateDialog extends JDialog {
panel.add(new JLabel(Translation.get("gb.passwordHint")));
panel.add(hint);
- panel.add(new JLabel(""));
- panel.add(sendEmail);
+ if (allowEmail) {
+ panel.add(new JLabel(""));
+ panel.add(sendEmail);
+ }
content.add(panel, BorderLayout.CENTER);
@@ -123,7 +125,7 @@ public class NewClientCertificateDialog extends JDialog {
private boolean validateInputs() {
if (getExpiration().getTime() < System.currentTimeMillis()) {
// expires before now
- JOptionPane.showMessageDialog(this, Translation.get("gb.invalidExpiraitonDate"),
+ JOptionPane.showMessageDialog(this, Translation.get("gb.invalidExpirationDate"),
Translation.get("gb.error"), JOptionPane.ERROR_MESSAGE);
return false;
}
diff --git a/src/com/gitblit/authority/NewWebCertificateDialog.java b/src/com/gitblit/authority/NewWebCertificateDialog.java
new file mode 100644
index 00000000..a6846c57
--- /dev/null
+++ b/src/com/gitblit/authority/NewWebCertificateDialog.java
@@ -0,0 +1,131 @@
+/*
+ * 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.authority;
+
+import java.awt.BorderLayout;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Date;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import com.gitblit.client.HeaderPanel;
+import com.gitblit.client.Translation;
+import com.gitblit.utils.StringUtils;
+import com.toedter.calendar.JDateChooser;
+
+public class NewWebCertificateDialog extends JDialog {
+
+ private static final long serialVersionUID = 1L;
+
+ JDateChooser expirationDate;
+ JTextField hostname;
+ boolean isCanceled = true;
+
+ public NewWebCertificateDialog(Frame owner, Date defaultExpiration) {
+ super(owner);
+
+ setTitle(Translation.get("gb.newWebCertificate"));
+
+ JPanel content = new JPanel(new BorderLayout(Utils.MARGIN, Utils.MARGIN)) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Insets getInsets() {
+
+ return Utils.INSETS;
+ }
+ };
+ content.add(new HeaderPanel(Translation.get("gb.newWebCertificate"), "rosette_16x16.png"), BorderLayout.NORTH);
+
+ expirationDate = new JDateChooser(defaultExpiration);
+ hostname = new JTextField(20);
+
+ JPanel panel = new JPanel(new GridLayout(0, 2, Utils.MARGIN, Utils.MARGIN));
+
+ panel.add(new JLabel(Translation.get("gb.hostname")));
+ panel.add(hostname);
+
+ panel.add(new JLabel(Translation.get("gb.expires")));
+ panel.add(expirationDate);
+
+ content.add(panel, BorderLayout.CENTER);
+
+ JButton ok = new JButton(Translation.get("gb.ok"));
+ ok.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if (validateInputs()) {
+ isCanceled = false;
+ setVisible(false);
+ }
+ }
+ });
+ JButton cancel = new JButton(Translation.get("gb.cancel"));
+ cancel.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ isCanceled = true;
+ setVisible(false);
+ }
+ });
+
+ JPanel controls = new JPanel();
+ controls.add(ok);
+ controls.add(cancel);
+
+ content.add(controls, BorderLayout.SOUTH);
+
+ getContentPane().add(content, BorderLayout.CENTER);
+ pack();
+
+ setLocationRelativeTo(owner);
+ }
+
+ private boolean validateInputs() {
+ if (getExpiration().getTime() < System.currentTimeMillis()) {
+ // expires before now
+ JOptionPane.showMessageDialog(this, Translation.get("gb.invalidExpirationDate"),
+ Translation.get("gb.error"), JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+ if (StringUtils.isEmpty(getHostname())) {
+ // must have hostname
+ JOptionPane.showMessageDialog(this, Translation.get("gb.hostnameRequired"),
+ Translation.get("gb.error"), JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+ return true;
+ }
+
+ public String getHostname() {
+ return hostname.getText();
+ }
+
+ public Date getExpiration() {
+ return expirationDate.getDate();
+ }
+
+ public boolean isCanceled() {
+ return isCanceled;
+ }
+}
diff --git a/src/com/gitblit/authority/UserCertificatePanel.java b/src/com/gitblit/authority/UserCertificatePanel.java
index 6b1daee3..79c0d940 100644
--- a/src/com/gitblit/authority/UserCertificatePanel.java
+++ b/src/com/gitblit/authority/UserCertificatePanel.java
@@ -16,12 +16,9 @@
package com.gitblit.authority;
import java.awt.BorderLayout;
-import java.awt.Component;
import java.awt.Cursor;
-import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
-import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
@@ -31,12 +28,10 @@ import java.util.Date;
import javax.swing.ImageIcon;
import javax.swing.JButton;
-import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
-import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableRowSorter;
@@ -55,15 +50,8 @@ public abstract class UserCertificatePanel extends JPanel {
private UserCertificateModel ucm;
- private JTextField displayname;
- private JTextField username;
- private JTextField emailAddress;
- private JTextField organizationalUnit;
- private JTextField organization;
- private JTextField locality;
- private JTextField stateProvince;
- private JTextField countryCode;
-
+ private UserOidsPanel oidsPanel;
+
private CertificatesTableModel tableModel;
private JButton saveUserButton;
@@ -80,29 +68,10 @@ public abstract class UserCertificatePanel extends JPanel {
super(new BorderLayout());
this.owner = owner;
+ oidsPanel = new UserOidsPanel();
- displayname = new JTextField(20);
- username = new JTextField(20);
- username.setEditable(false);
- emailAddress = new JTextField(20);
- organizationalUnit = new JTextField(20);
- organization = new JTextField(20);
- locality = new JTextField(20);
- stateProvince = new JTextField(20);
- countryCode = new JTextField(20);
-
- JPanel fields = new JPanel(new GridLayout(0, 1, 5, 5));
- fields.add(newFieldPanel(Translation.get("gb.displayName"), displayname));
- fields.add(newFieldPanel(Translation.get("gb.username") + " (CN)", username));
- fields.add(newFieldPanel(Translation.get("gb.emailAddress") + " (E)", emailAddress));
- fields.add(newFieldPanel(Translation.get("gb.organizationalUnit") + " (OU)", organizationalUnit));
- fields.add(newFieldPanel(Translation.get("gb.organization") + " (O)", organization));
- fields.add(newFieldPanel(Translation.get("gb.locality") + " (L)", locality));
- fields.add(newFieldPanel(Translation.get("gb.stateProvince") + " (ST)", stateProvince));
- fields.add(newFieldPanel(Translation.get("gb.countryCode") + " (C)", countryCode));
-
- JPanel fp = new JPanel(new BorderLayout(5, 5));
- fp.add(fields, BorderLayout.NORTH);
+ JPanel fp = new JPanel(new BorderLayout(Utils.MARGIN, Utils.MARGIN));
+ fp.add(oidsPanel, BorderLayout.NORTH);
JPanel fieldsPanel = new JPanel(new BorderLayout());
fieldsPanel.add(new HeaderPanel(Translation.get("gb.properties"), "vcard_16x16.png"), BorderLayout.NORTH);
@@ -114,7 +83,7 @@ public abstract class UserCertificatePanel extends JPanel {
public void actionPerformed(ActionEvent e) {
setEditable(false);
String username = ucm.user.username;
- updateUser();
+ oidsPanel.updateUser(ucm);
saveUser(username, ucm);
}
});
@@ -176,12 +145,12 @@ public abstract class UserCertificatePanel extends JPanel {
// save changes
String username = ucm.user.username;
setEditable(false);
- updateUser();
+ oidsPanel.updateUser(ucm);
saveUser(username, ucm);
}
NewClientCertificateDialog dialog = new NewClientCertificateDialog(UserCertificatePanel.this.owner,
- ucm.user.getDisplayName(), getDefaultExpiration());
+ ucm.user.getDisplayName(), getDefaultExpiration(), isAllowEmail());
dialog.setModal(true);
dialog.setVisible(true);
if (dialog.isCanceled()) {
@@ -224,7 +193,7 @@ public abstract class UserCertificatePanel extends JPanel {
Object choice = JOptionPane.showInputDialog(UserCertificatePanel.this.owner,
Translation.get("gb.revokeCertificateReason"), Translation.get("gb.revokeCertificate"),
- JOptionPane.PLAIN_MESSAGE, new ImageIcon(getClass().getResource("/rosette_16x16.png")), choices, Translation.get("gb.unspecified"));
+ JOptionPane.PLAIN_MESSAGE, new ImageIcon(getClass().getResource("/rosette_32x32.png")), choices, Translation.get("gb.unspecified"));
if (choice == null) {
return;
}
@@ -273,26 +242,10 @@ public abstract class UserCertificatePanel extends JPanel {
setEditable(false);
}
- private JPanel newFieldPanel(String label, Component c) {
- JLabel jlabel = new JLabel(label);
- jlabel.setPreferredSize(new Dimension(175, 20));
- JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
- panel.add(jlabel);
- panel.add(c);
- return panel;
- }
-
public void setUserCertificateModel(UserCertificateModel ucm) {
this.ucm = ucm;
setEditable(false);
- displayname.setText(ucm.user.getDisplayName());
- username.setText(ucm.user.username);
- emailAddress.setText(ucm.user.emailAddress);
- organizationalUnit.setText(ucm.user.organizationalUnit);
- organization.setText(ucm.user.organization);
- locality.setText(ucm.user.locality);
- stateProvince.setText(ucm.user.stateProvince);
- countryCode.setText(ucm.user.countryCode);
+ oidsPanel.setUserCertificateModel(ucm);
tableModel.setUserCertificateModel(ucm);
tableModel.fireTableDataChanged();
@@ -300,14 +253,7 @@ public abstract class UserCertificatePanel extends JPanel {
}
public void setEditable(boolean editable) {
- displayname.setEditable(editable);
-// username.setEditable(editable);
- emailAddress.setEditable(editable);
- organizationalUnit.setEditable(editable);
- organization.setEditable(editable);
- locality.setEditable(editable);
- stateProvince.setEditable(editable);
- countryCode.setEditable(editable);
+ oidsPanel.setEditable(editable);
editUserButton.setEnabled(!editable && ucm != null);
saveUserButton.setEnabled(editable && ucm != null);
@@ -316,18 +262,8 @@ public abstract class UserCertificatePanel extends JPanel {
revokeCertificateButton.setEnabled(false);
}
- private void updateUser() {
- ucm.user.displayName = displayname.getText();
- ucm.user.username = username.getText();
- ucm.user.emailAddress = emailAddress.getText();
- ucm.user.organizationalUnit = organizationalUnit.getText();
- ucm.user.organization = organization.getText();
- ucm.user.locality = locality.getText();
- ucm.user.stateProvince = stateProvince.getText();
- ucm.user.countryCode = countryCode.getText();
- }
-
public abstract Date getDefaultExpiration();
+ public abstract boolean isAllowEmail();
public abstract void saveUser(String username, UserCertificateModel ucm);
public abstract void newCertificate(UserCertificateModel ucm, X509Metadata metadata, boolean sendEmail);
diff --git a/src/com/gitblit/authority/UserOidsPanel.java b/src/com/gitblit/authority/UserOidsPanel.java
new file mode 100644
index 00000000..8c3adf66
--- /dev/null
+++ b/src/com/gitblit/authority/UserOidsPanel.java
@@ -0,0 +1,95 @@
+/*
+ * 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.authority;
+
+import java.awt.GridLayout;
+
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import com.gitblit.client.Translation;
+
+public class UserOidsPanel extends JPanel {
+
+ private static final long serialVersionUID = 1L;
+
+ private JTextField displayname;
+ private JTextField username;
+ private JTextField emailAddress;
+ private JTextField organizationalUnit;
+ private JTextField organization;
+ private JTextField locality;
+ private JTextField stateProvince;
+ private JTextField countryCode;
+
+ public UserOidsPanel() {
+ super();
+
+ displayname = new JTextField(20);
+ username = new JTextField(20);
+ username.setEditable(false);
+ emailAddress = new JTextField(20);
+ organizationalUnit = new JTextField(20);
+ organization = new JTextField(20);
+ locality = new JTextField(20);
+ stateProvince = new JTextField(20);
+ countryCode = new JTextField(20);
+
+ setLayout(new GridLayout(0, 1, Utils.MARGIN, Utils.MARGIN));
+ add(Utils.newFieldPanel(Translation.get("gb.displayName"), displayname));
+ add(Utils.newFieldPanel(Translation.get("gb.username") + " (CN)", username));
+ add(Utils.newFieldPanel(Translation.get("gb.emailAddress") + " (E)", emailAddress));
+ add(Utils.newFieldPanel(Translation.get("gb.organizationalUnit") + " (OU)", organizationalUnit));
+ add(Utils.newFieldPanel(Translation.get("gb.organization") + " (O)", organization));
+ add(Utils.newFieldPanel(Translation.get("gb.locality") + " (L)", locality));
+ add(Utils.newFieldPanel(Translation.get("gb.stateProvince") + " (ST)", stateProvince));
+ add(Utils.newFieldPanel(Translation.get("gb.countryCode") + " (C)", countryCode));
+ }
+
+ public void setUserCertificateModel(UserCertificateModel ucm) {
+ setEditable(false);
+ displayname.setText(ucm.user.getDisplayName());
+ username.setText(ucm.user.username);
+ emailAddress.setText(ucm.user.emailAddress);
+ organizationalUnit.setText(ucm.user.organizationalUnit);
+ organization.setText(ucm.user.organization);
+ locality.setText(ucm.user.locality);
+ stateProvince.setText(ucm.user.stateProvince);
+ countryCode.setText(ucm.user.countryCode);
+ }
+
+ public void setEditable(boolean editable) {
+ displayname.setEditable(editable);
+// username.setEditable(editable);
+ emailAddress.setEditable(editable);
+ organizationalUnit.setEditable(editable);
+ organization.setEditable(editable);
+ locality.setEditable(editable);
+ stateProvince.setEditable(editable);
+ countryCode.setEditable(editable);
+ }
+
+ protected void updateUser(UserCertificateModel ucm) {
+ ucm.user.displayName = displayname.getText();
+ ucm.user.username = username.getText();
+ ucm.user.emailAddress = emailAddress.getText();
+ ucm.user.organizationalUnit = organizationalUnit.getText();
+ ucm.user.organization = organization.getText();
+ ucm.user.locality = locality.getText();
+ ucm.user.stateProvince = stateProvince.getText();
+ ucm.user.countryCode = countryCode.getText();
+ }
+}
diff --git a/src/com/gitblit/authority/Utils.java b/src/com/gitblit/authority/Utils.java
index 5c824934..45e028e7 100644
--- a/src/com/gitblit/authority/Utils.java
+++ b/src/com/gitblit/authority/Utils.java
@@ -3,13 +3,16 @@ package com.gitblit.authority;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
+import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Insets;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
+import javax.swing.JLabel;
import javax.swing.JOptionPane;
+import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
@@ -20,8 +23,11 @@ import javax.swing.table.TableModel;
import com.gitblit.client.DateCellRenderer;
import com.gitblit.client.Translation;
+import com.gitblit.utils.StringUtils;
public class Utils {
+
+ public final static int LABEL_WIDTH = 175;
public final static int MARGIN = 5;
@@ -44,6 +50,22 @@ public class Utils {
return table;
}
+ public static JPanel newFieldPanel(String label, Component c) {
+ return newFieldPanel(label, c, null);
+ }
+
+ public static JPanel newFieldPanel(String label, Component c, String trailingLabel) {
+ JLabel jlabel = new JLabel(label);
+ jlabel.setPreferredSize(new Dimension(Utils.LABEL_WIDTH, 20));
+ JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ panel.add(jlabel);
+ panel.add(c);
+ if (!StringUtils.isEmpty(trailingLabel)) {
+ panel.add(new JLabel(trailingLabel));
+ }
+ return panel;
+ }
+
public static void showException(Component c, Throwable t) {
StringWriter writer = new StringWriter();
t.printStackTrace(new PrintWriter(writer));
diff --git a/src/com/gitblit/authority/X509CertificateViewer.java b/src/com/gitblit/authority/X509CertificateViewer.java
index d29c6e7d..1b095153 100644
--- a/src/com/gitblit/authority/X509CertificateViewer.java
+++ b/src/com/gitblit/authority/X509CertificateViewer.java
@@ -47,7 +47,7 @@ public class X509CertificateViewer extends JDialog {
setTitle(Translation.get("gb.viewCertificate"));
- JPanel content = new JPanel(new BorderLayout(5, 5)) {
+ JPanel content = new JPanel(new BorderLayout(Utils.MARGIN, Utils.MARGIN)) {
private static final long serialVersionUID = 1L;
@Override
@@ -63,7 +63,7 @@ public class X509CertificateViewer extends JDialog {
int l1 = 15;
int l2 = 25;
int l3 = 45;
- JPanel panel = new JPanel(new GridLayout(0, 1, 0, 10));
+ JPanel panel = new JPanel(new GridLayout(0, 1, 0, 2*Utils.MARGIN));
panel.add(newField(Translation.get("gb.version"), "" + cert.getVersion(), 3));
panel.add(newField(Translation.get("gb.subject"), cert.getSubjectDN().getName(), l3));
panel.add(newField(Translation.get("gb.issuer"), cert.getIssuerDN().getName(), l3));
@@ -103,7 +103,7 @@ public class X509CertificateViewer extends JDialog {
}
private JPanel newField(String label, String value, int cols) {
- JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
+ JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 2*Utils.MARGIN, 0));
JLabel lbl = new JLabel(label);
lbl.setHorizontalAlignment(SwingConstants.RIGHT);
lbl.setPreferredSize(new Dimension(125, 20));
diff --git a/src/com/gitblit/utils/X509Utils.java b/src/com/gitblit/utils/X509Utils.java
index 3caff358..1510b2cf 100644
--- a/src/com/gitblit/utils/X509Utils.java
+++ b/src/com/gitblit/utils/X509Utils.java
@@ -15,7 +15,6 @@
*/
package com.gitblit.utils;
-import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -108,7 +107,7 @@ public class X509Utils {
public static final String CA_CN = "Gitblit Certificate Authority";
- public static final String CA_FN = CA_CN;
+ public static final String CA_ALIAS = CA_CN;
private static final String BC = org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
@@ -151,6 +150,10 @@ public class X509Utils {
}
}
+ public interface X509Log {
+ void log(String message);
+ }
+
public static class X509Metadata {
// map for distinguished name OIDs
@@ -211,6 +214,21 @@ public class X509Utils {
clone.userDisplayname = userDisplayname;
return clone;
}
+
+ public String getOID(String oid, String defaultValue) {
+ if (oids.containsKey(oid)) {
+ return oids.get(oid);
+ }
+ return defaultValue;
+ }
+
+ public void setOID(String oid, String value) {
+ if (StringUtils.isEmpty(value)) {
+ oids.remove(oid);
+ } else {
+ oids.put(oid, value);
+ }
+ }
}
/**
@@ -218,9 +236,9 @@ public class X509Utils {
*
* @param metadata
* @param folder
- * @param logger
+ * @param x509log
*/
- public static void prepareX509Infrastructure(X509Metadata metadata, File folder) {
+ public static void prepareX509Infrastructure(X509Metadata metadata, File folder, X509Log x509log) {
// make the specified folder, if necessary
folder.mkdirs();
@@ -228,7 +246,7 @@ public class X509Utils {
File caKeyStore = new File(folder, CA_KEY_STORE);
if (!caKeyStore.exists()) {
logger.info(MessageFormat.format("Generating {0} ({1})", CA_CN, caKeyStore.getAbsolutePath()));
- X509Certificate caCert = newCertificateAuthority(metadata, caKeyStore);
+ X509Certificate caCert = newCertificateAuthority(metadata, caKeyStore, x509log);
saveCertificate(caCert, new File(caKeyStore.getParentFile(), "ca.cer"));
}
@@ -236,7 +254,8 @@ public class X509Utils {
File caRevocationList = new File(folder, CA_REVOCATION_LIST);
if (!caRevocationList.exists()) {
logger.info(MessageFormat.format("Generating {0} CRL ({1})", CA_CN, caRevocationList.getAbsolutePath()));
- newCertificateRevocationList(caRevocationList, caKeyStore, metadata.password);
+ newCertificateRevocationList(caRevocationList, caKeyStore, metadata.password);
+ x509log.log("new certificate revocation list created");
}
// rename the old keystore to the new name
@@ -250,17 +269,17 @@ public class X509Utils {
File serverKeyStore = new File(folder, SERVER_KEY_STORE);
if (!serverKeyStore.exists()) {
logger.info(MessageFormat.format("Generating SSL certificate for {0} signed by {1} ({2})", metadata.commonName, CA_CN, serverKeyStore.getAbsolutePath()));
- PrivateKey caPrivateKey = getPrivateKey(CA_FN, caKeyStore, metadata.password);
- X509Certificate caCert = getCertificate(CA_FN, caKeyStore, metadata.password);
- newSSLCertificate(metadata, caPrivateKey, caCert, serverKeyStore);
+ PrivateKey caPrivateKey = getPrivateKey(CA_ALIAS, caKeyStore, metadata.password);
+ X509Certificate caCert = getCertificate(CA_ALIAS, caKeyStore, metadata.password);
+ newSSLCertificate(metadata, caPrivateKey, caCert, serverKeyStore, x509log);
}
// server certificate trust store holds trusted public certificates
File serverTrustStore = new File(folder, X509Utils.SERVER_TRUST_STORE);
if (!serverTrustStore.exists()) {
- logger.info(MessageFormat.format("Importing {0} into trust store ({1})", CA_FN, serverTrustStore.getAbsolutePath()));
- X509Certificate caCert = getCertificate(CA_FN, caKeyStore, metadata.password);
- addTrustedCertificate(CA_FN, caCert, serverTrustStore, metadata.password);
+ logger.info(MessageFormat.format("Importing {0} into trust store ({1})", CA_ALIAS, serverTrustStore.getAbsolutePath()));
+ X509Certificate caCert = getCertificate(CA_ALIAS, caKeyStore, metadata.password);
+ addTrustedCertificate(CA_ALIAS, caCert, serverTrustStore, metadata.password);
}
}
@@ -506,8 +525,9 @@ public class X509Utils {
* @param caPrivateKey
* @param caCert
* @param targetStoreFile
+ * @param x509log
*/
- public static X509Certificate newSSLCertificate(X509Metadata sslMetadata, PrivateKey caPrivateKey, X509Certificate caCert, File targetStoreFile) {
+ public static X509Certificate newSSLCertificate(X509Metadata sslMetadata, PrivateKey caPrivateKey, X509Certificate caCert, File targetStoreFile, X509Log x509log) {
try {
KeyPair pair = newKeyPair();
@@ -541,8 +561,7 @@ public class X509Utils {
new Certificate[] { cert, caCert });
saveKeyStore(targetStoreFile, serverStore, sslMetadata.password);
- log(targetStoreFile.getParentFile(), MessageFormat.format("New web certificate {0,number,0} [{1}]", cert.getSerialNumber(), webDN.toString()));
-
+ x509log.log(MessageFormat.format("New web certificate {0,number,0} [{1}]", cert.getSerialNumber(), cert.getSubjectDN().getName()));
return cert;
} catch (Throwable t) {
throw new RuntimeException("Failed to generate SSL certificate!", t);
@@ -556,9 +575,10 @@ public class X509Utils {
* @param metadata
* @param storeFile
* @param keystorePassword
+ * @param x509log
* @return
*/
- public static X509Certificate newCertificateAuthority(X509Metadata metadata, File storeFile) {
+ public static X509Certificate newCertificateAuthority(X509Metadata metadata, File storeFile, X509Log x509log) {
try {
KeyPair caPair = newKeyPair();
@@ -597,11 +617,12 @@ public class X509Utils {
// Save private key and certificate to new keystore
KeyStore store = openKeyStore(storeFile, caMetadata.password);
- store.setKeyEntry(CA_FN, caPair.getPrivate(), caMetadata.password.toCharArray(),
+ store.setKeyEntry(CA_ALIAS, caPair.getPrivate(), caMetadata.password.toCharArray(),
new Certificate[] { cert });
saveKeyStore(storeFile, store, caMetadata.password);
- log(storeFile.getParentFile(), MessageFormat.format("New CA certificate {0,number,0} [{1}]", cert.getSerialNumber(), issuerDN.toString()));
+ x509log.log(MessageFormat.format("New CA certificate {0,number,0} [{1}]", cert.getSerialNumber(), cert.getIssuerDN().getName()));
+
return cert;
} catch (Throwable t) {
throw new RuntimeException("Failed to generate Gitblit CA certificate!", t);
@@ -621,8 +642,8 @@ public class X509Utils {
try {
// read the Gitblit CA key and certificate
KeyStore store = openKeyStore(caKeystoreFile, caKeystorePassword);
- PrivateKey caPrivateKey = (PrivateKey) store.getKey(CA_FN, caKeystorePassword.toCharArray());
- X509Certificate caCert = (X509Certificate) store.getCertificate(CA_FN);
+ PrivateKey caPrivateKey = (PrivateKey) store.getKey(CA_ALIAS, caKeystorePassword.toCharArray());
+ X509Certificate caCert = (X509Certificate) store.getCertificate(CA_ALIAS);
X500Name issuerDN = new X500Name(PrincipalUtil.getIssuerX509Principal(caCert).getName());
X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuerDN, new Date());
@@ -642,8 +663,6 @@ public class X509Utils {
caRevocationList.delete();
}
tmpFile.renameTo(caRevocationList);
-
- log(caRevocationList.getParentFile(), "new certificate revocation list created");
} finally {
if (fos != null) {
fos.close();
@@ -685,19 +704,22 @@ public class X509Utils {
* @param clientMetadata a container for dynamic parameters needed for generation
* @param caKeystoreFile
* @param caKeystorePassword
+ * @param x509log
* @return a zip file containing the P12, PEM, and personalized README
*/
- public static File newClientBundle(X509Metadata clientMetadata, File caKeystoreFile, String caKeystorePassword) {
+ public static File newClientBundle(X509Metadata clientMetadata, File caKeystoreFile,
+ String caKeystorePassword, X509Log x509log) {
try {
// read the Gitblit CA key and certificate
KeyStore store = openKeyStore(caKeystoreFile, caKeystorePassword);
- PrivateKey caPrivateKey = (PrivateKey) store.getKey(CA_FN, caKeystorePassword.toCharArray());
- X509Certificate caCert = (X509Certificate) store.getCertificate(CA_FN);
+ PrivateKey caPrivateKey = (PrivateKey) store.getKey(CA_ALIAS, caKeystorePassword.toCharArray());
+ X509Certificate caCert = (X509Certificate) store.getCertificate(CA_ALIAS);
// generate the P12 and PEM files
File targetFolder = new File(caKeystoreFile.getParentFile(), clientMetadata.commonName);
- newClientCertificate(clientMetadata, caPrivateKey, caCert, targetFolder);
-
+ X509Certificate cert = newClientCertificate(clientMetadata, caPrivateKey, caCert, targetFolder);
+ x509log.log(MessageFormat.format("New client certificate {0,number,0} [{1}]", cert.getSerialNumber(), cert.getSubjectDN().getName()));
+
// process template message
String readme = processTemplate(new File(caKeystoreFile.getParentFile(), "instructions.tmpl"), clientMetadata);
@@ -830,8 +852,6 @@ public class X509Utils {
// save certificate after successfully creating the key stores
saveCertificate(userCert, certFile);
- log(targetFolder.getParentFile(), MessageFormat.format("New client certificate {0,number,0} [{1}]", userCert.getSerialNumber(), userDN.toString()));
-
return userCert;
} catch (Throwable t) {
throw new RuntimeException("Failed to generate client certificate!", t);
@@ -924,25 +944,6 @@ public class X509Utils {
return content;
}
- private static void log(File folder, String message) {
- BufferedWriter writer = null;
- try {
- writer = new BufferedWriter(new FileWriter(new File(folder, "log.txt"), true));
- writer.write(MessageFormat.format("{0,date,yyyy-MM-dd HH:mm}: {1}", new Date(), message));
- writer.newLine();
- writer.flush();
- } catch (Exception e) {
- logger.error("Failed to append log entry!", e);
- } finally {
- if (writer != null) {
- try {
- writer.close();
- } catch (IOException e) {
- }
- }
- }
- }
-
/**
* Revoke a certificate.
*
@@ -951,15 +952,17 @@ public class X509Utils {
* @param caRevocationList
* @param caKeystoreFile
* @param caKeystorePassword
+ * @param x509log
* @return true if the certificate has been revoked
*/
public static boolean revoke(X509Certificate cert, RevocationReason reason,
- File caRevocationList, File caKeystoreFile, String caKeystorePassword) {
+ File caRevocationList, File caKeystoreFile, String caKeystorePassword,
+ X509Log x509log) {
try {
// read the Gitblit CA key and certificate
KeyStore store = openKeyStore(caKeystoreFile, caKeystorePassword);
- PrivateKey caPrivateKey = (PrivateKey) store.getKey(CA_FN, caKeystorePassword.toCharArray());
- return revoke(cert, reason, caRevocationList, caPrivateKey);
+ PrivateKey caPrivateKey = (PrivateKey) store.getKey(CA_ALIAS, caKeystorePassword.toCharArray());
+ return revoke(cert, reason, caRevocationList, caPrivateKey, x509log);
} catch (Exception e) {
logger.error(MessageFormat.format("Failed to revoke certificate {0,number,0} [{1}] in {2}",
cert.getSerialNumber(), cert.getSubjectDN().getName(), caRevocationList));
@@ -974,12 +977,12 @@ public class X509Utils {
* @param reason
* @param caRevocationList
* @param caPrivateKey
+ * @param x509log
* @return true if the certificate has been revoked
*/
public static boolean revoke(X509Certificate cert, RevocationReason reason,
- File caRevocationList, PrivateKey caPrivateKey) {
+ File caRevocationList, PrivateKey caPrivateKey, X509Log x509log) {
try {
- X500Name subjectDN = new X500Name(PrincipalUtil.getSubjectX509Principal(cert).getName());
X500Name issuerDN = new X500Name(PrincipalUtil.getIssuerX509Principal(cert).getName());
X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuerDN, new Date());
if (caRevocationList.exists()) {
@@ -1005,8 +1008,6 @@ public class X509Utils {
}
tmpFile.renameTo(caRevocationList);
- log(caRevocationList.getParentFile(), MessageFormat.format("Revoked certificate {0,number,0} reason: {1} [{2}]",
- cert.getSerialNumber(), reason.toString(), subjectDN.toString()));
} finally {
if (fos != null) {
fos.close();
@@ -1015,6 +1016,9 @@ public class X509Utils {
tmpFile.delete();
}
}
+
+ x509log.log(MessageFormat.format("Revoked certificate {0,number,0} reason: {1} [{2}]",
+ cert.getSerialNumber(), reason.toString(), cert.getSubjectDN().getName()));
return true;
} catch (Exception e) {
logger.error(MessageFormat.format("Failed to revoke certificate {0,number,0} [{1}] in {2}",
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties
index 6b2102ef..1a1ee175 100644
--- a/src/com/gitblit/wicket/GitBlitWebApp.properties
+++ b/src/com/gitblit/wicket/GitBlitWebApp.properties
@@ -414,4 +414,9 @@ gb.cessationOfOperation = cessation of operation
gb.privilegeWithdrawn = privilege withdrawn
gb.time.inMinutes = in {0} mins
gb.time.inHours = in {0} hours
-gb.time.inDays = in {0} days \ No newline at end of file
+gb.time.inDays = in {0} days
+gb.hostname = hostname
+gb.hostnameRequired = Please enter a hostname
+gb.newWebCertificate = new server SSL certificate
+gb.certificateDefaults = certificate defaults
+gb.duration = duration \ No newline at end of file
diff --git a/tests/com/gitblit/tests/X509UtilsTest.java b/tests/com/gitblit/tests/X509UtilsTest.java
index 85afce0c..85d30deb 100644
--- a/tests/com/gitblit/tests/X509UtilsTest.java
+++ b/tests/com/gitblit/tests/X509UtilsTest.java
@@ -34,6 +34,7 @@ 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;
/**
@@ -48,12 +49,18 @@ public class X509UtilsTest extends Assert {
// based on the JCE policy files
String caPassword = "aBcDeFg";
File folder = new File(System.getProperty("user.dir"), "x509test");
+
+ X509Log log = new X509Log() {
+ 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);
+ X509Utils.prepareX509Infrastructure(goMetadata, folder, log);
}
@After
@@ -66,16 +73,16 @@ public class X509UtilsTest extends Assert {
@Test
public void testNewCA() throws Exception {
File storeFile = new File(folder, X509Utils.CA_KEY_STORE);
- X509Utils.getPrivateKey(X509Utils.CA_FN, storeFile, caPassword);
- X509Certificate cert = X509Utils.getCertificate(X509Utils.CA_FN, storeFile, caPassword);
+ 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_FN, storeFile, caPassword);
- X509Certificate caCert = X509Utils.getCertificate(X509Utils.CA_FN, storeFile, caPassword);
+ 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";
@@ -108,7 +115,7 @@ public class X509UtilsTest extends Assert {
userMetadata.userDisplayname = "James Moger";
userMetadata.passwordHint = "your name";
- File zip = X509Utils.newClientBundle(userMetadata, storeFile, caPassword);
+ File zip = X509Utils.newClientBundle(userMetadata, storeFile, caPassword, log);
assertTrue(zip.exists());
List<String> expected = Arrays.asList(userMetadata.commonName + ".pem", userMetadata.commonName + ".p12", "README.TXT");
@@ -124,8 +131,8 @@ public class X509UtilsTest extends Assert {
@Test
public void testCertificateRevocation() throws Exception {
File storeFile = new File(folder, X509Utils.CA_KEY_STORE);
- PrivateKey caPrivateKey = X509Utils.getPrivateKey(X509Utils.CA_FN, storeFile, caPassword);
- X509Certificate caCert = X509Utils.getCertificate(X509Utils.CA_FN, storeFile, caPassword);
+ 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";
@@ -140,7 +147,7 @@ public class X509UtilsTest extends Assert {
assertFalse(X509Utils.isRevoked(cert1, caRevocationList));
// revoke certificate and then confirm it IS revoked
- X509Utils.revoke(cert1, RevocationReason.ACompromise, caRevocationList, storeFile, caPassword);
+ X509Utils.revoke(cert1, RevocationReason.ACompromise, caRevocationList, storeFile, caPassword, log);
assertTrue(X509Utils.isRevoked(cert1, caRevocationList));
// generate a second certificate
@@ -151,7 +158,7 @@ public class X509UtilsTest extends Assert {
assertFalse(X509Utils.isRevoked(cert2, caRevocationList));
// revoke second certificate and then confirm it IS revoked
- X509Utils.revoke(cert2, RevocationReason.ACompromise, caRevocationList, caPrivateKey);
+ X509Utils.revoke(cert2, RevocationReason.ACompromise, caRevocationList, caPrivateKey, log);
assertTrue(X509Utils.isRevoked(cert1, caRevocationList));
assertTrue(X509Utils.isRevoked(cert2, caRevocationList));
@@ -164,7 +171,7 @@ public class X509UtilsTest extends Assert {
assertFalse(X509Utils.isRevoked(cert3, caRevocationList));
// revoke third certificate and then confirm it IS revoked
- X509Utils.revoke(cert3, RevocationReason.ACompromise, caRevocationList, caPrivateKey);
+ X509Utils.revoke(cert3, RevocationReason.ACompromise, caRevocationList, caPrivateKey, log);
assertTrue(X509Utils.isRevoked(cert1, caRevocationList));
assertTrue(X509Utils.isRevoked(cert2, caRevocationList));
assertTrue(X509Utils.isRevoked(cert3, caRevocationList));