RealMeSetupTaskTest   A
last analyzed

Complexity

Total Complexity 5

Size/Duplication

Total Lines 273
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 147
c 4
b 0
f 0
dl 0
loc 273
rs 10
wmc 5

4 Methods

Rating   Name   Duplication   Size   Complexity  
A testValidateAuthNContext() 0 34 1
A testConfigurationTemplateDir() 0 34 1
A testEnvironmentValidation() 0 47 2
B testValidateEntityID() 0 101 1
1
<?php
2
3
namespace SilverStripe\RealMe\Tests;
4
5
use ReflectionMethod;
6
use ReflectionProperty;
7
use SilverStripe\Core\Config\Config;
8
use SilverStripe\Core\Injector\Injector;
9
use SilverStripe\Core\Manifest\Module;
10
use SilverStripe\Core\Manifest\ModuleLoader;
11
use SilverStripe\Dev\SapphireTest;
12
use SilverStripe\RealMe\RealMeService;
13
use SilverStripe\RealMe\Task\RealMeSetupTask;
14
use SilverStripe\View\ThemeResourceLoader;
15
16
/**
17
 * Class RealMeSetupTaskTest
18
 * Setup to unit test the Setup task to make sure metadata is being generated correctly.
19
 */
20
class RealMeSetupTaskTest extends SapphireTest
21
{
22
    /**
23
     * Valid entity id's tobe used for context.
24
     * @var array
25
     */
26
    private static $validEntityIDs = array(
27
        RealMeService::ENV_MTS => "https://dev.your-website.govt.nz/p-realm/s-name",
28
        RealMeService::ENV_ITE => 'https://uat.your-website.govt.nz/p-realm/s-name',
29
        RealMeService::ENV_PROD => 'https://www.your-website.govt.nz/p-realm/s-name'
30
    );
31
32
    private static $authnEnvContexts = array(
33
        RealMeService::ENV_MTS => 'urn:nzl:govt:ict:stds:authn:deployment:GLS:SAML:2.0:ac:classes:LowStrength',
34
        RealMeService::ENV_ITE => 'urn:nzl:govt:ict:stds:authn:deployment:GLS:SAML:2.0:ac:classes:LowStrength',
35
        RealMeService::ENV_PROD => 'urn:nzl:govt:ict:stds:authn:deployment:GLS:SAML:2.0:ac:classes:LowStrength'
36
    );
37
38
    private static $metadata_assertion_urls = array(
0 ignored issues
show
introduced by
The private property $metadata_assertion_urls is not used, and could be removed.
Loading history...
39
        RealMeService::ENV_MTS => "https://dev.your-website.govt.nz/",
40
        RealMeService::ENV_ITE => "https://staging.your-website.govt.nz/",
41
        RealMeService::ENV_PROD => "https://www.your-website.govt.nz/"
42
    );
43
44
    /**
45
     * We need to make sure that if an invalid environment, it raises the correct errors for correction.
46
     * - invalid environment
47
     * - no environment
48
     *
49
     * We must also not raise an error if we pass a correctly configured environment.
50
     */
51
    public function testEnvironmentValidation()
52
    {
53
        // Setup our objects for testing through reflection
54
        $realMeService = new RealMeService();
55
        $realMeSetupTask = new RealMeSetupTask();
56
57
        $errors = new ReflectionProperty($realMeSetupTask, 'errors');
58
        $errors->setAccessible(true);
59
60
        $service = new ReflectionProperty($realMeSetupTask, 'service');
61
        $service->setAccessible(true);
62
        $service->setValue($realMeSetupTask, $realMeService);
63
64
        // Make sure there's no errors to begin.
65
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
66
67
        // Test: Make an error
68
        $invalidEnv = "wrong-environment";
69
        $validateEnvironments = new ReflectionMethod($realMeSetupTask, 'validateRealMeEnvironments');
70
        $validateEnvironments->setAccessible(true);
71
        $validateEnvironments->invoke($realMeSetupTask, $invalidEnv);
72
        $this->assertCount(1, $errors->getValue($realMeSetupTask), "An invalid environment should raise an error");
73
74
        // reset errors & Make sure there's no errors to begin.
75
        $errors->setValue($realMeSetupTask, array());
76
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
77
78
        // Test: No environment passed
79
        $noEnvironment = null;
80
        $validateEnvironments = new ReflectionMethod($realMeSetupTask, 'validateRealMeEnvironments');
81
        $validateEnvironments->setAccessible(true);
82
        $validateEnvironments->invoke($realMeSetupTask, $noEnvironment);
83
        $this->assertCount(1, $errors->getValue($realMeSetupTask), "Missing environment should raise an error");
84
85
        // reset errors &&  Make sure there's no errors to begin.
86
        $errors->setValue($realMeSetupTask, array());
87
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
88
89
        // Test: allowed environments pass without error.
90
        $reflectionMethod = new ReflectionMethod($realMeService, 'getAllowedRealMeEnvironments');
91
        $reflectionMethod->setAccessible(true);
92
        foreach ($reflectionMethod->invoke($realMeService) as $validEnvironment) {
93
            $validateEnvironments->invoke($realMeSetupTask, $validEnvironment);
94
        }
95
96
        // Make sure there's no errors, they should all be valid
97
        $this->assertCount(0, $errors->getValue($realMeSetupTask), "valid environments should not raise an error");
98
    }
99
100
    /**
101
     * We need to make sure that there is an entity ID and that it's in the correct format for realme consumption
102
     * - It's present in the config
103
     * - it's not localhost
104
     * - it's not http (must be https)
105
     * - service name and privacy realm < 10 char.
106
     */
107
    public function testValidateEntityID()
108
    {
109
        $realMeService = new RealMeService();
110
        $realMeSetupTask = new RealMeSetupTask();
111
112
        $errors = new ReflectionProperty($realMeSetupTask, 'errors');
113
        $errors->setAccessible(true);
114
115
        $service = new ReflectionProperty($realMeSetupTask, 'service');
116
        $service->setAccessible(true);
117
        $service->setValue($realMeSetupTask, $realMeService);
118
119
        // Make sure there's no errors to begin.
120
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
121
122
        // Test valid entityIds just in case they're different in this configuration.
123
        $config = Config::inst();
124
        $config->update(RealMeService::class, 'sp_entity_ids', self::$validEntityIDs);
0 ignored issues
show
Bug introduced by
The method update() does not exist on SilverStripe\Config\Coll...nfigCollectionInterface. It seems like you code against a sub-type of SilverStripe\Config\Coll...nfigCollectionInterface such as SilverStripe\Config\Coll...\MemoryConfigCollection. ( Ignorable by Annotation )

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

124
        $config->/** @scrutinizer ignore-call */ 
125
                 update(RealMeService::class, 'sp_entity_ids', self::$validEntityIDs);
Loading history...
125
126
        // validate our list of valid entity IDs;
127
        $validateEntityId = new ReflectionMethod($realMeSetupTask, 'validateEntityID');
128
        $validateEntityId->setAccessible(true);
129
        $validateEntityId->invoke($realMeSetupTask, 'mts');
130
131
        // valid entityID's shouldn't have any issues
132
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
133
134
        // TEST entityId missing.
135
        $entityIdList = self::$validEntityIDs;
136
        $entityIdList[RealMeService::ENV_MTS] = 'destroy-humans-with-incorrect-entity-ids';
137
        $config->update(RealMeService::class, 'sp_entity_ids', $entityIdList);
138
        $validateEntityId->invoke($realMeSetupTask, 'mts');
139
        $this->assertCount(1, $errors->getValue($realMeSetupTask), 'validate entity id should fail for an invalid url');
140
141
        // reset errors &&  Make sure there's no errors to begin.
142
        $errors->setValue($realMeSetupTask, array());
143
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
144
145
        // TEST entityId localhost.
146
        $entityIdList = self::$validEntityIDs;
147
        $entityIdList[RealMeService::ENV_MTS] = 'https://localhost/';
148
        $config->update(RealMeService::class, 'sp_entity_ids', $entityIdList);
149
        $validateEntityId->invoke($realMeSetupTask, 'mts');
150
        $this->assertCount(1, $errors->getValue($realMeSetupTask), 'validate entity id should fail for localhost');
151
152
        $errors->setValue($realMeSetupTask, array());
153
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
154
155
        // TEST entityId not http
156
        $entityIdList = self::$validEntityIDs;
157
        $entityIdList[RealMeService::ENV_MTS] = 'http://dev.realme-integration.govt.nz/p-realm/s-name';
158
        $config->update(RealMeService::class, 'sp_entity_ids', $entityIdList);
159
        $validateEntityId->invoke($realMeSetupTask, 'mts');
160
        $this->assertCount(1, $errors->getValue($realMeSetupTask), 'validate entity id should fail for http');
161
162
        $errors->setValue($realMeSetupTask, array());
163
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
164
165
        // TEST privacy realm /service name  missing
166
        $entityIdList = self::$validEntityIDs;
167
        $entityIdList[RealMeService::ENV_MTS] = 'https://dev.realme-integration.govt.nz/';
168
        $config->update(RealMeService::class, 'sp_entity_ids', $entityIdList);
169
        $validateEntityId->invoke($realMeSetupTask, 'mts');
170
        $this->assertCount(
171
            2,
172
            $errors->getValue($realMeSetupTask),
173
            'validate entity id should fail for missing service name and privacy realm'
174
        );
175
176
        $errors->setValue($realMeSetupTask, array());
177
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
178
179
        // TEST privacy realm
180
        // "https://www.domain.govt.nz/<privacy-realm>/<service-name>"
181
        $entityIdList = self::$validEntityIDs;
182
        $entityIdList[RealMeService::ENV_MTS] =
183
            'https://dev.realme-integration.govt.nz/s-name/privacy-realm-is-too-big';
184
        $config->update(RealMeService::class, 'sp_entity_ids', $entityIdList);
185
        $validateEntityId->invoke($realMeSetupTask, 'mts');
186
        $this->assertCount(
187
            1,
188
            $errors->getValue($realMeSetupTask),
189
            'validate entity id should fail for privacy-realm-is-too-big'
190
        );
191
192
        $errors->setValue($realMeSetupTask, array());
193
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
194
195
        // "https://www.domain.govt.nz/<privacy-realm>/<service-name>"
196
        $entityIdList = self::$validEntityIDs;
197
        $entityIdList[RealMeService::ENV_MTS] = 'https://dev.realme-integration.govt.nz/s-name';
198
        $config->update(RealMeService::class, 'sp_entity_ids', $entityIdList);
199
        $validateEntityId->invoke($realMeSetupTask, 'mts');
200
        $this->assertCount(
201
            1,
202
            $errors->getValue($realMeSetupTask),
203
            'validate entity id should fail if privacy realm is missing'
204
        );
205
206
        $errors->setValue($realMeSetupTask, array());
207
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
208
    }
209
210
211
    /**
212
     * We require an authn context for each environment to determine how secure to ask realme to validate.
213
     * - it should be present for each environment, and one of four pre-determined authncontexts.
214
     */
215
    public function testValidateAuthNContext()
216
    {
217
        $realMeService = new RealMeService();
218
        $realMeSetupTask = new RealMeSetupTask();
219
220
        $errors = new ReflectionProperty($realMeSetupTask, 'errors');
221
        $errors->setAccessible(true);
222
223
        $service = new ReflectionProperty($realMeSetupTask, 'service');
224
        $service->setAccessible(true);
225
        $service->setValue($realMeSetupTask, $realMeService);
226
227
        // Make sure there's no errors to begin.
228
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
229
230
        // Test valid authnContexts just in case they're different in this configuration.
231
        $config = Config::inst();
232
        $config->update(RealMeService::class, 'authn_contexts', self::$authnEnvContexts);
233
234
        // validate our list of valid entity IDs;
235
        $validateAuthNContext = new ReflectionMethod($realMeSetupTask, 'validateAuthNContext');
236
        $validateAuthNContext->setAccessible(true);
237
        $validateAuthNContext->invoke($realMeSetupTask);
238
        $this->assertCount(0, $errors->getValue($realMeSetupTask));
239
240
        $invalidAuthNContextList = self::$authnEnvContexts;
241
        $invalidAuthNContextList[RealMeService::ENV_MTS] = 'im-an-invalid-context';
242
        $config->update(RealMeService::class, 'authn_contexts', $invalidAuthNContextList);
243
244
        $validateAuthNContext->invoke($realMeSetupTask);
245
        $this->assertCount(
246
            1,
247
            $errors->getValue($realMeSetupTask),
248
            "The authncontext validation should fail if invalid."
249
        );
250
    }
251
252
    /**
253
     * Ensure that setting the RealMeSetupTask template_config_dir config value
254
     * can adjust the path that the task looks in for its templates.
255
     * - ensure the default works
256
     * - ensure configuring a bad directory name falls back to the default
257
     * - ensure that configuring a good value uses the configured directory
258
     */
259
    public function testConfigurationTemplateDir()
260
    {
261
        /** @var Module $module */
262
        $module = ModuleLoader::inst()->getManifest()->getModule('realme');
263
        $fullPath = $module->getPath();
264
        $relativePath = $module->getRelativePath();
265
266
        $realMeSetupTask = new RealMeSetupTask();
267
268
        $getConfigurationTemplateDirMethod =
269
            new ReflectionMethod(RealMeSetupTask::class, 'getConfigurationTemplateDir');
270
        $getConfigurationTemplateDirMethod->setAccessible(true);
271
272
        $config = Config::inst();
273
274
        $config->update(RealMeSetupTask::class, 'template_config_dir', '');
275
        $this->assertEquals(
276
            $fullPath . '/templates/saml-conf',
277
            $getConfigurationTemplateDirMethod->invoke($realMeSetupTask),
278
            'Using no configuration for template_config_dir should use the default template directory.'
279
        );
280
281
        $config->update(RealMeSetupTask::class, 'template_config_dir', 'xyzzy');
282
        $this->assertEquals(
283
            $fullPath . '/templates/saml-conf',
284
            $getConfigurationTemplateDirMethod->invoke($realMeSetupTask),
285
            'Configuring a directory that does not exist should use the default template directory.'
286
        );
287
288
        $config->update(RealMeSetupTask::class, 'template_config_dir', $relativePath . '/tests');
289
        $this->assertEquals(
290
            $fullPath . '/tests', // doesn't contain templates, but does exist
291
            $getConfigurationTemplateDirMethod->invoke($realMeSetupTask),
292
            'Configuring a directory that exists should use the configured template directory.'
293
        );
294
    }
295
}
296