Passed
Push — release_2_0 ( db561b...cc9048 )
by Tomasz
10:42
created

Device_XML::innerAuth()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 16
dl 0
loc 27
rs 9.4222
c 1
b 1
f 0
cc 5
nc 5
nop 1
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 44 and the first side effect is on line 34.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/*
3
 * *****************************************************************************
4
 * Contributions to this work were made on behalf of the GÉANT project, a 
5
 * project that has received funding from the European Union’s Framework 
6
 * Programme 7 under Grant Agreements No. 238875 (GN3) and No. 605243 (GN3plus),
7
 * Horizon 2020 research and innovation programme under Grant Agreements No. 
8
 * 691567 (GN4-1) and No. 731122 (GN4-2).
9
 * On behalf of the aforementioned projects, GEANT Association is the sole owner
10
 * of the copyright in all material which was developed by a member of the GÉANT
11
 * project. GÉANT Vereniging (Association) is registered with the Chamber of 
12
 * Commerce in Amsterdam with registration number 40535155 and operates in the 
13
 * UK as a branch of GÉANT Vereniging.
14
 * 
15
 * Registered office: Hoekenrode 3, 1102BR Amsterdam, The Netherlands. 
16
 * UK branch address: City House, 126-130 Hills Road, Cambridge CB2 1PQ, UK
17
 *
18
 * License: see the web/copyright.inc.php file in the file structure or
19
 *          <base_url>/copyright.php after deploying the software
20
 */
21
22
/**
23
 * This file defines an abstract class used for generic XML
24
 * devices
25
 * actual modules only define available EAP types.
26
 *
27
 * @author Maja Gorecka-Wolniewicz <[email protected]>
28
 * @author Tomasz Wolniewicz <[email protected]>
29
 *
30
 * @package ModuleWriting
31
 */
32
namespace devices\xml;
33
use Exception;
34
require_once dirname(__FILE__) . '/XML.inc.php';
35
36
/**
37
 * This class implements full functionality of the generic XML device
38
 * the only fuction of the extenstions of this class is to specify
39
 * supported EAP methods.
40
 * Instead of specifying supported EAPS an extension can set $all_eaps to true
41
 * this will cause the installer to configure all EAP methods supported by 
42
 * the current profile and declared by the given device.
43
 */
