Passed
Pull Request — master (#348)
by Tim
02:24
created

Binding::getCurrentBinding()   C

Complexity

Conditions 16
Paths 24

Size

Total Lines 59
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

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