Passed
Push — master ( 85ce5c...236e48 )
by Tim
20:19 queued 11:13
created

NegotiateController::enable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 13
nc 1
nop 1
dl 0
loc 19
rs 9.8333
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\Module\negotiate\Controller;
6
7
use Exception;
8
use SimpleSAML\Auth;
9
use SimpleSAML\Configuration;
10
use SimpleSAML\Error;
11
use SimpleSAML\HTTP\RunnableResponse;
12
use SimpleSAML\Logger;
13
use SimpleSAML\Metadata\MetaDataStorageHandler;
14
use SimpleSAML\Module;
15
use SimpleSAML\Module\negotiate\Auth\Source\Negotiate;
16
use SimpleSAML\Session;
17
use SimpleSAML\XHTML\Template;
18
use Symfony\Component\HttpFoundation\Cookie;
19
use Symfony\Component\HttpFoundation\Request;
20
use Symfony\Component\HttpFoundation\StreamedResponse;
21
22
/**
23
 * Controller class for the negotiate module.
24
 *
25
 * This class serves the different views available in the module.
26
 *
27
 * @package simplesamlphp/simplesamlphp-module-negotiate
28
 */
29
class NegotiateController
30
{
31
    /**
32
     * @var \SimpleSAML\Auth\Source|string
33
     * @psalm-var \SimpleSAML\Auth\Source|class-string
34
     */
35
    protected $authSource = Auth\Source::class;
36
37
    /**
38
     * @var \SimpleSAML\Auth\State|string
39
     * @psalm-var \SimpleSAML\Auth\State|class-string
40
     */
41
    protected $authState = Auth\State::class;
42
43
    /** @var \SimpleSAML\Configuration */
44
    protected $config;
45
46
    /**
47
     * @var \SimpleSAML\Logger|string
48
     * @psalm-var \SimpleSAML\Logger|class-string
49
     */
50
    protected $logger = Logger::class;
51
52
    /** @var \SimpleSAML\Metadata\MetaDataStorageHandler|null */
53
    protected ?MetaDataStorageHandler $metadataHandler = null;
54
55
    /**
56
     * @var \SimpleSAML\Module|string
57
     * @psalm-var \SimpleSAML\Module|class-string
58
     */
59
    protected $module = Module::class;
60
61
    /** @var \SimpleSAML\Session */
62
    protected Session $session;
63
64
65
    /**
66
     * Controller constructor.
67
     *
68
     * It initializes the global configuration and session for the controllers implemented here.
69
     *
70
     * @param \SimpleSAML\Configuration $config The configuration to use by the controllers.
71
     * @param \SimpleSAML\Session $session The session to use by the controllers.
72
     *
73
     * @throws \Exception
74
     */
75
    public function __construct(
76
        Configuration $config,
77
        Session $session
78
    ) {
79
        $this->config = $config;
80
        $this->session = $session;
81
    }
82
83
84
    /**
85
     * Inject the \SimpleSAML\Auth\Source dependency.
86
     *
87
     * @param \SimpleSAML\Auth\Source $authSource
88
     */
89
    public function setAuthSource(Auth\Source $authSource): void
90
    {
91
        $this->authSource = $authSource;
92
    }
93
94
95
    /**
96
     * Inject the \SimpleSAML\Auth\State dependency.
97
     *
98
     * @param \SimpleSAML\Auth\State $authState
99
     */
100
    public function setAuthState(Auth\State $authState): void
101
    {
102
        $this->authState = $authState;
103
    }
104
105
106
    /**
107
     * Inject the \SimpleSAML\Logger dependency.
108
     *
109
     * @param \SimpleSAML\Logger $logger
110
     */
111
    public function setLogger(Logger $logger): void
112
    {
113
        $this->logger = $logger;
114
    }
115
116
117
    /**
118
     * Get the metadata storage handler instance.
119
     *
120
     * @return MetaDataStorageHandler
121
     */
122
    protected function getMetadataStorageHandler(): MetaDataStorageHandler
123
    {
124
        return $this->metadataHandler ?: MetaDataStorageHandler::getMetadataHandler();
125
    }
126
127
128
    /**
129
     * Inject the \SimpleSAML\Metadata\MetaDataStorageHandler dependency.
130
     *
131
     * @param \SimpleSAML\Metadata\MetaDataStorageHandler $handler
132
     */
133
    public function setMetadataStorageHandler(MetaDataStorageHandler $handler): void
134
    {
135
        $this->metadataHandler = $handler;
136
    }
137
138
139
    /**
140
     * Inject the \SimpleSAML\Module dependency.
141
     *
142
     * @param \SimpleSAML\Module $module
143
     */
144
    public function setModule(Module $module): void
145
    {
146
        $this->module = $module;
147
    }
148
149
150
    /**
151
     * Show enable.
152
     *
153
     * @param \Symfony\Component\HttpFoundation\Request $request
154
     * @return \SimpleSAML\XHTML\Template
155
     * @throws Exception
156
     */
157
    public function enable(Request $request): Template
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

157
    public function enable(/** @scrutinizer ignore-unused */ Request $request): Template

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
158
    {
159
        $this->session->setData('negotiate:disable', 'session', false, 86400); // 24*60*60=86400
160
161
        $cookie = new Cookie(
162
            'NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT',
163
            null, // value
164
            mktime(0, 0, 0, 1, 1, 2038), // expire
165
            '/', // path
166
            '', // domain
167
            true, // secure
168
            true // httponly
169
        );
170
171
        $t = new Template($this->config, 'negotiate:enable.twig');
172
        $t->headers->setCookie($cookie);
173
        $t->data['url'] = $this->module::getModuleURL('negotiate/disable');
174
175
        return $t;
176
    }
177
178
179
    /**
180
     * Show disable.
181
     *
182
     * @param \Symfony\Component\HttpFoundation\Request $request
183
     * @return \SimpleSAML\XHTML\Template
184
     * @throws Exception
185
     */
186
    public function disable(Request $request): Template
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

186
    public function disable(/** @scrutinizer ignore-unused */ Request $request): Template

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
187
    {
188
        $this->session->setData('negotiate:disable', 'session', false, 86400); //24*60*60=86400
189
190
        $cookie = new Cookie(
191
            'NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT',
192
            'true', // value
193
            mktime(0, 0, 0, 1, 1, 2038), // expire
194
            '/', // path
195
            '', // domain
196
            true, // secure
197
            true // httponly
198
        );
199
200
        $t = new Template($this->config, 'negotiate:disable.twig');
201
        $t->headers->setCookie($cookie);
202
        $t->data['url'] = $this->module::getModuleURL('negotiate/enable');
203
204
        return $t;
205
    }
206
207
208
    /**
209
     * Show retry
210
     *
211
     * @param Request $request The request that lead to this retry operation.
212
     * @return \SimpleSAML\HTTP\RunnableResponse
213
     * @throws \Exception
214
     * @throws \SimpleSAML\Error\BadRequest
215
     */
216
    public function retry(Request $request): RunnableResponse
217
    {
218
        $authState = $request->query->get('AuthState', null);
219
        if ($authState === null) {
220
            throw new Error\BadRequest('Missing required AuthState query parameter.');
221
        }
222
223
        /** @psalm-var array $state */
224
        $state = $this->authState::loadState($authState, Negotiate::STAGEID);
225
226
        $mdh = $this->getMetadataStorageHandler();
227
        $idpid = $mdh->getMetaDataCurrentEntityID('saml20-idp-hosted', 'metaindex');
228
        $idpmeta = $mdh->getMetaData($idpid, 'saml20-idp-hosted');
229
230
        if (isset($idpmeta['auth'])) {
231
            $source = $this->authSource::getById($idpmeta['auth']);
232
            if ($source === null) {
233
                throw new Error\BadRequest('Invalid AuthId "' . $idpmeta['auth'] . '" - not found.');
234
            }
235
236
            $this->session->setData('negotiate:disable', 'session', false, 86400); //24*60*60=86400
237
            $this->logger::debug('Negotiate(retry) - session enabled, retrying.');
238
239
            return new RunnableResponse([$source, 'authenticate'], [$state]);
240
        }
241
        throw new Exception('Negotiate - retry - no "auth" parameter found in IdP metadata.');
242
    }
243
244
245
    /**
246
     * Show fallback
247
     *
248
     * @param Request $request The request that lead to this retry operation.
249
     *
250
     * @return \Symfony\Component\HttpFoundation\StreamedResponse
251
     * @throws \SimpleSAML\Error\BadRequest
252
     * @throws \SimpleSAML\Error\NoState
253
     */
254
    public function fallback(Request $request): StreamedResponse
255
    {
256
        $authState = $request->query->get('AuthState', null);
257
        if ($authState === null) {
258
            throw new Error\BadRequest('Missing required AuthState query parameter.');
259
        }
260
261
        /** @psalm-var array $state */
262
        $state = $this->authState::loadState($authState, Negotiate::STAGEID);
263
264
        $this->logger::debug('backend - fallback: ' . $state['LogoutState']['negotiate:backend']);
265
266
        return new class ([Negotiate::class, 'fallBack'], $state) extends StreamedResponse
267
        {
268
            /** @var array $state */
269
            protected $state;
270
271
            public function __construct(callable $callback, &$state)
272
            {
273
                parent::__construct($callback);
274
                $this->state = $state;
275
            }
276
277
            public function sendContent()
278
            {
279
                call_user_func_array($this->callback, [&$this->state]);
280
                return $this;
281
            }
282
        };
283
    }
284
}
285