Passed
Push — master ( 9c121d...f1ee03 )
by Tim
02:00
created

Authorize   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 144
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 49
dl 0
loc 144
rs 10
c 0
b 0
f 0
wmc 23

3 Methods

Rating   Name   Duplication   Size   Complexity  
A unauthorized() 0 6 1
C __construct() 0 44 12
B process() 0 32 10
1
<?php
2
3
namespace SimpleSAML\Module\authorize\Auth\Process;
4
5
use SimpleSAML\Auth\State;
6
use SimpleSAML\Module;
7
use SimpleSAML\Utils\Arrays;
8
use SimpleSAML\Utils\HTTP;
9
use Webmozart\Assert\Assert;
10
11
/**
12
 * Filter to authorize only certain users.
13
 * See docs directory.
14
 *
15
 * @author Ernesto Revilla, Yaco Sistemas SL., Ryan Panning
16
 * @package SimpleSAMLphp
17
 */
18
19
class Authorize extends \SimpleSAML\Auth\ProcessingFilter
20
{
21
    /**
22
     * Flag to deny/unauthorize the user a attribute filter IS found
23
     *
24
     * @var bool
25
     */
26
    protected $deny = false;
27
28
    /**
29
     * Flag to turn the REGEX pattern matching on or off
30
     *
31
     * @var bool
32
     */
33
    protected $regex = true;
34
35
    /**
36
     * Array of localised rejection messages
37
     *
38
     * @var array
39
     */
40
    protected $reject_msg = [];
41
42
    /**
43
     * Array of valid users. Each element is a regular expression. You should
44
     * user \ to escape special chars, like '.' etc.
45
     *
46
     */
47
    protected $valid_attribute_values = [];
48
49
    /**
50
     * Initialize this filter.
51
     * Validate configuration parameters.
52
     *
53
     * @param array $config  Configuration information about this filter.
54
     * @param mixed $reserved  For future use.
55
     */
56
    public function __construct($config, $reserved)
57
    {
58
        parent::__construct($config, $reserved);
59
60
        Assert::isArray($config);
61
62
        // Check for the deny option
63
        // Must be bool specifically, if not, it might be for an attrib filter below
64
        if (isset($config['deny']) && is_bool($config['deny'])) {
65
            $this->deny = $config['deny'];
66
        }
67
68
        // Check for the regex option
69
        // Must be bool specifically, if not, it might be for an attrib filter below
70
        if (isset($config['regex']) && is_bool($config['regex'])) {
71
            $this->regex = $config['regex'];
72
        }
73
74
        // Check for the reject_msg option; Must be array of languages
75
        if (isset($config['reject_msg']) && is_array($config['reject_msg'])) {
76
            $this->reject_msg = $config['reject_msg'];
77
        }
78
79
        // Remove all above options
80
        unset($config['deny'], $config['regex'], $config['reject_msg']);
81
82
        foreach ($config as $attribute => $values) {
83
            if (is_string($values)) {
84
                $values = Arrays::arrayize($values);
85
            } else if (!is_array($values)) {
86
                throw new \Exception(
87
                    'Filter Authorize: Attribute values is neither string nor array: '.var_export($attribute, true)
88
                );
89
            }
90
91
            foreach ($values as $value) {
92
                if (!is_string($value)) {
93
                    throw new \Exception(
94
                        'Filter Authorize: Each value should be a string for attribute: '.var_export($attribute, true).
95
                            ' value: '.var_export($value, true).' Config is: '.var_export($config, true)
96
                    );
97
                }
98
            }
99
            $this->valid_attribute_values[$attribute] = $values;
100
        }
101
    }
102
103
    /**
104
     * Apply filter to validate attributes.
105
     *
106
     * @param array &$request  The current request
107
     * @return void
108
     */
109
    public function process(&$request)
110
    {
111
        Assert::isArray($request);
112
        Assert::keyExists($request, 'Attributes');
113
114
        $authorize = $this->deny;
115
        $attributes = &$request['Attributes'];
116
        // Store the rejection message array in the $request
117
        if (!empty($this->reject_msg)) {
118
            $request['authprocAuthorize_reject_msg'] = $this->reject_msg;
119
        }
120
121
        foreach ($this->valid_attribute_values as $name => $patterns) {
122
            if (array_key_exists($name, $attributes)) {
123
                foreach ($patterns as $pattern) {
124
                    $values = Arrays::arrayize($attributes[$name]);
125
                    foreach ($values as $value) {
126
                        if ($this->regex) {
127
                            $matched = preg_match($pattern, $value);
128
                        } else {
129
                            $matched = ($value == $pattern);
130
                        }
131
                        if ($matched) {
132
                            $authorize = ($this->deny ? false : true);
133
                            break 3;
134
                        }
135
                    }
136
                }
137
            }
138
        }
139
        if (!$authorize) {
140
            $this->unauthorized($request);
141
        }
142
    }
143
144
    /**
145
     * When the process logic determines that the user is not
146
     * authorized for this service, then forward the user to
147
     * an 403 unauthorized page.
148
     *
149
     * Separated this code into its own method so that child
150
     * classes can override it and change the action. Forward
151
     * thinking in case a "chained" ACL is needed, more complex
152
     * permission logic.
153
     *
154
     * @param array $request
155
     * @return void
156
     */
157
    protected function unauthorized(&$request)
158
    {
159
        // Save state and redirect to 403 page
160
        $id = State::saveState($request, 'authorize:Authorize');
161
        $url = Module::getModuleURL('authorize/authorize_403.php');
162
        HTTP::redirectTrustedURL($url, ['StateId' => $id]);
163
    }
164
}
165