Passed
Pull Request — master (#2)
by Tim
02:11
created

MetaEditor::import()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 4
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\Module\metaedit\Controller;
6
7
use Exception;
8
use SAML2\Constants;
9
use SimpleSAML\Auth;
10
use SimpleSAML\Configuration;
11
use SimpleSAML\Error;
12
use SimpleSAML\Metadata;
13
use SimpleSAML\Module\metaedit\MetaEditor as Editor;
14
use SimpleSAML\Session;
15
use SimpleSAML\Utils;
16
use SimpleSAML\XHTML\Template;
17
use Symfony\Component\HttpFoundation\Request;
18
19
use function array_key_exists;
20
use function array_pop;
21
22
/**
23
 * Controller class for the metaedit module.
24
 *
25
 * This class serves the different views available in the module.
26
 *
27
 * @package simplesamlphp/simplesamlphp-module-metaedit
28
 */
29
class MetaEditor
30
{
31
    /** @var \SimpleSAML\Configuration */
32
    protected Configuration $config;
33
34
    /** @var \SimpleSAML\Session */
35
    protected Session $session;
36
37
38
    /**
39
     * Controller constructor.
40
     *
41
     * It initializes the global configuration and session for the controllers implemented here.
42
     *
43
     * @param \SimpleSAML\Configuration $config The configuration to use by the controllers.
44
     * @param \SimpleSAML\Session $session The session to use by the controllers.
45
     *
46
     * @throws \Exception
47
     */
48
    public function __construct(
49
        Configuration $config,
50
        Session $session
51
    ) {
52
        $this->config = $config;
53
        $this->session = $session;
54
    }
55
56
57
    /**
58
     * Main index
59
     *
60
     * @param \Symfony\Component\HttpFoundation\Request $request The current request.
61
     *
62
     * @return \SimpleSAML\XHTML\Template
63
     */
64
    public function main(Request $request): Template
65
    {
66
        /* Load simpleSAMLphp, configuration and metadata */
67
        $moduleConfig = Configuration::getConfig('module_metaedit.php');
68
69
        $authsource = $moduleConfig->getValue('auth', 'login-admin');
70
        $useridattr = $moduleConfig->getValue('useridattr', 'eduPersonPrincipalName');
71
72
        $as = new Auth\Simple($authsource);
73
        $as->requireAuth();
74
        $attributes = $as->getAttributes();
75
76
        // Check if userid exists
77
        if (!isset($attributes[$useridattr])) {
78
            throw new Error\Exception('User ID is missing');
79
        }
80
        $userid = $attributes[$useridattr][0];
81
82
        $mdh = new Metadata\MetaDataStorageHandlerSerialize($moduleConfig->getArray('metahandlerConfig', []));
83
84
        $delete = $request->get('delete');
85
        if ($delete !== null) {
86
            $premetadata = $mdh->getMetadata($delete, 'saml20-sp-remote');
87
            $this->requireOwnership($premetadata, $userid);
0 ignored issues
show
Bug introduced by
It seems like $premetadata can also be of type null; however, parameter $metadata of SimpleSAML\Module\metaed...tor::requireOwnership() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

87
            $this->requireOwnership(/** @scrutinizer ignore-type */ $premetadata, $userid);
Loading history...
88
            $mdh->deleteMetadata($delete, 'saml20-sp-remote');
89
        }
90
91
        $list = $mdh->getMetadataSet('saml20-sp-remote');
92
93
        $slist = ['mine' => [], 'others' => []];
94
        foreach ($list as $listitem) {
95
            if (array_key_exists('owner', $listitem)) {
96
                if ($listitem['owner'] === $userid) {
97
                    $slist['mine'][] = $listitem;
98
                    continue;
99
                }
100
            }
101
            $slist['others'][] = $listitem;
102
        }
103
104
        $t = new Template($this->config, 'metaedit:metalist.twig');
105
        $t->data['metadata'] = $slist;
106
        $t->data['userid'] = $userid;
107
        return $t;
108
    }
109
110
111
    /**
112
     * Editor
113
     *
114
     * @param \Symfony\Component\HttpFoundation\Request $request The current request.
115
     *
116
     * @return \SimpleSAML\XHTML\Template
117
     */
118
    public function edit(Request $request): Template
119
    {
120
        /* Load configuration and metadata */
121
        $moduleConfig = Configuration::getConfig('module_metaedit.php');
122
123
        $authsource = $moduleConfig->getValue('auth', 'login-admin');
124
        $useridattr = $moduleConfig->getValue('useridattr', 'eduPersonPrincipalName');
125
126
        $as = new Auth\Simple($authsource);
127
        $as->requireAuth();
128
129
        $attributes = $as->getAttributes();
130
        // Check if userid exists
131
        if (!isset($attributes[$useridattr])) {
132
            throw new Error\Exception('User ID is missing');
133
        }
134
        $userid = $attributes[$useridattr][0];
135
136
        $entityId = $request->get('entityid');
137
        $xmlMetadata = $request->get('xmlmetadata');
138
139
        $mdh = new Metadata\MetaDataStorageHandlerSerialize($moduleConfig->getArray('metahandlerConfig', []));
140
141
        if ($entityId !== null) {
142
            $metadata = $mdh->getMetadata($entityId, 'saml20-sp-remote');
143
            $this->requireOwnership($metadata, $userid);
0 ignored issues
show
Bug introduced by
It seems like $metadata can also be of type null; however, parameter $metadata of SimpleSAML\Module\metaed...tor::requireOwnership() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

143
            $this->requireOwnership(/** @scrutinizer ignore-type */ $metadata, $userid);
Loading history...
144
        } elseif ($xmlMetadata !== null) {
145
            $xmlUtils = new Utils\XML();
146
            $xmlUtils->checkSAMLMessage($xmlMetadata, 'saml-meta');
147
            $entities = Metadata\SAMLParser::parseDescriptorsString($xmlMetadata);
148
            $entity = array_pop($entities);
149
            $metadata =  $entity->getMetadata20SP();
150
151
            /* Trim metadata endpoint arrays. */
152
            $metadata['AssertionConsumerService'] = [
153
                Utils\Config\Metadata::getDefaultEndpoint(
154
                    $metadata['AssertionConsumerService'],
155
                    [Constants::BINDING_HTTP_POST]
156
                )
157
            ];
158
            $metadata['SingleLogoutService'] = [
159
                Utils\Config\Metadata::getDefaultEndpoint(
160
                    $metadata['SingleLogoutService'],
161
                    [Constants::BINDING_HTTP_REDIRECT]
162
                )
163
            ];
164
        } else {
165
            $metadata = [
166
                'owner' => $userid,
167
            ];
168
        }
169
170
        $editor = new Editor();
171
172
        if ($request->get('submit')) {
173
            $editor->checkForm($request->request->all());
174
            $metadata = $editor->formToMeta($request->request->all(), [], ['owner' => $userid]);
175
            $wasEntityId = $request->get('was-entityid');
176
            if (($wasEntityId !== null) && ($wasEntityId !== $metadata['entityid'])) {
177
                $premetadata = $mdh->getMetadata($wasEntityId, 'saml20-sp-remote');
178
                $this->requireOwnership($premetadata, $userid);
179
                $mdh->deleteMetadata($wasEntityId, 'saml20-sp-remote');
180
            }
181
182
            $testmetadata = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $testmetadata is dead and can be removed.
Loading history...
183
            try {
184
                $testmetadata = $mdh->getMetadata($metadata['entityid'], 'saml20-sp-remote');
185
            } catch (Exception $e) {
186
                // catch
187
            }
188
189
            if ($testmetadata) {
190
                $this->requireOwnership($testmetadata, $userid);
191
            }
192
193
            $result = $mdh->saveMetadata($metadata['entityid'], 'saml20-sp-remote', $metadata);
194
            if ($result === false) {
195
                throw new Error\Exception("Could not save metadata. See log for details");
196
            }
197
198
            return new Template($this->config, 'metaedit:saved.twig');
199
        }
200
201
        $form = $editor->metaToForm($metadata);
202
203
        $t = new Template($this->config, 'metaedit:formedit.twig');
204
        $t->data['form'] = $form;
205
        $t->send();
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return SimpleSAML\XHTML\Template. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
206
    }
207
208
209
    /**
210
     * Importer
211
     *
212
     * @param \Symfony\Component\HttpFoundation\Request $request The current request.
213
     *
214
     * @return \SimpleSAML\XHTML\Template
215
     */
216
    public function import(Request $request): Template
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

216
    public function import(/** @scrutinizer ignore-unused */ Request $request): Template

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
217
    {
218
        /* Load simpleSAMLphp, configuration and metadata */
219
        return new Template($this->config, 'metaedit:xmlimport.twig');
220
    }
221
222
223
    /**
224
     * @param array $metadata
225
     * @param string $userid
226
     * @return void
227
     */
228
    private function requireOwnership(array $metadata, string $userid): void
229
    {
230
        if (!isset($metadata['owner'])) {
231
            throw new Exception('Metadata has no owner. Which means no one is granted access, not even you.');
232
        }
233
234
        if ($metadata['owner'] !== $userid) {
235
            throw new Exception(
236
                'Metadata has an owner that is not equal to your userid, hence you are not granted access.'
237
            );
238
        }
239
    }
240
}
241