* EMail/sMime: allow non-admin users to upload their keys

This commit is contained in:
Ralf Becker 2018-04-10 13:15:09 +02:00
parent 544dc160ca
commit e72c7c76b6
6 changed files with 102 additions and 44 deletions

View File

@ -1,13 +1,12 @@
<?php <?php
/** /**
* EGroupware EMailAdmin: Wizard to create mail Api\Accounts * EGroupware EMailAdmin: Wizard to create mail accounts
* *
* @link http://www.stylite.de * @link http://www.egroupware.org
* @package emailadmin * @package emailadmin
* @author Ralf Becker <rb@stylite.de> * @author Ralf Becker <rb@egroupware.org>
* @copyright (c) 2013-16 by Ralf Becker <rb@stylite.de> * @copyright (c) 2013-18 by Ralf Becker <rb@egroupware.org>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/ */
use EGroupware\Api; use EGroupware\Api;
@ -1031,30 +1030,7 @@ class admin_mail
// SMIME SAVE // SMIME SAVE
if (isset($content['smimeKeyUpload'])) if (isset($content['smimeKeyUpload']))
{ {
$smime = new Mail\Smime; self::save_smime_key($content, $tpl, $content['called_for']);
$content['acc_smime_username'] = $smime->getEmailFromKey($content['smime_cert']);
$AB_bo = new addressbook_bo();
if (($pkcs12 = file_get_contents($content['smimeKeyUpload']['tmp_name'])))
{
$cert_info = Mail\Smime::extractCertPKCS12($pkcs12, $content['smime_pkcs12_password']);
if (is_array($cert_info))
{
$content['acc_smime_password'] = $pkcs12;
$content['smime_cert'] = $cert_info['cert'];
if ($content['smime_cert'])
{
$content['acc_smime_username'] = $smime->getEmailFromKey($content['smime_cert']);
$AB_bo = new addressbook_bo();
$AB_bo->set_smime_keys(array(
$content['acc_smime_username'] => $content['smime_cert']
));
}
}
else
{
$tpl->set_validation_error('smimeKeyUpload', lang('Could not extract private key from given p12 file. Either the p12 file is broken or password is wrong!'));
}
}
} }
self::fix_account_id_0($content['account_id'], true); self::fix_account_id_0($content['account_id'], true);
$content = Mail\Account::write($content, $content['called_for'] || !$this->is_admin ? $content = Mail\Account::write($content, $content['called_for'] || !$this->is_admin ?
@ -1117,6 +1093,11 @@ class admin_mail
$content['mailForwardingAddress'], $content['mailForwardingAddress'],
$content['forwardOnly'] ? null : 'yes'); $content['forwardOnly'] ? null : 'yes');
} }
// smime (private) key uploaded by user himself
if (!empty($content['smimeKeyUpload']))
{
self::save_smime_key($content, $tpl);
}
} }
} }
catch (Horde_Imap_Client_Exception $e) catch (Horde_Imap_Client_Exception $e)
@ -1167,7 +1148,7 @@ class admin_mail
} }
// SMIME UPLOAD/DELETE/EXPORT control // SMIME UPLOAD/DELETE/EXPORT control
$content['hide_smime_upload'] = false; $content['hide_smime_upload'] = false;
if (!empty($content['acc_smime_password'])) if (isset($content['acc_smime_password']))
{ {
if (!empty($content['smime_delete_p12']) && if (!empty($content['smime_delete_p12']) &&
Mail\Credentials::delete ( Mail\Credentials::delete (
@ -1181,6 +1162,9 @@ class admin_mail
} }
else else
{ {
// do NOT send smime private key to client side, it's unnecessary and binary blob breaks json encoding
$content['acc_smime_password'] = '';
$content['hide_smime_upload'] = true; $content['hide_smime_upload'] = true;
} }
} }
@ -1203,8 +1187,10 @@ class admin_mail
$readonlys['button[cancel]'] = false; $readonlys['button[cancel]'] = false;
// allow to edit notification-folders // allow to edit notification-folders
$readonlys['button[save]'] = $readonlys['button[apply]'] = $readonlys['button[save]'] = $readonlys['button[apply]'] =
$readonlys['notify_folders'] = $readonlys['notify_use_default'] = $readonlys['notify_folders'] = $readonlys['notify_use_default'] = false;
$readonlys['smimeKeyUpload'] = $readonlys['smime_pkcs12_password']= false; // allow to edit sMime stuff
$readonlys['smimeGenerate'] = $readonlys['smimeKeyUpload'] = $readonlys['smime_pkcs12_password'] =
$readonlys['smime_export_p12'] = $readonlys['smime_delete_p12'] = false;
} }
$sel_options['acc_imap_ssl'] = $sel_options['acc_sieve_ssl'] = $sel_options['acc_imap_ssl'] = $sel_options['acc_sieve_ssl'] =
@ -1379,6 +1365,38 @@ class admin_mail
$tpl->exec(static::APP_CLASS.'edit', $content, $sel_options, $readonlys, $content, 2); $tpl->exec(static::APP_CLASS.'edit', $content, $sel_options, $readonlys, $content, 2);
} }
/**
* Saves the smime key
*
* @param array $content
* @param Etemplate $tpl
* @param int $account_id =null account to save smime key for, default current user
*/
private static function save_smime_key(array $content, Etemplate $tpl, $account_id=null)
{
if (($pkcs12 = file_get_contents($content['smimeKeyUpload']['tmp_name'])))
{
$cert_info = Mail\Smime::extractCertPKCS12($pkcs12, $content['smime_pkcs12_password']);
if (is_array($cert_info) && !empty($cert_info['cert']))
{
// save public key
$smime = new Mail\Smime;
$email = $smime->getEmailFromKey($cert_info['cert']);
$AB_bo = new addressbook_bo();
$AB_bo->set_smime_keys(array(
$email => $cert_info['cert']
));
// save private key
if (!isset($account_id)) $account_id = $GLOBALS['egw_info']['user']['account_id'];
Mail\Credentials::write($content['acc_id'], $email, $pkcs12, Mail\Credentials::SMIME, $account_id);
}
else
{
$tpl->set_validation_error('smimeKeyUpload', lang('Could not extract private key from given p12 file. Either the p12 file is broken or password is wrong!'));
}
}
}
/** /**
* Replace 0 with '' or back * Replace 0 with '' or back
* *

View File

@ -1269,7 +1269,7 @@ app.classes.admin = AppJS.extend(
content:{ content:{
value: '' value: ''
}}, }},
template: egw.webserverUrl+'/mail/templates/default/smimeCertGen.xet', template: egw.webserverUrl+'/mail/templates/default/smimeCertGen.xet?'+Date.now(),
resizable: false, resizable: false,
position: 'left top' position: 'left top'
}, et2_dialog._create_parent('mail')); }, et2_dialog._create_parent('mail'));

View File

@ -297,19 +297,21 @@
</columns> </columns>
<rows> <rows>
<row> <row>
<description value="S/MIME"/> <description value="S/MIME" span="all"/>
</row> </row>
<row> <!-- disabled, because not working/fully implemented
<row disabled="@hide_smime_upload">
<description value="Certificate"/> <description value="Certificate"/>
<hbox> <hbox>
<buttononly label="Generate Certificate" onclick="app.admin.smime_genCertificate" image="add" background_image="1"/> <buttononly id="smimeGenerate" label="Generate Certificate" onclick="app.admin.smime_genCertificate" image="add" background_image="1"/>
</hbox> </hbox>
</row> </row>
<row disabled="@hide_smime_upload"> -->
<row disabled="@hide_smime_upload" valign="top">
<description value="Upload your certificate .p12/.pfx file"/> <description value="Upload your certificate .p12/.pfx file"/>
<vbox> <vbox>
<file id="smimeKeyUpload" accept=".p12,.pfx"/> <file id="smimeKeyUpload" accept=".p12,.pfx"/>
<passwd id="smime_pkcs12_password" size="32" maxlength="128" blur="Password to unlock encrypted p12" autocomplete="off"/> <passwd id="smime_pkcs12_password" size="48" maxlength="128" blur="Password to unlock encrypted p12" autocomplete="off"/>
</vbox> </vbox>
</row> </row>
<row disabled="!@hide_smime_upload"> <row disabled="!@hide_smime_upload">

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE overlay PUBLIC "-//EGroupware GmbH//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
<!-- $Id$ -->
<overlay>
<template id="mail.smimeCertGen" template="" lang="" group="0" version="17.1">
<grid width="100%">
<columns>
<column/>
</columns>
<rows>
<row>
<groupbox>
<caption label="Certificate details"/>
<vbox>
<textbox id="countryName" class="et2_fullWidth" blur="Country name"/>
<textbox id="stateOrProvinceName" class="et2_fullWidth" blur="State or province name"/>
<textbox id="localityName" class="et2_fullWidth" blur="Locality name"/>
<textbox id="organizationName" class="et2_fullWidth" blur="Organization name"/>
<textbox id="organizationalUnitName" class="et2_fullWidth" blur="Organizational unit name"/>
<textbox id="commonName" class="et2_fullWidth" blur="Common name"/>
<textbox id="emailAddress" class="et2_fullWidth" blur="Email address"/>
<textbox id="validation" type="integer" label="Certificate validation in days" blur="365"/>
</vbox>
</groupbox>
</row>
<row>
<groupbox>
<caption label="passphrase"/>
<description value="Enter a passphrase if you would like to protect your private key by password."/>
<vbox>
<passwd id="passphrase" blur="Enter a passphrase" class="et2_fullWidth"/>
<passwd id="passphraseConf" blur="Repeat the passphrase" class="et2_fullWidth"/>
</vbox>
</groupbox>
</row>
</rows>
</grid>
</template>
</overlay>

View File

@ -2270,14 +2270,14 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
$smime = new Mail\Smime(); $smime = new Mail\Smime();
$response = Api\Json\Response::get(); $response = Api\Json\Response::get();
// fields need to be excluded from data // fields need to be excluded from data
$discards = array ('passphrase', 'passphraseConf', 'ca'); $discards = array ('passphrase', 'passphraseConf', 'ca', 'validity');
$ca = $_data['ca']; $ca = $_data['ca'];
$passphrase = $_data['passphrase']; $passphrase = $_data['passphrase'];
foreach ($_data as $key => $val) foreach (array_keys($_data) as $key)
{ {
if (empty($_data[$key]) || in_array($key, $discards)) unset($_data[$key]); if (empty($_data[$key]) || in_array($key, $discards)) unset($_data[$key]);
} }
$response->data($smime->generate_certificate($_data, $ca, null, $passphrase)); $response->data($smime->generate_certificate($_data, $ca, null, $passphrase, $_data['validity']));
} }
/** /**

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE overlay PUBLIC "-//EGroupware GmbH//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd"> <!DOCTYPE overlay PUBLIC "-//EGroupware GmbH//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
<!-- $Id$ -->
<overlay> <overlay>
<template id="mail.smimeCertGen" template="" lang="" group="0" version="17.1"> <template id="mail.smimeCertGen" template="" lang="" group="0" version="17.1">
<grid width="100%"> <grid width="100%">
@ -12,14 +11,14 @@
<groupbox> <groupbox>
<caption label="Certificate details"/> <caption label="Certificate details"/>
<vbox> <vbox>
<textbox id="countryName" class="et2_fullWidth" blur="Country name"/> <textbox id="countryName" class="et2_fullWidth" blur="Country name (2 letter code, eg. DE)" maxlength="2"/>
<textbox id="stateOrProvinceName" class="et2_fullWidth" blur="State or province name"/> <textbox id="stateOrProvinceName" class="et2_fullWidth" blur="State or province name"/>
<textbox id="localityName" class="et2_fullWidth" blur="Locality name"/> <textbox id="localityName" class="et2_fullWidth" blur="Locality name"/>
<textbox id="organizationName" class="et2_fullWidth" blur="Organization name"/> <textbox id="organizationName" class="et2_fullWidth" blur="Organization name"/>
<textbox id="organizationalUnitName" class="et2_fullWidth" blur="Organizational unit name"/> <textbox id="organizationalUnitName" class="et2_fullWidth" blur="Organizational unit name"/>
<textbox id="commonName" class="et2_fullWidth" blur="Common name"/> <textbox id="commonName" class="et2_fullWidth" blur="Common name"/>
<textbox id="emailAddress" class="et2_fullWidth" blur="Email address"/> <textbox id="emailAddress" class="et2_fullWidth" blur="Email address"/>
<textbox id="validation" type="integer" label="Certificate validation in days" blur="365"/> <textbox id="validity" type="integer" label="Certificate validity in days" blur="3650"/>
</vbox> </vbox>
</groupbox> </groupbox>
</row> </row>