LDIF export

This commit is contained in:
Roland Gruber 2018-10-04 21:07:55 +02:00
parent f2d77dc851
commit 1d7db3794b
5 changed files with 205 additions and 10 deletions

View File

@ -342,6 +342,14 @@ $helpArray = array (
// import/export // import/export
"750" => array ("Headline" => _('LDIF data'), "750" => array ("Headline" => _('LDIF data'),
"Text" => _('The input data must be formatted in LDIF format.')), "Text" => _('The input data must be formatted in LDIF format.')),
"751" => array ("Headline" => _('Base DN'),
"Text" => _('The export will read entries of this DN.')),
"752" => array ("Headline" => _('Search filter'),
"Text" => _('Please enter an LDAP filter to specifiy the exported entries.')),
"753" => array ("Headline" => _('Attributes'),
"Text" => _('Please enter a comma separated list of attributes to export. Using "*" will export all attributes.')),
"754" => array ("Headline" => _('Include system attributes'),
"Text" => _('Activate this option to export internal attributes that are not visible by default.')),
// 800 - 899 // 800 - 899
// jobs // jobs
'800' => array( '800' => array(

View File

@ -854,6 +854,32 @@ function ldapGetDN($dn, $attributes = array('dn'), $handle = null) {
return $return; return $return;
} }
/**
* Returns the DN and children of a given DN.
*
* @param String $dn DN
* @param String $filter LDAP filter
* @param array $attributes list of attributes to fetch
* @param handle $handle LDAP handle (optional for admin interface pages)
* @return array attributes or null if not found
*/
function ldapListDN($dn, $filter = '(objectclass=*)', $attributes = array('dn'), $handle = null) {
if ($handle == null) {
$handle = $_SESSION['ldap']->server();
}
$return = null;
$sr = @ldap_list($handle, escapeDN($dn), $filter, $attributes, 0, 0, 0, LDAP_DEREF_NEVER);
if ($sr) {
$entries = ldap_get_entries($handle, $sr);
if ($entries) {
cleanLDAPResult($entries);
$return = $entries;
}
@ldap_free_result($sr);
}
return $return;
}
/** /**
* Deletes a DN and all child entries. * Deletes a DN and all child entries.
* *

View File

@ -43,6 +43,8 @@ class Exporter {
const DATA = 'data'; const DATA = 'data';
const STATUS = 'status'; const STATUS = 'status';
const FILE = 'file';
const OUTPUT = 'output';
private $baseDn = null; private $baseDn = null;
private $searchScope = null; private $searchScope = null;
@ -84,6 +86,8 @@ class Exporter {
public function doExport() { public function doExport() {
try { try {
$this->checkParameters(); $this->checkParameters();
$results = $this->getLDAPData();
return $this->writeDataAndReturnJson($results);
} }
catch (LAMException $e) { catch (LAMException $e) {
$data = Exporter::formatMessage('ERROR', $e->getTitle(), $e->getMessage()); $data = Exporter::formatMessage('ERROR', $e->getTitle(), $e->getMessage());
@ -124,4 +128,151 @@ class Exporter {
} }
} }
/**
* Returns the LDAP entries
*
* @return array[] LDAP entries
*/
private function getLDAPData() {
$attributes = preg_split('/,[ ]*/', $this->attributes);
if ($this->includeSystem) {
$attributes = array_merge($attributes, array('+', 'passwordRetryCount', 'accountUnlockTime', 'nsAccountLock',
'nsRoleDN', 'passwordExpirationTime', 'pwdChangedTime'));
}
$attributes = array_unique($attributes);
switch ($this->searchScope) {
case 'base':
return array(ldapGetDN($this->baseDn, $attributes));
break;
case 'one':
return ldapListDN($this->baseDn, $this->filter, $attributes);
break;
case 'sub':
return searchLDAP($this->baseDn, $this->filter, $attributes);
break;
default:
throw new LAMException('Invalid scope');
break;
}
}
/**
* Writes the entries to file/response and prints JSON.
*
* @param array $entries LDAP entries
*/
private function writeDataAndReturnJson(&$entries) {
$lineEnding = ($this->ending === 'windows') ? "\r\n" : "\n";
if ($this->format === 'csv') {
$output = $this->getCsvOutput($entries, $lineEnding);
}
elseif ($this->format === 'ldif') {
$output = $this->getLdifOutput($entries, $lineEnding);
}
else {
throw new LAMException('Invalid format');
}
if ($this->saveAsFile) {
$filename = '../../tmp/' . getRandomNumber() . time() .'.' . $this->format;
$handle = fopen($filename, 'w');
chmod($filename, 0640);
fwrite($handle, $output);
fclose($handle);
return json_encode(array(
Exporter::FILE => $filename,
Exporter::STATUS => 'done'
));
}
return json_encode(array(
Exporter::OUTPUT => htmlspecialchars($output),
Exporter::STATUS => 'done'
));
}
/**
* Converts the given LDAP entries to CSV format.
*
* @param string $entries entries
* @param string $lineEnding line ending
*/
private function getCsvOutput(&$entries, $lineEnding) {
return 'CSV';
}
/**
* Converts the given LDAP entries to LDIF format.
*
* @param string $entries entries
* @param string $lineEnding line ending
*/
private function getLdifOutput(&$entries, $lineEnding) {
$output = '';
$output .= '#' . $lineEnding;
$output .= '# ' . _('Base DN') . ': ' . $this->baseDn . $lineEnding;
$output .= '# ' . _('Search scope') . ': ' . $this->searchScope . $lineEnding;
$output .= '# ' . _('Search filter') . ': ' . $this->filter . $lineEnding;
$output .= '# ' . _('Total entries') . ': ' . sizeof($entries) . $lineEnding;
$output .= '#' . $lineEnding;
$output .= '# Generated by LDAP Account Manager on ' . date('Y-m-d H:i:s') . $lineEnding;
$output .= $lineEnding;
$output .= $lineEnding;
$output .= 'version: 1';
$output .= $lineEnding;
$output .= $lineEnding;
foreach ($entries as $entry) {
$output .= 'dn: ' . $entry['dn'] . $lineEnding;
unset($entry['dn']);
ksort($entry);
foreach ($entry as $attributeName => $values) {
foreach ($values as $value) {
if ($this->isPlainAscii($value)) {
$output .= $this->wrapLdif($attributeName . ': ' . $value, $lineEnding) . $lineEnding;
}
else {
$output .= $this->wrapLdif($attributeName . ':: ' . base64_encode($value), $lineEnding) . $lineEnding;
}
}
}
$output .= $lineEnding;
}
return $output;
}
/**
* Splits the LDIF line if needed.
*
* @param string $content line content
* @param string $lineEnding line ending
*/
private function wrapLdif($content, $lineEnding) {
$line_length = 76;
if (strlen($content) <= $line_length) {
return $content;
}
$wrappedContent = substr($content, 0, $line_length) . $lineEnding;
$contentLeft = substr($content, $line_length);
$line_length = $line_length - 1;
$lines = str_split($contentLeft, $line_length);
foreach ($lines as $line) {
$wrappedContent .= ' ' . $line . $lineEnding;
}
return trim($wrappedContent);
}
/**
* Checks if the value is plain ASCII.
*
* @param string $content content to check
* @return bool is plain ASCII
*/
private function isPlainAscii($content) {
for ($i=0; $i < strlen($content); $i++) {
if (ord($content[$i]) < 32 || ord($content[$i]) > 127) {
return false;
}
}
return true;
}
} }

View File

@ -986,6 +986,12 @@ window.lam.importexport.startExport = function(tokenName, tokenValue) {
jQuery('#statusExportInprogress').hide(); jQuery('#statusExportInprogress').hide();
jQuery('#statusExportDone').show(); jQuery('#statusExportDone').show();
jQuery('.newexport').show(); jQuery('.newexport').show();
if (jsonData.output) {
jQuery('#exportResults > pre').text(jsonData.output);
}
else if (jsonData.file) {
window.open(jsonData.file, '_blank');
}
} }
else { else {
jQuery('#progressbarExport').hide(); jQuery('#progressbarExport').hide();
@ -994,6 +1000,13 @@ window.lam.importexport.startExport = function(tokenName, tokenValue) {
jQuery('#statusExportFailed').show(); jQuery('#statusExportFailed').show();
jQuery('.newexport').show(); jQuery('.newexport').show();
} }
})
.fail(function() {
jQuery('#progressbarExport').hide();
jQuery('#btn_submitExportCancel').hide();
jQuery('#statusExportInprogress').hide();
jQuery('#statusExportFailed').show();
jQuery('.newexport').show();
}); });
}); });
}; };

View File

@ -262,12 +262,7 @@ function printExportTabContent(&$tabindex) {
$container = new htmlResponsiveRow(); $container = new htmlResponsiveRow();
$container->add(new htmlTitle(_("Export")), 12); $container->add(new htmlTitle(_("Export")), 12);
$container->addLabel(new htmlOutputText(_('Base DN'), true, true)); $container->add(new htmlResponsiveInputField(_('Base DN'), 'baseDn', getDefaultBaseDn(), '751', true), 12);
$baseDnGroup = new htmlGroup();
$baseDnInput = new htmlInputField('baseDn', getDefaultBaseDn());
$baseDnInput->setRequired(true);
$baseDnGroup->addElement($baseDnInput);
$container->addField($baseDnGroup);
$searchScopes = array( $searchScopes = array(
_('Base (base dn only)') => 'base', _('Base (base dn only)') => 'base',
@ -278,9 +273,9 @@ function printExportTabContent(&$tabindex) {
$searchScopeSelect->setHasDescriptiveElements(true); $searchScopeSelect->setHasDescriptiveElements(true);
$searchScopeSelect->setSortElements(false); $searchScopeSelect->setSortElements(false);
$container->add($searchScopeSelect, 12); $container->add($searchScopeSelect, 12);
$container->add(new htmlResponsiveInputField(_('Search filter'), 'filter', '(objectClass=*)'), 12); $container->add(new htmlResponsiveInputField(_('Search filter'), 'filter', '(objectClass=*)', '752'), 12);
$container->add(new htmlResponsiveInputField(_('Attributes'), 'attributes', '*'), 12); $container->add(new htmlResponsiveInputField(_('Attributes'), 'attributes', '*', '753'), 12);
$container->add(new htmlResponsiveInputCheckbox('includeSystem', false, _('Include system attributes')), 12); $container->add(new htmlResponsiveInputCheckbox('includeSystem', false, _('Include system attributes'), '754'), 12);
$container->add(new htmlResponsiveInputCheckbox('saveAsFile', false, _('Save as file')), 12); $container->add(new htmlResponsiveInputCheckbox('saveAsFile', false, _('Save as file')), 12);
$formats = array( $formats = array(
@ -375,7 +370,9 @@ function printExportTabProcessing(&$tabindex) {
$container->addVerticalSpacer('3rem'); $container->addVerticalSpacer('3rem');
$container->add(new htmlDiv('exportResults', new htmlOutputText('')), 12); $exportText = new htmlOutputText('');
$exportText->setPreformatted(true);
$container->add(new htmlDiv('exportResults', $exportText), 12);
$container->add(new htmlJavaScript( $container->add(new htmlJavaScript(
'window.lam.importexport.startExport(\'' . getSecurityTokenName() . '\', \'' . getSecurityTokenValue() . '\');' 'window.lam.importexport.startExport(\'' . getSecurityTokenName() . '\', \'' . getSecurityTokenValue() . '\');'
), 12); ), 12);