44
abstract class Device_XML extends \core\DeviceConfig {
0 ignored issues
show
Coding Style introduced by
This class is not in CamelCase format.

Classes in PHP are usually named in CamelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. The whole name starts with a capital letter as well.

Thus the name database provider becomes DatabaseProvider.

Loading history...
45
46
    /**
47
     * construct the device
48
     */
49
    public function __construct() {
50
        parent::__construct();
51
    }
52
53
    /**
54
     * $lang_scope can be 'global' wheb all lang and all lang-specific information
55
     * is dumped or 'single' when only the selected lang (and defaults) are passed
56
     * NOTICE: 'global' is not yet supported
57
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @var tag in member variable comment
Loading history...
58
    public $langScope;
59
    public $allEaps = FALSE;
0 ignored issues
show
Coding Style Documentation introduced by
Missing member variable doc comment
Loading history...
60
    public $VendorSpecific;
0 ignored issues
show
Coding Style Documentation introduced by
Missing member variable doc comment
Loading history...
61
    /**
62
     * A flag to penable correct handling if TTLS-MSCHAP
63
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @var tag in member variable comment
Loading history...
64
    public $eduroamCATcompatibility = TRUE; 
65
    /**
66
     * create HTML code explaining the installer
67
     * 
68
     * @return string
69
     */
70
    public function writeDeviceInfo() {
71
        \core\common\Entity::intoThePotatoes();
72
        $out = "<p>";
73
        $out .= sprintf(_("This is a generic configuration file in the IETF <a href='%s'>EAP Metadata -00</a> XML format."), "https://tools.ietf.org/html/draft-winter-opsawg-eap-metadata-00");
74
        \core\common\Entity::outOfThePotatoes();
75
        return $out;
76
    }
77
78
    /**
79
     * create the actual XML file
80
     * 
81
     * @return string filename of the generated installer
82
     *
83
     */
0 ignored issues
show
Coding Style Documentation introduced by
Missing @throws tag in function comment
Loading history...
84
    public function writeInstaller() {
85
        $attr = $this->attributes;
86
        $NAMESPACE = 'urn:RFC4282:realm';
87
//EAPIdentityProvider  begin
88
        $eapIdp = new EAPIdentityProvider();
89
        $eapIdp->setProperty('CredentialApplicability', $this->getCredentialApplicability());
90
//    $eap_idp->setProperty('ValidUntil',$this->getValidUntil());
91
// ProviderInfo->
92
        $eapIdp->setProperty('ProviderInfo', $this->getProviderInfo());
93
// TODO    $eap_idp->setProperty('VendorSpecific',$this->getVendorSpecific());
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
94
//AuthenticationMethods
95
// TODO
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
96
//ID attribute
97
//lang attribute
98
        $methodList = [];
99
        if ($this->allEaps) {
100
            $eapmethods = [];
101
            foreach ($attr['all_eaps'] as $eap) {
102
                $eapRep = $eap->getArrayRep();
103
                if (in_array($eapRep, $this->supportedEapMethods)) {
104
                    $eapmethods[] = $eapRep;
105
                }
106
            }
107
        } else {
108
            $eapmethods = [$this->selectedEap];
109
        }
110
        foreach ($eapmethods as $eap) {
111
            $methodList[] = $this->getAuthMethod($eap);
112
        }
113
        $authMethods = new AuthenticationMethods();
114
        $authMethods->setProperty('AuthenticationMethods', $methodList);
115
        $eapIdp->setProperty('AuthenticationMethods', $authMethods);
116
        if (empty($attr['internal:realm'][0])) {
117
            $eapIdp->setAttribute('ID', 'undefined');
118
            $eapIdp->setAttribute('namespace', 'urn:undefined');
119
        } else {
120
            $eapIdp->setAttribute('ID', $attr['internal:realm'][0]);
121
            $eapIdp->setAttribute('namespace', $NAMESPACE);
122
        }
123
        if ($this->langScope === 'single') {
124
            $eapIdp->setAttribute('lang', $this->languageInstance->getLang());
125
        }
126
        $eapIdp->setAttribute('version', '1');
127
128
129
// EAPIdentityProvider end
130
// Generate XML
131
132
        $rootname = 'EAPIdentityProviderList';
133
        $root = new \SimpleXMLElement("<?xml version=\"1.0\" encoding=\"utf-8\" ?><{$rootname} xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"eap-metadata.xsd\"></{$rootname}>");
134
135
        marshalObject($root, $eapIdp);
136
        $dom = dom_import_simplexml($root)->ownerDocument;
137
        //TODO schema validation makes sense so probably should be used
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
138
        if ($dom->schemaValidate(ROOT . '/devices/xml/eap-metadata.xsd') === FALSE) {
139
            throw new Exception("Schema validation failed for eap-metadata");
140
        }
141
        file_put_contents($this->installerBasename . '.eap-config', $dom->saveXML());
142
        return($this->installerBasename . '.eap-config');
143
    }
144
145
    private $AttributeNames = [
0 ignored issues
show
Coding Style Documentation introduced by
Missing member variable doc comment
Loading history...
146
        'support:email' => 'EmailAddress',
147
        'support:url' => 'WebAddress',
148
        'support:phone' => 'Phone',
149
        'profile:description' => 'Description',
150
        'support:info_file' => 'TermsOfUse',
151
        'general:logo_file' => 'ProviderLogo',
152
    ];
153
154
    /**
155
     * 
156
     * @param string $attrName
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
157
     * @return array of values for this attribute
158
     */
159
    private function getSimpleMLAttribute($attrName) {
160
        if (empty($this->attributes[$attrName][0])) {
161
            return([]);
162
        }
163
        $attributeList = $this->attributes[$attrName];
164
        if (!isset($this->AttributeNames[$attrName])) {
165
            $this->loggerInstance->debug(4, "Missing class definition for $attrName\n");
166
            return([]);
167
        }
168
        $className = "\devices\xml\\" . $this->AttributeNames[$attrName];
169
        $objs = [];
170
        if ($this->langScope === 'global') {
171
            foreach ($attributeList['langs'] as $language => $value) {
172
                $language = ($language === 'C' ? 'any' : $language);
173
                $obj = new $className();
174
                $obj->setValue($value);
175
                $obj->setAttributes(['lang' => $language]);
176
                $objs[] = $obj;
177
            }
178
        } else {
179
            $obj = new $className();
180
            $obj->setValue($attributeList[0]);
181
            $objs[] = $obj;
182
        }
183
        return($objs);
184
    }
185
186
    private function getDisplayName() {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
187
        $attr = $this->attributes;
188
        $objs = [];
189
        if ($this->langScope === 'global') {
190
            $instNameLangs = $attr['general:instname']['langs'];
191
            if ($attr['internal:profile_count'][0] > 1) {
192
                $profileNameLangs = $attr['profile:name']['langs'];
193
            }
194
            foreach ($instNameLangs as $language => $value) {
195
                $language = ($language === 'C' ? 'any' : $language);
196
                $displayname = new DisplayName();
197
                if (isset($profileNameLangs)) {
198
                    $langOrC = isset($profileNameLangs[$language]) ? $profileNameLangs[$language] : $profileNameLangs['C'];
199
                    $value .= ' - ' . $langOrC;
200
                }
201
                $displayname->setValue($value);
202
                $displayname->setAttributes(['lang' => $language]);
203
                $objs[] = $displayname;
204
            }
205
        } else {
206
            $displayname = new DisplayName();
207
            $value = $attr['general:instname'][0];
208
            if ($attr['internal:profile_count'][0] > 1) {
209
                $value .= ' - ' . $attr['profile:name'][0];
210
            }
211
            $displayname->setValue($value);
212
            $objs[] = $displayname;
213
        }
214
        return $objs;
215
    }
216
217
    private function getProviderLogo() {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
218
        $attr = $this->attributes;
219
        if (isset($attr['general:logo_file'][0])) {
220
            $logoString = base64_encode($attr['general:logo_file'][0]);
221
            $logoMime = 'image/' . $attr['internal:logo_file'][0]['mime'];
222
            $providerlogo = new ProviderLogo();
223
            $providerlogo->setAttributes(['mime' => $logoMime, 'encoding' => 'base64']);
224
            $providerlogo->setValue($logoString);
225
            return $providerlogo;
226
        }
227
    }
228
229
    private function getProviderInfo() {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
230
        $providerinfo = new ProviderInfo();
231
        $providerinfo->setProperty('DisplayName', $this->getDisplayName());
232
        $providerinfo->setProperty('Description', $this->getSimpleMLAttribute('profile:description'));
233
        $providerinfo->setProperty('ProviderLocation', $this->getProvideLocation());
234
        $providerinfo->setProperty('ProviderLogo', $this->getProviderLogo());
235
        $providerinfo->setProperty('TermsOfUse', $this->getSimpleMLAttribute('support:info_file'));
236
        $providerinfo->setProperty('Helpdesk', $this->getHelpdesk());
237
        return $providerinfo;
238
    }
239
240
    private function getProvideLocation() {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
241
        $attr = $this->attributes;
242
        if (isset($attr['general:geo_coordinates'])) {
243
            $attrCoordinates = $attr['general:geo_coordinates'];
244
            if (count($attrCoordinates) > 1) {
245
                $location = [];
246
                foreach ($attrCoordinates as $a) {
247
                    $providerlocation = new ProviderLocation();
248
                    $b = json_decode($a, true);
249
                    $providerlocation->setProperty('Longitude', $b['lon']);
250
                    $providerlocation->setProperty('Latitude', $b['lat']);
251
                    $location[] = $providerlocation;
252
                }
253
            } else {
254
                $providerlocation = new ProviderLocation();
255
                $b = json_decode($attrCoordinates[0], true);
256
                $providerlocation->setProperty('Longitude', $b['lon']);
257
                $providerlocation->setProperty('Latitude', $b['lat']);
258
                $location = $providerlocation;
259
            }
260
            return $location;
261
        }
262
    }
263
264
    private function getHelpdesk() {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
265
        $helpdesk = new Helpdesk();
266
        $helpdesk->setProperty('EmailAddress', $this->getSimpleMLAttribute('support:email'));
267
        $helpdesk->setProperty('WebAddress', $this->getSimpleMLAttribute('support:url'));
268
        $helpdesk->setProperty('Phone', $this->getSimpleMLAttribute('support:phone'));
269
        return $helpdesk;
270
    }
271
272
   private function getCredentialApplicability() {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
273
        $setWired = isset($this->attributes['media:wired'][0]) && 
274
            $this->attributes['media:wired'][0] == 'on' ? 1 : 0;  
275
        $ssids = $this->attributes['internal:SSID'];
276
        $oids = $this->attributes['internal:consortia'];
277
        $credentialapplicability = new CredentialApplicability();
278
        $ieee80211s = [];
279
        foreach ($ssids as $ssid => $ciph) {
280
            $ieee80211 = new IEEE80211();
281
            $ieee80211->setProperty('SSID', $ssid);
282
            $ieee80211->setProperty('MinRSNProto', $ciph == 'AES' ? 'CCMP' : 'TKIP');
283
            $ieee80211s[] = $ieee80211;
284
        }
285
        foreach ($oids as $oid) {
286
            $ieee80211 = new IEEE80211();
287
            $ieee80211->setProperty('ConsortiumOID', $oid);
288
            $ieee80211s[] = $ieee80211;
289
        }
290
        $credentialapplicability->setProperty('IEEE80211', $ieee80211s);
291
        if ($setWired) {
292
            $credentialapplicability->setProperty('IEEE8023', '');
293
        }
294
        return($credentialapplicability);
295
    }
296
    
297
    /**
298
     * determines the inner authentication. Is it EAP, and which mechanism is used to convey actual auth data
299
     * @param array $eap the EAP type for which we want to get the inner auth
300
     * @return array
301
     */
302
    private function innerAuth($eap)
303
    {
304
        $out = [];
305
        $out['EAP'] = 0;
306
        
307
        if ($eap == \core\common\EAP::EAPTYPE_TTLS_MSCHAP2) {
308
            if ($this->eduroamCATcompatibility === TRUE) {
309
                $out['METHOD'] = \core\common\EAP::MSCHAP2;
310
                $out['EAP'] = 1;
311
            } else {
312
                $out['METHOD'] = \core\common\EAP::NE_MSCHAP2;
313
            }
314
            return $out;
315
        }
316
        
317
        if ($eap == \core\common\EAP::EAPTYPE_SILVERBULLET) {
318
            $out['METHOD'] = \core\common\EAP::NONE;
319
            return $out;           
320
        }
321
        
322
        $out['METHOD'] = $eap["INNER"];
323
324
        // override if there is an inner EAP
325
        if ($eap["INNER"] != 0) { // there is an inner EAP method
326
            $out['EAP'] = 1;
327
        }
328
        return $out;
329
    }
330
331
    private function getAuthenticationMethodParams($eap) {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
332
        $inner = $this->innerAuth($eap);
333
        $outerMethod = $eap["OUTER"];
334
335
        if (isset($inner["METHOD"]) && $inner["METHOD"]) {
336
            $innerauthmethod = new InnerAuthenticationMethod();
337
            $typeOfInner = "\devices\xml\\" . ($inner["EAP"] ? 'EAPMethod' : 'NonEAPAuthMethod');
338
            $eapmethod = new $typeOfInner();
339
            $eaptype = new Type();
340
            $eaptype->setValue($inner['METHOD']);
341
            $eapmethod->setProperty('Type', $eaptype);
342
            $innerauthmethod->setProperty($typeOfInner, $eapmethod);
343
            return ['inner_method' => $innerauthmethod, 'methodID' => $outerMethod, 'inner_methodID' => $inner['METHOD']];
344
        } else {
345
            return ['inner_method' => 0, 'methodID' => $outerMethod, 'inner_methodID' => 0];
346
        }
347
    }
348
349
    private function setServerSideCredentials($eaptype) {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
350
        $attr = $this->attributes;
351
        $serversidecredential = new ServerSideCredential();
352
// Certificates and server names
353
        $cAlist = [];
354
        $attrCaList = $attr['internal:CAs'][0];
355
        foreach ($attrCaList as $ca) {
356
            $caObject = new CA();
357
            $caObject->setValue(base64_encode($ca['der']));
358
            $caObject->setAttributes(['format' => 'X.509', 'encoding' => 'base64']);
359
            $cAlist[] = $caObject;
360
        }
361
        $serverids = [];
362
        $servers = $attr['eap:server_name'];
363
        foreach ($servers as $server) {
364
            $serverid = new ServerID();
365
            $serverid->setValue($server);
366
            $serverids[] = $serverid;
367
        }
368
        $serversidecredential->setProperty('EAPType', $eaptype->getValue());
369
        $serversidecredential->setProperty('CA', $cAlist);
370
        $serversidecredential->setProperty('ServerID', $serverids);
371
        return($serversidecredential);
372
    }
373
    
374
    private function setClientSideRealm ($clientsidecredential) {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
375
        $attr = $this->attributes;
376
        $realm = \core\common\Entity::getAttributeValue($attr, 'internal:realm', 0);
377
        if ($realm === NULL) {
378
            return;
379
        }
380
        if (\core\common\Entity::getAttributeValue($attr, 'internal:verify_userinput_suffix', 0) !== 1) {
381
            return;
382
        }
383
        $clientsidecredential->setProperty('InnerIdentitySuffix', $realm);
384
        if (\core\common\Entity::getAttributeValue($attr, 'internal:hint_userinput_suffix', 0) === 1) {
385
            $clientsidecredential->setProperty('InnerIdentityHint', 'true');
386
        }
387
    }
388
    
389
    private function setClientCetificate() {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
390
        $clientCertificateObject = new ClientCertificate();
391
        $clientCertificateObject->setValue(base64_encode($this->clientCert["certdata"]));
392
        $clientCertificateObject->setAttributes(['format' => 'PKCS12', 'encoding' => 'base64']);
393
        return($clientCertificateObject);
394
    }
395
396
    private function setClientSideCredentials($eapParams) {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
397
        $clientsidecredential = new ClientSideCredential();
398
        $outerId = $this->determineOuterIdString();
399
        if ($outerId !== NULL) {
400
            $clientsidecredential->setProperty('OuterIdentity', $outerId);
401
        }
402
        $this->setClientSideRealm($clientsidecredential);
403
        $clientsidecredential->setProperty('EAPType', $eapParams['inner_methodID'] ? $eapParams['inner_methodID'] : $eapParams['methodID']);
404
                
405
        // Client Certificate
406
        if ($this->selectedEap == \core\common\EAP::EAPTYPE_SILVERBULLET) {
407
            $attr = $this->attributes;
408
            $outerId = \core\common\Entity::getAttributeValue($attr, 'internal:username', 0);
409
            $clientsidecredential->setProperty('OuterIdentity', $outerId);
410
            $clientsidecredential->setProperty('ClientCertificate', $this->setClientCetificate());
411
        }
412
        return($clientsidecredential);
413
    }
414
    
415
    private function setEapMethod($eaptype) {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
416
        $eapmethod = new EAPMethod();
417
        $eapmethod->setProperty('Type', $eaptype);
418
        if (isset($this->VendorSpecific)) {
419
            $vendorspecifics = [];
420
            foreach ($this->VendorSpecific as $vs) {
421
                $vendorspecific = new VendorSpecific();
422
                $vs['value']->addAttribute('xsi:noNamespaceSchemaLocation', "xxx.xsd");
423
                $vendorspecific->setValue($vs['value']);
424
                $vendorspecific->setAttributes(['vendor' => $vs['vendor']]);
425
                $vendorspecifics[] = $vendorspecific;
426
            }
427
            $eapmethod->setProperty('VendorSpecific', $vendorspecifics);
428
        }
429
        return($eapmethod);
430
    }
431
    
432
    private function getAuthMethod($eap) {
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
433
 //       $attr = $this->attributes;
434
        $authmethod = new AuthenticationMethod();
435
        $eapParams = $this->getAuthenticationMethodParams($eap);
436
        $eaptype = new Type();
437
        $eaptype->setValue($eapParams['methodID']);
438
// Type
439
        $authmethod->setProperty('EAPMethod', $this->setEapMethod($eaptype));
440
441
// ServerSideCredentials
442
        $authmethod->setProperty('ServerSideCredential', $this->setServerSideCredentials($eaptype));
443
444
// ClientSideCredentials
445
        $authmethod->setProperty('ClientSideCredential', $this->setClientSideCredentials($eapParams));
446
        
447
        if ($eapParams['inner_method']) {
448
            $authmethod->setProperty('InnerAuthenticationMethod', $eapParams['inner_method']);
449
        }
450
        return $authmethod;
451
452
453
    }
454
    
455
456
457
}
458