Verified Commit 230f2671 authored by Côme Chilliet's avatar Côme Chilliet
Browse files

:sparkles: feat(zimbra) Add zimbra plugin to synchronize accounts

Through Zimbra SOAP API

issue #6089
Showing with 1154 additions and 0 deletions
+1154 -0
<?php
/*
This code is part of FusionDirectory (http://www.fusiondirectory.org/)
Copyright (C) 2016-2021 FusionDirectory
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
class serviceZimbra extends simpleMailMethodService
{
static function plInfo (): array
{
return [
'plShortName' => _('Zimbra'),
'plDescription' => _('Zimbra'),
'plIcon' => 'geticon.php?context=applications&icon=zimbra&size=16',
'plObjectClass' => ['fdZimbraServer'],
'plProvidedAcls' => parent::generatePlProvidedAcls(static::getAttributesInfo())
];
}
static function getAttributesInfo (): array
{
return [
'main' => [
'name' => _('Settings'),
'class' => ['fullwidth'],
'attrs' => [
new URLAttribute(
_('URI'), _('URI of the Zimbra server'),
'fdZimbraServerUri', TRUE
),
new StringAttribute(
_('User Agent'), _('User Agent to use to contact the Zimbra API'),
'fdZimbraServerUserAgent', TRUE,
'FusionDirectory'
),
new SelectAttribute(
_('Mailbox deletion'), _('What to do with the Zimbra account when mail tab is deactivated or user is deleted'),
'fdZimbraServerDeletionType', TRUE,
[ 'delete', 'disable'], '',
[_('Delete'),_('Disable')]
),
new StringAttribute(
_('Login'), _('Login to use to contact the Zimbra API'),
'fdZimbraServerLogin', TRUE
),
new PasswordAttribute(
_('Password'), _('Password to use to contact the Zimbra API'),
'fdZimbraServerPassword', TRUE
),
]
],
'domains' => [
'template' => get_template_path('zimbra_domains.tpl', TRUE, dirname(__FILE__)),
'name' => _('Domains'),
'class' => ['fullwidth'],
'attrs' => [
new OrderedArrayAttribute(
new CharSeparatedCompositeAttribute(
_('Domains handled by this Zimbra server'),
'fdZimbraServerMailDomain',
[
new StringAttribute(
_('Domain'), _('Domain handled by this server'),
'zimbraDomain', TRUE
),
new StringAttribute(
_('Classes of service'), _('Possible classes of service for this domain and their ids, separated by commas. Format is cos1Name|cos1Id,cos2Name|cos2Id.'),
'zimbraDomainCOS', TRUE,
'', '',
'/^[^,|]+\|[^,|]+(,[^,|]+\|[^,|]+)*$/',
'cos1|cos1id,cos2|cos2id'
)
],
':',
'',
_('Domains')
),
FALSE, [], TRUE
)
]
]
];
}
function __construct ($dn = NULL, $parent = NULL)
{
parent::__construct($dn, $parent);
$this->attributesAccess['fdZimbraServerMailDomain']->setLinearRendering(FALSE);
}
}
<fieldset id="{$sectionId}" class="plugin-section{$sectionClasses}">
<legend><span><label for="{$attributes.fdZimbraServerMailDomain.htmlid}">{if $sectionIcon}<img src="{$sectionIcon|escape}" alt=""/>{/if}{$section|escape}</label></span></legend>
<div>
<table>
<tr>
<td title="{$attributes.fdZimbraServerMailDomain.description}" colspan="4">
{eval var=$attributes.fdZimbraServerMailDomain.input}
</td>
</tr>
<tr>
<td title="{$attributes.zimbraDomain.description}">
<label for="{$attributes.zimbraDomain.htmlid}">
{eval var=$attributes.zimbraDomain.label}
</label>
</td>
<td>{eval var=$attributes.zimbraDomain.input}</td>
</tr>
<tr>
<td title="{$attributes.zimbraDomainCOS.description}">
<label for="{$attributes.zimbraDomainCOS.htmlid}">
{eval var=$attributes.zimbraDomainCOS.label}
</label>
</td>
<td>{eval var=$attributes.zimbraDomainCOS.input}</td>
</tr>
<tr>
<td title="{$attributes.fdZimbraServerMailDomain_buttons.description}" colspan="4">
{eval var=$attributes.fdZimbraServerMailDomain_buttons.input}
</td>
</tr>
</table>
</div>
</fieldset>
##
## zimbra-fd.schema - Needed by Fusion Directory for managing Zimbra
##
# attributes
attributetype ( 1.3.6.1.4.1.38414.83.10.1 NAME 'fdZimbraServerUri'
DESC 'FusionDirectory - URI of Zimbra'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE)
attributetype ( 1.3.6.1.4.1.38414.83.10.2 NAME 'fdZimbraServerMailDomain'
DESC 'FusionDirectory - Domain name, key and available classes of service separated by a colon'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26)
attributetype ( 1.3.6.1.4.1.38414.83.10.3 NAME 'fdZimbraServerUserAgent'
DESC 'FusionDirectory - User Agent to connect to Zimbra API'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE)
attributetype ( 1.3.6.1.4.1.38414.83.10.4 NAME 'fdZimbraServerLogin'
DESC 'FusionDirectory - Login to connect to Zimbra API'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE)
attributetype ( 1.3.6.1.4.1.38414.83.10.5 NAME 'fdZimbraServerPassword'
DESC 'FusionDirectory - Password to connect to Zimbra API'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE)
attributetype ( 1.3.6.1.4.1.38414.83.10.6 NAME 'fdZimbraServerDeletionType'
DESC 'FusionDirectory - Should user be deleted or deactivated upon deletion - should contain delete or disable'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE)
# Objectclasses
objectclass (1.3.6.1.4.1.38414.83.2.1 NAME 'fdZimbraServer' SUP top AUXILIARY
DESC 'FusionDirectory - Zimbra server description'
MUST ( cn $ fdZimbraServerUri $ fdZimbraServerUserAgent )
MAY (
fdZimbraServerMailDomain $ fdZimbraServerDeletionType $
fdZimbraServerLogin $ fdZimbraServerPassword
))
zimbra/html/themes/breezy/icons/16/apps/zimbra.png

6.65 KB

This diff is collapsed.
<?php
/*
This code is part of FusionDirectory (http://www.fusiondirectory.org/)
Copyright (C) 2020-2021 FusionDirectory
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
namespace ZimbraSoap;
/*
* Missing:
* GetGroup (getDistributionListRequest)
* CreateGroup
* ModifyGroup
* RemoveDistributionListAlias
* AddDistributionListAlias
* RemoveGroupMembers
* AddGroupMembers
* RenameGroup
* DeleteGroup
*/
class Request
{
public static function getMapping (): array
{
return [
'getAccountRequest' => 'ZimbraSoap\\getAccountRequest',
'getAccountResponse' => 'ZimbraSoap\\genericAccountResponse',
'authResponse' => 'ZimbraSoap\\authResponse',
'createAccountRequest' => 'ZimbraSoap\\createAccountRequest',
'createAccountResponse' => 'ZimbraSoap\\genericAccountResponse',
'modifyAccountRequest' => 'ZimbraSoap\\modifyAccountRequest',
'modifyAccountResponse' => 'ZimbraSoap\\genericAccountResponse',
'setPasswordRequest' => 'ZimbraSoap\\setPasswordRequest',
'setPasswordResponse' => 'ZimbraSoap\\setPasswordResponse',
'renameAccountRequest' => 'ZimbraSoap\\renameAccountRequest',
'renameAccountResponse' => 'ZimbraSoap\\genericAccountResponse',
'deleteAccountRequest' => 'ZimbraSoap\\deleteAccountRequest',
'deleteAccountResponse' => 'ZimbraSoap\\emptyResponse',
'addAccountAliasRequest' => 'ZimbraSoap\\addAccountAliasRequest',
'addAccountAliasResponse' => 'ZimbraSoap\\emptyResponse',
'removeAccountAliasRequest' => 'ZimbraSoap\\removeAccountAliasRequest',
'removeAccountAliasResponse' => 'ZimbraSoap\\emptyResponse',
'getMailboxRequest' => 'ZimbraSoap\\getMailboxRequest',
'getMailboxResponse' => 'ZimbraSoap\\getMailboxResponse',
'endSessionRequest' => 'ZimbraSoap\\endSessionRequest',
'endSessionResponse' => 'ZimbraSoap\\emptyResponse',
];
}
public function soapCall (\SoapClient $client): Response
{
return $client->__soapCall((new \ReflectionClass($this))->getShortName(), [new \SoapVar($this, SOAP_ENC_OBJECT)]);
}
/* Build request object from PARTAGE command and data array */
static public function build (string $command, array $data): Request
{
switch ($command) {
case 'Auth':
return new authRequest($data);
case 'CreateAccount':
return new createAccountRequest($data);
case 'ModifyAccount':
return new modifyAccountRequest($data);
case 'GetMailbox':
return new getMailboxRequest($data);
case 'GetAccount':
return new getAccountRequest($data);
case 'SetPassword':
return new setPasswordRequest($data);
case 'RenameAccount':
return new renameAccountRequest($data);
case 'DeleteAccount':
return new deleteAccountRequest($data);
case 'AddAccountAlias':
return new addAccountAliasRequest($data);
case 'RemoveAccountAlias':
return new removeAccountAliasRequest($data);
case 'EndSession':
return new endSessionRequest($data);
default:
throw new FusionDirectoryException('Unsupported command '.$command);
}
}
static protected function attributesListFromArray ($a): array
{
$data = [];
foreach ($a as $k => $v) {
if (is_array($v)) {
$values = $v;
} else {
$values = [$v];
}
foreach ($values as $value) {
$o = new \stdClass();
$o->n = $k;
$o->_ = $value;
$data[] = $o;
}
}
return $data;
}
}
abstract class Response
{
public abstract function toArray (): array;
static protected function attributesListToArray ($a): array
{
$data = [];
foreach ($a as $n) {
if (isset($data[$n->n])) {
if (!is_array($data[$n->n])) {
$data[$n->n] = [$data[$n->n]];
}
$data[$n->n][] = $n->_;
} else {
$data[$n->n] = $n->_;
}
}
return $data;
}
}
class emptyResponse extends Response
{
public function toArray (): array
{
return [];
}
}
class authRequest extends Request {
/* authRequest do not work through a class, use an array */
public $data;
public function __construct (array $data)
{
$this->data = $data;
}
public function soapCall (\SoapClient $client): Response
{
return $client->__soapCall((new \ReflectionClass($this))->getShortName(), [$this->data]);
}
}
class authResponse extends Response {
public $authToken;
public $lifetime;
public function toArray (): array
{
return ['token' => $this->authToken, 'lifetime' => $this->lifetime];
}
}
class getAccountRequest extends Request {
public $account;
public $applyCos;
public $attrs;
public function __construct (array $data)
{
$this->account = new \stdClass();
$this->account->by = 'name';
$this->account->_ = $data['name'];
$this->applyCos = FALSE;
$this->attrs = $data['attrs'] ?? NULL;
}
}
class genericAccountResponse extends Response {
public $account;
public function toArray (): array
{
if (!is_array($this->account->a)) {
$this->account->a = [$this->account->a];
}
return ['account' => static::attributesListToArray($this->account->a)];
}
}
class createAccountRequest extends Request {
public $name;
public $password;
public $a;
public function __construct (array $data)
{
$this->name = ($data['name'] ?? NULL);
$this->password = ($data['password'] ?? NULL);
unset($data['name']);
unset($data['password']);
$this->a = static::attributesListFromArray($data);
}
}
class modifyAccountRequest extends Request {
/* string */
public $id;
public $a;
public function __construct (array $data)
{
$this->id = ($data['zimbraId'] ?? NULL);
unset($data['zimbraId']);
$this->a = static::attributesListFromArray($data);
}
}
class setPasswordRequest extends Request {
/* string */
public $id;
/* string */
public $newPassword;
public function __construct (array $data)
{
$this->id = ($data['zimbraId'] ?? NULL);
$this->newPassword = ($data['password'] ?? NULL);
}
}
class setPasswordResponse extends Response {
/* string */
public $message;
public function toArray (): array
{
return ['message' => $this->message];
}
}
class renameAccountRequest extends Request {
/* string */
public $id;
/* string */
public $newName;
public function __construct (array $data)
{
$this->id = ($data['zimbraId'] ?? NULL);
$this->newName = ($data['newName'] ?? NULL);
}
}
class deleteAccountRequest extends Request {
/* string */
public $id;
public function __construct (array $data)
{
$this->id = ($data['zimbraId'] ?? NULL);
}
}
class addAccountAliasRequest extends Request {
/* string */
public $id;
/* string */
public $alias;
public function __construct (array $data)
{
$this->id = ($data['zimbraId'] ?? NULL);
$this->alias = ($data['alias'] ?? NULL);
}
}
class removeAccountAliasRequest extends addAccountAliasRequest {
}
class getMailboxRequest extends Request {
public $mbox;
public function __construct (array $data)
{
$this->mbox = ['id' => ($data['zimbraId'] ?? NULL)];
}
}
class getMailboxResponse extends Response {
public $mbox;
public function toArray (): array
{
return [
'id' => $this->mbox->mbxid,
'usage' => $this->mbox->s,
];
}
}
class endSessionRequest extends Request {
/* boolean */
public $logoff;
/* boolean */
public $all;
/* boolean */
public $excludeCurrent;
/* string */
public $sessionId;
public function __construct (array $data)
{
$this->logoff = ($data['logoff'] ?? NULL);
$this->all = ($data['all'] ?? NULL);
$this->excludeCurrent = ($data['excludeCurrent'] ?? NULL);
$this->sessionId = ($data['sessionId'] ?? NULL);
}
}
  • SonarQube analysis reported 1 issue

    • :information_source: 1 info

    Watch the comments in this conversation to review them.

Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment