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