Auth.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. <?php
  2. /**
  3. * Zm_Auth
  4. *
  5. * @author Yannick Lorenz <ylorenz@1g6.biz>
  6. * @author Fabrizio La Rosa <fabrizio.larosa@unime.it>
  7. * @version 2.2
  8. * @copyright Copyright (c) 2009, Yannick Lorenz
  9. * @copyright Copyright (c) 2012, Fabrizio La Rosa
  10. */
  11. /**
  12. * Zm_Auth class documentation
  13. */
  14. // utils.php contains a small collection of useful functions
  15. require_once ("utils.php");
  16. /**
  17. * Zm_Auth is a class which allows to connect to the Kerio admin or user space via SOAP
  18. *
  19. * Use this class to connect and login to a Kerio server
  20. *
  21. * Example:
  22. *
  23. * // either authenticate as admin:
  24. *
  25. * $auth = new Zm_Auth($kerioServer, $kerioAdminEmail, $kerioAdminPassword, "admin");
  26. *
  27. * // or authenticate as user:
  28. *
  29. * $auth = new Zm_Auth($kerioServer, $userEmail, $userPassword, "user");
  30. *
  31. * // then login
  32. *
  33. * $l = $auth->login();
  34. *
  35. * if(is_a($l, "Exception")) {
  36. *
  37. * echo "Error : cannot login to $kerioServer\n";
  38. *
  39. * echo $l->getMessage()."\n";
  40. *
  41. * exit();
  42. *
  43. * }
  44. *
  45. */
  46. class Zm_Auth
  47. {
  48. /////////////////////
  49. // Class Variables //
  50. /////////////////////
  51. /**
  52. * $auth
  53. * @var Zm_Auth $auth soap authentication
  54. */
  55. private $client;
  56. private $soapHeader;
  57. private $params;
  58. private $authToken;
  59. private $context;
  60. private $retryAttempts;
  61. /**
  62. * Constructor
  63. * @param string $server server name (example: kerio.yourdomain.com)
  64. * @param string $username admin/user account's username
  65. * @param string $password admin/user account's password
  66. * @param string $authas authenticate as admin or user (default admin)
  67. * @param int $attempts how many times we retry to invoke a soapCall (default 3)
  68. */
  69. function __construct($server, $username, $password, $authas="admin", $attempts=3)
  70. {
  71. $ssl_context = stream_context_create([
  72. 'ssl' => [
  73. // set some SSL/TLS specific options
  74. 'verify_peer' => false,
  75. 'verify_peer_name' => false,
  76. 'allow_self_signed' => true
  77. ]
  78. ]);
  79. if ($authas == "admin")
  80. {
  81. $location = "https://" . $server . ":7071/service/admin/soap/";
  82. $uri = "urn:kerioAdmin";
  83. }
  84. if ($authas == "user")
  85. {
  86. $location = "https://" . $server . "/service/soap/";
  87. $uri = "urn:kerioAccount";
  88. }
  89. $this->context = $authas;
  90. $this->client = new SoapClient(null,
  91. array(
  92. 'location' => $location,
  93. 'uri' => $uri,
  94. 'trace' => 1,
  95. 'exceptions' => 1,
  96. 'soap_version' => SOAP_1_2,
  97. 'style' => SOAP_RPC,
  98. 'use' => SOAP_LITERAL,
  99. 'stream_context' => $ssl_context,
  100. )
  101. );
  102. $this->params = array (
  103. new SoapVar('<ns1:account by="name">' . $username . '</ns1:account>', XSD_ANYXML),
  104. new SoapParam($password, "password")
  105. );
  106. $this->retryAttempts = $attempts;
  107. }
  108. /**
  109. * @internal
  110. */
  111. function execSoapCall($request, $params = array(), $options = null)
  112. {
  113. $result = null;
  114. $soapHeader = $this->getSoapHeader();
  115. if ($options["retry"] === false)
  116. $retry = false;
  117. else
  118. $retry = true;
  119. unset($options["retry"]);
  120. $n = 0;
  121. while (true)
  122. {
  123. try
  124. {
  125. $soapRes = null;
  126. $this->client->__soapCall(
  127. $request,
  128. $params,
  129. $options,
  130. $soapHeader
  131. );
  132. $soapRes = $this->client->__getLastResponse();
  133. //$this->auth->setSoapHeader($soapRes['authToken']);
  134. $xml = new xml2Array();
  135. $result = $xml->parse($soapRes);
  136. //echo htmlentities($result);
  137. //A tester : $this->objLastResponse = simplexml_load_string($this->_getBodyContent($this->objLastResponseRaw));
  138. break;
  139. }
  140. catch (SoapFault $exception)
  141. {
  142. // if $retryAttempts>0 retry after a random time using exponential backoff
  143. // if 'retry' option is false (usually when checking account existence) retries just once
  144. $n++;
  145. if ($this->retryAttempts > 0 &&
  146. $n <= $this->retryAttempts && ($retry || $n == 1) ) {
  147. $minT = 1+$n*1000000/10;
  148. $maxT = pow(2, $n-1)*1000000;
  149. $waitT = rand($minT, $maxT);
  150. usleep($waitT);
  151. } else {
  152. // we must re-throw the exception here because this method is only called by the
  153. // Zm_Account, Zm_Domain, Zm_Server class methods with their own try ... catch
  154. throw($exception);
  155. break;
  156. }
  157. }
  158. }
  159. return $result;
  160. }
  161. /**
  162. * @internal
  163. */
  164. function getSoapHeader()
  165. {
  166. return $this->soapHeader;
  167. }
  168. /**
  169. * @internal
  170. */
  171. function setSoapHeader($authToken = null)
  172. {
  173. if(!$authToken)
  174. {
  175. $this->soapHeader = new SoapHeader('urn:kerio','context');
  176. }
  177. else
  178. {
  179. $this->soapHeader = array(
  180. new SoapHeader(
  181. 'urn:kerio',
  182. 'context',
  183. new SoapVar('<ns2:context><ns2:authToken>' . $authToken . '</ns2:authToken></ns2:context>', XSD_ANYXML)
  184. )
  185. );
  186. }
  187. }
  188. /**
  189. * @internal
  190. */
  191. function getClient()
  192. {
  193. return $this->client;
  194. }
  195. /**
  196. * getRetryAttempts
  197. * @return int attempts how many times we retry to invoke a soapCall
  198. */
  199. function getRetryAttempts()
  200. {
  201. return $this->retryAttempts;
  202. }
  203. /**
  204. * setRetryAttempts
  205. * @param int $attempts how many times we retry to invoke a soapCall
  206. the wait time between attempts is progressively increased using an exponential backoff algorithm
  207. */
  208. function setRetryAttempts($attempts)
  209. {
  210. if (!$attempts)
  211. $attempts = 0;
  212. $this->retryAttempts = $attempts;
  213. }
  214. /**
  215. * login
  216. *
  217. * Use this method to login to a Kerio server after you create an instance of this class
  218. *
  219. * Login parameters must be specified when calling the constructor
  220. */
  221. function login()
  222. {
  223. $result = null;
  224. $n = 0;
  225. while (true)
  226. {
  227. try
  228. {
  229. $this->setSoapHeader();
  230. $result = $this->client->__soapCall("AuthRequest", $this->params, null, $this->getSoapHeader());
  231. // $result = $this->client->__getLastResponse();
  232. // print_var($result);
  233. // Save the soapHeader with token
  234. $this->setSoapHeader($result['authToken']);
  235. break;
  236. }
  237. catch (SoapFault $exception)
  238. {
  239. // if $retryAttempts>0 retry after a random time using exponential backoff
  240. // for user logins retries just once
  241. $n++;
  242. if ($this->retryAttempts > 0 &&
  243. $n <= $this->retryAttempts && ($this->context == "admin" || $n == 1) ) {
  244. $minT = 1+$n*1000000/10;
  245. $maxT = pow(2, $n-1)*1000000;
  246. $waitT = rand($minT, $maxT);
  247. // wait times are shorter on login
  248. $waitT = $waitT/5;
  249. usleep($waitT);
  250. } else {
  251. $result = $exception;
  252. break;
  253. }
  254. }
  255. }
  256. return $result;
  257. }
  258. }
  259. ?>