1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
<?php
declare(strict_types=1);
namespace SimpleSAML\Module\core\Auth\Process;
use SimpleSAML\Logger;
/**
* Filter to generate a groups attribute based on many of the attributes of the user.
*
* @author Olav Morken, UNINETT AS.
* @package SimpleSAMLphp
*/
class GenerateGroups extends \SimpleSAML\Auth\ProcessingFilter
{
/**
* The attributes we should generate groups from.
* @var array
*/
private $generateGroupsFrom;
/**
* Initialize this filter.
*
* @param array &$config Configuration information about this filter.
* @param mixed $reserved For future use.
*/
public function __construct(&$config, $reserved)
{
parent::__construct($config, $reserved);
assert(is_array($config));
if (count($config) === 0) {
// Use default groups
$this->generateGroupsFrom = [
'eduPersonAffiliation',
'eduPersonOrgUnitDN',
'eduPersonEntitlement',
];
} else {
// Validate configuration
foreach ($config as $attributeName) {
if (!is_string($attributeName)) {
throw new \Exception('Invalid attribute name for core:GenerateGroups filter: ' .
var_export($attributeName, true));
}
}
$this->generateGroupsFrom = $config;
}
}
/**
* Apply filter to add groups attribute.
*
* @param array &$request The current request
* @return void
*/
public function process(&$request)
{
assert(is_array($request));
assert(array_key_exists('Attributes', $request));
$groups = [];
$attributes = &$request['Attributes'];
$realm = self::getRealm($attributes);
if ($realm !== null) {
$groups[] = 'realm-' . $realm;
}
foreach ($this->generateGroupsFrom as $name) {
if (!array_key_exists($name, $attributes)) {
Logger::debug('GenerateGroups - attribute \'' . $name . '\' not found.');
// Attribute not present
continue;
}
foreach ($attributes[$name] as $value) {
$value = self::escapeIllegalChars($value);
$groups[] = $name . '-' . $value;
if ($realm !== null) {
$groups[] = $name . '-' . $realm . '-' . $value;
}
}
}
if (count($groups) > 0) {
$attributes['groups'] = $groups;
}
}
/**
* Determine which realm the user belongs to.
*
* This function will attempt to determine the realm a user belongs to based on the
* eduPersonPrincipalName attribute if it is present. If it isn't, or if it doesn't contain
* a realm, NULL will be returned.
*
* @param array $attributes The attributes of the user.
* @return string|null The realm of the user, or NULL if we are unable to determine the realm.
*/
private static function getRealm(array $attributes): ?string
{
if (!array_key_exists('eduPersonPrincipalName', $attributes)) {
return null;
}
$eppn = $attributes['eduPersonPrincipalName'];
if (count($eppn) < 1) {
return null;
}
$eppn = $eppn[0];
$realm = explode('@', $eppn, 2);
if (count($realm) < 2) {
return null;
}
$realm = $realm[1];
return self::escapeIllegalChars($realm);
}
/**
* Escape special characters in a string.
*
* This function is similar to urlencode, but encodes many more characters.
* This function takes any characters not in [a-zA-Z0-9_@=.] and encodes them with as
* %<hex version>. For example, it will encode '+' as '%2b' and '%' as '%25'.
*
* @param string $string The string which should be escaped.
* @return string The escaped string.
*/
private static function escapeIllegalChars(string $string): string
{
return preg_replace_callback(
'/([^a-zA-Z0-9_@=.])/',
/**
* @param array $m
* @return string
*/
function ($m) {
return sprintf("%%%02x", ord($m[1]));
},
$string
);
}
}
|