AttributeServer::setMetadataStorageHandler()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\Module\exampleattributeserver\Controller;
6
7
use SAML2\Assertion;
8
use SAML2\AttributeQuery;
9
use SAML2\Binding;
10
use SAML2\Constants;
11
use SAML2\HTTPPost;
12
use SAML2\Response;
13
use SAML2\XML\saml\Issuer;
14
use SAML2\XML\saml\SubjectConfirmation;
15
use SAML2\XML\saml\SubjectConfirmationData;
16
use SimpleSAML\Configuration;
17
use SimpleSAML\Error;
18
use SimpleSAML\HTTP\RunnableResponse;
19
use SimpleSAML\Logger;
20
use SimpleSAML\Metadata\MetaDataStorageHandler;
21
use SimpleSAML\Module\saml\Message;
22
use Symfony\Component\HttpFoundation\Request;
23
24
/**
25
 * Controller class for the exampleattributeserver module.
26
 *
27
 * This class serves the attribute server available in the module.
28
 *
29
 * @package SimpleSAML\Module\exampleattributeserver
30
 */
31
class AttributeServer
32
{
33
    /** @var \SimpleSAML\Configuration */
34
    protected Configuration $config;
35
36
    /** @var \SimpleSAML\Metadata\MetaDataStorageHandler|null */
37
    protected ?MetaDataStorageHandler $metadataHandler = null;
38
39
40
    /**
41
     * ConfigController constructor.
42
     *
43
     * @param \SimpleSAML\Configuration $config The configuration to use.
44
     */
45
    public function __construct(Configuration $config)
46
    {
47
        $this->config = $config;
48
    }
49
50
51
    /**
52
     * Inject the \SimpleSAML\Metadata\MetaDataStorageHandler dependency.
53
     *
54
     * @param \SimpleSAML\Metadata\MetaDataStorageHandler $handler
55
     */
56
    public function setMetadataStorageHandler(MetaDataStorageHandler $handler): void
57
    {
58
        $this->metadataHandler = $handler;
59
    }
60
61
62
    /**
63
     * @param \Symfony\Component\HttpFoundation\Request $request The current request.
64
     *
65
     * @return \SimpleSAML\HTTP\RunnableResponse
66
     * @throws \SimpleSAML\Error\BadRequest
67
     */
68
    public function main(/** @scrutinizer ignore-unused */ Request $request): RunnableResponse
69
    {
70
        $binding = Binding::getCurrentBinding();
71
        $query = $binding->receive();
72
        if (!($query instanceof AttributeQuery)) {
73
            throw new Error\BadRequest('Invalid message received to AttributeQuery endpoint.');
74
        }
75
76
        $idpEntityId = $this->metadataHandler->getMetaDataCurrentEntityID('saml20-idp-hosted');
0 ignored issues
show
Bug introduced by
The method getMetaDataCurrentEntityID() 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

76
        /** @scrutinizer ignore-call */ 
77
        $idpEntityId = $this->metadataHandler->getMetaDataCurrentEntityID('saml20-idp-hosted');

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...
77
78
        $issuer = $query->getIssuer();
79
        if ($issuer === null) {
80
            throw new Error\BadRequest('Missing <saml:Issuer> in <samlp:AttributeQuery>.');
81
        } else {
82
            $spEntityId = $issuer->getValue();
83
            if ($spEntityId === '') {
84
                throw new Error\BadRequest('Empty <saml:Issuer> in <samlp:AttributeQuery>.');
85
            }
86
        }
87
88
        $idpMetadata = $this->metadataHandler->getMetaDataConfig($idpEntityId, 'saml20-idp-hosted');
89
        $spMetadata = $this->metadataHandler->getMetaDataConfig($spEntityId, 'saml20-sp-remote');
90
91
        // The endpoint we should deliver the message to
92
        $endpoint = $spMetadata->getString('testAttributeEndpoint');
93
94
        // The attributes we will return
95
        $attributes = [
96
            'name' => ['value1', 'value2', 'value3'],
97
            'test' => ['test'],
98
        ];
99
100
        // The name format of the attributes
101
        $attributeNameFormat = Constants::NAMEFORMAT_UNSPECIFIED;
102
103
        // Determine which attributes we will return
104
        $returnAttributes = array_keys($query->getAttributes());
105
        if (count($returnAttributes) === 0) {
106
            Logger::debug('No attributes requested - return all attributes.');
107
            $returnAttributes = $attributes;
108
        } elseif ($query->getAttributeNameFormat() !== $attributeNameFormat) {
109
            Logger::debug('Requested attributes with wrong NameFormat - no attributes returned.');
110
            $returnAttributes = [];
111
        } else {
112
            /** @var array $values */
113
            foreach ($returnAttributes as $name => $values) {
114
                if (!array_key_exists($name, $attributes)) {
115
                    // We don't have this attribute
116
                    unset($returnAttributes[$name]);
117
                    continue;
118
                }
119
                if (count($values) === 0) {
120
                    // Return all attributes
121
                    $returnAttributes[$name] = $attributes[$name];
122
                    continue;
123
                }
124
125
                // Filter which attribute values we should return
126
                $returnAttributes[$name] = array_intersect($values, $attributes[$name]);
127
            }
128
        }
129
130
        // $returnAttributes contains the attributes we should return. Send them
131
        $issuer = new Issuer();
132
        $issuer->setValue($idpEntityId);
133
134
        $assertion = new Assertion();
135
        $assertion->setIssuer($issuer);
136
        $assertion->setNameId($query->getNameId());
137
        $assertion->setNotBefore(time());
138
        $assertion->setNotOnOrAfter(time() + 300); // 60*5 = 5min
139
        $assertion->setValidAudiences([$spEntityId]);
140
        $assertion->setAttributes($returnAttributes);
141
        $assertion->setAttributeNameFormat($attributeNameFormat);
142
143
        $sc = new SubjectConfirmation();
144
        $sc->setMethod(Constants::CM_BEARER);
145
146
        $scd = new SubjectConfirmationData();
147
        $scd->setNotOnOrAfter(time() + 300); // 60*5 = 5min
148
        $scd->setRecipient($endpoint);
149
        $scd->setInResponseTo($query->getId());
150
        $sc->setSubjectConfirmationData($scd);
151
        $assertion->setSubjectConfirmation([$sc]);
152
153
        Message::addSign($idpMetadata, $spMetadata, $assertion);
154
155
        $response = new Response();
156
        $response->setRelayState($query->getRelayState());
157
        $response->setDestination($endpoint);
158
        $response->setIssuer($issuer);
159
        $response->setInResponseTo($query->getId());
160
        $response->setAssertions([$assertion]);
161
        Message::addSign($idpMetadata, $spMetadata, $response);
162
163
        return new RunnableResponse([new HTTPPost(), 'send'], [$response]);
164
    }
165
}
166