Binding::getCurrentBinding()   C
last analyzed

Complexity

Conditions 16
Paths 24

Size

Total Lines 59
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
eloc 36
nc 24
nop 1
dl 0
loc 59
rs 5.5666
c 0
b 0
f 0

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
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2;
6
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\ServerRequestInterface;
9
use SimpleSAML\SAML2\Binding\HTTPArtifact;
10
use SimpleSAML\SAML2\Binding\HTTPPost;
11
use SimpleSAML\SAML2\Binding\HTTPRedirect;
12
use SimpleSAML\SAML2\Binding\SOAP;
13
use SimpleSAML\SAML2\Constants as C;
14
use SimpleSAML\SAML2\Exception\Protocol\UnsupportedBindingException;
15
use SimpleSAML\SAML2\XML\samlp\AbstractMessage;
16
17
use function array_key_exists;
18
use function array_keys;
19
use function array_map;
20
use function explode;
21
use function implode;
22
use function var_export;
23
24
/**
25
 * Base class for SAML 2 bindings.
26
 *
27
 * @package simplesamlphp/saml2
28
 */
29
abstract class Binding
30
{
31
    /**
32
     * The destination of messages.
33
     *
34
     * This can be null, in which case the destination in the message is used.
35
     * @var string|null
36
     */
37
    protected ?string $destination = null;
38
39
40
    /**
41
     * Retrieve a binding with the given URN.
42
     *
43
     * Will throw an exception if it is unable to locate the binding.
44
     *
45
     * @param string $urn The URN of the binding.
46
     * @throws \SimpleSAML\SAML2\Exception\Protocol\UnsupportedBindingException
47
     * @return \SimpleSAML\SAML2\Binding The binding.
48
     */
49
    public static function getBinding(string $urn): Binding
50
    {
51
        switch ($urn) {
52
            case C::BINDING_HTTP_POST:
53
            case C::BINDING_HOK_SSO:
54
                return new HTTPPost();
55
            case C::BINDING_HTTP_REDIRECT:
56
                return new HTTPRedirect();
57
            case C::BINDING_HTTP_ARTIFACT:
58
                return new HTTPArtifact();
59
            // ECP ACS is defined with the PAOS binding, but as the IdP, we
60
            // talk to the ECP using SOAP -- if support for ECP as an SP is
61
            // implemented, this logic may need to change
62
            case C::BINDING_PAOS:
63
                return new SOAP();
64
            default:
65
                throw new UnsupportedBindingException('Unsupported binding: ' . var_export($urn, true));
66
        }
67
    }
68
69
70
    /**
71
     * Guess the current binding.
72
     *
73
     * This function guesses the current binding and creates an instance
74
     * of \SimpleSAML\SAML2\Binding matching that binding.
75
     *
76
     * An exception will be thrown if it is unable to guess the binding.
77
     *
78
     * @param \Psr\Http\Message\ServerRequestInterface $request
79
     * @throws \SimpleSAML\SAML2\Exception\Protocol\UnsupportedBindingException
80
     * @return \SimpleSAML\SAML2\Binding The binding.
81
     */
82
    public static function getCurrentBinding(ServerRequestInterface $request): Binding
83
    {
84
        $method = $request->getMethod();
85
86
        switch ($method) {
87
            case 'GET':
88
                $query = $request->getQueryParams();
89
                if (array_key_exists('SAMLRequest', $query) || array_key_exists('SAMLResponse', $query)) {
90
                    return new Binding\HTTPRedirect();
91
                } elseif (array_key_exists('SAMLart', $query)) {
92
                    return new Binding\HTTPArtifact();
93
                }
94
                break;
95
96
            case 'POST':
97
                $contentType = null;
98
                if ($request->hasHeader('Content-Type')) {
99
                    $contentType = $request->getHeader('Content-Type')[0];
100
                    $contentType = explode(';', $contentType);
101
                    $contentType = $contentType[0]; /* Remove charset. */
102
                }
103
104
                $query = $request->getParsedBody();
105
                if (array_key_exists('SAMLRequest', $query) || array_key_exists('SAMLResponse', $query)) {
106
                    return new Binding\HTTPPost();
107
                } elseif (array_key_exists('SAMLart', $query)) {
108
                    return new Binding\HTTPArtifact();
109
                } else {
110
                    /**
111
                     * The registration information for text/xml is in all respects the same
112
                     * as that given for application/xml (RFC 7303 - Section 9.1)
113
                     */
114
                    if (
115
                        ($contentType === 'text/xml' || $contentType === 'application/xml')
116
                        // See paragraph 3.2.3 of Binding for SAML2 (OASIS)
117
                        || ($request->hasHeader('SOAPAction')
118
                            && $request->getHeader('SOAPAction')[0] === 'http://www.oasis-open.org/committees/security')
119
                    ) {
120
                        return new Binding\SOAP();
121
                    }
122
                }
123
                break;
124
        }
125
126
        $logger = Utils::getContainer()->getLogger();
127
        $logger->warning('Unable to find the SAML 2 binding used for this request.');
128
        $logger->warning('Request method: ' . var_export($method, true));
129
130
        if (!empty($query)) {
131
            $logger->warning(
132
                $method . " parameters: '" . implode("', '", array_map('addslashes', array_keys($query))) . "'",
133
            );
134
        }
135
136
        if ($request->hasHeader('Content-Type')) {
137
            $logger->warning('Content-Type: ' . var_export($request->getHeader('Content-Type')[0], true));
138
        }
139
140
        throw new UnsupportedBindingException('Unable to find the SAML 2 binding used for this request.');
141
    }
142
143
144
    /**
145
     * Retrieve the destination of a message.
146
     *
147
     * @return string|null $destination The destination the message will be delivered to.
148
     */
149
    public function getDestination(): ?string
150
    {
151
        return $this->destination;
152
    }
153
154
155
    /**
156
     * Override the destination of a message.
157
     *
158
     * Set to null to use the destination set in the message.
159
     *
160
     * @param string|null $destination The destination the message should be delivered to.
161
     */
162
    public function setDestination(?string $destination = null): void
163
    {
164
        $this->destination = $destination;
165
    }
166
167
168
    /**
169
     * Send a SAML 2 message.
170
     *
171
     * This function will send a message using the specified binding.
172
     * The message will be delivered to the destination set in the message.
173
     *
174
     * @param \SimpleSAML\SAML2\XML\samlp\AbstractMessage $message The message which should be sent.
175
     * @return \Psr\Http\Message\ResponseInterface
176
     */
177
    abstract public function send(AbstractMessage $message): ResponseInterface;
178
179
180
    /**
181
     * Receive a SAML 2 message.
182
     *
183
     * This function will extract the message from the current request.
184
     * An exception will be thrown if we are unable to process the message.
185
     *
186
     * @param \Psr\Http\Message\ServerRequestInterface $request
187
     * @return \SimpleSAML\SAML2\XML\samlp\AbstractMessage The received message.
188
     */
189
    abstract public function receive(ServerRequestInterface $request): AbstractMessage;
190
}
191