Difference between revisions of "Cassifying Zimbra 5"

(Generation of the SSL_Certificate with Java Keytool)
(Generation of the SSL_Certificate with Java Keytool)
Line 23: Line 23:
 
  # Keytool -delete -alias cas -file server.cert  
 
  # 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 homedire and "cacerts" files in "/opt/java/jre/lib/security":  
+
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 /opt/java/jre/lib/security/cacerts  
 
  # rm /root/.keystore  
 
  # rm /root/.keystore  
Line 224: Line 224:
  
 
Execute the zmprov command:
 
Execute the zmprov command:
Launch the Server Zimbra
+
Launch the ZCS server
 
Under the user "zimbra", execute the command:  
 
Under the user "zimbra", execute the command:  
  # zmprov gdpak Domaine_Name
+
  # zmprov gdpak your_domain_name
 
(This will create a preAuthKey" as this one:
 
(This will create a preAuthKey" as this one:
 
"45a9743161d93f5c2e2194890bca9c1452e45078844ea0134e357709bf11a06f")
 
"45a9743161d93f5c2e2194890bca9c1452e45078844ea0134e357709bf11a06f")
  
'''''Note:''' To force the execution of the command zmprov you can add the option "-f" and the command will be: zmprov gdpak -f Domaine_Name''
+
'''''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)
  
Configure the page "preauth.jsp" (Attachements):
+
<pre>
Under the user "root", copy the page "preauth.jsp" in the directory: "/opt/zimbra/jetty/webapps/zimbra"  
+
<%@ page import="java.security.InvalidKeyException" %>
Replace the "DOMAIN_KEY" with the key which you produced with the "zmprov" in the previous stage.
+
<%@ page import="java.security.NoSuchAlgorithmException" %>
//A ScreenShot is missing
+
<%@ 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"+
 +
          "&timestamp="+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>
 +
</pre>
  
 +
Then copy this file to directory "/opt/zimbra/jetty/webapps/zimbra"
  
Modify the following lines towards the end of the JSP page, by substituting "domaine-name" by your domain:
 
//A ScreenShot is missing
 
  
 
Restart Zimbra to identify the new "jar" and the files of configuration:  
 
Restart Zimbra to identify the new "jar" and the files of configuration:  

Revision as of 08:55, 28 March 2008


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"+
           "&timestamp="+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

Verified Against: unknown Date Created: 3/18/2008
Article ID: https://wiki.zimbra.com/index.php?title=Cassifying_Zimbra_5 Date Modified: 2008-03-28



Try Zimbra

Try Zimbra Collaboration with a 60-day free trial.
Get it now »

Want to get involved?

You can contribute in the Community, Wiki, Code, or development of Zimlets.
Find out more. »

Looking for a Video?

Visit our YouTube channel to get the latest webinars, technology news, product overviews, and so much more.
Go to the YouTube channel »


Jump to: navigation, search