File: GenerateGroups.php

package info (click to toggle)
simplesamlphp 1.19.7-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 42,920 kB
  • sloc: php: 202,044; javascript: 14,867; xml: 2,700; sh: 225; perl: 82; makefile: 70; python: 5
file content (153 lines) | stat: -rw-r--r-- 4,410 bytes parent folder | download | duplicates (3)
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
        );
    }
}