Skip to content
Snippets Groups Projects
Commit f521d103 authored by Dominik Baránek's avatar Dominik Baránek
Browse files

feat: security texts

parent 8e7c786b
No related branches found
No related tags found
1 merge request!36feat: security texts
Pipeline #215843 passed
......@@ -173,21 +173,23 @@ In addition to the remember me function, you can turn on security images. Image
`showFreshImage` - if set to true, the security image is fetched everytime user access the login page. Otherwise, it is stored in the cookie. Default `false`.
`storageClass` - an implementation of `SimpleSAML\Module\campusmultiauth\Data\Storage`, default `SimpleSAML\Module\campusmultiauth\Data\DatabaseStorage`.
`pictureStorage` - if some other storage than `SimpleSAML\Module\campusmultiauth\Data\DatabaseStorage` is used (e.g. `SimpleSAML\Module\campusmultiauth\Data\PerunStorage`), this is the place for the configuration of the storage.
`security.cookie.path` - cookie path.
`security.cookie.samesite` - cookie SameSite.
`pictureDir` - if set, the security image is stored in this directory instead of the cookie. The cookie than contains only a link to the picture. Also, if this option is enabled, `securityImageSalt` and `pictureBaseURL` are mandatory. Default `null`.
`securityImageSalt` - a salt which is used in the filename of the picture if the `pictureDir` is on.
`pictureBaseURL` - base URL to the pictures if the `pictureDir` is on.
`storageClass` - an implementation of `SimpleSAML\Module\campusmultiauth\Data\Storage`, default `SimpleSAML\Module\campusmultiauth\Data\DatabaseStorage`.
`pictures_table` - name of the table with security images, default `security_image`.
`pictureStorage` - if some other storage than `SimpleSAML\Module\campusmultiauth\Data\DatabaseStorage` is used (e.g. `SimpleSAML\Module\campusmultiauth\Data\PerunStorage`), this is the place for the configuration of the storage.
`security.cookie.path` - cookie path.
`security.cookie.samesite` - cookie SameSite.
`texts_table` - default `alternative_text`. You can also add an alternative text to images. User can specify his/her own text, so this is an additional antiphishing feature. If user does not have the alternative text set, the alt is an empty string. In case he/she does not have the image set, this text will be displayed instead of it.
## Hinting
......
......@@ -140,6 +140,7 @@ $config = [
// 'ldap.basedn' => '',
// 'search.filter' => '',
// 'attribute' => '',
// 'alternative_text_attribute' => '',
// ],
],
// 'uidName' => '',
......
......@@ -203,6 +203,7 @@ class RememberMe extends ProcessingFilter
if (!$this->showFreshImage) {
$payload['security_image'] = Utils::getSecurityImageOfUser($username);
$payload['alternative_text'] = Utils::getAlternativeTextOfUser($username);
}
$this->setCookie($payload);
......
......@@ -22,6 +22,11 @@ class DatabaseStorage implements Storage
*/
private $pictures_table;
/**
* DB table name for texts.
*/
private $texts_table;
/**
* DB table name for tokens.
*/
......@@ -48,9 +53,13 @@ class DatabaseStorage implements Storage
$imagesConfiguration = $this->config->getConfigItem('security_images', []);
$this->db = Database::getInstance($this->config->getConfigItem('store', []));
$this->pictures_table = $this->db->applyPrefix(
$imagesConfiguration->getString('pictures_table', 'security_image')
);
$this->texts_table = $this->db->applyPrefix(
$imagesConfiguration->getString('texts_table', 'alternative_text')
);
$this->tokens_table = $this->db->applyPrefix(
$this->config->getString('tokens_table', 'cookie_counter')
);
......@@ -61,17 +70,17 @@ class DatabaseStorage implements Storage
*/
public function getSecurityImageOfUser(string $uid): ?string
{
$query = 'SELECT picture FROM ' . $this->pictures_table
. ' WHERE ' . self::UID_COL . '=:userid';
$statement = $this->db->read($query, [
'userid' => $uid,
]);
$picture = $statement->fetchColumn();
if ($picture === false) {
return null;
}
$query = 'SELECT picture FROM ' . $this->pictures_table . ' WHERE ' . self::UID_COL . '=:userid';
return $this->getSecurityAttributeOfUser($uid, $query);
}
return $picture;
/**
* @override
*/
public function getAlternativeTextOfUser(string $uid): ?string
{
$query = 'SELECT alternative_text FROM ' . $this->texts_table . ' WHERE ' . self::UID_COL . '=:userid';
return $this->getSecurityAttributeOfUser($uid, $query);
}
/**
......@@ -140,4 +149,18 @@ class DatabaseStorage implements Storage
return (bool) $this->db->write($query, $params);
}
private function getSecurityAttributeOfUser(string $uid, string $query)
{
$statement = $this->db->read($query, [
'userid' => $uid,
]);
$attribute = $statement->fetchColumn();
if ($attribute === false) {
return null;
}
return $attribute;
}
}
......@@ -59,11 +59,25 @@ class PerunStorage extends DatabaseStorage
* @override
*/
public function getSecurityImageOfUser(string $uid): ?string
{
$attribute = $this->config->getString('attribute', null);
return $attribute === null ? null : $this->getSecurityAttributeOfUser($uid, $attribute);
}
/**
* @override
*/
public function getAlternativeTextOfUser(string $uid): ?string
{
$attribute = $this->config->getString('alternative_text_attribute', null);
return $attribute === null ? null : $this->getSecurityAttributeOfUser($uid, $attribute);
}
private function getSecurityAttributeOfUser(string $uid, string $attribute)
{
$base = $this->config->getString('ldap.basedn');
$filter = $this->config->getString('search.filter');
$filter = str_replace('%uid%', $uid, $filter);
$attribute = $this->config->getString('attribute');
try {
$entries = $this->ldap->searchformultiple([$base], $filter, [$attribute], [], true, false);
......
......@@ -13,6 +13,11 @@ interface Storage
*/
public function getSecurityImageOfUser(string $uid): ?string;
/**
* Null if user has none, text otherwise.
*/
public function getAlternativeTextOfUser(string $uid): ?string;
/**
* False if not found (should not happen), counter otherwise.
*/
......
......@@ -29,4 +29,15 @@ class Utils
return $storage->getSecurityImageOfUser($username);
}
public static function getAlternativeTextOfUser($username)
{
$storage = self::getInterfaceInstance(
'SimpleSAML\\Module\\campusmultiauth\\Data\\Storage',
'storageClass',
'SimpleSAML\\Module\\campusmultiauth\\Data\\DatabaseStorage'
);
return $storage->getAlternativeTextOfUser($username);
}
}
......@@ -13,7 +13,9 @@
</h4>
{% if securityImage is defined %}
<img src='{{ securityImage|escape }}' class='security-image' alt=''>
<img src='{{ securityImage|escape('html_attr') }}' class='security-image' alt='{{ alternativeText|default('')|escape('html_attr') }}'>
{% elseif alternativeText is defined %}
<p class="security-image-text">{{ alternativeText|escape }}</p>
{% endif %}
{% if wrongUserPass == true %}
......
......@@ -343,14 +343,21 @@ if ($t->data['userInfo']) {
if (empty($t->data['username']) || $t->data['userInfo']['username'] === $t->data['username']) {
$t->data['username'] = $t->data['userInfo']['username'];
$showFreshImage = $imagesConfig->getBoolean('showFreshImage', false);
if ($showFreshImage && (($t->data['userInfo']['security_image'] ?? true) !== false)) {
$t->data['securityImage'] = Utils::getSecurityImageOfUser($t->data['userInfo']['username']);
} elseif (!$showFreshImage && !empty($t->data['userInfo']['security_image'])) {
$t->data['securityImage'] = $t->data['userInfo']['security_image'];
}
if ($showFreshImage && (($t->data['userInfo']['alternative_text'] ?? true) !== false)) {
$t->data['alternativeText'] = Utils::getAlternativeTextOfUser($t->data['userInfo']['username']);
} elseif (!$showFreshImage && !empty($t->data['userInfo']['alternative_text'])) {
$t->data['alternativeText'] = $t->data['userInfo']['alternative_text'];
}
$pictureDir = $imagesConfig->getString('pictureDir', null);
if ($t->data['securityImage'] && $pictureDir !== null) {
if (!empty($t->data['securityImage']) && $pictureDir !== null) {
$pictureDataSrc = $t->data['securityImage'];
if (preg_match('~^data:image/(png|jpeg|gif);base64,(.*)$~', $pictureDataSrc, $matches)) {
list(, $pictureType, $pictureContent) = $matches;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment