Passed
Pull Request — master (#280)
by Tim
02:30
created

AttributeQuery::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 8
dl 0
loc 13
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\samlp;
6
7
use DOMElement;
8
use SimpleSAML\Assert\Assert;
9
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
10
use SimpleSAML\SAML2\XML\saml\Attribute;
11
use SimpleSAML\SAML2\XML\saml\Issuer;
12
use SimpleSAML\SAML2\XML\saml\Subject;
13
use SimpleSAML\XML\Exception\InvalidDOMElementException;
14
use SimpleSAML\XML\Exception\MissingElementException;
15
use SimpleSAML\XML\Exception\TooManyElementsException;
16
use SimpleSAML\XML\Utils as XMLUtils;
17
use SimpleSAML\XMLSecurity\XML\ds\Signature;
18
19
use function array_pop;
20
use function in_array;
21
22
/**
23
 * Class for SAML 2 attribute query messages.
24
 *
25
 * An attribute query asks for a set of attributes. The following
26
 * rules apply:
27
 *
28
 * - If no attributes are present in the query, all attributes should be
29
 *   returned.
30
 * - If any attributes are present, only those attributes which are present
31
 *   in the query should be returned.
32
 * - If an attribute contains any attribute values, only the attribute values
33
 *   which match those in the query should be returned.
34
 *
35
 * @package simplesamlphp/saml2
36
 */
37
class AttributeQuery extends AbstractSubjectQuery
38
{
39
    /**
40
     * The attributes, as an associative array.
41
     *
42
     * @var \SimpleSAML\SAML2\XML\saml\Attribute[]
43
     */
44
    protected array $attributes = [];
45
46
47
    /**
48
     * Constructor for SAML 2 AttributeQuery.
49
     *
50
     * @param \SimpleSAML\SAML2\XML\saml\Subject $subject
51
     * @param \SimpleSAML\SAML2\XML\saml\Attribute[] $attributes
52
     * @param \SimpleSAML\SAML2\XML\saml\Issuer $issuer
53
     * @param string $id
54
     * @param int $issueInstant
55
     * @param string|null $destination
56
     * @param string|null $consent
57
     * @param \SimpleSAML\SAML2\XML\samlp\Extensions $extensions
58
     */
59
    public function __construct(
60
        Subject $subject,
61
        array $attributes = [],
62
        ?Issuer $issuer = null,
63
        ?string $id = null,
64
        ?int $issueInstant = null,
65
        ?string $destination = null,
66
        ?string $consent = null,
67
        ?Extensions $extensions = null
68
    ) {
69
        parent::__construct($subject, $issuer, $id, $issueInstant, $destination, $consent, $extensions);
70
71
        $this->setAttributes($attributes);
72
    }
73
74
75
    /**
76
     * Retrieve all requested attributes.
77
     *
78
     * @return \SimpleSAML\SAML2\XML\saml\Attribute[] All requested attributes, as an associative array.
79
     */
80
    public function getAttributes(): array
81
    {
82
        return $this->attributes;
83
    }
84
85
86
    /**
87
     * Set all requested attributes.
88
     *
89
     * @param \SimpleSAML\SAML2\XML\saml\Attribute[] $attributes All requested attributes, as an associative array.
90
     */
91
    public function setAttributes(array $attributes): void
92
    {
93
        Assert::allIsInstanceOf($attributes, Attribute::class);
94
95
        $cache = [];
96
        foreach ($attributes as $attribute) {
97
            $name = $attribute->getName();
98
            $nameFormat = $attribute->getNameFormat();
99
100
            if (isset($cache[$nameFormat])) {
101
                Assert::true(
102
                    !in_array($name, $cache[$nameFormat], true),
103
                    'A single query MUST NOT contain two <saml:Attribute> elements with the same Name and NameFormat.',
104
                    ProtocolViolationException::class
105
                );
106
            }
107
            $cache[$nameFormat][] = $name;
108
        }
109
        unset($cache);
110
111
        $this->attributes = $attributes;
112
    }
113
114
115
    /**
116
     * Create a class from XML
117
     *
118
     * @param \DOMElement $xml
119
     * @return self
120
     *
121
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException if the qualified name of the supplied element is wrong
122
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the supplied element is missing one of the mandatory attributes
123
     * @throws \SimpleSAML\XML\Exception\MissingElementException if one of the mandatory child-elements is missing
124
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException if too many child-elements of a type are specified
125
     */
126
    public static function fromXML(DOMElement $xml): object
127
    {
128
        Assert::same($xml->localName, 'AttributeQuery', InvalidDOMElementException::class);
129
        Assert::same($xml->namespaceURI, AttributeQuery::NS, InvalidDOMElementException::class);
130
        Assert::same('2.0', self::getAttribute($xml, 'Version'));
131
132
        $id = self::getAttribute($xml, 'ID');
133
        $destination = self::getAttribute($xml, 'Destination', null);
134
        $consent = self::getAttribute($xml, 'Consent', null);
135
136
        $issueInstant = self::getAttribute($xml, 'IssueInstant');
137
        Assert::validDateTimeZulu($issueInstant, ProtocolViolationException::class);
138
        $issueInstant = XMLUtils::xsDateTimeToTimestamp($issueInstant);
139
140
        $issuer = Issuer::getChildrenOfClass($xml);
141
        Assert::countBetween($issuer, 0, 1);
142
143
        $extensions = Extensions::getChildrenOfClass($xml);
144
        Assert::maxCount($extensions, 1, 'Only one saml:Extensions element is allowed.', TooManyElementsException::class);
145
146
        $subject = Subject::getChildrenOfClass($xml);
147
        Assert::notEmpty($subject, 'Missing subject in subject query.', MissingElementException::class);
148
        Assert::maxCount($subject, 1, 'More than one <saml:Subject> in AttributeQuery', TooManyElementsException::class);
149
150
        $signature = Signature::getChildrenOfClass($xml);
151
        Assert::maxCount($signature, 1, 'Only one ds:Signature element is allowed.', TooManyElementsException::class);
152
153
        $request = new self(
154
            array_pop($subject),
155
            Attribute::getChildrenOfClass($xml),
156
            array_pop($issuer),
157
            $id,
158
            $issueInstant,
159
            $destination,
160
            $consent,
161
            array_pop($extensions)
162
        );
163
164
        if (!empty($signature)) {
165
            $request->setSignature($signature[0]);
166
        }
167
168
        $request->setXML($xml);
169
        return $request;
170
    }
171
172
173
    /**
174
     * Convert this message to an unsigned XML document.
175
     * This method does not sign the resulting XML document.
176
     *
177
     * @return \DOMElement The root element of the DOM tree
178
     */
179
    protected function toUnsignedXML(?DOMElement $parent = null): DOMElement
180
    {
181
        $e = parent::toUnsignedXML($parent);
182
183
        foreach ($this->attributes as $attribute) {
184
            $attribute->toXML($e);
185
        }
186
187
        return $e;
188
    }
189
}
190