comanage-dev - [comanage-dev] r519 - in registry/trunk/app: Lib Model Model/Behavior Plugin/LdapProvisioner/Config/Schema Plugin/LdapProvisioner/Controller Plugin/LdapProvisioner/Lib Plugin/LdapProvisioner/Model View/CoProvisioningTargets View/Layouts
Subject: COmanage Developers List
List archive
[comanage-dev] r519 - in registry/trunk/app: Lib Model Model/Behavior Plugin/LdapProvisioner/Config/Schema Plugin/LdapProvisioner/Controller Plugin/LdapProvisioner/Lib Plugin/LdapProvisioner/Model View/CoProvisioningTargets View/Layouts
Chronological Thread
- From:
- To:
- Subject: [comanage-dev] r519 - in registry/trunk/app: Lib Model Model/Behavior Plugin/LdapProvisioner/Config/Schema Plugin/LdapProvisioner/Controller Plugin/LdapProvisioner/Lib Plugin/LdapProvisioner/Model View/CoProvisioningTargets View/Layouts
- Date: Mon, 27 May 2013 23:58:10 -0400
- Authentication-results: sfpop-ironport03.merit.edu; dkim=neutral (message not signed) header.i=none
Author: benno
Date: 2013-05-27 23:58:10 -0400 (Mon, 27 May 2013)
New Revision: 519
Added:
registry/trunk/app/Plugin/LdapProvisioner/Model/CoLdapProvisionerAttrGrouping.php
registry/trunk/app/Plugin/LdapProvisioner/Model/CoLdapProvisionerAttribute.php
Modified:
registry/trunk/app/Lib/lang.php
registry/trunk/app/Model/Behavior/ProvisionerBehavior.php
registry/trunk/app/Model/CoGroupMember.php
registry/trunk/app/Plugin/LdapProvisioner/Config/Schema/schema.xml
registry/trunk/app/Plugin/LdapProvisioner/Controller/CoLdapProvisionerTargetsController.php
registry/trunk/app/Plugin/LdapProvisioner/Lib/lang.php
registry/trunk/app/Plugin/LdapProvisioner/Model/CoLdapProvisionerDn.php
registry/trunk/app/Plugin/LdapProvisioner/Model/CoLdapProvisionerTarget.php
registry/trunk/app/View/CoProvisioningTargets/fields.inc
registry/trunk/app/View/Layouts/default.ctp
Log:
Configure LdapProvisioner attributes (CO-549)
Modified: registry/trunk/app/Lib/lang.php
===================================================================
--- registry/trunk/app/Lib/lang.php 2013-05-11 10:42:44 UTC (rev 518)
+++ registry/trunk/app/Lib/lang.php 2013-05-28 03:58:10 UTC (rev 519)
@@ -233,7 +233,7 @@
ProvisionerStatusEnum::Disabled => 'Disabled'
),
- 'en.status.prov.desc' => 'In automatic mode, provisioners are called
automatically as needed.<br />In manual mode, an administrator must invoke
the provisioner.',
+ 'en.status.prov.desc' => 'In automatic mode, provisioners are called
automatically as needed<br />In manual mode, an administrator must invoke the
provisioner',
'en.status.prov.target' => array(
ProvisioningStatusEnum::NotProvisioned => 'Not Provisioned',
@@ -513,6 +513,7 @@
'fd.perms' => 'Permissions',
'fd.petitioner' => 'Petitioner',
'fd.plugin' => 'Plugin',
+ 'fd.plugin.ptwarn' => 'Once a Provisioning Target has been created, the
Plugin cannot be changed',
'fd.prov.status.for' => 'Provisioning Status for %1$s',
'fd.req' => '* denotes required field',
'fd.required' => 'Required',
Modified: registry/trunk/app/Model/Behavior/ProvisionerBehavior.php
===================================================================
--- registry/trunk/app/Model/Behavior/ProvisionerBehavior.php 2013-05-11
10:42:44 UTC (rev 518)
+++ registry/trunk/app/Model/Behavior/ProvisionerBehavior.php 2013-05-28
03:58:10 UTC (rev 519)
@@ -38,41 +38,15 @@
* @return boolean true on success, false on failure
*/
- public function beforeDelete(Model $model, $cascade = true) {
+ public function afterDelete(Model $model) {
// Note that in most cases this is just an edit. ie: deleting a
telephone number is
// CoPersonUpdated not CoPersonDeleted. In those cases, we can just call
afterSave.
+ // CoPerson was already handled by beforeDelete().
if($model->name != 'CoPerson') {
return $this->afterSave($model, false);
}
- // However, deleting a CoPerson needs to be handled specially.
- // Note that $model->data is generally populated by
StandardController::delete
- // calling $model->read().
-
- if(!empty($model->data['CoPerson']['id'])) {
- // Invoke all provisioning plugins
-
- try {
- $this->invokePlugins($model,
- $model->data['CoPerson']['id'],
- $model->data,
- ProvisioningActionEnum::CoPersonDeleted);
- }
- // What we really want to do here is catch the result (success or
exception)
- // and set the appropriate session flash message, but we don't have
access to
- // the current session, and anyway that doesn't cover RESTful
interactions.
- // So instead we syslog (which is better than nothing).
- catch(InvalidArgumentException $e) {
- syslog(LOG_ERR, $e->getMessage());
- //throw new InvalidArgumentException($e->getMessage());
- }
- catch(RuntimeException $e) {
- syslog(LOG_ERR, $e->getMessage());
- //throw new RuntimeException($e->getMessage());
- }
- }
-
return true;
}
@@ -163,6 +137,53 @@
}
/**
+ * Handle provisioning following (before) delete of Model.
+ *
+ * @since COmanage Registry v0.8
+ * @param Model $model Model instance.
+ * @return boolean true on success, false on failure
+ */
+
+ public function beforeDelete(Model $model, $cascade = true) {
+ // Note that in most cases this is just an edit. ie: deleting a
telephone number is
+ // CoPersonUpdated not CoPersonDeleted. However, in those cases we don't
want to
+ // process anything until afterDelete().
+
+ if($model->name != 'CoPerson') {
+ return true;
+ }
+
+ // However, deleting a CoPerson needs to be handled specially.
+ // Note that $model->data is generally populated by
StandardController::delete
+ // calling $model->read().
+
+ if(!empty($model->data['CoPerson']['id'])) {
+ // Invoke all provisioning plugins
+
+ try {
+ $this->invokePlugins($model,
+ $model->data['CoPerson']['id'],
+ $model->data,
+ ProvisioningActionEnum::CoPersonDeleted);
+ }
+ // What we really want to do here is catch the result (success or
exception)
+ // and set the appropriate session flash message, but we don't have
access to
+ // the current session, and anyway that doesn't cover RESTful
interactions.
+ // So instead we syslog (which is better than nothing).
+ catch(InvalidArgumentException $e) {
+ syslog(LOG_ERR, $e->getMessage());
+ //throw new InvalidArgumentException($e->getMessage());
+ }
+ catch(RuntimeException $e) {
+ syslog(LOG_ERR, $e->getMessage());
+ //throw new RuntimeException($e->getMessage());
+ }
+ }
+
+ return true;
+ }
+
+ /**
* Invoke a provisioning plugin.
*
* @since COmanage Registry v0.8
Modified: registry/trunk/app/Model/CoGroupMember.php
===================================================================
--- registry/trunk/app/Model/CoGroupMember.php 2013-05-11 10:42:44 UTC (rev
518)
+++ registry/trunk/app/Model/CoGroupMember.php 2013-05-28 03:58:10 UTC (rev
519)
@@ -173,6 +173,9 @@
$curRoles = $this->findCoPersonGroupRoles($coPersonId);
foreach($memberships as $m) {
+ // Reset model state between transactions
+ $this->create();
+
// Determine desired roles for this row
$member = isset($m['member']) && $m['member'];
$owner = isset($m['owner']) && $m['owner'];
Modified: registry/trunk/app/Plugin/LdapProvisioner/Config/Schema/schema.xml
===================================================================
--- registry/trunk/app/Plugin/LdapProvisioner/Config/Schema/schema.xml
2013-05-11 10:42:44 UTC (rev 518)
+++ registry/trunk/app/Plugin/LdapProvisioner/Config/Schema/schema.xml
2013-05-28 03:58:10 UTC (rev 519)
@@ -34,6 +34,10 @@
<field name="binddn" type="C" size="128" />
<field name="password" type="C" size="64" />
<field name="basedn" type="C" size="128" />
+ <field name="opt_lang" type="L" />
+ <field name="opt_role" type="L" />
+ <field name="oc_eduperson" type="L" />
+ <field name="oc_edumember" type="L" />
<field name="created" type="T" />
<field name="modified" type="T" />
@@ -64,4 +68,53 @@
<unique />
</index>
</table>
+
+ <table name="co_ldap_provisioner_attributes">
+ <field name="id" type="I">
+ <key />
+ <autoincrement />
+ </field>
+ <field name="co_ldap_provisioner_target_id" type="I">
+ <constraint>REFERENCES cm_co_ldap_provisioner_targets(id)</constraint>
+ </field>
+ <field name="attribute" type="C" size="80" />
+ <field name="type" type="C" size="32" />
+ <field name="export" type="L" />
+ <field name="created" type="T" />
+ <field name="modified" type="T" />
+
+ <index name="co_ldap_provisioner_attributes_i1">
+ <col>co_ldap_provisioner_target_id</col>
+ </index>
+
+ <index name="co_ldap_provisioner_attributes_i2">
+ <col>co_ldap_provisioner_target_id</col>
+ <col>attribute</col>
+ <unique />
+ </index>
+ </table>
+
+ <table name="co_ldap_provisioner_attr_groupings">
+ <field name="id" type="I">
+ <key />
+ <autoincrement />
+ </field>
+ <field name="co_ldap_provisioner_target_id" type="I">
+ <constraint>REFERENCES cm_co_ldap_provisioner_targets(id)</constraint>
+ </field>
+ <field name="grouping" type="C" size="80" />
+ <field name="type" type="C" size="32" />
+ <field name="created" type="T" />
+ <field name="modified" type="T" />
+
+ <index name="co_ldap_provisioner_attr_groupings_i1">
+ <col>co_ldap_provisioner_target_id</col>
+ </index>
+
+ <index name="co_ldap_provisioner_attr_groupings_i2">
+ <col>co_ldap_provisioner_target_id</col>
+ <col>grouping</col>
+ <unique />
+ </index>
+ </table>
</schema>
\ No newline at end of file
Modified:
registry/trunk/app/Plugin/LdapProvisioner/Controller/CoLdapProvisionerTargetsController.php
===================================================================
---
registry/trunk/app/Plugin/LdapProvisioner/Controller/CoLdapProvisionerTargetsController.php
2013-05-11 10:42:44 UTC (rev 518)
+++
registry/trunk/app/Plugin/LdapProvisioner/Controller/CoLdapProvisionerTargetsController.php
2013-05-28 03:58:10 UTC (rev 519)
@@ -40,6 +40,25 @@
public $requires_co = true;
/**
+ * Add a Standard Object.
+ * - precondition: Model specific attributes in $this->request->data
(optional)
+ * - postcondition: On success, new Object created
+ * - postcondition: Session flash message updated (HTML) or HTTP status
returned (REST)
+ * - postcondition: $<object>_id or $invalid_fields set (REST)
+ *
+ * @since COmanage Registry v0.8
+ */
+
+ function add() {
+ $this->set('supportedAttributes',
$this->CoLdapProvisionerTarget->supportedAttributes());
+
+ // As an interim hack, populate a variable with the available Identifier
types (CO-370)
+ $this->set('identifier_types',
$this->CoLdapProvisionerTarget->CoProvisioningTarget->Co->CoPerson->Identifier->types($this->cur_co['Co']['id']));
+
+ parent::add();
+ }
+
+ /**
* Perform any dependency checks required prior to a write (add/edit)
operation.
* This method is intended to be overridden by model-specific controllers.
*
@@ -67,6 +86,28 @@
}
/**
+ * Update a Standard Object.
+ * - precondition: Model specific attributes in $this->request->data
(optional)
+ * - precondition: <id> must exist
+ * - postcondition: On GET, $<object>s set (HTML)
+ * - postcondition: On POST success, object updated
+ * - postcondition: On POST, session flash message updated (HTML) or HTTP
status returned (REST)
+ * - postcondition: On POST error, $invalid_fields set (REST)
+ *
+ * @since COmanage Registry v0.8
+ * @param integer Object identifier (eg: cm_co_groups:id) representing
object to be retrieved
+ */
+
+ function edit($id) {
+ $this->set('supportedAttributes',
$this->CoLdapProvisionerTarget->supportedAttributes());
+
+ // As an interim hack, populate a variable with the available Identifier
types (CO-370)
+ $this->set('identifier_types',
$this->CoLdapProvisionerTarget->CoProvisioningTarget->Co->CoPerson->Identifier->types($this->cur_co['Co']['id']));
+
+ parent::edit($id);
+ }
+
+ /**
* Perform a redirect back to the controller's default view.
* - postcondition: Redirect generated
*
Modified: registry/trunk/app/Plugin/LdapProvisioner/Lib/lang.php
===================================================================
--- registry/trunk/app/Plugin/LdapProvisioner/Lib/lang.php 2013-05-11
10:42:44 UTC (rev 518)
+++ registry/trunk/app/Plugin/LdapProvisioner/Lib/lang.php 2013-05-28
03:58:10 UTC (rev 519)
@@ -37,9 +37,12 @@
'er.ldapprovisioner.basedn' => 'Base DN not found',
'er.ldapprovisioner.connect' => 'Failed to connect to LDAP server',
'er.ldapprovisioner.dn.component' => 'DN component %1$s not available',
+ 'er.ldapprovisioner.dn.noattr' => 'DN attributes not found for CO
Person %1$s',
'er.ldapprovisioner.dn.none' => 'DN not found for CO Person %1$s',
// Plugin texts
+ 'pl.ldapprovisioner.attrs' => 'Attributes',
+ 'pl.ldapprovisioner.attrs.desc' => 'Attributes to export to this LDAP
server',
'pl.ldapprovisioner.basedn' => 'Base DN',
'pl.ldapprovisioner.basedn.desc' => 'Base DN to provision entries
under',
'pl.ldapprovisioner.binddn' => 'Bind DN',
@@ -47,6 +50,12 @@
'pl.ldapprovisioner.info' => 'The LDAP server must be available
and the specified credentials must be valid before this configuration can be
saved.',
'pl.ldapprovisioner.password' => 'Password',
'pl.ldapprovisioner.password.desc' => 'Password to use for
authentication',
+ 'pl.ldapprovisioner.oc.enable' => 'Enable <font
style="font-family:monospace">%1$s</font> objectclass',
+ 'pl.ldapprovisioner.opts' => 'Attribute Options',
+ 'pl.ldapprovisioner.opts.desc' => 'XXX link to documentation',
+ 'pl.ldapprovisioner.opt.lang' => 'Enable attribute options for
languages',
+ 'pl.ldapprovisioner.opt.role' => 'Enable attribute options for
roles',
'pl.ldapprovisioner.serverurl' => 'Server URL',
- 'pl.ldapprovisioner.serverurl.desc' => 'URL to connect to
(<tt>ldap[s]://hostname[:port]</tt>)'
+ 'pl.ldapprovisioner.serverurl.desc' => 'URL to connect to (<font
style="font-family:monospace">ldap[s]://hostname[:port]</font>)',
+ 'pl.ldapprovisioner.types.all' => 'All Types'
);
Modified:
registry/trunk/app/Plugin/LdapProvisioner/Model/CoLdapProvisionerDn.php
===================================================================
--- registry/trunk/app/Plugin/LdapProvisioner/Model/CoLdapProvisionerDn.php
2013-05-11 10:42:44 UTC (rev 518)
+++ registry/trunk/app/Plugin/LdapProvisioner/Model/CoLdapProvisionerDn.php
2013-05-28 03:58:10 UTC (rev 519)
@@ -66,7 +66,7 @@
*/
public function assignDn($coProvisioningTargetData, $coPersonData) {
-// XXX make this configurable (or cut a ticket)
+ // XXX make this configurable (CO-550)
if(!isset($coPersonData['CoPerson']['id'])) {
throw new RuntimeException(_txt('er.ldapprovisioner.dn.component',
array("co_person_id")));
@@ -85,4 +85,33 @@
throw new RuntimeException(_txt('er.db.save'));
}
}
+
+ /**
+ * Determine the attributes used to generate a DN.
+ *
+ * @since COmanage Registry v0.8
+ * @param Array CO Provisioning Target data
+ * @param String DN
+ * @return Array Attribute/value pairs used to generate the DN, not
including the base DN
+ * @throws RuntimeException
+ */
+
+ public function dnAttributes($coProvisioningTargetData, $dn) {
+ // We assume dn is of the form attr1=val1, attr2=val2, basedn
+ // where based matches $coProvisioningTargetData. Strip off basedn
+ // and then split up the remaining string. Note we'll fail if the
+ // base DN changes. Currently, that would require manual cleanup.
+
+ $ret = array();
+
+ $attrs = explode(",",
rtrim(str_replace($coProvisioningTargetData['CoLdapProvisionerTarget']['basedn'],
"", $dn), " ,"));
+
+ foreach($attrs as $a) {
+ $av = explode("=", $a, 2);
+
+ $ret[ $av[0] ] = $av[1];
+ }
+
+ return $ret;
+ }
}
Modified:
registry/trunk/app/Plugin/LdapProvisioner/Model/CoLdapProvisionerTarget.php
===================================================================
---
registry/trunk/app/Plugin/LdapProvisioner/Model/CoLdapProvisionerTarget.php
2013-05-11 10:42:44 UTC (rev 518)
+++
registry/trunk/app/Plugin/LdapProvisioner/Model/CoLdapProvisionerTarget.php
2013-05-28 03:58:10 UTC (rev 519)
@@ -34,7 +34,20 @@
// Association rules from this model to other models
public $belongsTo = array("CoProvisioningTarget");
- public $hasMany = array("LdapProvisioner.CoLdapProvisionerDn");
+ public $hasMany = array(
+ "CoLdapProvisionerDn" => array(
+ 'className' => 'LdapProvisioner.CoLdapProvisionerDn',
+ 'dependent' => true
+ ),
+ "CoLdapProvisionerAttribute" => array(
+ 'className' => 'LdapProvisioner.CoLdapProvisionerAttribute',
+ 'dependent' => true
+ ),
+ "CoLdapProvisionerAttrGrouping" => array(
+ 'className' => 'LdapProvisioner.CoLdapProvisionerAttrGrouping',
+ 'dependent' => true
+ )
+ );
// Default display field for cake generated views
public $displayField = "serverurl";
@@ -60,10 +73,306 @@
),
'basedn' => array(
'rule' => 'notEmpty'
+ ),
+ 'oc_person' => array(
+ 'rule' => 'boolean'
+ ),
+ 'oc_orgperson' => array(
+ 'rule' => 'boolean'
+ ),
+ 'oc_inetorgperson' => array(
+ 'rule' => 'boolean'
+ ),
+ 'oc_eduperson' => array(
+ 'rule' => 'boolean'
)
);
/**
+ * Assemble attributes for an LDAP record.
+ *
+ * @since COmanage Registry v0.8
+ * @param Array CO Provisioning Target data
+ * @param Array CO Person Data used for provisioning
+ * @param Boolean Whether or not this will be for a modify operation
+ * @param Array Attributes used to generate the DN for this person, as
returned by CoLdapProvisionerDn::dnAttributes
+ * @return Array Attribute data suitable for passing to ldap_add, etc
+ */
+
+ protected function assembleAttributes($coProvisioningTargetData,
$coPersonData, $modify, $dnAttributes) {
+ // Pull the attribute configuration
+ $args = array();
+
$args['conditions']['CoLdapProvisionerAttribute.co_ldap_provisioner_target_id']
= $coProvisioningTargetData['CoLdapProvisionerTarget']['id'];
+ $args['contain'] = false;
+
+ $cAttrs = $this->CoLdapProvisionerAttribute->find('all', $args);
+
+ // Rekey the attributes array on attribute name
+
+ $configuredAttributes = array();
+
+ foreach($cAttrs as $a) {
+ if(!empty($a['CoLdapProvisionerAttribute']['attribute'])) {
+ $configuredAttributes[ $a['CoLdapProvisionerAttribute']['attribute']
] = $a['CoLdapProvisionerAttribute'];
+ }
+ }
+
+ // Pull the attribute groupings
+ $args = array();
+
$args['conditions']['CoLdapProvisionerAttrGrouping.co_ldap_provisioner_target_id']
= $coProvisioningTargetData['CoLdapProvisionerTarget']['id'];
+ $args['contain'] = false;
+
+ $cAttrGrs = $this->CoLdapProvisionerAttrGrouping->find('all', $args);
+
+ // Rekey the attributes array on attribute name
+
+ $configuredAttributeGroupings = array();
+
+ foreach($cAttrGrs as $g) {
+ if(!empty($g['CoLdapProvisionerAttrGrouping']['grouping'])) {
+ $configuredAttributeGroupings[
$g['CoLdapProvisionerAttrGrouping']['grouping'] ] =
$g['CoLdapProvisionerAttrGrouping'];
+ }
+ }
+
+ // Marshalled attributes ready for export
+ $attributes = array();
+
+ // Full set of supported attributes (not what's configured)
+ $supportedAttributes = $this->supportedAttributes();
+
+ // Note we don't need to check for inactive status where relevant since
+ // ProvisionerBehavior will remove those from the data we get.
+
+ foreach(array_keys($supportedAttributes) as $oc) {
+ // Iterate across objectclasses, looking for those that are required
or enabled
+
+ if($supportedAttributes[$oc]['objectclass']['required']
+ ||
(isset($coProvisioningTargetData['CoLdapProvisionerTarget']['oc_' .
strtolower($oc)])
+ && $coProvisioningTargetData['CoLdapProvisionerTarget']['oc_' .
strtolower($oc)])) {
+ $attributes['objectclass'][] = $oc;
+
+ // Within the objectclass, iterate across the supported attributes
looking
+ // for required or enabled attributes
+
+ foreach(array_keys($supportedAttributes[$oc]['attributes']) as
$attr) {
+ if($supportedAttributes[$oc]['attributes'][$attr]['required']
+ || (isset($configuredAttributes[$attr]['export'])
+ && $configuredAttributes[$attr]['export'])) {
+ // Does this attribute support multiple values?
+ $multiple =
(isset($supportedAttributes[$oc]['attributes'][$attr]['multiple'])
+ &&
$supportedAttributes[$oc]['attributes'][$attr]['multiple']);
+
+ // Is a type specified for this attribute via a grouping?
+ $targetType = null;
+
+
if(!empty($supportedAttributes[$oc]['attributes'][$attr]['grouping'])) {
+ $grouping =
$supportedAttributes[$oc]['attributes'][$attr]['grouping'];
+
+ if(!empty($configuredAttributeGroupings[$grouping]['type'])) {
+ $targetType =
$configuredAttributeGroupings[$grouping]['type'];
+ }
+ }
+
+ // Or explicitly?
+ if(!$targetType && !empty($configuredAttributes[$attr]['type']))
{
+ $targetType = $configuredAttributes[$attr]['type'];
+ }
+
+ switch($attr) {
+ // Name attributes
+ case 'cn':
+ // Currently only preferred name supported (CO-333)
+ $attributes[$attr] = generateCn($coPersonData['Name']);
+ break;
+ case 'givenName':
+ // Currently only preferred name supported (CO-333)
+ $attributes[$attr] = $coPersonData['Name']['given'];
+ break;
+ case 'sn':
+ // Currently only preferred name supported (CO-333)
+ $attributes[$attr] = $coPersonData['Name']['family'];
+ break;
+ // Attributes from CO Person Role
+ case 'eduPersonAffiliation':
+ case 'o':
+ case 'ou':
+ case 'title':
+ // Map the attribute to the column
+ $cols = array(
+ 'eduPersonAffiliation' => 'affiliation',
+ 'o' => 'o',
+ 'ou' => 'ou',
+ 'title' => 'title'
+ );
+
+ // Walk through each role
+ $found = false;
+
+ foreach($coPersonData['CoPersonRole'] as $r) {
+ if(!empty($r[ $cols[$attr] ])) {
+ if($attr == 'eduPersonAffiliation') {
+ // Map back to the controlled vocabulary
+ $attributes[$attr][] = _txt('en.affil', null, $r[
$cols[$attr] ]);
+ } else {
+ $attributes[$attr][] = $r[ $cols[$attr] ];
+ }
+
+ $found = true;
+ }
+
+ if(!$multiple && $found) {
+ break;
+ }
+ }
+
+ if(!$found && $modify) {
+ $attributes[$attr] = array();
+ }
+ break;
+ // Attributes from models attached to CO Person
+ case 'eduPersonPrincipalName':
+ case 'employeeNumber':
+ case 'mail':
+ case 'uid':
+ // Map the attribute to the model and column
+ $mods = array(
+ 'eduPersonPrincipalName' => 'Identifier',
+ 'employeeNumber' => 'Identifier',
+ 'mail' => 'EmailAddress',
+ 'uid' => 'Identifier'
+ );
+
+ $cols = array(
+ 'eduPersonPrincipalName' => 'identifier',
+ 'employeeNumber' => 'identifier',
+ 'mail' => 'mail',
+ 'uid' => 'identifier'
+ );
+
+ // Walk through each model instance
+ $found = false;
+
+ if(isset($coPersonData[ $mods[$attr] ])) {
+ foreach($coPersonData[ $mods[$attr] ] as $m) {
+ // If a type is set, make sure it matches
+ if(empty($targetType) || ($targetType == $m['type'])) {
+ // And finally that the attribute itself is set
+ if(!empty($m[ $cols[$attr] ])) {
+ $attributes[$attr][] = $m[ $cols[$attr] ];
+ $found = true;
+ }
+ }
+
+ if(!$multiple && $found) {
+ break;
+ }
+ }
+
+ if(!$multiple && $found) {
+ break;
+ }
+ }
+
+ if(!$found && $modify) {
+ $attributes[$attr] = array();
+ }
+ break;
+ // Attributes from models attached to CO Person Role
+ case 'facsimileTelephoneNumber':
+ case 'l':
+ case 'mail':
+ case 'mobile':
+ case 'postalCode':
+ case 'st':
+ case 'street':
+ case 'telephoneNumber':
+ // Map the attribute to the model and column
+ $mods = array(
+ 'facsimileTelephoneNumber' => 'TelephoneNumber',
+ 'l' => 'Address',
+ 'mail' => 'EmailAddress',
+ 'mobile' => 'TelephoneNumber',
+ 'postalCode' => 'Address',
+ 'st' => 'Address',
+ 'street' => 'Address',
+ 'telephoneNumber' => 'TelephoneNumber'
+ );
+
+ $cols = array(
+ 'facsimileTelephoneNumber' => 'number',
+ 'l' => 'locality',
+ 'mail' => 'mail',
+ 'mobile' => 'number',
+ 'postalCode' => 'postal_code',
+ 'st' => 'state',
+ 'street' => 'line1',
+ 'telephoneNumber' => 'number'
+ );
+
+ // Walk through each role, each of which can have more than
one
+ $found = false;
+
+ foreach($coPersonData['CoPersonRole'] as $r) {
+ if(isset($r[ $mods[$attr] ])) {
+ foreach($r[ $mods[$attr] ] as $m) {
+ // If a type is set, make sure it matches
+ if(empty($targetType) || ($targetType == $m['type'])) {
+ // And finally that the attribute itself is set
+ if(!empty($m[ $cols[$attr] ])) {
+ $attributes[$attr][] = $m[ $cols[$attr] ];
+ $found = true;
+ }
+ }
+
+ if(!$multiple && $found) {
+ break;
+ }
+ }
+
+ if(!$multiple && $found) {
+ break;
+ }
+ }
+ }
+
+ if(!$found && $modify) {
+ $attributes[$attr] = array();
+ }
+ break;
+ // Group attributes
+ case 'isMemberOf':
+ foreach($coPersonData['CoGroupMember'] as $gm) {
+ if(isset($gm['member']) && $gm['member']
+ && !empty($gm['CoGroup']['name'])) {
+ $attributes['isMemberOf'][] = $gm['CoGroup']['name'];
+ }
+ }
+ break;
+ default:
+ throw new InternalErrorException("Unknown attribute: " .
$attr);
+ break;
+ }
+ } elseif($modify) {
+ // In case this attribute is no longer being exported (but was
previously),
+ // set an empty value to indicate delete
+ $attributes[$attr] = array();
+ }
+ }
+ }
+ }
+
+ // Make sure the DN values are in the list
+
+ foreach(array_keys($dnAttributes) as $a) {
+ if(empty($attributes[$a]) || !in_array($dnAttributes[$a],
$attributes[$a])) {
+ $attributes[$a][] = $dnAttributes[$a];
+ }
+ }
+
+ return $attributes;
+ }
+
+ /**
* Query an LDAP server.
*
* @since COmanage Registry v0.8
@@ -243,7 +552,12 @@
if($assigndn) {
// If we don't have a DN, assign one
- $dn =
$this->CoLdapProvisionerDn->assignDn($coProvisioningTargetData,
$coPersonData);
+ try {
+ $dn =
$this->CoLdapProvisionerDn->assignDn($coProvisioningTargetData,
$coPersonData);
+ }
+ catch(RuntimeException $e) {
+ throw new RuntimeException($e->getMessage());
+ }
}
} else {
$dn = $dnRecord['CoLdapProvisionerDn']['dn'];
@@ -253,59 +567,20 @@
throw new RuntimeException(_txt('er.ldapprovisioner.dn.none',
array($coPersonData['CoPerson']['id'])));
}
- // Assemble an LDAP record
+ // Find out what attributes went into the DN to make sure they got
populated into
+ // the attribute array
- // XXX make this configurable, at least as per (CO-549)
- // multi-valued attributes can be set via $attributes['mail'][0]
- $attributes = array();
- $attributes['objectclass'][] = 'top';
- $attributes['objectclass'][] = 'person';
- $attributes['objectclass'][] = 'organizationalperson';
- $attributes['objectclass'][] = 'inetorgperson';
- // Note: RFC4519 requires sn and cn for person
- $attributes['cn'] = generateCn($coPersonData['Name']);
- $attributes['sn'] = $coPersonData['Name']['family'];
- $attributes['givenname'] = $coPersonData['Name']['given'];
- $attributes['uid'] = $coPersonData['CoPerson']['id'];
- if(!empty($coPersonData['CoPersonRole'][0]['title'])) {
- $attributes['title'] = $coPersonData['CoPersonRole'][0]['title'];
- } elseif($modify) {
- $attributes['title'] = array();
+ try {
+ $dnAttributes =
$this->CoLdapProvisionerDn->dnAttributes($coProvisioningTargetData, $dn);
}
- if(!empty($coPersonData['CoPersonRole'][0]['Address'][0]['line1'])) {
- // XXX should concatenate line2, or implement CO-539 and convert
newlines to $
- $attributes['street'] =
$coPersonData['CoPersonRole'][0]['Address'][0]['line1'];
- } elseif($modify) {
- $attributes['street'] = array();
+ catch(RuntimeException $e) {
+ throw new RuntimeException($e->getMessage());
}
- if(!empty($coPersonData['CoPersonRole'][0]['Address'][0]['locality'])) {
- $attributes['l'] =
$coPersonData['CoPersonRole'][0]['Address'][0]['locality'];
- } elseif($modify) {
- $attributes['l'] = array();
- }
- if(!empty($coPersonData['CoPersonRole'][0]['Address'][0]['state'])) {
- $attributes['st'] =
$coPersonData['CoPersonRole'][0]['Address'][0]['state'];
- } elseif($modify) {
- $attributes['st'] = array();
- }
-
if(!empty($coPersonData['CoPersonRole'][0]['Address'][0]['postal_code'])) {
- $attributes['postalcode'] =
$coPersonData['CoPersonRole'][0]['Address'][0]['postal_code'];
- } elseif($modify) {
- $attributes['postalcode'] = array();
- }
- if(!empty($coPersonData['CoPersonRole'][0]['TelephoneNumber'])) {
- foreach($coPersonData['CoPersonRole'][0]['TelephoneNumber'] as $t) {
- $attributes['telephonenumber'][] = $t['number'];
- }
- } elseif($modify) {
- $attributes['telephonenumber'] = array();
- }
- if(!empty($coPersonData['EmailAddress'][0]['mail'])) {
- $attributes['mail'] = $coPersonData['EmailAddress'][0]['mail'];
- } elseif($modify) {
- $attributes['mail'] = array();
- }
+ // Assemble an LDAP record
+
+ $attributes = $this->assembleAttributes($coProvisioningTargetData,
$coPersonData, $modify, $dnAttributes);
+
// Bind to the server
$cxn =
ldap_connect($coProvisioningTargetData['CoLdapProvisionerTarget']['serverurl']);
@@ -362,6 +637,178 @@
}
/**
+ * Obtain the list of attributes supported for export.
+ *
+ * @since COmanage Registry v0.8
+ * @return Array Array of supported attributes
+ */
+
+ public function supportedAttributes() {
+ // Attributes should be listed in the order they are to be rendered in.
+ // The outermost key is the object class. If the objectclass is flagged
+ // as required => false, it MUST have a corresponding column oc_FOO in
+ // the cm_co_ldap_provisioner_targets.
+
+ $attributes = array(
+ 'person' => array(
+ 'objectclass' => array(
+ 'required' => true
+ ),
+ // RFC4519 requires sn and cn for person
+ // For now, CO Person is always attached to preferred name (CO-333)
+ 'attributes' => array(
+ 'sn' => array(
+ 'required' => true,
+ 'multiple' => false
+// 'multiple' => true,
+// 'typekey' => 'en.name',
+// 'defaulttype' => NameEnum::Official
+ ),
+ 'cn' => array(
+ 'required' => true,
+ 'multiple' => false
+// 'multiple' => true,
+// 'typekey' => 'en.name',
+// 'defaulttype' => NameEnum::Official
+ )
+ )
+ ),
+ 'organizationalPerson' => array(
+ 'objectclass' => array(
+ 'required' => true
+ ),
+ 'attributes' => array(
+ 'title' => array(
+ 'required' => false,
+ 'multiple' => true
+ ),
+ 'ou' => array(
+ 'required' => false,
+ 'multiple' => true
+ ),
+ 'telephoneNumber' => array(
+ 'required' => false,
+ 'multiple' => true,
+ 'typekey' => 'en.contact.phone',
+ 'defaulttype' => ContactEnum::Office
+ ),
+ 'facsimileTelephoneNumber' => array(
+ 'required' => false,
+ 'multiple' => true,
+ 'typekey' => 'en.contact.phone',
+ 'defaulttype' => ContactEnum::Fax
+ ),
+ 'street' => array(
+ 'required' => false,
+ 'grouping' => 'address'
+ ),
+ 'l' => array(
+ 'required' => false,
+ 'grouping' => 'address'
+ ),
+ 'st' => array(
+ 'required' => false,
+ 'grouping' => 'address'
+ ),
+ 'postalCode' => array(
+ 'required' => false,
+ 'grouping' => 'address'
+ )
+ ),
+ 'groupings' => array(
+ 'address' => array (
+ 'label' => _txt('fd.address'),
+ 'multiple' => true,
+ 'typekey' => 'en.contact.address',
+ 'defaulttype' => ContactEnum::Office
+ )
+ ),
+ ),
+ 'inetOrgPerson' => array(
+ 'objectclass' => array(
+ 'required' => true
+ ),
+ 'attributes' => array(
+ // For now, CO Person is always attached to preferred name (CO-333)
+ 'givenName' => array(
+ 'required' => false,
+ 'multiple' => false
+// 'multiple' => true,
+// 'typekey' => 'en.name',
+// 'defaulttype' => NameEnum::Official
+ ),
+ // And since there is only one name, there's no point in
supporting displayName
+ /* 'displayName' => array(
+ 'required' => false,
+ 'multiple' => false,
+ 'typekey' => 'en.name',
+ 'defaulttype' => NameEnum::Preferred
+ ),*/
+ 'o' => array(
+ 'required' => false,
+ 'multiple' => true
+ ),
+ 'mail' => array(
+ 'required' => false,
+ 'multiple' => true,
+ 'typekey' => 'en.contact.mail',
+ 'defaulttype' => EmailAddressEnum::Official
+ ),
+ 'mobile' => array(
+ 'required' => false,
+ 'multiple' => true,
+ 'typekey' => 'en.contact.phone',
+ 'defaulttype' => ContactEnum::Mobile
+ ),
+ 'employeeNumber' => array(
+ 'required' => false,
+ 'multiple' => false,
+ 'extendedtype' => 'identifier_types',
+ 'typekey' => 'en.identifier',
+ 'defaulttype' => IdentifierEnum::ePPN
+ ),
+ 'uid' => array(
+ 'required' => false,
+ 'multiple' => false,
+ 'extendedtype' => 'identifier_types',
+ 'defaulttype' => IdentifierEnum::UID
+ )
+ )
+ ),
+ 'eduPerson' => array(
+ 'objectclass' => array(
+ 'required' => false
+ ),
+ 'attributes' => array(
+ 'eduPersonAffiliation' => array(
+ 'required' => false,
+ 'multiple' => true
+ ),
+ 'eduPersonPrincipalName' => array(
+ 'required' => false,
+ 'multiple' => false,
+ 'extendedtype' => 'identifier_types',
+ 'defaulttype' => IdentifierEnum::ePPN
+ )
+ )
+ ),
+ 'eduMember' => array(
+ 'objectclass' => array(
+ 'required' => false
+ ),
+ 'attributes' => array(
+ 'isMemberOf' => array(
+ 'required' => true,
+ 'multiple' => true
+ )
+ )
+ )
+ );
+
+ return $attributes;
+ }
+
+ /**
* Test an LDAP server to verify that the connection available is valid.
*
* @since COmanage Registry v0.8
Modified: registry/trunk/app/View/CoProvisioningTargets/fields.inc
===================================================================
--- registry/trunk/app/View/CoProvisioningTargets/fields.inc 2013-05-11
10:42:44 UTC (rev 518)
+++ registry/trunk/app/View/CoProvisioningTargets/fields.inc 2013-05-28
03:58:10 UTC (rev 519)
@@ -72,7 +72,8 @@
</tr>
<tr class="line2">
<td>
- <?php print _txt('fd.plugin'); ?><font class="required">*</font>
+ <?php print _txt('fd.plugin'); ?><font class="required">*</font><br
/>
+ <font class="desc"><?php print _txt('fd.plugin.ptwarn'); ?></font>
</td>
<td>
<?php
@@ -97,15 +98,15 @@
$pl =
Inflector::underscore(Sanitize::html($co_provisioning_targets[0]['CoProvisioningTarget']['plugin']));
$plmodel = "Co" .
Sanitize::html($co_provisioning_targets[0]['CoProvisioningTarget']['plugin'])
. "Target";
- print " " . $this->Html->link(_txt('op.config'),
- array(
- 'plugin' => $pl,
- 'controller' => 'co_' . $pl .
'_targets',
- 'action' => 'edit',
-
$co_provisioning_targets[0][$plmodel]['id'],
- 'co' => $cur_co['Co']['id']
- ),
- array('class' => 'editbutton'));
+ print "<br />" . $this->Html->link(_txt('op.config'),
+ array(
+ 'plugin' => $pl,
+ 'controller' => 'co_' . $pl
. '_targets',
+ 'action' => 'edit',
+
$co_provisioning_targets[0][$plmodel]['id'],
+ 'co' => $cur_co['Co']['id']
+ ),
+ array('class' =>
'configurebutton'));
}
?>
</td>
Modified: registry/trunk/app/View/Layouts/default.ctp
===================================================================
--- registry/trunk/app/View/Layouts/default.ctp 2013-05-11 10:42:44 UTC (rev
518)
+++ registry/trunk/app/View/Layouts/default.ctp 2013-05-28 03:58:10 UTC (rev
519)
@@ -185,6 +185,12 @@
text: false
});
+ $(".configurebutton").button({
+ icons: {
+ primary: 'ui-icon-pencil'
+ }
+ });
+
$(".deletebutton").button({
icons: {
primary: 'ui-icon-circle-close'
- [comanage-dev] r519 - in registry/trunk/app: Lib Model Model/Behavior Plugin/LdapProvisioner/Config/Schema Plugin/LdapProvisioner/Controller Plugin/LdapProvisioner/Lib Plugin/LdapProvisioner/Model View/CoProvisioningTargets View/Layouts, svnlog, 05/27/2013
Archive powered by MHonArc 2.6.16.