Merge remote-tracking branch 'origin/support/2.7' into support/3.0

# Conflicts:
#	composer.lock
#	core/log.class.inc.php
#	datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml
#	lib/composer/autoload_real.php
#	setup/licenses/community-licenses.xml
#	setup/setuputils.class.inc.php
This commit is contained in:
Eric Espie
2022-07-11 09:23:18 +02:00
33 changed files with 950 additions and 711 deletions

View File

@@ -1,2 +1,5 @@
# Extension OAuth 2.0 client
## GMail
If the account is in test, after 7 days the tokens are no longer valid, you have to renew the tokens manually.

View File

@@ -17,8 +17,7 @@ if (version_compare(ITOP_DESIGN_LATEST_VERSION , '3.0') >= 0) {
}
$oUpdateController = new AjaxOauthClientController($sTemplates, 'itop-oauth-client');
$oUpdateController->AllowOnlyAdmin();
$oUpdateController->SetDefaultOperation('CreateMailbox');
$oUpdateController->SetMenuId('OAuthClient');
$oUpdateController->HandleOperation();

View File

@@ -5,7 +5,7 @@
<class id="OAuthClient" _delta="define">
<parent>cmdbAbstractObject</parent>
<properties>
<category>cloud,searchable</category>
<category>grant_by_profile,application</category>
<abstract>true</abstract>
<key_type>autoincrement</key_type>
<db_table>priv_oauth_client</db_table>
@@ -119,22 +119,21 @@
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function DisplayBareHeader(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareHeader($oPage, $bEditMode);
if (!$bEditMode) {
$oConfig = utils::GetConfig();
$sScope = $this->Get('scope');
if ($this->Get('status') == 'inactive') {
$oPage->p('<b>'.Dict::S('itop-oauth-client:Message:MissingToken').'</b>');
} elseif (($sScope == 'SMTP' || $sScope == 'EMail') && $oConfig->Get('email_transport_smtp.username') == $this->Get('name')) {
$sLabel = Dict::S('itop-oauth-client:UsedForSMTP');
$sTestLabel = Dict::S('itop-oauth-client:TestSMTP');
$sTestURL = utils::GetAbsoluteUrlAppRoot().'setup/email.test.php';
$oPage->p("<b>$sLabel</b>&nbsp;<a href='$sTestURL' target='_blank'>$sTestLabel</a>");
}
}
}
public function DisplayBareHeader(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareHeader($oPage, $bEditMode);
if (!$bEditMode) {
$oConfig = utils::GetConfig();
if ($this->Get('status') == 'inactive') {
$oPage->p('<b>'.Dict::S('itop-oauth-client:Message:MissingToken').'</b>');
} elseif ($this->Get('used_for_smtp') == 'yes' && $oConfig->Get('email_transport_smtp.username') == $this->Get('name')) {
$sLabel = Dict::S('itop-oauth-client:UsedForSMTP');
$sTestLabel = Dict::S('itop-oauth-client:TestSMTP');
$sTestURL = utils::GetAbsoluteUrlAppRoot().'setup/email.test.php';
$oPage->p("<b>$sLabel</b>&nbsp;<a href='$sTestURL' target='_blank'>$sTestLabel</a>");
}
}
}
]]></code>
</method>
<method id="GetAttributeFlags">
@@ -142,14 +141,14 @@
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{
if ($sAttCode == 'status') {
return OPT_ATT_READONLY;
}
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{
if ($sAttCode == 'status') {
return OPT_ATT_READONLY;
}
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
}
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
}
]]></code>
</method>
<method id="GetInitialStateAttributeFlags">
@@ -157,68 +156,68 @@
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
{
if ($sAttCode == 'status') {
return OPT_ATT_READONLY;
}
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
{
if ($sAttCode == 'status') {
return OPT_ATT_READONLY;
}
return parent::GetInitialStateAttributeFlags($sAttCode, $aReasons);
}
return parent::GetInitialStateAttributeFlags($sAttCode, $aReasons);
}
]]></code>
</method>
<method id="GetDefaultMailServer">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function GetDefaultMailServer()
{
return 'imap.'.$this->Get('provider').'.com';
}
public function GetDefaultMailServer()
{
return 'imap.'.$this->Get('provider').'.com';
}
]]></code>
</method>
<method id="GetDefaultMailServerPort">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function GetDefaultMailServerPort()
{
return 993;
}
public function GetDefaultMailServerPort()
{
return 993;
}
]]></code>
</method>
<method id="GetAccessToken">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function GetAccessToken()
{
if ($this->Get('status') == 'active') {
return new \League\OAuth2\Client\Token\AccessToken([
'access_token' => $this->Get('token'),
'expires_in' => date_format(new DateTime($this->Get('token_expiration')), 'U') - time(),
'refresh_token' => $this->Get('refresh_token'),
'token_type' => 'Bearer',
]);
}
return null;
}
public function GetAccessToken()
{
if ($this->Get('status') == 'active') {
return new \League\OAuth2\Client\Token\AccessToken([
'access_token' => $this->Get('token'),
'expires_in' => date_format(new DateTime($this->Get('token_expiration')), 'U') - time(),
'refresh_token' => $this->Get('refresh_token'),
'token_type' => 'Bearer',
]);
}
return null;
}
]]></code>
</method>
<method id="SetAccessToken">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function SetAccessToken(\League\OAuth2\Client\Token\AccessTokenInterface $oAccessToken)
{
$this->Set('token', $oAccessToken->getToken());
$this->Set('token_expiration', date(AttributeDateTime::GetSQLFormat(), $oAccessToken->getExpires()));
if (!empty($oAccessToken->getRefreshToken())) {
$this->Set('refresh_token', $oAccessToken->getRefreshToken());
}
$this->Set('status', 'active');
$this->DBUpdate();
}
public function SetAccessToken(\League\OAuth2\Client\Token\AccessTokenInterface $oAccessToken)
{
$this->Set('token', $oAccessToken->getToken());
$this->Set('token_expiration', date(AttributeDateTime::GetSQLFormat(), $oAccessToken->getExpires()));
if (!empty($oAccessToken->getRefreshToken())) {
$this->Set('refresh_token', $oAccessToken->getRefreshToken());
}
$this->Set('status', 'active');
$this->DBUpdate();
}
]]></code>
</method>
</methods>
@@ -280,6 +279,606 @@
</default_search>
</presentation>
</class>
<class id="OAuthClientAzure" _delta="define">
<parent>OAuthClient</parent>
<properties>
<category>grant_by_profile,application</category>
<abstract>false</abstract>
<key_type>autoincrement</key_type>
<db_table>priv_oauth_client_azure</db_table>
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<attributes>
<attribute id="provider"/>
<attribute id="name"/>
</attributes>
</naming>
<display_template/>
<icon/>
<reconciliation>
<attributes>
<attribute id="provider"/>
<attribute id="name"/>
</attributes>
</reconciliation>
<uniqueness_rules>
<rule id="server">
<attributes>
<attribute id="provider"/>
<attribute id="client_id"/>
<attribute id="client_secret"/>
</attributes>
<is_blocking>true</is_blocking>
</rule>
</uniqueness_rules>
</properties>
<fields>
<field id="scope" xsi:type="AttributeEnumSet">
<always_load_in_tables>true</always_load_in_tables>
<values>
<value id="SMTP">SMTP</value>
<value id="IMAP">IMAP</value>
</values>
<sql>scope</sql>
<default_value>SMTP,IMAP</default_value>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="advanced_scope" xsi:type="AttributeString">
<sql>advanced_scope</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="used_scope" xsi:type="AttributeEnum">
<always_load_in_tables>true</always_load_in_tables>
<values>
<value id="simple">simple</value>
<value id="advanced">advanced</value>
</values>
<sql>used_scope</sql>
<default_value>simple</default_value>
<is_null_allowed>false</is_null_allowed>
<dependencies>
<attribute id="scope"/>
<attribute id="advanced_scope"/>
</dependencies>
</field>
<field id="used_for_smtp" xsi:type="AttributeEnum">
<always_load_in_tables>true</always_load_in_tables>
<values>
<value id="yes">yes</value>
<value id="no">no</value>
</values>
<sql>used_for_smtp</sql>
<default_value>no</default_value>
<is_null_allowed>true</is_null_allowed>
</field>
</fields>
<presentation>
<details>
<items>
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:OAuthClient:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="status">
<rank>20</rank>
</item>
<item id="description">
<rank>30</rank>
</item>
<item id="provider">
<rank>40</rank>
</item>
<item id="redirect_url">
<rank>50</rank>
</item>
<item id="client_id">
<rank>60</rank>
</item>
<item id="client_secret">
<rank>70</rank>
</item>
<item id="mailbox_list">
<rank>80</rank>
</item>
</items>
</item>
</items>
</item>
<item id="col:col2">
<rank>20</rank>
<items>
<item id="fieldset:OAuthClient:scope">
<rank>10</rank>
<items>
<item id="used_scope">
<rank>10</rank>
</item>
<item id="scope">
<rank>20</rank>
</item>
<item id="advanced_scope">
<rank>30</rank>
</item>
<item id="used_for_smtp">
<rank>40</rank>
</item>
</items>
</item>
</items>
</item>
</items>
</details>
<list>
<items>
<item id="provider">
<rank>10</rank>
</item>
<item id="status">
<rank>10</rank>
</item>
</items>
</list>
<standard_search>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="provider">
<rank>10</rank>
</item>
<item id="status">
<rank>10</rank>
</item>
</items>
</standard_search>
</presentation>
<methods>
<method id="PrefillCreationForm">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function PrefillCreationForm(&$aContextParam)
{
$this->Set('provider', 'Azure');
$this->Set('redirect_url', Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory::GetRedirectUri());
$this->Set('scope', 'SMTP, IMAP');
parent::PrefillCreationForm($aContextParam);
}
]]></code>
</method>
<method id="DoCheckToWrite">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[ public function DoCheckToWrite()
{
parent::DoCheckToWrite();
$aChanges = $this->ListChanges();
if (array_key_exists('name', $aChanges) || array_key_exists('used_for_smtp', $aChanges))
{
$sNewName = $this->Get('name');
$sNewUseForSMTP = $this->Get('used_for_smtp');
if ($sNewUseForSMTP == 'yes') {
$oSearch = DBObjectSearch::FromOQL_AllData("SELECT OAuthClientGoogle WHERE name = :newname AND used_for_smtp = :newuseforsmtp AND id != :id UNION SELECT OAuthClientAzure WHERE name = :newname AND used_for_smtp = :newuseforsmtp AND id != :id");
$oSet = new DBObjectSet($oSearch, array(), ['id' => $this->GetKey(), 'newname' => $sNewName, 'newuseforsmtp' => $sNewUseForSMTP]);
if ($oSet->Count() > 0)
{
$this->m_aCheckIssues[] = Dict::Format('OAuthClient:Name/UseForSMTPMustBeUnique', $sNewName, $sNewUseForSMTP);
}
}
}
} ]]></code>
</method>
<method id="ComputeValues">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function ComputeValues()
{
parent::ComputeValues();
if (empty($this->Get('provider'))) {
$this->Set('provider', 'Azure');
}
if (empty($this->Get('redirect_url'))) {
$this->Set('redirect_url', Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory::GetRedirectUri());
}
if (empty($this->Get('advanced_scope'))) {
$this->Set('used_scope', 'simple');
if (count($this->Get('scope')->GetValues()) == 0) {
$this->Set('scope', 'SMTP, IMAP');
}
} else {
$this->Set('used_scope', 'advanced');
$this->Set('scope', '');
}
}
]]></code>
</method>
<method id="GetAttributeFlags">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{
switch ($sAttCode) {
case 'provider':
case 'redirect_url':
case 'used_scope':
return OPT_ATT_READONLY;
}
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
}
]]></code>
</method>
<method id="GetInitialStateAttributeFlags">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
{
switch ($sAttCode) {
case 'provider':
case 'redirect_url':
case 'used_scope':
return OPT_ATT_READONLY;
}
return parent::GetInitialStateAttributeFlags($sAttCode, $aReasons);
}
]]></code>
</method>
<method id="GetDefaultMailServer">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function GetDefaultMailServer()
{
return 'outlook.office365.com';
}
]]></code>
</method>
<method id="GetScope">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function GetScope()
{
if (!empty($this->Get('advanced_scope'))) {
return $this->Get('advanced_scope');
}
$aScopes = $this->Get('scope')->GetValues();
$aRawScopes = ['offline_access'];
foreach ($aScopes as $sScope) {
switch ($sScope) {
case 'SMTP':
$aRawScopes[] = 'https://outlook.office.com/SMTP.Send';
break;
case 'IMAP':
$aRawScopes[] = 'https://outlook.office.com/IMAP.AccessAsUser.All';
break;
}
}
return implode(' ', $aRawScopes);
}
]]></code>
</method>
</methods>
</class>
<class id="OAuthClientGoogle" _delta="define">
<parent>OAuthClient</parent>
<properties>
<category>grant_by_profile,application</category>
<abstract>false</abstract>
<key_type>autoincrement</key_type>
<db_table>priv_oauth_client_google</db_table>
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<attributes>
<attribute id="provider"/>
<attribute id="name"/>
</attributes>
</naming>
<display_template/>
<icon/>
<reconciliation>
<attributes>
<attribute id="provider"/>
<attribute id="name"/>
</attributes>
</reconciliation>
<uniqueness_rules>
<rule id="server">
<attributes>
<attribute id="provider"/>
<attribute id="client_id"/>
<attribute id="client_secret"/>
</attributes>
<is_blocking>true</is_blocking>
</rule>
</uniqueness_rules>
</properties>
<fields>
<field id="scope" xsi:type="AttributeEnumSet">
<always_load_in_tables>true</always_load_in_tables>
<values>
<value id="SMTP">SMTP</value>
<value id="IMAP">IMAP</value>
</values>
<sql>scope</sql>
<default_value>SMTP,IMAP</default_value>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="advanced_scope" xsi:type="AttributeString">
<sql>advanced_scope</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="used_scope" xsi:type="AttributeEnum">
<always_load_in_tables>true</always_load_in_tables>
<values>
<value id="simple">simple</value>
<value id="advanced">advanced</value>
</values>
<sql>used_scope</sql>
<default_value>simple</default_value>
<is_null_allowed>false</is_null_allowed>
<dependencies>
<attribute id="scope"/>
<attribute id="advanced_scope"/>
</dependencies>
</field>
<field id="used_for_smtp" xsi:type="AttributeEnum">
<always_load_in_tables>true</always_load_in_tables>
<values>
<value id="yes">yes</value>
<value id="no">no</value>
</values>
<sql>used_for_smtp</sql>
<default_value>no</default_value>
<is_null_allowed>true</is_null_allowed>
</field>
</fields>
<presentation>
<details>
<items>
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:OAuthClient:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="status">
<rank>20</rank>
</item>
<item id="description">
<rank>30</rank>
</item>
<item id="provider">
<rank>40</rank>
</item>
<item id="redirect_url">
<rank>50</rank>
</item>
<item id="client_id">
<rank>60</rank>
</item>
<item id="client_secret">
<rank>70</rank>
</item>
<item id="mailbox_list">
<rank>80</rank>
</item>
</items>
</item>
</items>
</item>
<item id="col:col2">
<rank>20</rank>
<items>
<item id="fieldset:OAuthClient:scope">
<rank>10</rank>
<items>
<item id="used_scope">
<rank>10</rank>
</item>
<item id="scope">
<rank>20</rank>
</item>
<item id="advanced_scope">
<rank>30</rank>
</item>
<item id="used_for_smtp">
<rank>40</rank>
</item>
</items>
</item>
</items>
</item>
</items>
</details>
<list>
<items>
<item id="provider">
<rank>10</rank>
</item>
<item id="status">
<rank>10</rank>
</item>
</items>
</list>
<standard_search>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="provider">
<rank>10</rank>
</item>
<item id="status">
<rank>10</rank>
</item>
</items>
</standard_search>
</presentation>
<methods>
<method id="PrefillCreationForm">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function PrefillCreationForm(&$aContextParam)
{
$this->Set('provider', 'Google');
$this->Set('redirect_url', Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory::GetRedirectUri());
$this->Set('scope', 'SMTP, IMAP');
parent::PrefillCreationForm($aContextParam);
}
]]></code>
</method>
<method id="DoCheckToWrite">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[ public function DoCheckToWrite()
{
parent::DoCheckToWrite();
$aChanges = $this->ListChanges();
if (array_key_exists('name', $aChanges) || array_key_exists('used_for_smtp', $aChanges))
{
$sNewName = $this->Get('name');
$sNewUseForSMTP = $this->Get('used_for_smtp');
if ($sNewUseForSMTP == 'yes') {
$oSearch = DBObjectSearch::FromOQL_AllData("SELECT OAuthClientGoogle WHERE name = :newname AND used_for_smtp = :newuseforsmtp AND id != :id UNION SELECT OAuthClientAzure WHERE name = :newname AND used_for_smtp = :newuseforsmtp AND id != :id");
$oSet = new DBObjectSet($oSearch, array(), ['id' => $this->GetKey(), 'newname' => $sNewName, 'newuseforsmtp' => $sNewUseForSMTP]);
if ($oSet->Count() > 0)
{
$this->m_aCheckIssues[] = Dict::Format('OAuthClient:Name/UseForSMTPMustBeUnique', $sNewName, $sNewUseForSMTP);
}
}
}
} ]]></code>
</method>
<method id="ComputeValues">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function ComputeValues()
{
parent::ComputeValues();
if (empty($this->Get('provider'))) {
$this->Set('provider', 'Google');
}
if (empty($this->Get('redirect_url'))) {
$this->Set('redirect_url', Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory::GetRedirectUri());
}
if (empty($this->Get('advanced_scope'))) {
$this->Set('used_scope', 'simple');
if (count($this->Get('scope')->GetValues()) == 0) {
$this->Set('scope', 'SMTP, IMAP');
}
} else {
$this->Set('used_scope', 'advanced');
$this->Set('scope', '');
}
}
]]></code>
</method>
<method id="GetAttributeFlags">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{
switch ($sAttCode) {
case 'provider':
case 'redirect_url':
case 'used_scope':
return OPT_ATT_READONLY;
}
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
}
]]></code>
</method>
<method id="GetInitialStateAttributeFlags">
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
{
switch ($sAttCode) {
case 'provider':
case 'redirect_url':
case 'used_scope':
return OPT_ATT_READONLY;
}
return parent::GetInitialStateAttributeFlags($sAttCode, $aReasons);
}
]]></code>
</method>
<method id="GetDefaultMailServer">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function GetDefaultMailServer()
{
return 'imap.gmail.com';
}
]]></code>
</method>
<method id="GetScope">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function GetScope()
{
if (!empty($this->Get('advanced_scope'))) {
return $this->Get('advanced_scope');
}
$aScopes = $this->Get('scope')->GetValues();
$aRawScopes = [];
foreach ($aScopes as $sScope) {
switch ($sScope) {
case 'SMTP':
$aRawScopes['https://mail.google.com/'] = 'https://mail.google.com/';
break;
case 'IMAP':
$aRawScopes['https://mail.google.com/'] = 'https://mail.google.com/';
break;
}
}
return implode(' ', $aRawScopes);
}
]]></code>
</method>
</methods>
</class>
</classes>
<menus>
<menu id="OAuthClient" xsi:type="OQLMenuNode" _delta="define">
@@ -289,11 +888,16 @@
<do_search>1</do_search>
<enable_admin_only>0</enable_admin_only>
<enable_class>OAuthClient</enable_class>
<enable_action>UR_ACTION_READ</enable_action>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
</menus>
<user_rights>
<groups>
<group id="OauthConnection" _delta="define">
<classes>
<class id="OAuthClient"/>
</classes>
</group>
</groups>
<profiles>
</profiles>

View File

@@ -21,6 +21,11 @@ Dict::Add('EN US', 'English', 'English', [
'itop-oauth-client:Message:MissingToken' => 'Generate access token before using this OAuth client',
'itop-oauth-client:Message:TokenCreated' => 'Access token created',
'itop-oauth-client:Message:TokenRecreated' => 'Access token regenerated',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'The combination Login (%1$s) and Use for SMTP (%2$s) has already be used for OAuth Client',
'OAuthClient:baseinfo' => 'Base Information',
'OAuthClient:scope' => 'Scope',
]);
//
@@ -32,19 +37,17 @@ Dict::Add('EN US', 'English', 'English', [
'Class:OAuthClient/Attribute:provider' => 'Provider',
'Class:OAuthClient/Attribute:provider+' => '',
'Class:OAuthClient/Attribute:name' => 'Login',
'Class:OAuthClient/Attribute:name+' => '',
'Class:OAuthClient/Attribute:scope' => 'Scope',
'Class:OAuthClient/Attribute:scope+' => '',
'Class:OAuthClient/Attribute:name+' => 'In general, this is your email address',
'Class:OAuthClient/Attribute:status' => 'Status',
'Class:OAuthClient/Attribute:status+' => '',
'Class:OAuthClient/Attribute:status+' => 'After creation, use the action “Generate access token” to be able to use this OAuth client',
'Class:OAuthClient/Attribute:status/Value:active' => 'Access token generated',
'Class:OAuthClient/Attribute:status/Value:inactive' => 'No Access token',
'Class:OAuthClient/Attribute:description' => 'Description',
'Class:OAuthClient/Attribute:description+' => '',
'Class:OAuthClient/Attribute:client_id' => 'Client id',
'Class:OAuthClient/Attribute:client_id+' => '',
'Class:OAuthClient/Attribute:client_id+' => 'A long string of characters provided by your OAuth2 provider',
'Class:OAuthClient/Attribute:client_secret' => 'Client secret',
'Class:OAuthClient/Attribute:client_secret+' => '',
'Class:OAuthClient/Attribute:client_secret+' => 'Another long string of characters provided by your OAuth2 provider',
'Class:OAuthClient/Attribute:refresh_token' => 'Refresh token',
'Class:OAuthClient/Attribute:refresh_token+' => '',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Refresh token expiration',
@@ -54,7 +57,7 @@ Dict::Add('EN US', 'English', 'English', [
'Class:OAuthClient/Attribute:token_expiration' => 'Access token expiration',
'Class:OAuthClient/Attribute:token_expiration+' => '',
'Class:OAuthClient/Attribute:redirect_url' => 'Redirect url',
'Class:OAuthClient/Attribute:redirect_url+' => '',
'Class:OAuthClient/Attribute:redirect_url+' => 'This url must be copied in the OAuth2 configuration of the provider',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list',
'Class:OAuthClient/Attribute:mailbox_list+' => '',
]);
@@ -62,17 +65,53 @@ Dict::Add('EN US', 'English', 'English', [
//
// Class: OAuthClientAzure
//
Dict::Add('EN US', 'English', 'English', [
Dict::Add('EN US', 'English', 'English', array(
'Class:OAuthClientAzure' => 'OAuth client for Microsoft Azure',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
]);
'Class:OAuthClientAzure/Attribute:scope' => 'Scope',
'Class:OAuthClientAzure/Attribute:scope+' => 'Usually default selection is appropriate',
'Class:OAuthClientAzure/Attribute:scope/Value:SMTP' => 'SMTP',
'Class:OAuthClientAzure/Attribute:scope/Value:SMTP+' => '',
'Class:OAuthClientAzure/Attribute:scope/Value:IMAP' => 'IMAP',
'Class:OAuthClientAzure/Attribute:scope/Value:IMAP+' => '',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Advanced scope',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence on the “Scope” selection which is then ignored',
'Class:OAuthClientAzure/Attribute:used_scope' => 'Used scope',
'Class:OAuthClientAzure/Attribute:used_scope+' => '',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Simple',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '',
'Class:OAuthClientAzure/Attribute:used_scope/Value:advanced' => 'Advanced',
'Class:OAuthClientAzure/Attribute:used_scope/Value:advanced+' => '',
'Class:OAuthClientAzure/Attribute:used_for_smtp' => 'Used for SMTP',
'Class:OAuthClientAzure/Attribute:used_for_smtp+' => 'At least one OAuth client must have this flag to “Yes”, if you want iTop to use it for sending mails',
'Class:OAuthClientAzure/Attribute:used_for_smtp/Value:yes' => 'Yes',
'Class:OAuthClientAzure/Attribute:used_for_smtp/Value:no' => 'No',
));
//
// Class: OAuthClientGoogle
//
Dict::Add('EN US', 'English', 'English', [
Dict::Add('EN US', 'English', 'English', array(
'Class:OAuthClientGoogle' => 'OAuth client for Google',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
]);
'Class:OAuthClientGoogle/Attribute:scope' => 'Scope',
'Class:OAuthClientGoogle/Attribute:scope+' => 'Usually default selection is appropriate',
'Class:OAuthClientGoogle/Attribute:scope/Value:SMTP' => 'SMTP',
'Class:OAuthClientGoogle/Attribute:scope/Value:SMTP+' => '',
'Class:OAuthClientGoogle/Attribute:scope/Value:IMAP' => 'IMAP',
'Class:OAuthClientGoogle/Attribute:scope/Value:IMAP+' => '',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Advanced scope',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'As soon as you enter something here it takes precedence on the “Scope” selection which is then ignored',
'Class:OAuthClientGoogle/Attribute:used_scope' => 'Used scope',
'Class:OAuthClientGoogle/Attribute:used_scope+' => '',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:simple' => 'Simple',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:simple+' => '',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:advanced' => 'Advanced',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:advanced+' => '',
'Class:OAuthClientGoogle/Attribute:used_for_smtp' => 'Used for SMTP',
'Class:OAuthClientGoogle/Attribute:used_for_smtp+' => 'At least one OAuth client must have this flag to “Yes”, if you want iTop to use it for sending mails',
'Class:OAuthClientGoogle/Attribute:used_for_smtp/Value:yes' => 'Yes',
'Class:OAuthClientGoogle/Attribute:used_for_smtp/Value:no' => 'No',
));

View File

@@ -5,6 +5,7 @@
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('FR FR', 'French', 'Français', [
'Menu:CreateMailbox' => 'Créer une boite mail...',
'Menu:OAuthClient' => 'Client OAuth',
@@ -20,6 +21,11 @@ Dict::Add('FR FR', 'French', 'Français', [
'itop-oauth-client:Message:MissingToken' => 'Générez le jeton d\'accès avant d\'utiliser ce client OAuth',
'itop-oauth-client:Message:TokenCreated' => 'Le jeton d\'accès à été créé',
'itop-oauth-client:Message:TokenRecreated' => 'Le jeton d\'accès à été renouvelé',
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'La combinaison Login (%1$s) and Utilisé pour SMTP (%2$s) a déjà été utilisée pour OAuth Client',
'OAuthClient:baseinfo' => 'Information',
'OAuthClient:scope' => 'Scope',
]);
//
@@ -31,15 +37,17 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:OAuthClient/Attribute:provider' => 'Fournisseur',
'Class:OAuthClient/Attribute:provider+' => '',
'Class:OAuthClient/Attribute:name' => 'Login',
'Class:OAuthClient/Attribute:name+' => '',
'Class:OAuthClient/Attribute:scope' => 'Niveaux d\'accès',
'Class:OAuthClient/Attribute:scope+' => '',
'Class:OAuthClient/Attribute:name+' => 'L\'adresse email à utiliser chez ce fournisseur',
'Class:OAuthClient/Attribute:status' => 'Statut',
'Class:OAuthClient/Attribute:status+' => 'Après la création, effectuer l\'action \'Créer un jeton d\'accès...\' pour activer ce client OAuth',
'Class:OAuthClient/Attribute:status/Value:active' => 'Jeton d\'accès créé',
'Class:OAuthClient/Attribute:status/Value:inactive' => 'Pas de jeton d\'accès',
'Class:OAuthClient/Attribute:description' => 'Description',
'Class:OAuthClient/Attribute:description+' => '',
'Class:OAuthClient/Attribute:client_id' => 'ID Client',
'Class:OAuthClient/Attribute:client_id+' => '',
'Class:OAuthClient/Attribute:client_id+' => 'Recopier la chaine fournie par votre fournisseur OAuth2',
'Class:OAuthClient/Attribute:client_secret' => 'Code secret du client',
'Class:OAuthClient/Attribute:client_secret+' => '',
'Class:OAuthClient/Attribute:client_secret+' => 'Recopier l\'information fournie par votre fournisseur OAuth2',
'Class:OAuthClient/Attribute:refresh_token' => 'Jeton de renouvellement',
'Class:OAuthClient/Attribute:refresh_token+' => '',
'Class:OAuthClient/Attribute:refresh_token_expiration' => 'Date d\'expiration du jeton de renouvellement',
@@ -49,7 +57,7 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:OAuthClient/Attribute:token_expiration' => 'Date d\'expiration du jeton d\'accès',
'Class:OAuthClient/Attribute:token_expiration+' => '',
'Class:OAuthClient/Attribute:redirect_url' => 'URL de redirection',
'Class:OAuthClient/Attribute:redirect_url+' => '',
'Class:OAuthClient/Attribute:redirect_url+' => 'Cet URL doit être recopié dans la configuration OAuth2 de votre fournisseur',
'Class:OAuthClient/Attribute:mailbox_list' => 'Mailbox list',
'Class:OAuthClient/Attribute:mailbox_list+' => '',
]);
@@ -57,22 +65,52 @@ Dict::Add('FR FR', 'French', 'Français', [
//
// Class: OAuthClientAzure
//
Dict::Add('FR FR', 'French', 'Français', [
Dict::Add('FR FR', 'French', 'Français', array(
'Class:OAuthClientAzure' => 'Client OAuth pour Microsoft Azure',
'Class:OAuthClientAzure/Name' => '%1$s (%2$s)',
]);
'Class:OAuthClientAzure/Attribute:scope' => 'Niveaux d\'accès',
'Class:OAuthClientAzure/Attribute:scope+' => 'Les niveaux par défaut sont les plus souvent suffisants',
'Class:OAuthClientAzure/Attribute:scope/Value:SMTP' => 'SMTP',
'Class:OAuthClientAzure/Attribute:scope/Value:SMTP+' => '',
'Class:OAuthClientAzure/Attribute:scope/Value:IMAP' => 'IMAP',
'Class:OAuthClientAzure/Attribute:scope/Value:IMAP+' => '',
'Class:OAuthClientAzure/Attribute:advanced_scope' => 'Niveaux d\'accès avancé',
'Class:OAuthClientAzure/Attribute:advanced_scope+' => 'A saisir, lorsque les niveaux prédéfinis ne suffisent pas',
'Class:OAuthClientAzure/Attribute:used_scope' => 'Niveaux d\'accès utilisés',
'Class:OAuthClientAzure/Attribute:used_scope+' => '',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple' => 'Simple',
'Class:OAuthClientAzure/Attribute:used_scope/Value:simple+' => '',
'Class:OAuthClientAzure/Attribute:used_scope/Value:advanced' => 'Avancé',
'Class:OAuthClientAzure/Attribute:used_scope/Value:advanced+' => '',
'Class:OAuthClientAzure/Attribute:used_for_smtp' => 'Utilisé pour SMTP',
'Class:OAuthClientAzure/Attribute:used_for_smtp+' => 'Le Client OAuth utilisé pour l\'envoi d\'emails doit être à \'Oui\'',
'Class:OAuthClientAzure/Attribute:used_for_smtp/Value:yes' => 'Oui',
'Class:OAuthClientAzure/Attribute:used_for_smtp/Value:no' => 'Non',
));
//
// Class: OAuthClientGoogle
//
Dict::Add('FR FR', 'French', 'Français', [
Dict::Add('FR FR', 'French', 'Français', array(
'Class:OAuthClientGoogle' => 'Client OAuth pour Google',
'Class:OAuthClientGoogle/Name' => '%1$s (%2$s)',
]);
// Additional language entries not present in English dict
Dict::Add('FR FR', 'French', 'Français', array(
'Class:OAuthClient/Name' => '%1$s-%%2$~',
'Class:OAuthClientGoogle/Attribute:scope' => 'Niveaux d\'accès',
'Class:OAuthClientGoogle/Attribute:scope+' => 'Les niveaux par défaut sont les plus souvent suffisants',
'Class:OAuthClientGoogle/Attribute:scope/Value:SMTP' => 'SMTP',
'Class:OAuthClientGoogle/Attribute:scope/Value:SMTP+' => '',
'Class:OAuthClientGoogle/Attribute:scope/Value:IMAP' => 'IMAP',
'Class:OAuthClientGoogle/Attribute:scope/Value:IMAP+' => '',
'Class:OAuthClientGoogle/Attribute:advanced_scope' => 'Niveaux d\'accès avancé',
'Class:OAuthClientGoogle/Attribute:advanced_scope+' => 'A saisir, lorsque les niveaux prédéfinis ne suffisent pas',
'Class:OAuthClientGoogle/Attribute:used_scope' => 'Niveaux d\'accès utilisés',
'Class:OAuthClientGoogle/Attribute:used_scope+' => '',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:simple' => 'Simple',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:advanced' => 'Avancé',
'Class:OAuthClientGoogle/Attribute:used_scope/Value:advanced+' => '',
'Class:OAuthClientGoogle/Attribute:used_for_smtp' => 'Utilisé pour SMTP',
'Class:OAuthClientGoogle/Attribute:used_for_smtp+' => 'Le Client OAuth utilisé pour l\'envoi d\'emails doit être à \'Oui\'',
'Class:OAuthClientGoogle/Attribute:used_for_smtp/Value:yes' => 'Oui',
'Class:OAuthClientGoogle/Attribute:used_for_smtp/Value:no' => 'Non',
));

View File

@@ -25,9 +25,8 @@ SetupWebPage::AddModule(
'datamodel' => array(
'vendor/autoload.php',
'model.itop-oauth-client.php', // Contains the PHP code generated by the "compilation" of datamodel.remote-authent-oauth.xml
'src/Model/OAuthClientGoogle.php',
'src/Model/OAuthClientAzure.php',
'src/Service/PopupMenuExtension.php',
'src/Service/ApplicationUIExtension.php',
),
'webservice' => array(

View File

@@ -1,128 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory;
class OAuthClientAzure extends OAuthClient
{
public static function Init()
{
$aParams = [
'category' => 'cloud',
'key_type' => 'autoincrement',
'name_attcode' => ['name', 'scope'],
'state_attcode' => '',
'reconc_keys' => ['provider', 'name'],
'db_table' => 'priv_oauth_client_azure',
'db_key_field' => 'id',
'icon' => utils::GetAbsoluteUrlModulesRoot().'itop-oauth-client/assets/img/icons8-azure.svg',
'db_finalclass_field' => '',
'uniqueness_rules' => [
'Username for scope' =>
[
'attributes' => ['name', 'scope'],
'filter' => null,
'disabled' => false,
'is_blocking' => true,
],
'OAuth Server' =>
[
'attributes' => ['provider', 'scope', 'client_id', 'client_secret'],
'filter' => null,
'disabled' => false,
'is_blocking' => true,
],
],
];
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeEnum('scope', [
'allowed_values' => new ValueSetEnum('EMail'),
'display_style' => 'list',
'sql' => 'scope',
'default_value' => 'EMail',
'is_null_allowed' => false,
'depends_on' => [],
'always_load_in_tables' => true,
]));
MetaModel::Init_SetZListItems('details', [
'name',
'status',
'description',
'provider',
'scope',
'redirect_url',
'client_id',
'client_secret',
'mailbox_list',
]);
MetaModel::Init_SetZListItems('standard_search', [
'name',
'provider',
'status',
]);
MetaModel::Init_SetZListItems('list', [
'status',
'provider',
]);
}
public function PrefillCreationForm(&$aContextParam)
{
$this->Set('provider', 'Azure');
$this->Set('redirect_url', OAuthClientProviderFactory::GetRedirectUri());
parent::PrefillCreationForm($aContextParam);
}
/**
* Compute read-only values
*
* @return void
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
*/
public function ComputeValues()
{
parent::ComputeValues();
if (empty($this->Get('provider'))) {
$this->Set('provider', 'Azure');
}
if (empty($this->Get('redirect_url'))) {
$this->Set('redirect_url', OAuthClientProviderFactory::GetRedirectUri());
}
}
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{
if ($sAttCode == 'provider' || $sAttCode == 'redirect_url') {
return OPT_ATT_READONLY;
}
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
}
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
{
if ($sAttCode == 'provider' || $sAttCode == 'redirect_url') {
return OPT_ATT_READONLY;
}
return parent::GetInitialStateAttributeFlags($sAttCode, $aReasons);
}
public function GetDefaultMailServer()
{
return 'outlook.office365.com';
}
public function GetScope()
{
return 'https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send offline_access';
}
}

View File

@@ -1,134 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory;
class OAuthClientGoogle extends OAuthClient
{
public static function Init()
{
$aParams = array
(
'category' => 'cloud',
'key_type' => 'autoincrement',
'name_attcode' => ['name', 'scope'],
'state_attcode' => '',
'reconc_keys' => ['provider', 'name'],
'db_table' => 'priv_oauth_client_google',
'db_key_field' => 'id',
'icon' => utils::GetAbsoluteUrlModulesRoot().'itop-oauth-client/assets/img/icons8-google.svg',
'db_finalclass_field' => '',
'uniqueness_rules' => [
'Username for scope' =>
[
'attributes' => ['name', 'scope'],
'filter' => null,
'disabled' => false,
'is_blocking' => true,
],
'OAuth Server' =>
[
'attributes' => ['provider', 'scope', 'client_id', 'client_secret'],
'filter' => null,
'disabled' => false,
'is_blocking' => true,
],
],
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeEnum('scope', [
'allowed_values' => new ValueSetEnum('EMail'),
'display_style' => 'list',
'sql' => 'scope',
'default_value' => 'EMail',
'is_null_allowed' => false,
'depends_on' => [],
'always_load_in_tables' => true,
]));
MetaModel::Init_SetZListItems('details', [
'name',
'status',
'description',
'provider',
'scope',
'redirect_url',
'client_id',
'client_secret',
'mailbox_list',
]);
MetaModel::Init_SetZListItems('standard_search', [
'name',
'provider',
'status',
]);
MetaModel::Init_SetZListItems('list', [
'status',
'provider',
]);
}
public function PrefillCreationForm(&$aContextParam)
{
$this->Set('provider', 'Google');
$this->Set('scope', 'EMail');
$this->Set('redirect_url', OAuthClientProviderFactory::GetRedirectUri());
parent::PrefillCreationForm($aContextParam);
}
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{
if ($sAttCode == 'provider' || $sAttCode == 'scope' || $sAttCode == 'redirect_url') {
return OPT_ATT_READONLY;
}
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
}
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
{
if ($sAttCode == 'provider' || $sAttCode == 'scope' || $sAttCode == 'redirect_url') {
return OPT_ATT_READONLY;
}
return parent::GetInitialStateAttributeFlags($sAttCode, $aReasons);
}
/**
* Compute read-only values
*
* @return void
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
*/
public function ComputeValues()
{
parent::ComputeValues();
if (empty($this->Get('provider'))) {
$this->Set('provider', 'Google');
}
if (empty($this->Get('redirect_url'))) {
$this->Set('redirect_url', OAuthClientProviderFactory::GetRedirectUri());
}
if (empty($this->Get('scope'))) {
$this->Set('scope', 'EMail');
}
}
public function GetDefaultMailServer()
{
return 'imap.gmail.com';
}
public function GetScope()
{
return 'https://mail.google.com/';
}
}

View File

@@ -0,0 +1,31 @@
<?php
/**
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\OAuthClient\Service;
use AbstractApplicationUIExtension;
use OAuthClient;
use utils;
class ApplicationUIExtension extends AbstractApplicationUIExtension
{
public function GetHilightClass($oObject)
{
if ($oObject instanceof OAuthClient) {
// Possible return values are:
// HILIGHT_CLASS_CRITICAL, HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
$oConfig = utils::GetConfig();
if ($oObject->Get('status') == 'inactive') {
return HILIGHT_CLASS_WARNING;
} elseif ($oObject->Get('used_for_smtp') == 'yes' && $oConfig->Get('email_transport_smtp.username') == $oObject->Get('name')) {
return HILIGHT_CLASS_OK;
}
}
return HILIGHT_CLASS_NONE;
}
}

View File

@@ -51,8 +51,8 @@ class PopupMenuExtension implements \iPopupMenuExtension
);
if ($bHasToken) {
$sScope = $oObj->Get('scope');
if ($sScope == 'EMail') {
$aScopes = $oObj->Get('scope')->GetValues();
if (in_array('IMAP', $aScopes)) {
$aParams = $oAppContext->GetAsHash();
$sMenu = 'Menu:CreateMailbox';
$sObjClass = get_class($oObj);

View File

@@ -93,7 +93,7 @@ class ObjectFormManager extends FormManager
* @since 2.7.6 3.0.0 N°4384 method creation : factorize as this is used twice now
* @since 2.7.7 3.0.1 N°4867 now only used once, but we decided to keep this method anyway
*/
protected static function DecodeFormManagerData($formManagerData)
public static function DecodeFormManagerData($formManagerData)
{
if (is_array($formManagerData)) {
return $formManagerData;

View File

@@ -452,7 +452,7 @@ class ObjectFormHandlerHelper
* @throws \OQLException
*/
public function CheckReadFormDataAllowed($sFormManagerData){
$aJsonFromData = json_decode($sFormManagerData, true);
$aJsonFromData = ObjectFormManager::DecodeFormManagerData($sFormManagerData);
if(isset($aJsonFromData['formobject_class'])
&& isset($aJsonFromData['formobject_id'])
&& !$this->oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $aJsonFromData['formobject_class'], $aJsonFromData['formobject_id'])){

View File

@@ -1388,4 +1388,10 @@
</navigation_rules>
</module_design>
</module_designs>
<module_parameters>
<parameters id="itop-portal" _delta="define">
<lazy_loading_threshold>500</lazy_loading_threshold><!-- Will be placed in the conf/<env>/config-itop.php file under the itop-portal module's settings -->
<enable_formmanager_content_check type="boolean">true</enable_formmanager_content_check>
</parameters>
</module_parameters>
</itop_design>