Passed
Push — master ( 456b71...7604f4 )
by Tim
03:27
created

NegotiateController.php$0 ➔ sendContent()   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
dl 0
loc 4
rs 10
1
<?php
2
3
namespace SimpleSAML\Module\negotiate\Controller;
4
5
use Exception;
6
use SimpleSAML\Auth;
7
use SimpleSAML\Configuration;
8
use SimpleSAML\Error;
9
use SimpleSAML\HTTP\RunnableResponse;
10
use SimpleSAML\Logger;
11
use SimpleSAML\Metadata\MetaDataStorageHandler;
12
use SimpleSAML\Module;
13
use SimpleSAML\Module\negotiate\Auth\Source\Negotiate;
14
use SimpleSAML\Session;
15
use SimpleSAML\XHTML\Template;
16
use Symfony\Component\HttpFoundation\Cookie;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\StreamedResponse;
19
20
/**
21
 * Controller class for the negotiate module.
22
 *
23
 * This class serves the different views available in the module.
24
 *
25
 * @package simplesamlphp/simplesamlphp-module-negotiate
26
 */
27
class NegotiateController
28
{
29
    /** @var \SimpleSAML\Auth\Source|class-string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment \SimpleSAML\Auth\Source|class-string at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in \SimpleSAML\Auth\Source|class-string.
Loading history...
30
    protected $authSource = Auth\Source::class;
31
32
    /** @var \SimpleSAML\Auth\State|class-string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment \SimpleSAML\Auth\State|class-string at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in \SimpleSAML\Auth\State|class-string.
Loading history...
33
    protected $authState = Auth\State::class;
34
35
    /** @var \SimpleSAML\Configuration */
36
    protected $config;
37
38
    /** @var \SimpleSAML\Logger|class-string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment \SimpleSAML\Logger|class-string at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in \SimpleSAML\Logger|class-string.
Loading history...
39
    protected $logger = Logger::class;
40
41
    /** @var \SimpleSAML\Metadata\MetaDataStorageHandler|null */
42
    protected $metadataHandler = null;
43
44
    /** @var \SimpleSAML\Module|class-string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment \SimpleSAML\Module|class-string at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in \SimpleSAML\Module|class-string.
Loading history...
45
    protected $module = Module::class;
46
47
    /** @var \SimpleSAML\Session */
48
    protected $session;
49
50
51
    /**
52
     * Controller constructor.
53
     *
54
     * It initializes the global configuration and session for the controllers implemented here.
55
     *
56
     * @param \SimpleSAML\Configuration $config The configuration to use by the controllers.
57
     * @param \SimpleSAML\Session $session The session to use by the controllers.
58
     *
59
     * @throws \Exception
60
     */
61
    public function __construct(
62
        Configuration $config,
63
        Session $session
64
    ) {
65
        $this->config = $config;
66
        $this->session = $session;
67
    }
68
69
70
    /**
71
     * Inject the \SimpleSAML\Auth\Source dependency.
72
     *
73
     * @param \SimpleSAML\Auth\Source $authSource
74
     */
75
    public function setAuthSource(Auth\Source $authSource): void
76
    {
77
        $this->authSource = $authSource;
78
    }
79
80
81
    /**
82
     * Inject the \SimpleSAML\Auth\State dependency.
83
     *
84
     * @param \SimpleSAML\Auth\State $authState
85
     */
86
    public function setAuthState(Auth\State $authState): void
87
    {
88
        $this->authState = $authState;
89
    }
90
91
92
    /**
93
     * Inject the \SimpleSAML\Logger dependency.
94
     *
95
     * @param \SimpleSAML\Logger $logger
96
     */
97
    public function setLogger(Logger $logger): void
98
    {
99
        $this->logger = $logger;
100
    }
101
102
103
    /**
104
     * Get the metadata storage handler instance.
105
     *
106
     * @return MetaDataStorageHandler
107
     */
108
    protected function getMetadataStorageHandler(): MetaDataStorageHandler
109
    {
110
        return $this->metadataHandler ?: MetaDataStorageHandler::getMetadataHandler();
111
    }
112
113
114
    /**
115
     * Inject the \SimpleSAML\Metadata\MetaDataStorageHandler dependency.
116
     *
117
     * @param \SimpleSAML\Metadata\MetaDataStorageHandler $handler
118
     */
119
    public function setMetadataStorageHandler(MetaDataStorageHandler $handler): void
120
    {
121
        $this->metadataHandler = $handler;
122
    }
123
124
125
    /**
126
     * Inject the \SimpleSAML\Module dependency.
127
     *
128
     * @param \SimpleSAML\Module $module
129
     */
130
    public function setModule(Module $module): void
131
    {
132
        $this->module = $module;
133
    }
134
135
136
    /**
137
     * Show enable.
138
     *
139
     * @return \SimpleSAML\XHTML\Template
140
     * @throws Exception
141
     */
142
    public function enable(): Template
143
    {
144
        $this->session->setData('negotiate:disable', 'session', false, 86400); // 24*60*60=86400
145
146
        $cookie = new Cookie(
147
            'NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT',
148
            null, // value
149
            mktime(0, 0, 0, 1, 1, 2038), // expire
150
            '/', // path
151
            '', // domain
152
            true, // secure
153
            true // httponly
154
        );
155
156
        $t = new Template($this->config, 'negotiate:enable.twig');
157
        $t->headers->setCookie($cookie);
158
        $t->data['url'] = $this->module::getModuleURL('negotiate/disable');
159
160
        return $t;
161
    }
162
163
164
    /**
165
     * Show disable.
166
     *
167
     * @return \SimpleSAML\XHTML\Template
168
     * @throws Exception
169
     */
170
    public function disable(): Template
171
    {
172
        $this->session->setData('negotiate:disable', 'session', false, 86400); //24*60*60=86400
173
174
        $cookie = new Cookie(
175
            'NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT',
176
            'true', // value
177
            mktime(0, 0, 0, 1, 1, 2038), // expire
178
            '/', // path
179
            '', // domain
180
            true, // secure
181
            true // httponly
182
        );
183
184
        $t = new Template($this->config, 'negotiate:disable.twig');
185
        $t->headers->setCookie($cookie);
186
        $t->data['url'] = $this->module::getModuleURL('negotiate/enable');
187
188
        return $t;
189
    }
190
191
192
    /**
193
     * Show retry
194
     *
195
     * @param Request $request The request that lead to this retry operation.
196
     * @return \SimpleSAML\HTTP\RunnableResponse
197
     * @throws \Exception
198
     * @throws \SimpleSAML\Error\BadRequest
199
     */
200
    public function retry(Request $request): RunnableResponse
201
    {
202
        $authState = $request->get('AuthState', null);
203
        if ($authState === null) {
204
            throw new Error\BadRequest('Missing required AuthState query parameter.');
205
        }
206
207
        /** @psalm-var array $state */
208
        $state = $this->authState::loadState($authState, Negotiate::STAGEID);
209
210
        $mdh = $this->getMetadataStorageHandler();
211
        $idpid = $mdh->getMetaDataCurrentEntityID('saml20-idp-hosted', 'metaindex');
212
        $idpmeta = $mdh->getMetaData($idpid, 'saml20-idp-hosted');
213
214
        if (isset($idpmeta['auth'])) {
215
            $source = $this->authSource::getById($idpmeta['auth']);
216
            if ($source === null) {
217
                throw new Error\BadRequest('Invalid AuthId "' . $idpmeta['auth'] . '" - not found.');
218
            }
219
220
            $this->session->setData('negotiate:disable', 'session', false, 86400); //24*60*60=86400
221
            $this->logger::debug('Negotiate(retry) - session enabled, retrying.');
222
223
            return new RunnableResponse([$source, 'authenticate'], [$state]);
224
        }
225
        throw new Exception('Negotiate - retry - no "auth" parameter found in IdP metadata.');
226
    }
227
228
229
    /**
230
     * Show fallback
231
     *
232
     * @param Request $request The request that lead to this retry operation.
233
     *
234
     * @return \SimpleSAML\HTTP\RunnableResponse
235
     * @throws \SimpleSAML\Error\BadRequest
236
     * @throws \SimpleSAML\Error\NoState
237
     */
238
    public function fallback(Request $request): StreamedResponse
239
    {
240
        $authState = $request->get('AuthState', null);
241
        if ($authState === null) {
242
            throw new Error\BadRequest('Missing required AuthState query parameter.');
243
        }
244
245
        /** @psalm-var array $state */
246
        $state = $this->authState::loadState($authState, Negotiate::STAGEID);
247
248
        $this->logger::debug('backend - fallback: ' . $state['LogoutState']['negotiate:backend']);
249
250
        return new class([Negotiate::class, 'fallBack'], [&$state]) extends StreamedResponse {
0 ignored issues
show
Bug Best Practice introduced by
The expression return new ClassNode(arr...lBack'), array($state)) returns the type anonymous//lib/Controlle...gotiateController.php$0 which is incompatible with the documented return type SimpleSAML\HTTP\RunnableResponse.
Loading history...
251
            protected $args;
252
253
            public function __construct(callable $callback, $args) {
254
                parent::__construct($callback);
255
                $this->args = $args;
256
            }
257
258
            public function sendContent(): self
259
            {
260
                call_user_func_array($this->callback, $this->args);
261
                return $this;
262
            }
263
        };
264
    }
265
}
266