From 7e872417a534ef34e6c6f76b0b68edcef935877c Mon Sep 17 00:00:00 2001 From: Olav Morken <olav.morken@uninett.no> Date: Tue, 19 Aug 2008 13:49:07 +0000 Subject: [PATCH] Add core::GenerateGroups filter. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@814 44740490-163a-0410-bde0-09ae8108e29a --- .../core/lib/Auth/Process/GenerateGroups.php | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 modules/core/lib/Auth/Process/GenerateGroups.php diff --git a/modules/core/lib/Auth/Process/GenerateGroups.php b/modules/core/lib/Auth/Process/GenerateGroups.php new file mode 100644 index 000000000..6e8c2e35a --- /dev/null +++ b/modules/core/lib/Auth/Process/GenerateGroups.php @@ -0,0 +1,182 @@ +<?php + +/** + * Filter to generate a groups attribute based on many of the attributes of the user. + * + * By default this filter will generate groups from the following set of attributes: + * - 'eduPersonAffiliation' + * - 'eduPersonOrgUnitDN' + * - 'eduPersonEntitlement' + * + * This can be overridden by specifying the names of the attributes in the configuration. + * + * It will attempt to determine a realm the user belongs to based on the eduPersonPrincipalName + * attribute, if it is present. + * + * The groups this filter generates are on the form: + * <attribute name>-<attributevalue> and <attributename>-<realm>-<attributevalue>. + * + * + * Note that this filter isn't a drop-in replacement for the groups attributealter function. The + * difference is that it uses the full attribute name, instead of shortening them to for example + * affiliation, and it escapes illegal characters in a style similar to urlencoding. It also generates + * groups both with and without a realm part. If no realm is determined, it will only generate attributes + * without a realm-part. + * + * + * Example - generate from default set of attributes: + * <code> + * 'authproc' => array( + * array('core:GenerateGroups'), + * ), + * </code> + * + * Example - generate from only the eduPersonAffilitation attribute: + * <code> + * 'authproc' => array( + * array('core:GenerateGroups', 'eduPersonAffiliation'), + * ), + * </code> + * + * @author Olav Morken, UNINETT AS. + * @package simpleSAMLphp + * @version $Id$ + */ +class sspmod_core_Auth_Process_GenerateGroups extends SimpleSAML_Auth_ProcessingFilter { + + + /** + * The attributes we should generate groups from. + */ + 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 = array( + '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 + */ + public function process(&$request) { + assert('is_array($request)'); + assert('array_key_exists("Attributes", $request)'); + + $groups = array(); + $attributes =& $request['Attributes']; + + $realm = self::getRealm($attributes); + if ($realm !== NULL) { + $groups[] = 'realm-' . $realm; + } + + + foreach ($this->generateGroupsFrom as $name) { + if (!array_key_exists($name, $attributes)) { + SimpleSAML_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($attributes) { + assert('is_array($attributes)'); + + 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) { + assert('is_string($string)'); + + /* Since preg_replace escapes both ["] and ['], while either of them isn't unescaped in the string + * evaluation, we need a test to catch both of them. + */ + $replacement = '("\\1" === "\\\'") ? "%27" : sprintf("%%%02x", ord("\\1"))'; + return preg_replace('/([^a-zA-Z0-9_@=.])/e', $replacement, $string); + } + +} + +?> \ No newline at end of file -- GitLab