Adfs::mex()   A
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 60
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 38
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 60
rs 9.0008

How to fix   Long Method   

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
declare(strict_types=1);
4
5
namespace SimpleSAML\Module\adfs\Controller;
6
7
use Exception;
8
use SimpleSAML\Configuration;
9
use SimpleSAML\Error as SspError;
10
use SimpleSAML\IdP;
11
use SimpleSAML\Logger;
12
use SimpleSAML\Metadata;
13
use SimpleSAML\Module\adfs\IdP\ADFS as ADFS_IDP;
14
use SimpleSAML\Module\adfs\IdP\MetadataBuilder;
15
use SimpleSAML\Module\adfs\IdP\PassiveIdP;
16
use SimpleSAML\Module\adfs\MetadataExchange;
17
use SimpleSAML\Session;
18
use SimpleSAML\SOAP\XML\env_200305\Envelope;
19
use SimpleSAML\Utils;
20
use SimpleSAML\XML\DOMDocumentFactory;
21
use Symfony\Component\HttpFoundation\Request;
22
use Symfony\Component\HttpFoundation\Response;
23
use Symfony\Component\HttpFoundation\StreamedResponse;
24
25
/**
26
 * Controller class for the adfs module.
27
 *
28
 * This class serves the adfs views available in the module.
29
 *
30
 * @package SimpleSAML\Module\adfs
31
 */
32
class Adfs
33
{
34
    /** @var \SimpleSAML\Configuration */
35
    protected Configuration $config;
36
37
    /** @var \SimpleSAML\Metadata\MetaDataStorageHandler */
38
    protected Metadata\MetaDataStorageHandler $metadata;
39
40
    /** @var \SimpleSAML\Session */
41
    protected Session $session;
42
43
    /** @var \SimpleSAML\Utils\Crypto */
44
    protected Utils\Crypto $cryptoUtils;
45
46
47
    /**
48
     * AdfsController constructor.
49
     *
50
     * @param \SimpleSAML\Configuration $config The configuration to use.
51
     * @param \SimpleSAML\Session $session The current user session.
52
     */
53
    public function __construct(Configuration $config, Session $session)
54
    {
55
        $this->config = $config;
56
        $this->metadata = Metadata\MetaDataStorageHandler::getMetadataHandler($config);
0 ignored issues
show
Unused Code introduced by
The call to SimpleSAML\Metadata\Meta...r::getMetadataHandler() has too many arguments starting with $config. ( Ignorable by Annotation )

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

56
        /** @scrutinizer ignore-call */ 
57
        $this->metadata = Metadata\MetaDataStorageHandler::getMetadataHandler($config);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
57
        $this->session = $session;
58
        $this->cryptoUtils = new Utils\Crypto();
59
    }
60
61
62
    /**
63
     * @param \Symfony\Component\HttpFoundation\Request $request
64
     * @return \Symfony\Component\HttpFoundation\Response|\SimpleSAML\XHTML\Template
65
     */
66
    public function metadata(Request $request): Response
67
    {
68
        if (!$this->config->getOptionalBoolean('enable.adfs-idp', false)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->config->getOption...nable.adfs-idp', false) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
69
            throw new SspError\Error('NOACCESS');
70
        }
71
72
        // check if valid local session exists
73
        $authUtils = new Utils\Auth();
74
        if ($this->config->getOptionalBoolean('admin.protectmetadata', false) && !$authUtils->isAdmin()) {
75
            return new StreamedResponse([$authUtils, 'requireAdmin']);
76
        }
77
78
        try {
79
            if ($request->query->has('idpentityid')) {
80
                $idpentityid = $request->query->get('idpentityid');
81
            } else {
82
                $idpentityid = $this->metadata->getMetaDataCurrentEntityID('adfs-idp-hosted');
83
            }
84
            $idpmeta = $this->metadata->getMetaDataConfig($idpentityid, 'adfs-idp-hosted');
85
86
            $builder = new MetadataBuilder($this->config, $idpmeta);
87
88
            $document = $builder->buildDocument()->toXML();
89
            // Some products like DirX are known to break on pretty-printed XML
90
            $document->ownerDocument->formatOutput = false;
91
            $document->ownerDocument->encoding = 'UTF-8';
92
            $metaxml = $document->ownerDocument->saveXML();
0 ignored issues
show
Bug introduced by
The method saveXML() does not exist on null. ( Ignorable by Annotation )

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

92
            /** @scrutinizer ignore-call */ 
93
            $metaxml = $document->ownerDocument->saveXML();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
93
94
            $response = new Response();
95
            $response->setEtag(hash('sha256', $metaxml));
96
            $response->setPublic();
97
            if ($response->isNotModified($request)) {
98
                return $response;
99
            }
100
            $response->headers->set('Content-Type', 'application/samlmetadata+xml');
101
            $response->headers->set('Content-Disposition', 'attachment; filename="FederationMetadata.xml"');
102
            $response->setContent($metaxml);
103
104
            return $response;
105
        } catch (Exception $exception) {
106
            throw new SspError\Error('METADATA', $exception);
107
        }
108
    }
109
110
111
    /**
112
     * @param \Symfony\Component\HttpFoundation\Request $request
113
     * @return \Symfony\Component\HttpFoundation\Response
114
     */
115
    public function prp(Request $request): Response
116
    {
117
        Logger::info('ADFS - IdP.prp: Accessing ADFS IdP endpoint prp');
118
119
        $idpEntityId = $this->metadata->getMetaDataCurrentEntityID('adfs-idp-hosted');
120
        $idp = IdP::getById('adfs:' . $idpEntityId);
121
122
        if ($request->get('wa', null) !== null) {
123
            $wa = $request->get('wa');
124
            if ($wa === 'wsignout1.0') {
125
                return new StreamedResponse(
126
                    function () use ($idp) {
127
                        ADFS_IDP::receiveLogoutMessage($idp);
128
                    },
129
                );
130
            } elseif ($wa === 'wsignin1.0') {
131
                return ADFS_IDP::receiveAuthnRequest($request, $idp);
132
            }
133
            throw new SspError\BadRequest("Unsupported value for 'wa' specified in request.");
134
        } elseif ($request->get('assocId', null) !== null) {
135
            // logout response from ADFS SP
136
            // Association ID of the SP that sent the logout response
137
            $assocId = $request->get('assocId');
138
            // Data that was sent in the logout request to the SP. Can be null
139
            $relayState = $request->get('relayState');
140
            // null on success, or an instance of a \SimpleSAML\Error\Exception on failure.
141
            $logoutError = null;
142
143
            return new StreamedResponse(
144
                function () use ($idp, /** @scrutinizer ignore-type */ $assocId, $relayState, $logoutError) {
145
                    $idp->handleLogoutResponse($assocId, $relayState, $logoutError);
146
                },
147
            );
148
        }
149
        throw new SspError\BadRequest("Missing parameter 'wa' or 'assocId' in request.");
150
    }
151
152
153
    /**
154
     * @param \Symfony\Component\HttpFoundation\Request $request
155
     * @return \Symfony\Component\HttpFoundation\Response
156
     */
157
    public function mex(Request $request): Response
158
    {
159
        if (!$this->config->getOptionalBoolean('enable.adfs-idp', false)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->config->getOption...nable.adfs-idp', false) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
160
            throw new SspError\Error('NOACCESS');
161
        }
162
163
        // check if valid local session exists
164
        $authUtils = new Utils\Auth();
165
        if ($this->config->getOptionalBoolean('admin.protectmetadata', false) && !$authUtils->isAdmin()) {
166
            return new StreamedResponse([$authUtils, 'requireAdmin']);
167
        }
168
169
        $mexBuilder = new MetadataExchange();
170
        $document = $mexBuilder->buildDocument()->toXML();
171
        // Some products like DirX are known to break on pretty-printed XML
172
        $document->ownerDocument->formatOutput = false;
173
        $document->ownerDocument->encoding = 'UTF-8';
174
175
        $document->setAttributeNS(
176
            'http://www.w3.org/2000/xmlns/',
177
            'xmlns:tns',
178
            'http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice',
179
        );
180
181
        $document->setAttributeNS(
182
            'http://www.w3.org/2000/xmlns/',
183
            'xmlns:soapenc',
184
            'http://schemas.xmlsoap.org/soap/encoding/',
185
        );
186
187
        $document->setAttributeNS(
188
            'http://www.w3.org/2000/xmlns/',
189
            'xmlns:msc',
190
            'http://schemas.microsoft.com/ws/2005/12/wsdl/contract',
191
        );
192
193
        $document->setAttributeNS(
194
            'http://www.w3.org/2000/xmlns/',
195
            'xmlns:wsam',
196
            'http://www.w3.org/2007/05/addressing/metadata',
197
        );
198
199
        $document->setAttributeNS(
200
            'http://www.w3.org/2000/xmlns/',
201
            'xmlns:wsap',
202
            'http://schemas.xmlsoap.org/ws/2004/08/addressing/policy',
203
        );
204
205
        $metaxml = $document->ownerDocument->saveXML();
206
207
        $response = new Response();
208
        $response->setEtag(hash('sha256', $metaxml));
209
        $response->setPublic();
210
        if ($response->isNotModified($request)) {
211
            return $response;
212
        }
213
        $response->headers->set('Content-Type', 'text/xml');
214
        $response->setContent($metaxml);
215
216
        return $response;
217
    }
218
219
220
    /**
221
     * @param \Symfony\Component\HttpFoundation\Request $request
222
     * @return \Symfony\Component\HttpFoundation\Response
223
     */
224
    public function usernamemixed(Request $request): Response
225
    {
226
        if (!$this->config->getOptionalBoolean('enable.adfs-idp', false)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->config->getOption...nable.adfs-idp', false) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
227
            throw new SspError\Error('NOACCESS');
228
        }
229
230
        $soapMessage = $request->getContent();
231
        if ($soapMessage === false) {
0 ignored issues
show
introduced by
The condition $soapMessage === false is always false.
Loading history...
232
            throw new SspError\BadRequest('Missing SOAP-content.');
233
        }
234
235
        $domDocument = DOMDocumentFactory::fromString($soapMessage);
236
        $soapEnvelope = Envelope::fromXML($domDocument->documentElement);
237
238
        $idpEntityId = $this->metadata->getMetaDataCurrentEntityID('adfs-idp-hosted');
239
        $idp = PassiveIdP::getById($this->config, 'adfs:' . $idpEntityId);
240
241
        return ADFS_IDP::receivePassiveAuthnRequest($request, $soapEnvelope, $idp);
242
    }
243
}
244