]> source.dussan.org Git - gitblit.git/commitdiff
Gitblit Certificate Authority revisions. Eliminate certificate scripts.
authorJames Moger <james.moger@gitblit.com>
Sun, 25 Nov 2012 16:35:31 +0000 (11:35 -0500)
committerJames Moger <james.moger@gitblit.com>
Sun, 25 Nov 2012 16:35:31 +0000 (11:35 -0500)
24 files changed:
build.xml
distrib/makeclientcertificate.cmd [deleted file]
distrib/makeclientcertificate.sh [deleted file]
distrib/makekeystore.cmd [deleted file]
distrib/makekeystore.sh [deleted file]
distrib/makekeystore_jdk.cmd [deleted file]
distrib/makekeystore_jdk.sh [deleted file]
resources/rosette_32x32.png [new file with mode: 0644]
resources/settings_32x32.png [new file with mode: 0644]
src/com/gitblit/GitBlitServer.java
src/com/gitblit/MakeCertificate.java [deleted file]
src/com/gitblit/authority/DefaultOidsPanel.java [new file with mode: 0644]
src/com/gitblit/authority/GitblitAuthority.java
src/com/gitblit/authority/MakeClientCertificate.java [deleted file]
src/com/gitblit/authority/NewCertificateConfig.java
src/com/gitblit/authority/NewClientCertificateDialog.java
src/com/gitblit/authority/NewWebCertificateDialog.java [new file with mode: 0644]
src/com/gitblit/authority/UserCertificatePanel.java
src/com/gitblit/authority/UserOidsPanel.java [new file with mode: 0644]
src/com/gitblit/authority/Utils.java
src/com/gitblit/authority/X509CertificateViewer.java
src/com/gitblit/utils/X509Utils.java
src/com/gitblit/wicket/GitBlitWebApp.properties
tests/com/gitblit/tests/X509UtilsTest.java

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