{
	"id": "316212ba-c6a7-4de3-b6d9-17ec1997c8fb",
	"created_at": "2026-04-06T00:17:15.80435Z",
	"updated_at": "2026-04-10T03:21:22.805687Z",
	"deleted_at": null,
	"sha1_hash": "5202c32eabec628ba292177fb2843eaae1565f5f",
	"title": "Preauth - Zimbra :: Tech Center",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 121794,
	"plain_text": "Preauth - Zimbra :: Tech Center\r\nArchived: 2026-04-05 17:08:12 UTC\r\nPreauth\r\n   KB 2218        Last updated on 2023-03-16  \r\n0.00\r\n (0 votes)\r\nWhat is preauth?\r\nPreauth stands for pre-authentication, and is a mechanism to enable a trusted third party to \"vouch\" for a user's\r\nidentity. For example, if a user has already signed into a portal and wants to enter the mail application, they should\r\nnot have to be prompted again for their password.\r\nThis can be accomplished by having the mail link they click on in the portal construct a special URL and redirect\r\nthe user to the Zimbra server, which will then verify the data passed in the URL and create authentication token\r\n(the standard mechanism within Zimbra to identify users), save it in a cookie, and redirect the user to the mail app.\r\nHow does it work?\r\nIt works by having a key that is shared between the third party and Zimbra. Knowing this key, the third party\r\nspecifies the desired username, a timestamp (to ensure the request is \"fresh\"), optionally an expiration time, and\r\nthen computes a SHA-1 HMAC over that data using secret key.\r\nThe server computes the HMAC using the supplied data, and its key, to verify that it matches the HMAC sent in\r\nthe request. If it does, the server will construct an auth token, save it in a cookie, and redirect the user to the mail\r\napplication.\r\nPreparing a domain for preauth\r\nIn order for preauth to be enabled for a domain, you need to run the zmprov command and create a key:\r\n zmprov generateDomainPreAuthKey domain.com\r\n preAuthKey: 4e2816f16c44fab20ecdee39fb850c3b0bb54d03f1d8e073aaea376a4f407f0c\r\nMake note of that key value, as you'll need to use it to generate the computed-preauth values below. Also make\r\nsure you keep it secret, as it can be used to generate valid auth tokens for any user in the given domain!\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 1 of 20\n\nBehind the scenes, this command is simply generating 32 random bytes, hex encoding them, then setting the\r\n\"zimbraPreAuthKey\" attr for the specified domain with the value of the key.\r\nTo see the key value after it's generated again [replace YOUR_DOMAIN with the actual domain name you need\r\nto check]:\r\nzmprov gd YOUR_DOMAIN zimbraPreAuthKey\r\nAfter generating the key, you'll probably need to restart the ZCS server so it picks up the updated value.\r\nRedirect security setting\r\nZimbra 9.0.0 Kepler Patch 30 and 8.8.15 James Prescott Joule Patch 37, Zimbra Pre-Auth will only work when it\r\nredirects to the zimbraPublicServiceHostname and that means your DNS domain should match\r\nzimbraPublicServiceHostname. In case you have not configured this correctly or use multiple redirection domains,\r\nrefer to https://wiki.zimbra.com/wiki/Fix_preauth_redirection.\r\nVerify you logging\r\nPreAuth when implemented via REST API will not log the originating IP of the user, in addition you need to\r\nconfigure originating IP so it can be logged via the SOAP API. See: https://wiki.zimbra.com/wiki/Secopstips#Pre-authentication and https://wiki.zimbra.com/wiki/Log_Files#Logging_the_Originating_IP\r\nWhat are the interfaces?\r\nThere are two interfaces. One interface is URL-based, for ease of integration. The other interface is SOAP-based,\r\nfor cases where the third party wants more control over generating the auth token and redirecting the user.\r\nWe'll describe the URL interface first, followed by the SOAP interface.\r\nURL Interface\r\nThe URL interface uses the /service/preauth URL:\r\n/service/preauth?\r\n account={account-identifier}\r\n by={by-value}\r\n timestamp={time}\r\n expires={expires}\r\n [\u0026admin=1]\r\n preauth={computed-preauth}\r\nThe values are as follows:\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 2 of 20\n\n{account-identifier} depends on the value of the \"by\" attr. If \"by\" is not\r\n specified, it is the name (i.e., john.doe@domain.com).\r\n{by-value} name|id|foreignPrincipal, same as AuthRequest. defaults\r\n to name.\r\n{timestamp} current time, in milliseconds. The timestamp must\r\n be within 5 minutes of the server's time for the\r\n preauth to work.\r\n{expires} expiration time of the authtoken, in milliseconds.\r\n set to 0 to use the default expiration time for the\r\n account. Can be used to sync the auth token expiration\r\n time with the external system's notion of expiration\r\n (like a Kerberos TGT lifetime, for example).\r\n{admin} set to \"1\" if this preauth is for admin console. This\r\n only works if given account is an admin, and the request\r\n comes in on the admin port (https 7071 by default).\r\n If admin is specified, then include its value while computing the\r\n HMAC below, after the \"account\" value, and before the \"by\" value.\r\n{computed-preauth} the computed pre-auth value. See below for details.\r\nThe preauth value is computed as follows:\r\n 1. concat the values for account, by, expires, timestamp together\r\n (in that order, order is definitely important!), separated by \"|\"\r\n 2. compute the HMAC on that value using the shared key\r\n (the zimbraPreAuthKey value for the account's domain, generating one\r\n is described below).\r\n 3. convert the HMAC value into a hex string.\r\nFor example, given the following values:\r\nkey: 6b7ead4bd425836e8cf0079cd6c1a05acc127acd07c8ee4b61023e19250e929c\r\naccount: john.doe@domain.com\r\nby: name\r\nexpires: 0\r\ntimestamp: 1135280708088\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 3 of 20\n\nYou would concat the account/by/expires/timestamp values together to get:\r\njohn.doe@domain.com|name|0|1135280708088\r\nYou would then compute the SHA-1 HMAC on that string, using the key:\r\npreauth = hmac(\"john.doe@domain.com|name|0|1135280708088\", \"6b7ead4bd425836e8cf0079cd6c1a05acc127acd0\r\nFinally, you would take the returned hmac (which is most likely an array of bytes), and convert it to a hex string:\r\npreauth-value: b248f6cfd027edd45c5369f8490125204772f844\r\nThe resulting URL would be:\r\n/service/preauth?account=john.doe@domain.com\u0026expires=0\u0026timestamp=1135280708088\u0026preauth=b248f6cfd027ed\r\nHitting that URL on the ZCS server will cause the preauth value to be verified, followed by a redirect to\r\n/zimbra/mail with the auth token in a cookie.\r\nIf a URL other then /zimbra/mail is desired, then you can also pass in a redirectURL:\r\n...\u0026redirectURL=/zimbra/h/\r\nIf you are pre-authing an admin, the value to use with the hmac would be:\r\njohn.doe@domain.com|1|name|0|1135280708088\r\nand you would include \"\u0026admin=1\" in the URL.\r\nIf you are not pre-authing an admin, then you must *NOT* include any value for it in string passed to the hmac.\r\nSOAP Interface\r\nThe SOAP interface uses the standard AuthRequest message, but instead of passing in a password, you specify\r\n\u003cpreauth\u003e data.\r\nFor example:\r\n\u003cAuthRequest xmlns=\"urn:zimbraAccount\"\u003e\r\n\u003caccount by=\"name|id|foreignPrincipal\"\u003e{account-identifier}\u003c/account\u003e\r\n\u003cpreauth timestamp=\"{timestamp}\" expires=\"{expires}\"\u003e{computed-preauth}\u003c/preauth\u003e\r\n\u003c/AuthRequest\u003e\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 4 of 20\n\nThe values are exactly the same as they were for the URL case:\r\n\u003cAuthRequest xmlns=\"urn:zimbraAccount\"\u003e\r\n\u003caccount\u003ejohn.doe@domain.com\u003c/account\u003e\r\n\u003cpreauth timestamp=\"1135280708088\" expires=\"0\"\u003eb248f6cfd027edd45c5369f8490125204772f844\u003c/preauth\u003e\r\n\u003c/AuthRequest\u003e\r\nThe auth token will be return in the AuthResponse. At which point, you can \"inject\" it into the app via the URL\r\ninterface:\r\nhttps://server/service/preauth?isredirect=1\u0026authtoken={...}\r\nGoing to this URL will set the cookie and redirect to /zimbra/mail. If a URL other then /zimbra/mail is desired,\r\nthen you can also pass in a redirectURL:\r\n...\u0026redirectURL=/zimbra/h/\r\nSample Java code for computing the preauth value\r\nThe following Java Code (1.5) will compute the pre-auth value.\r\nimport java.security.InvalidKeyException;\r\nimport java.security.NoSuchAlgorithmException;\r\nimport java.security.SecureRandom;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\nimport java.util.TreeSet;\r\nimport javax.crypto.Mac;\r\nimport javax.crypto.SecretKey;\r\npublic class test {\r\n \r\n public static void main(String args[]) {\r\n HashMap\u003cString,String\u003e params = new HashMap\u003cString,String\u003e();\r\n params.put(\"account\", \"john.doe@domain.com\");\r\n params.put(\"by\", \"name\"); // needs to be part of hmac\r\n params.put(\"timestamp\", \"1135280708088\");\r\n params.put(\"expires\", \"0\");\r\n String key =\r\n \"6b7ead4bd425836e8cf0079cd6c1a05acc127acd07c8ee4b61023e19250e929c\";\r\n System.out.printf(\"preAuth: %s\\n\", computePreAuth(params, key));\r\n }\r\n public static String computePreAuth(Map\u003cString,String\u003e params, String key)\r\n {\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 5 of 20\n\nTreeSet\u003cString\u003e names = new TreeSet\u003cString\u003e(params.keySet());\r\n StringBuilder sb = new StringBuilder();\r\n for (String name: names) {\r\n if (sb.length() \u003e 0) sb.append('|');\r\n sb.append(params.get(name));\r\n }\r\n return getHmac(sb.toString(), key.getBytes());\r\n }\r\n private static String getHmac(String data, byte[] key) {\r\n try {\r\n ByteKey bk = new ByteKey(key);\r\n Mac mac = Mac.getInstance(\"HmacSHA1\");\r\n mac.init(bk);\r\n return toHex(mac.doFinal(data.getBytes()));\r\n } catch (NoSuchAlgorithmException e) {\r\n throw new RuntimeException(\"fatal error\", e);\r\n } catch (InvalidKeyException e) {\r\n throw new RuntimeException(\"fatal error\", e);\r\n }\r\n }\r\n \r\n static class ByteKey implements SecretKey {\r\n private byte[] mKey;\r\n \r\n ByteKey(byte[] key) {\r\n mKey = (byte[]) key.clone();;\r\n }\r\n \r\n public byte[] getEncoded() {\r\n return mKey;\r\n }\r\n public String getAlgorithm() {\r\n return \"HmacSHA1\";\r\n }\r\n public String getFormat() {\r\n return \"RAW\";\r\n }\r\n }\r\n public static String toHex(byte[] data) {\r\n StringBuilder sb = new StringBuilder(data.length * 2);\r\n for (int i=0; i\u003cdata.length; i++ ) {\r\n sb.append(hex[(data[i] \u0026 0xf0) \u003e\u003e\u003e 4]);\r\n sb.append(hex[data[i] \u0026 0x0f] );\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 6 of 20\n\n}\r\nreturn sb.toString();\r\n }\r\n private static final char[] hex =\r\n { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,\r\n '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f'};\r\n}\r\nYou can also use zmprov while debugging to generate preAuth values for comparison:\r\nprov\u003e gdpa domain.com john.doe@domain.com name 1135280708088 0\r\naccount: john.doe@domain.com\r\nby: name\r\ntimestamp: 1135280708088\r\nexpires: 0\r\npreAuth: b248f6cfd027edd45c5369f8490125204772f844\r\nprov\u003e\r\n \r\nSample preauth.jsp\r\nHere is a sample JSP that does everything needed for preauth. It has a hardcoded username, which should of\r\ncourse be changed to match the username of the user you have \"pre-authenticated\".\r\nFile Edit Options Buffers Tools Help\r\n\u003c!--\r\nTo configure:\r\n1) Generate a preauth domain key for your domain using zmprov:\r\nzmprov gdpak domain.com\r\npreAuthKey: ee0e096155314d474c8a8ba0c941e9382bb107cc035c7a24838b79271e32d7b0\r\nTake that value, and set it below as the value of DOMAIN_KEY\r\n2) restart server (only needed the first time you generate the domain pre-auth key)\r\n3) redirect users to this (this, as in *this* file after you install it) JSP page:\r\nhttp://server/zimbra/preauth.jsp\r\nAnd it will construct the preauth URL\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 7 of 20\n\n--\u003e\r\n\u003c%@ page import=\"java.security.InvalidKeyException\"%\u003e\r\n\u003c%@ page import=\"java.security.NoSuchAlgorithmException\"%\u003e\r\n\u003c%@ page import=\"java.security.SecureRandom\"%\u003e\r\n\u003c%@ page import=\"java.util.HashMap\"%\u003e\r\n\u003c%@ page import=\"java.util.Map\"%\u003e\r\n\u003c%@ page import=\"java.util.Iterator\"%\u003e\r\n\u003c%@ page import=\"java.util.TreeSet\"%\u003e\r\n\u003c%@ page import=\"javax.crypto.Mac\"%\u003e\r\n\u003c%@ page import=\"javax.crypto.SecretKey\"%\u003e\r\n\u003c%!\r\n public static final String DOMAIN_KEY =\r\n \"ee0e096155314d474c8a8ba0c941e9382bb107cc035c7a24838b79271e32d7b0\";\r\n public static String generateRedirect(HttpServletRequest request, String name) {\r\n HashMap params = new HashMap();\r\n String ts = System.currentTimeMillis()+\"\";\r\n params.put(\"account\", name);\r\n params.put(\"by\", \"name\"); // needs to be part of hmac\r\n params.put(\"timestamp\", ts);\r\n params.put(\"expires\", \"0\"); // means use the default\r\n String preAuth = computePreAuth(params, DOMAIN_KEY);\r\n return request.getScheme()+\"://\"+request.getServerName()+\":\"+request.getServerPort()+\"/service/p\r\n \"account=\"+name+\r\n \"\u0026by=name\"+\r\n \"\u0026timestamp=\"+ts+\r\n \"\u0026expires=0\"+\r\n \"\u0026preauth=\"+preAuth;\r\n }\r\n public static String computePreAuth(Map params, String key) {\r\n TreeSet names = new TreeSet(params.keySet());\r\n StringBuffer sb = new StringBuffer();\r\n for (Iterator it=names.iterator(); it.hasNext();) {\r\n if (sb.length() \u003e 0) sb.append('|');\r\n sb.append(params.get(it.next()));\r\n }\r\n return getHmac(sb.toString(), key.getBytes());\r\n }\r\n private static String getHmac(String data, byte[] key) {\r\n try {\r\n ByteKey bk = new ByteKey(key);\r\n Mac mac = Mac.getInstance(\"HmacSHA1\");\r\n mac.init(bk);\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 8 of 20\n\nreturn toHex(mac.doFinal(data.getBytes()));\r\n } catch (NoSuchAlgorithmException e) {\r\n throw new RuntimeException(\"fatal error\", e);\r\n } catch (InvalidKeyException e) {\r\n throw new RuntimeException(\"fatal error\", e);\r\n }\r\n }\r\n \r\n \r\n static class ByteKey implements SecretKey {\r\n private byte[] mKey;\r\n ByteKey(byte[] key) {\r\n mKey = (byte[]) key.clone();;\r\n }\r\n public byte[] getEncoded() {\r\n return mKey;\r\n }\r\n public String getAlgorithm() {\r\n return \"HmacSHA1\";\r\n }\r\n public String getFormat() {\r\n return \"RAW\";\r\n }\r\n }\r\n public static String toHex(byte[] data) {\r\n StringBuilder sb = new StringBuilder(data.length * 2);\r\n for (int i=0; i\u003cdata.length; i++ ) {\r\n sb.append(hex[(data[i] \u0026 0xf0) \u003e\u003e\u003e 4]);\r\n sb.append(hex[data[i] \u0026 0x0f] );\r\n }\r\n return sb.toString();\r\n }\r\n private static final char[] hex =\r\n { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,\r\n '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f'};\r\n%\u003e\u003c%\r\nString redirect = generateRedirect(request, \"user1@slapshot.liquidsys.com\");\r\nresponse.sendRedirect(redirect);\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 9 of 20\n\n%\u003e\r\n\u003chtml\u003e\r\n\u003chead\u003e\r\n\u003ctitle\u003ePre-auth redirect\u003c/title\u003e\r\n\u003c/head\u003e\r\n\u003cbody\u003e\r\nYou should never see this page.\r\n\u003c/body\u003e\r\n\u003c/html\u003e\r\nJava Program for Zimbra Autologin from Windows\r\nThe following program is based mainly on the sample Java code provided above. This program fetches the\r\nWindows login name and uses it to construct the preauth URL, open the default web browser, and autologin to the\r\nZimbra server. The preauth key and server are hard-coded into the source, so you will need to set them before you\r\ncompile. You should be aware that this program creates a potential security problem whereby UserA copies\r\nthe compiled jar file, creates a Windows login account on a computer with UserB's login name, and runs the\r\nprogram under that account. UserA will be authenticated as UserB in this scenario.\r\n/*\r\n * Main.java\r\n *\r\n * Created on October 25, 2007, 1:54 PM\r\n *\r\n * Some code originally from: http://wiki.zimbra.com/index.php?title=Preauth\r\n *\r\n * For this program to work, you must follow the directions for enabling preauth\r\n * on your server (available at the URL above). You must also set preAuthKey and\r\n * preAuthUrl in the main method below.\r\n *\r\n * By default, this program uses the Windows login name to set the Zimbra login\r\n * name. These names must match for this program to work.\r\n *\r\n * This method of determining username creates a security problem wherein a user\r\n * could copy the compiled jar and use it to login as any other user. To do so,\r\n * he has to create a Windows login account with the username of whomever he\r\n * wants to login as.\r\n */\r\npackage zimbrapreauthloader;\r\nimport java.security.InvalidKeyException;\r\nimport java.security.NoSuchAlgorithmException;\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 10 of 20\n\nimport java.security.SecureRandom;\r\nimport java.io.IOException;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\nimport java.util.TreeSet;\r\nimport javax.crypto.Mac;\r\nimport javax.crypto.SecretKey;\r\n/**\r\n *\r\n */\r\npublic class Main {\r\n \r\n static String newline = System.getProperty(\"line.separator\");\r\n \r\n /** Creates a new instance of Main */\r\n public Main() {\r\n }\r\n public static void main(String args[]) {\r\n String account = getAccount(); // Account name you are trying to login\r\n String by = \"name\"; // Specifies how account should be determined\r\n String timestamp = \"\"; // Current Unix date and time\r\n String expires = \"0\"; // Length of time in milliseconds to expire the auth\r\n String preAuthKey = \" \"; // Se\r\n String preAuthValue = \"\"; // Calculated value for preauth\r\n String preAuthUrl = \"https://mail.domain.com/service/preauth?\"; // URL to use preauth\r\n String openBrowser = \"rundll32 url.dll,FileProtocolHandler \"; // Command to open browser af\r\n \r\n // Generate timestamp\r\n Date date = new Date();\r\n timestamp = \"\" + date.getTime();\r\n \r\n // Assign values needed to calculate preauth\r\n HashMap\u003cString,String\u003e params = new HashMap\u003cString,String\u003e();\r\n params.put(\"account\", account);\r\n params.put(\"by\", by); // needs to be part of hmac\r\n params.put(\"timestamp\", timestamp);\r\n params.put(\"expires\", expires);\r\n \r\n // Compute preAuthValue\r\n preAuthValue = computePreAuth(params, preAuthKey);\r\n \r\n // Construct preAuthUrl\r\n preAuthUrl += constructUrl(account, expires, timestamp, preAuthValue);\r\n \r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 11 of 20\n\n// Open Browser;\r\n try {\r\n Runtime.getRuntime().exec(openBrowser + preAuthUrl);\r\n }\r\n catch (IOException e) {\r\n System.out.println(\"Unable to open browser.\");\r\n System.exit(1);\r\n }\r\n }\r\n /**\r\n * Constructs the URL needed to authorize\r\n *\r\n * Example url:\r\n * https://mail.domain.com/service/preauth?account=john.doe@domain.com\u0026expires=0\u0026timestamp=113528\r\n */\r\n public static String constructUrl(String useAccount, String useExpires, String useTimestamp, Stri\r\n String url = \"\";\r\n // Account part\r\n url += \"account=\" + useAccount + \"\u0026\";\r\n // Expires part\r\n url += \"expires=\" + useExpires + \"\u0026\";\r\n // Timestamp part\r\n url += \"timestamp=\" + useTimestamp + \"\u0026\";\r\n // PreAuth part\r\n url += \"preauth=\" + usePreAuthValue;\r\n return url;\r\n }\r\n \r\n /**\r\n * Provides the account name to login as\r\n *\r\n * Retrieves the Windows login name and uses that as the Zimbra login name\r\n */\r\n private static String getAccount() {\r\n String username = System.getProperty(\"user.name\");\r\n return username;\r\n }\r\n \r\n /**\r\n * Computes the preauth string\r\n */\r\n public static String computePreAuth(Map\u003cString,String\u003e params, String key) {\r\n TreeSet\u003cString\u003e names = new TreeSet\u003cString\u003e(params.keySet());\r\n StringBuilder sb = new StringBuilder();\r\n for (String name: names) {\r\n if (sb.length() \u003e 0) {\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 12 of 20\n\nsb.append('|');\r\n }\r\n sb.append(params.get(name));\r\n }\r\n return getHmac(sb.toString(), key.getBytes());\r\n }\r\n /**\r\n * Computes the preAuth excryption key\r\n */\r\n private static String getHmac(String data, byte[] key) {\r\n try {\r\n ByteKey bk = new ByteKey(key);\r\n Mac mac = Mac.getInstance(\"HmacSHA1\");\r\n mac.init(bk);\r\n return toHex(mac.doFinal(data.getBytes()));\r\n } catch (NoSuchAlgorithmException e) {\r\n throw new RuntimeException(\"fatal error\", e);\r\n } catch (InvalidKeyException e) {\r\n throw new RuntimeException(\"fatal error\", e);\r\n }\r\n }\r\n \r\n static class ByteKey implements SecretKey {\r\n private byte[] mKey;\r\n \r\n ByteKey(byte[] key) {\r\n mKey = (byte[]) key.clone();\r\n }\r\n \r\n public byte[] getEncoded() {\r\n return mKey;\r\n }\r\n \r\n public String getAlgorithm() {\r\n return \"HmacSHA1\";\r\n }\r\n \r\n public String getFormat() {\r\n return \"RAW\";\r\n }\r\n }\r\n public static String toHex(byte[] data) {\r\n StringBuilder sb = new StringBuilder(data.length * 2);\r\n for (int i=0; i\u003cdata.length; i++ ) {\r\n sb.append(hex[(data[i] \u0026 0xf0) \u003e\u003e\u003e 4]);\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 13 of 20\n\nsb.append(hex[data[i] \u0026 0x0f] );\r\n }\r\n return sb.toString();\r\n }\r\n private static final char[] hex = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f\r\n \r\n}\r\n--Brousch 12:56, 25 October 2007 (PDT)\r\n.NET C# Code For Redirecting to Zimbra Preauth\r\nusing System;\r\nusing System.Collections;\r\nusing System.ComponentModel;\r\nusing System.Data;\r\nusing System.Drawing;\r\nusing System.Web;\r\nusing System.Web.SessionState;\r\nusing System.Web.UI;\r\nusing System.Web.UI.WebControls;\r\nusing System.Web.UI.HtmlControls;\r\nusing System.Text;\r\nusing System.Security.Cryptography;\r\n \r\nnamespace Zimbra\r\n{\r\n/// \u003csummary\u003e\r\n/// Summary description for Zimbra.\r\n/// \u003c/summary\u003e\r\npublic class Zimbra: System.Web.UI.Page\r\n{\r\nprivate void Page_Load(object sender, System.EventArgs e)\r\n{\r\n/*\r\n * This page authenticates a user to zimbra using zimbra's preauth method.\r\n * A user should be authenticated before reaching this page via some external\r\n * method which populates LOGON_USER, then a one time key is generated and forwarded the user\r\n * is forwarded to zimbra. Zimbra validates the key, generates a cookie for the\r\n * user, and they are then authenticated.\r\n */\r\n// warning.Text = Request.ServerVariables[\"ALL_HTTP\"];\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 14 of 20\n\nstring preauthkey = \"3298a239b8983c723874893274...\"; //copied from zimbra dom\r\nstring preauthurl = \"https://zimbra.example.com/service/preauth\";\r\nstring account = Request.ServerVariables[\"LOGON_USER\"] + \"@zimbra.example.com\r\nstring preauthvalue; //holds the string to be encoded\r\nstring preauthencoded; //holds the preauthvalue after it has been sha1-hmac'd\r\nstring timestamp; //millisecs since epoch\r\n \r\n//convert key to byte form, as required for hmac\r\nSystem.Text.ASCIIEncoding encoding=new System.Text.ASCIIEncoding();\r\nHMACSHA1 hmacsha1 = new HMACSHA1(encoding.GetBytes(preauthkey));\r\n \r\n//get timestamp\r\nDateTime d1 = new DateTime(1970, 1, 1);\r\nDateTime d2 = DateTime.Now;\r\nTimeSpan ts = new TimeSpan(d2.Ticks - d1.Ticks);\r\n//correct .net timezone\r\nTimeSpan utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset( d2 );\r\nInt64 tsint = (long) ts.TotalMilliseconds - (long) utcOffset.TotalMillisecond\r\ntimestamp = tsint.ToString();\r\n//have everything we need to make our preauth string\r\n //we need using SortedDictionary to reorder params by alphabet\r\n SortedDictionary\u003cString, String\u003e parms = new SortedDictionary\u003cString, String\u003e\r\n parms.Add(\"account\", account);\r\n parms.Add(\"by\", name);\r\n parms.Add(\"expires\", 0);\r\n parms.Add(\"timestamp\", timestamp);\r\n StringBuilder sb = new StringBuilder();\r\n foreach (var parm in parms)\r\n {\r\n if (sb.Length!= 0)\r\n {\r\n sb.Append(\"|\");\r\n }\r\n sb.Append(parm.Value);\r\n }\r\n//preauthvalue = account + \"|name|0|\" + timestamp;\r\n preauthvalue = sb.toString();\r\n//encode our preauth string\r\nbyte[] preauthvaluebytes = encoding.GetBytes(preauthvalue);\r\nbyte[] hashmessage = hmacsha1.ComputeHash(preauthvaluebytes);\r\nStringBuilder sb = new StringBuilder(hashmessage.Length * 2);\r\nforeach (byte b in hashmessage)\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 15 of 20\n\n{\r\nsb.AppendFormat(\"{0:x2}\", b);\r\n}\r\npreauthencoded = sb.ToString();\r\n//send the user over to zimbra. hope all is well.\r\nResponse.Redirect(preauthurl + \"?account=\" + account + \"\u0026by=name\u0026timestamp=\"\r\n}\r\n#region Web Form Designer generated code\r\noverride protected void OnInit(EventArgs e)\r\n{\r\n//\r\n// CODEGEN: This call is required by the ASP.NET Web Form Designer.\r\n//\r\nInitializeComponent();\r\nbase.OnInit(e);\r\n}\r\n/// \u003csummary\u003e\r\n/// Required method for Designer support - do not modify\r\n/// the contents of this method with the code editor.\r\n/// \u003c/summary\u003e\r\nprivate void InitializeComponent()\r\n{\r\nthis.Load += new System.EventHandler(this.Page_Load);\r\n}\r\n#endregion\r\n}\r\n}\r\n--User:djlarsu 10:43, 19 May 2009 (EDT)\r\nPHP Code For Redirecting to Zimbra Preauth\r\nThe following PHP script takes user name and domain name as GET parameters and redirects the browser to ZCS\r\npreauth. In order to use this code, you need to put your own values for $WEB_MAIL_PREAUTH_URL and\r\n$PREAUTH_KEY\r\n\u003c?php\r\n /**\r\n * Globals. Can be stored in external config.inc.php or retreived from a DB.\r\n */\r\n $PREAUTH_KEY=\"0f6f5bbf7f3ee4e99e2d24a7091e262db37eb9542bc921b2ae4434fcb6338284\";\r\n $WEB_MAIL_PREAUTH_URL=\"http://zimbra.server.com/service/preauth\";\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 16 of 20\n\n/**\r\n * User's email address and domain. In this example obtained from a GET query parameter.\r\n * i.e. preauthExample.php?email=user@domain.com\u0026domain=domain.com\r\n * You could also parse the email instead of passing domain as a separate parameter\r\n */\r\n $user = $_GET[\"user\"];\r\n $domain=$_GET[\"domain\"];\r\n \r\n $email = \"{$user}@{$domain}\";\r\n if(empty($PREAUTH_KEY)) {\r\n die(\"Need preauth key for domain \".$domain);\r\n }\r\n \r\n /**\r\n * Create preauth token and preauth URL\r\n */\r\n $timestamp=time()*1000;\r\n $preauthToken=hash_hmac(\"sha1\",$email.\"|name|0|\".$timestamp,$PREAUTH_KEY);\r\n $preauthURL = $WEB_MAIL_PREAUTH_URL.\"?account=\".$email.\"\u0026by=name\u0026timestamp=\".$timestamp.\"\u0026expires\r\n \r\n /**\r\n * Redirect to Zimbra preauth URL\r\n */\r\n header(\"Location: $preauthURL\");\r\n?\u003e\r\n--User:Greg 2:37, 5 November 2008 (MST)\r\nSample Ruby code for computing the preauth value\r\nrequire 'openssl'\r\ninclude OpenSSL\r\ninclude Digest\r\ndef compute_preauth(name, time_st, authkey)\r\n plaintext=\"#{name}|name|0|#{time_st}\"\r\n key=authkey\r\n hmacd=HMAC.new(key, SHA1.new)\r\n hmacd.update(plaintext)\r\n return hmacd.to_s\r\nend\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 17 of 20\n\nUser: Rahul Chaudhari 10:52, 29 October 2009 (IST)\r\nDjango/Python Code For Redirecting to Zimbra Preauth\r\nThe following Python code uses Django's built in user management to perform preauth. Can be used as a reference\r\nfor non-Django Python code as well. In order to use this code, you need to put your own values for preauth_key\r\nand preauth_url.\r\ndef webmail_redirect(request):\r\n from time import time\r\n import hmac, hashlib\r\n preauth_key = \"0f6f5bbf7f3ee4e99e2d24a7091e262db37eb9542bc921b2ae4434fcb6338284\"\r\n preauth_url = \"http://zimbra.server.com/service/preauth\"\r\n timestamp = int(time()*1000)\r\n try:\r\n #If they're not logged in, an exception will be thrown.\r\n acct = request.user.email\r\n pak = hmac.new(preauth_key, '%s|name|0|%s'%(acct, timestamp), hashlib.sha1).hexdigest()\r\n return HttpResponseRedirect(\"%s?account=%s\u0026expires=0\u0026timestamp=%s\u0026preauth=%s\"%(preauth_url, a\r\n except:\r\n pass\r\n return HttpResponseRedirect(\"/not_logged_in/\")\r\nPerl Code from LemonLDAP::NG\r\nThis code is used in LemonLDAP::NG ([1]), an open source WebSSO product. An URL is catched, ant then\r\nZimbra URL is built. The integration with LemonLDAP::NG is explained here: [2].\r\nuse Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);\r\n## @method private string buildZimbraPreAuthUrl(string key, string url, string account, string by)\r\n# Build Zimbra PreAuth URL\r\n# @param key PreAuthKey\r\n# @param url URL\r\n# @param account User account\r\n# @param by Account type\r\n# @return Zimbra PreAuth URL\r\nsub buildZimbraPreAuthUrl {\r\n my ( $key, $url, $account, $by ) = splice @_;\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 18 of 20\n\n# Expiration time\r\n my $expires = 0;\r\n # Timestamp\r\n my $timestamp = time() * 1000;\r\n # Compute preauth value\r\n my $computed_value =\r\n hmac_sha1_hex( \"$account|$by|$expires|$timestamp\", $key );\r\n # Build PreAuth URL\r\n my $zimbra_url;\r\n $zimbra_url .= $url;\r\n $zimbra_url .= '?account=' . $account;\r\n $zimbra_url .= '\u0026by=' . $by;\r\n $zimbra_url .= '\u0026timestamp=' . $timestamp;\r\n $zimbra_url .= '\u0026expires=' . $expires;\r\n $zimbra_url .= '\u0026preauth=' . $computed_value;\r\n return $zimbra_url;\r\n}\r\n--Coudot 08:11, 7 May 2010 (UTC)\r\nCas And PreAuth\r\nPlease see:\r\nCassifying_Zimbra_5\r\nCASifying_Zimbra_6.0\r\nAjcody-External-Authentication#JA-SIG_Central_Authentication_Service_Or_CAS\r\nRapidSSL Certificate\r\nTrouble Shooting\r\nDoesn't Work After Upgrade Of ZCS\r\nPlease check the data/time on your servers. If they are off by more than 5 minutes preauth will fail.\r\n--Niosop 03:45, 6 January 2009 (UTC)\r\nTry Zimbra\r\nTry Zimbra Collaboration with a 60-day free trial.\r\nGet it now »\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 19 of 20\n\nWant to get involved?\r\nYou can contribute in the Community, Wiki, Code, or development of Zimlets.\r\nFind out more. »\r\nLooking for a Video?\r\nVisit our YouTube channel to get the latest webinars, technology news, product overviews, and so much more.\r\nGo to the YouTube channel »\r\nSource: https://wiki.zimbra.com/wiki/Preauth\r\nhttps://wiki.zimbra.com/wiki/Preauth\r\nPage 20 of 20",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://wiki.zimbra.com/wiki/Preauth"
	],
	"report_names": [
		"Preauth"
	],
	"threat_actors": [],
	"ts_created_at": 1775434635,
	"ts_updated_at": 1775791282,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/5202c32eabec628ba292177fb2843eaae1565f5f.pdf",
		"text": "https://archive.orkl.eu/5202c32eabec628ba292177fb2843eaae1565f5f.txt",
		"img": "https://archive.orkl.eu/5202c32eabec628ba292177fb2843eaae1565f5f.jpg"
	}
}