Single Sign On With Zimbra And PHP

Mfadly N
4 min readDec 25, 2020

Imagine, when your company developed so many applications and most of them are web applications, developed using PHP and designed with monolith architecture, so it means that every single application has there own username & password. This becomes a problem since we have to maintain so many user accounts, every single day, you may facing lots of tickets request to reset user passwords or disable the user account for the employee who has been inactive .

This is reasonable because many of them (the employees) unable to remember all of their password. So I was thinking how do I integrate all username & password to our zimbra email. It means that we want to make every username and password in every web applications are equal with zimbra user and password. See this detail scenario

Before that, we need to know what attributes of POST request/response are sent from user while accessing zimbra email from web. So I’m using fiddler to analyze the traffic, and found several informations here.

As you see, there are 4 POST request parameter that send from zimbra web client to server:

  1. loginOP : This marked as login operation “login/logout”
  2. username : Username (with email format username@domain.com)
  3. password : Password zimbra mail
  4. Client : set as preffered

For your information that I’m using zimbra mail version 8, but this parameters are also valid for older version. Now we gonna use PHP CURL to handling POST Request:

<?php  if (isset($_POST['userid']) and isset($_POST['userpass'])){

$username = $_POST['userid'];
$password = $_POST['userpass'];
if (zimbraLogin($username,$password)){
echo "<b>LOGIN ZIMBRA VALID";}else{
echo "<b><font color=red>LOGIN ZIMBRA TIDAK VALID</font>";
}
}
function zimbraLogin($username, $password) { $ch = curl_init();
curl_setopt($ch, CURLOPT_COOKIE, 'ZM_TEST=true');
curl_setopt($ch, CURLOPT_REFERER, "https://yourzimbra.com/"); // Change this to your zimbra web url page
curl_setopt($ch, CURLOPT_URL, "https://yourzimbra.com/"); // Change this to your zimbra web url page
curl_setopt($ch, CURLOPT_VERBOSE, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // Disable curl validating SSL cert - needed for self-signed
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_FAILONERROR, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); // Allow auto redirect page
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Return value into a variable
curl_setopt($ch, CURLOPT_TIMEOUT, 0); // Setting waktu timeout 0
curl_setopt($ch, CURLOPT_HEADER, 1); // Set header
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "loginOp=login&username=$username&password=$password&client=preferred");
$result = curl_exec($ch);
curl_close($ch);
$values = explode("
",$result);
foreach($values as $key => $value) { list($start,$good) = array_pad(explode(':', $value),2,null);
// Baca header Location, kondisi ini untuk mengecek redirect page setelah login valid
if($start == "Location")
{
// Valid jika exist
// header($values[$key]);
return true;
die;
}
}
// Tidak valid
return false;
}
?>
<html>
<head>
<title>TEST LOGIN ZIMBRA</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body id="body_bg">
<div <div align="center">
<h3>TEST LOGIN ZIMBRA</h3>
<form id="login-form" method="post" action="loginzimbra.php" >
<table border="0.5" >
<tr>
<td><label for="userid">User Name</label></td>
<td><input type="text" name="userid" id="userid"></td>
</tr>
<tr>
<td><label for="userpass">Password</label></td>
<td><input type="password" name="userpass" id="userpass"></input></td>
</tr>

<tr>

<td><input type="submit" value="Submit" />
<td><input type="reset" value="Reset"/>

</tr>
</table>
</form>
</div>
</body>
</html>

You can also download the source code from my github page

TESTING THE CODE

Set the code with your zimbra environment then test it. Now you can use your valid zimbra account to test login page.

Valid zimbra account

Invalid zimbra mail account

The logic of the code is very simple. We only need to check the existence of “Location” Header from POST Response, otherwise will fail. You can also make an auto redirection page by replacing the header values from the code:

if($start == "Location")
{
// Valid if exist
return true;
header($values[$key]); //replace this value to your valid login page
die;
}

I tested this code with zimbra version 6 and 8, both of them are working fine without any problem. But this only proof of concept code, when you have a thousand or more users, I suggest you to use caching technique like mongoDB or Redis to prevent server performance issues.

OK thats all, hope this post can help you also, I also put this code on my github page, just mail me if you have any questions, or you can contact me on my linkedin page.

--

--

Mfadly N

Normative citizen, A Husband & Father, IT Guy, Freelance Hacker, Freelance Gamer, Boxing, Basketball and Cuan enthusiast