Passed
Push — master ( a8e5a9...dbfe67 )
by Tim
02:47
created

Authorize::unauthorized()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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