Passed
Push — master ( 27834c...10fd1c )
by Tim
02:39
created

AdfsController::metadata()   F

Complexity

Conditions 25
Paths > 20000

Size

Total Lines 182
Code Lines 120

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 120
dl 0
loc 182
rs 0
c 0
b 0
f 0
cc 25
nc 1466797
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SimpleSAML\Module\adfs\Controller;
4
5
use SAML2\Constants;
6
use SimpleSAML\Configuration;
7
use SimpleSAML\Error as SspError;
8
use SimpleSAML\IdP;
9
use SimpleSAML\Locale\Translate;
10
use SimpleSAML\Logger;
11
use SimpleSAML\Module;
12
use SimpleSAML\Module\adfs\IdP\ADFS;
13
use SimpleSAML\Metadata;
14
use SimpleSAML\Session;
15
use SimpleSAML\Utils;
16
use SimpleSAML\XHTML\Template;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\Response;
19
use Symfony\Component\HttpFoundation\StreamedResponse;
20
use Webmozart\Assert\Assert;
21
22
/**
23
 * Controller class for the adfs module.
24
 *
25
 * This class serves the adfs views available in the module.
26
 *
27
 * @package SimpleSAML\Module\adfs
28
 */
29
class AdfsController
30
{
31
    /** @var \SimpleSAML\Configuration */
32
    protected $config;
33
34
    /** @var \SimpleSAML\Metadata\MetaDataStorageHandler */
35
    protected $metadata;
36
37
    /** @var \SimpleSAML\Session */
38
    protected $session;
39
40
    /**
41
     * AdfsController constructor.
42
     *
43
     * @param \SimpleSAML\Configuration $config The configuration to use.
44
     * @param \SimpleSAML\Session $session The current user session.
45
     */
46
    public function __construct(Configuration $config, Session $session)
47
    {
48
        $this->config = $config;
49
        $this->metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
50
        $this->session = $session;
51
    }
52
53
54
    /**
55
     * @param \Symfony\Component\HttpFoundation\Request $request
56
     * @return \Symfony\Component\HttpFoundation\Response|\SimpleSAML\XHTML\Template
57
     */
58
    public function metadata(Request $request): Response
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

58
    public function metadata(/** @scrutinizer ignore-unused */ Request $request): Response

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...
59
    {
60
        if (!$this->config->getBoolean('enable.adfs-idp', false)) {
61
            throw new SspError\Error('NOACCESS');
62
        }
63
64
        // check if valid local session exists
65
        if ($this->config->getBoolean('admin.protectmetadata', false)) {
66
            Utils\Auth::requireAdmin();
67
        }
68
69
        try {
70
            $idpentityid = isset($_GET['idpentityid']) ?
71
                $_GET['idpentityid'] : $this->metadata->getMetaDataCurrentEntityID('adfs-idp-hosted');
72
            $idpmeta = $this->metadata->getMetaDataConfig($idpentityid, 'adfs-idp-hosted');
73
74
            $availableCerts = [];
75
            $keys = [];
76
            $certInfo = Utils\Crypto::loadPublicKey($idpmeta, false, 'new_');
77
78
            if ($certInfo !== null) {
79
                $availableCerts['new_idp.crt'] = $certInfo;
80
                $keys[] = [
81
                    'type'            => 'X509Certificate',
82
                    'signing'         => true,
83
                    'encryption'      => true,
84
                    'X509Certificate' => $certInfo['certData'],
85
                ];
86
                $hasNewCert = true;
87
            } else {
88
                $hasNewCert = false;
89
            }
90
91
            /** @var array $certInfo */
92
            $certInfo = Utils\Crypto::loadPublicKey($idpmeta, true);
93
            $availableCerts['idp.crt'] = $certInfo;
94
            $keys[] = [
95
                'type'            => 'X509Certificate',
96
                'signing'         => true,
97
                'encryption'      => ($hasNewCert ? false : true),
98
                'X509Certificate' => $certInfo['certData'],
99
            ];
100
101
            if ($idpmeta->hasValue('https.certificate')) {
102
                /** @var array $httpsCert */
103
                $httpsCert = Utils\Crypto::loadPublicKey($idpmeta, true, 'https.');
104
                Assert::keyExists($httpsCert, 'certData');
105
                $availableCerts['https.crt'] = $httpsCert;
106
                $keys[] = [
107
                    'type'            => 'X509Certificate',
108
                    'signing'         => true,
109
                    'encryption'      => false,
110
                    'X509Certificate' => $httpsCert['certData'],
111
                ];
112
            }
113
114
            $adfs_service_location = Module::getModuleURL('adfs') . '/idp/prp.php';
115
            $metaArray = [
116
                'metadata-set'        => 'adfs-idp-remote',
117
                'entityid'            => $idpentityid,
118
                'SingleSignOnService' => [
119
                    0 => [
120
                        'Binding'  => Constants::BINDING_HTTP_REDIRECT,
121
                        'Location' => $adfs_service_location
122
                    ]
123
                ],
124
                'SingleLogoutService' => [
125
                    0 => [
126
                        'Binding'  => Constants::BINDING_HTTP_REDIRECT,
127
                        'Location' => $adfs_service_location
128
                    ]
129
                ],
130
            ];
131
132
            if (count($keys) === 1) {
133
                $metaArray['certData'] = $keys[0]['X509Certificate'];
134
            } else {
135
                $metaArray['keys'] = $keys;
136
            }
137
138
            $metaArray['NameIDFormat'] = $idpmeta->getString(
139
                'NameIDFormat',
140
                Constants::NAMEID_TRANSIENT
141
            );
142
143
            if ($idpmeta->hasValue('OrganizationName')) {
144
                $metaArray['OrganizationName'] = $idpmeta->getLocalizedString('OrganizationName');
145
                $metaArray['OrganizationDisplayName'] = $idpmeta->getLocalizedString(
146
                    'OrganizationDisplayName',
147
                    $metaArray['OrganizationName']
148
                );
149
150
                if (!$idpmeta->hasValue('OrganizationURL')) {
151
                    throw new SspError\Exception('If OrganizationName is set, OrganizationURL must also be set.');
152
                }
153
                $metaArray['OrganizationURL'] = $idpmeta->getLocalizedString('OrganizationURL');
154
            }
155
156
            if ($idpmeta->hasValue('scope')) {
157
                $metaArray['scope'] = $idpmeta->getArray('scope');
158
            }
159
160
            if ($idpmeta->hasValue('EntityAttributes')) {
161
                $metaArray['EntityAttributes'] = $idpmeta->getArray('EntityAttributes');
162
            }
163
164
            if ($idpmeta->hasValue('UIInfo')) {
165
                $metaArray['UIInfo'] = $idpmeta->getArray('UIInfo');
166
            }
167
168
            if ($idpmeta->hasValue('DiscoHints')) {
169
                $metaArray['DiscoHints'] = $idpmeta->getArray('DiscoHints');
170
            }
171
172
            if ($idpmeta->hasValue('RegistrationInfo')) {
173
                $metaArray['RegistrationInfo'] = $idpmeta->getArray('RegistrationInfo');
174
            }
175
176
            $metaflat = '$metadata[' . var_export($idpentityid, true) . '] = ' . var_export($metaArray, true) . ';';
177
178
            $metaBuilder = new Metadata\SAMLBuilder($idpentityid);
179
            $metaBuilder->addSecurityTokenServiceType($metaArray);
180
            $metaBuilder->addOrganizationInfo($metaArray);
181
            $technicalContactEmail = $this->config->getString('technicalcontact_email', null);
182
            if ($technicalContactEmail && $technicalContactEmail !== '[email protected]') {
183
                $metaBuilder->addContact('technical', Utils\Config\Metadata::getContact([
184
                    'emailAddress' => $technicalContactEmail,
185
                    'name'         => $this->config->getString('technicalcontact_name', null),
186
                    'contactType'  => 'technical',
187
                ]));
188
            }
189
            $output_xhtml = array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml';
190
            $metaxml = $metaBuilder->getEntityDescriptorText($output_xhtml);
191
            if (!$output_xhtml) {
192
                $metaxml = str_replace("\n", '', $metaxml);
193
            }
194
195
            // sign the metadata if enabled
196
            $metaxml = Metadata\Signer::sign($metaxml, $idpmeta->toArray(), 'ADFS IdP');
197
198
            if ($output_xhtml) {
199
                $t = new Template($this->config, 'metadata.twig', 'admin');
200
201
                $t->data['clipboard.js'] = true;
202
                $t->data['available_certs'] = $availableCerts;
203
                $certdata = [];
204
                foreach (array_keys($availableCerts) as $availableCert) {
205
                    $certdata[$availableCert]['name'] = $availableCert;
206
                    $certdata[$availableCert]['url'] = Module::getModuleURL('saml/idp/certs.php') .
207
                        '/' . $availableCert;
208
209
                    $certdata[$availableCert]['comment'] = '';
210
                    if ($availableCerts[$availableCert]['certFingerprint'][0] === 'afe71c28ef740bc87425be13a2263d37971da1f9') {
211
                        $certdata[$availableCert]['comment'] = 'This is the default certificate.' .
212
                            ' Generate a new certificate if this is a production system.';
213
                    }
214
                }
215
                $t->data['certdata'] = $certdata;
216
                $t->data['header'] = 'adfs-idp'; // TODO: Replace with headerString in 2.0
217
                $t->data['headerString'] = Translate::noop('metadata_adfs-idp');
218
                $t->data['metaurl'] = Utils\HTTP::getSelfURLNoQuery();
219
                $t->data['metadata'] = htmlspecialchars($metaxml);
220
                $t->data['metadataflat'] = htmlspecialchars($metaflat);
221
222
                return $t;
223
            } else {
224
                // make sure to export only the md:EntityDescriptor
225
                $i = strpos($metaxml, '<md:EntityDescriptor');
226
                $metaxml = substr($metaxml, $i ? $i : 0);
227
228
                // 22 = strlen('</md:EntityDescriptor>')
229
                $i = strrpos($metaxml, '</md:EntityDescriptor>');
230
                $metaxml = substr($metaxml, 0, $i ? $i + 22 : 0);
231
232
                $response = new Response();
233
                $response->headers->set('Content-Type', 'application/xml');
234
                $response->setContent($metaxml);
235
236
                return $response;
237
            }
238
        } catch (\Exception $exception) {
239
            throw new SspError\Error('METADATA', $exception);
240
        }
241
    }
242
243
244
    /**
245
     * @param \Symfony\Component\HttpFoundation\Request $request
246
     * @return \Symfony\Component\HttpFoundation\Response
247
     */
248
    public function prp(Request $request): Response
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

248
    public function prp(/** @scrutinizer ignore-unused */ Request $request): Response

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...
249
    {
250
        Logger::info('ADFS - IdP.prp: Accessing ADFS IdP endpoint prp');
251
252
        $idpEntityId = $this->metadata->getMetaDataCurrentEntityID('adfs-idp-hosted');
253
        $idp = IdP::getById('adfs:' . $idpEntityId);
254
255
        if (isset($_GET['wa'])) {
256
            if ($_GET['wa'] === 'wsignout1.0') {
257
                return new StreamedResponse(
258
                    /** @return void */
259
                    function () use ($idp) {
260
                        ADFS::receiveLogoutMessage($idp);
261
                    }
262
                );
263
            } elseif ($_GET['wa'] === 'wsignin1.0') {
264
                return new StreamedResponse(
265
                    /** @return void */
266
                    function () use ($idp) {
267
                        ADFS::receiveAuthnRequest($idp);
268
                    }
269
                );
270
            }
271
            throw new SspError\BadRequest("Unsupported value for 'wa' specified in request.");
272
        } elseif (isset($_GET['assocId'])) {
273
            // logout response from ADFS SP
274
            $assocId = $_GET['assocId']; // Association ID of the SP that sent the logout response
275
            $relayState = $_GET['relayState']; // Data that was sent in the logout request to the SP. Can be null
276
            $logoutError = null; // null on success, or an instance of a \SimpleSAML\Error\Exception on failure.
277
278
            return new StreamedResponse(
279
                /** @return void */
280
                function () use ($idp, $assocId, $relayState, $logoutError) {
281
                    $idp->handleLogoutResponse($assocId, $relayState, $logoutError);
282
                }
283
            );
284
        }
285
        throw new SspError\BadRequest("Missing parameter 'wa' or 'assocId' in request.");
286
    }
287
}
288