Cassifying Zimbra 5
CASIFYING ZIMBRA COLLABORATION SUITE 5
This document allows guiding you in the process of cassifying Zimbra Collaboration Suite 5.
Installation of the Cas Client
Download the CAS Client Java 2.1.0 from "http://www.ja-sig.org/products/cas/downloads/".
Untar the downloaded file:
# tar xzvf cas-client-java-2.1.0.tar.gz
Then copy the CASclient JAR file to Jetty's lib directory
# cp cas-client-java-2.1.10/dist/casclient.jar /opt/zimbra/jetty/common/lib
Configuration of the Server Zimbra
Edit the file "zimbra.web.xml.in" (/opt/zimbra/jetty/etc) Add the following information after sections "<filter>" and "<filter-mapping>" and before the first section of "<servlet>" (by adapting them): //A ScreenShot is missing
Generation of the SSL_Certificate with Java Keytool
Important Note: It is necessary to delete the certificate if it already exists by using the following commands:
# keytool -delete -alias cas -keystore %JAVA_HOME%/jre/lib/security/cacerts # Keytool -delete -alias cas -file server.cert
If you don't know the name of the certificates (or if these commands did not succeed), you can delete the ".keystore" file in root's homedir and "cacerts" files in "/opt/java/jre/lib/security":
# rm /opt/java/jre/lib/security/cacerts # rm /root/.keystore
Generate the certificate by the following command:
# keytool -genkey -alias cas -keypass changeit -keyalg RSA
Enter ‘changeit’ for the password Answer the list of questions. //A ScreenShot is missing
Export the certificate you generated from your personal keystore by the following command:
# keytool -export -alias cas -keypass changeit -file server.cert
Enter ‘changeit’ for the password. //A ScreenShot is missing
Import the certificate into Java's keystore with this command:
# keytool -import -alias cas -file server.cert -keypass changeit -keystore %JAVA_HOME%/jre/lib/security/cacerts
Enter ‘changeit’ for the password. Answer by 'oui' to add the certificate to the keystore. //A ScreenShot is missing
Validation of the Certificate: Download the class InstallCert.java from http://blogs.sun.com/andreas/resource/InstallCert.java and modify it to comment out some lines :
import java.io.*; import java.net.URL; import java.security.*; import java.security.cert.*; import javax.net.ssl.*; public class InstallCert { public static void main(String[] args) throws Exception { String host; int port; char[] passphrase; args = new String[1]; args[0]="cas-server:8443"; if ((args.length == 1) || (args.length == 2)) { String[] c = args[0].split(":"); host = c[0]; port = (c.length == 1) ? 443 : Integer.parseInt(c[1]); String p = (args.length == 1) ? "changeit" : args[1]; passphrase = p.toCharArray(); } else { System.out.println("Usage: java InstallCert <host>[:port] [passphrase]"); return; } //for my windows and java File file = new File("/opt/zimbra/java/jre/lib/security/cacerts"); // if (file.isFile() == false) { // char SEP = File.separatorChar; // // File dir = new File(System.getProperty("java.home") + SEP // + "lib" + SEP + "security"); // file = new File(dir, "jssecacerts"); // if (file.isFile() == false) { // file = new File(dir, "cacerts"); // } // } System.out.println("Loading KeyStore " + file + "..."); InputStream in = new FileInputStream(file); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(in, passphrase); in.close(); SSLContext context = SSLContext.getInstance("TLS"); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0]; SavingTrustManager tm = new SavingTrustManager(defaultTrustManager); context.init(null, new TrustManager[] {tm}, null); SSLSocketFactory factory = context.getSocketFactory(); System.out.println("Opening connection to " + host + ":" + port + "..."); SSLSocket socket = (SSLSocket)factory.createSocket(host, port); //socket.setSoTimeout(10000); try { System.out.println("Starting SSL handshake..."); socket.startHandshake(); socket.close(); System.out.println(); System.out.println("No errors, certificate is already trusted"); } catch (SSLException e) { System.out.println(); e.printStackTrace(System.out); } X509Certificate[] chain = tm.chain; if (chain == null) { System.out.println("Could not obtain server certificate chain"); return; } BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); System.out.println(); System.out.println("Server sent " + chain.length + " certificate(s):"); System.out.println(); MessageDigest sha1 = MessageDigest.getInstance("SHA1"); MessageDigest md5 = MessageDigest.getInstance("MD5"); for (int i = 0; i < chain.length; i++) { X509Certificate cert = chain[i]; System.out.println (" " + (i + 1) + " Subject " + cert.getSubjectDN()); System.out.println(" Issuer " + cert.getIssuerDN()); sha1.update(cert.getEncoded()); System.out.println(" sha1 " + toHexString(sha1.digest())); md5.update(cert.getEncoded()); System.out.println(" md5 " + toHexString(md5.digest())); System.out.println(); } System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]"); String line = reader.readLine().trim(); int k; try { k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1; } catch (NumberFormatException e) { System.out.println("KeyStore not changed"); return; } X509Certificate cert = chain[k]; String alias = host + "-" + (k + 1); ks.setCertificateEntry(alias, cert); OutputStream out = new FileOutputStream("/opt/zimbra/java/jre/lib/security/cacerts"); ks.store(out, passphrase); out.close(); System.out.println(); System.out.println(cert); System.out.println(); System.out.println ("Added certificate to keystore 'jssecacerts' using alias '" + alias + "'"); String gdzie = new String(System.getProperty("java.home//") + "lib//" + "security"); System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); System.out.println(gdzie); } private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray(); private static String toHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 3); for (int b : bytes) { b &= 0xff; sb.append(HEXDIGITS[b >> 4]); sb.append(HEXDIGITS[b & 15]); sb.append(' '); } return sb.toString(); } private static class SavingTrustManager implements X509TrustManager { private final X509TrustManager tm; private X509Certificate[] chain; SavingTrustManager(X509TrustManager tm) { this.tm = tm; } public X509Certificate[] getAcceptedIssuers() { throw new UnsupportedOperationException(); } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { throw new UnsupportedOperationException(); } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { this.chain = chain; tm.checkServerTrusted(chain, authType); } } }
Compile and execute the class downloaded by the commands:
# javac InstallCert.java
Launch the CAS Server and execute the following command:
# java InstallCert
//A ScreenShot is missing
Answer the composed question by typing "Enter"
//A ScreenShot is missing
Execute the zmprov command: Launch the ZCS server Under the user "zimbra", execute the command:
# zmprov gdpak your_domain_name
(This will create a preAuthKey" as this one: "45a9743161d93f5c2e2194890bca9c1452e45078844ea0134e357709bf11a06f")
Note: To force the execution of the command zmprov you can add the option "-f" and the command will be: zmprov gdpak -f your_domain_name
You can now modify preauth.jsp:
. use the preAuthKey you just got for DOMAIN_KEY . put your own domain name to replace "your_domain_name" (end of file)
<%@ page import="java.security.InvalidKeyException" %> <%@ page import="java.security.NoSuchAlgorithmException" %> <%@ page import="java.security.SecureRandom" %> <%@ page import="java.util.HashMap" %> <%@ page import="java.util.Map" %> <%@ page import="java.util.Iterator" %> <%@ page import="java.util.TreeSet" %> <%@ page import="javax.crypto.Mac" %> <%@ page import="javax.crypto.SecretKey" %> <%! public static final String DOMAIN_KEY = "45a9743161d93f5c2e2194890bca9c1452e45078844ea0134e357709bf11a06f"; public static String generateRedirect(HttpServletRequest request, String name) { HashMap params = new HashMap(); String ts = System.currentTimeMillis()+""; params.put("account", name); params.put("by", "name"); // needs to be part of hmac params.put("timestamp", ts); params.put("expires", "0"); // means use the default String preAuth = computePreAuth(params, DOMAIN_KEY); return request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/service/preauth/?" + "account="+name+ "&by=name"+ "×tamp="+ts+ "&expires=0"+ "&preauth="+preAuth; } public static String computePreAuth(Map params, String key) { TreeSet names = new TreeSet(params.keySet()); StringBuffer sb = new StringBuffer(); for (Iterator it=names.iterator(); it.hasNext();) { if (sb.length() > 0) sb.append('|'); sb.append(params.get(it.next())); } return getHmac(sb.toString(), key.getBytes()); } private static String getHmac(String data, byte[] key) { try { ByteKey bk = new ByteKey(key); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(bk); return toHex(mac.doFinal(data.getBytes())); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("fatal error", e); } catch (InvalidKeyException e) { throw new RuntimeException("fatal error", e); } } static class ByteKey implements SecretKey { private byte[] mKey; ByteKey(byte[] key) { mKey = (byte[]) key.clone();; } public byte[] getEncoded() { return mKey; } public String getAlgorithm() { return "HmacSHA1"; } public String getFormat() { return "RAW"; } } public static String toHex(byte[] data) { StringBuilder sb = new StringBuilder(data.length * 2); for (int i=0; i<data.length; i++ ) { sb.append(hex[(data[i] & 0xf0) >>> 4]); sb.append(hex[data[i] & 0x0f] ); } return sb.toString(); } private static final char[] hex = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f'}; %><% String casUser = (String) session.getAttribute (edu.yale.its.tp.cas.client.filter.CASFilter.CAS_FILTER_USER); out.println(casUser); String redirect = generateRedirect(request, casUser+"@your_domain_name"); out.println(redirect); response.sendRedirect(redirect); %> <html> <head> <title>Pre-auth redirect</title> </head> <body> You should never see this page. </body> </html>
Then copy this file to directory "/opt/zimbra/jetty/webapps/zimbra"
Restart Zimbra to identify the new "jar" and the files of configuration:
# su root # su - zimbra # zmcontrol stop # zmcontrol start
Test the Cassified Zimbra’s Server: Lunch the CAS server Launch Zimbra in the Web browser with the url "http://ecm.ecmteggo.tp/zimbra/preauth.jsp" If everything is set up correctly you will be redirected to the CAS server’s login screen.File:Example.jpg