Passed
Push — master ( 17bffe...10bee5 )
by Stefan
06:13
created

Device_XML::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 2
c 0
b 0
f 0
rs 10
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
/* 
3
 *******************************************************************************
4
 * Copyright 2011-2017 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 
5
 * and GN4-2 consortia
6
 *
7
 * License: see the web/copyright.php file in the file structure
8
 *******************************************************************************
9
 */
10
11
/**
12
 * This file defines an abstract class used for generic XML
13
 * devices
14
 * actual modules only define available EAP types.
15
 *
16
 * @author Maja Gorecka-Wolniewicz <[email protected]>
17
 * @author Tomasz Wolniewicz <[email protected]>
18
 *
19
 * @package ModuleWriting
20
 */
21
namespace devices\xml;
22
require_once(dirname(__FILE__).'/XML.inc.php');
23
24
/**
25
 * This class implements full functionality of the generic XML device
26
 * the only fuction of the extenstions of this class is to specify
27
 * supported EAP methods.
28
 * Instead of specifying supported EAPS an extension can set $all_eaps to true
29
 * this will cause the installer to configure all EAP methods supported by 
30
 * the current profile and declared by the given device.
31
 */
32
abstract class Device_XML extends \core\DeviceConfig {
33
34
    public function __construct() {
35
        parent::__construct();
36
    }
37
38
    /**
39
     * $lang_scope can be 'global' wheb all lang and all lang-specific information
40
     * is dumped or 'single' when only the selected lang (and defaults) are passed
41
     * NOTICE: 'global' is not yet supported
42
     */
43
    public $langScope;
44
    public $allEaps = FALSE;
45
    public $VendorSpecific;
46
47
    public function writeDeviceInfo() {
48
        $out = "<p>";
49
        $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");
50
        return $out;
51
    }
52
53
    public function writeInstaller() {
54
        $attr = $this->attributes;
55
        $NAMESPACE = 'urn:RFC4282:realm';
56
//EAPIdentityProvider  begin
57
        $eapIdp = new EAPIdentityProvider();
58
//    $eap_idp->setProperty('ValidUntil',$this->getValidUntil());
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
59
// ProviderInfo->
60
        $eapIdp->setProperty('ProviderInfo', $this->getProviderInfo());
61
// TODO    $eap_idp->setProperty('VendorSpecific',$this->getVendorSpecific());
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
62
//AuthenticationMethods
63
// TODO
64
//ID attribute
65
//lang attribute
66
        $methodList = [];
67
        if ($this->allEaps) {
68
            $eapmethods = [];
69
            foreach ($attr['all_eaps'] as $eap) {
70
                if (in_array($eap, $this->supportedEapMethods)) {
71
                    $eapmethods[] = $eap;
72
                }
73
            }
74
        } else {
75
            $eapmethods = [$this->selectedEap];
76
        }
77
78
        foreach ($eapmethods as $eap) {
79
            $methodList[] = $this->getAuthMethod($eap);
80
        }
81
        $authMethods = new AuthenticationMethods();
82
        $authMethods->setProperty('AuthenticationMethods', $methodList);
83
        $eapIdp->setProperty('AuthenticationMethods', $authMethods);
84
        if (empty($attr['internal:realm'][0])) {
85
            $eapIdp->setAttribute('ID', 'undefined');
86
            $eapIdp->setAttribute('namespace', 'urn:undefined');
87
        } else {
88
            $eapIdp->setAttribute('ID', $attr['internal:realm'][0]);
89
            $eapIdp->setAttribute('namespace', $NAMESPACE);
90
        }
91
        if ($this->langScope === 'single') {
92
            $eapIdp->setAttribute('lang', $this->languageInstance->getLang());
93
        }
94
        $eapIdp->setAttribute('version', '1');
95
96
97
// EAPIdentityProvider end
98
// Generate XML
99
100
        $rootname = 'EAPIdentityProviderList';
101
        $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}>");
102
103
        marshalObject($root, $eapIdp);
104
        $dom = dom_import_simplexml($root)->ownerDocument;
105
        //TODO schema validation makes sense so probably should be used
106
        $res = $dom->schemaValidate(ROOT . '/devices/xml/eap-metadata.xsd');
0 ignored issues
show
Unused Code introduced by
The assignment to $res is dead and can be removed.
Loading history...
107
        file_put_contents($this->installerBasename . '.eap-config', $dom->saveXML());
108
        return($this->installerBasename . '.eap-config');
109
    }
110
111
    private $AttributeNames = [
112
        'support:email' => 'EmailAddress',
113
        'support:url' => 'WebAddress',
114
        'support:phone' => 'Phone',
115
        'profile:description' => 'Description',
116
        'support:info_file' => 'TermsOfUse',
117
        'general:logo_file' => 'ProviderLogo',
118
    ];
119
120
    private function getSimpleAttribute($attrName) {
0 ignored issues
show
Unused Code introduced by
The method getSimpleAttribute() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
121 View Code Duplication
        if ((!isset($this->attributes[$attrName][0]) || !$this->attributes[$attrName][0])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
122
            return '';
123
        }
124
125
        $attributeList = $this->attributes[$attrName];
126
        if (!isset($this->AttributeNames[$attrName])) {
127
            $this->loggerInstance->debug(4, "Missing class definition for $attrName\n");
128
            return;
129
        }
130
        $className = $this->AttributeNames[$attrName];
131
        $obj = new $className();
132
        $obj->setValue($attributeList[0]);
133
        return($obj);
134
    }
135
136
    /**
137
     * 
138
     * @param string $attrName
139
     * @return array of values for this attribute
140
     */
141
    private function getSimpleMLAttribute($attrName) {
142 View Code Duplication
        if ((!isset($this->attributes[$attrName][0]) || !$this->attributes[$attrName][0])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
143
            return '';
0 ignored issues
show
Bug Best Practice introduced by
The expression return '' returns the type string which is incompatible with the documented return type array.
Loading history...
144
        }
145
146
        $attributeList = $this->attributes[$attrName];
147
        if (!isset($this->AttributeNames[$attrName])) {
148
            $this->loggerInstance->debug(4, "Missing class definition for $attrName\n");
149
            return;
150
        }
151
        $className = "\devices\xml\\" . $this->AttributeNames[$attrName];
152
        $objs = [];
153
        if ($this->langScope === 'global') {
154
            foreach ($attributeList['langs'] as $language => $value) {
155
                $language = ( $language === 'C' ? 'any' : $language );
156
                $obj = new $className();
157
                $obj->setValue($value);
158
                $obj->setAttributes(['lang' => $language]);
159
                $objs[] = $obj;
160
            }
161
        } else {
162
            $obj = new $className();
163
            $obj->setValue($attributeList[0]);
164
            $objs[] = $obj;
165
        }
166
167
        return($objs);
168
    }
169
170
    private function getDisplayName() {
171
        $attr = $this->attributes;
172
        $objs = [];
173
        if ($this->langScope === 'global') {
174
            $instNameLangs = $attr['general:instname']['langs'];
175
            if ($attr['internal:profile_count'][0] > 1) {
176
                $profileNameLangs = $attr['profile:name']['langs'];
177
            }
178
            foreach ($instNameLangs as $language => $value) {
179
                $language = ( $language === 'C' ? 'any' : $language );
180
                $displayname = new DisplayName();
181
                if (isset($profileNameLangs)) {
182
                    $langOrC = isset($profileNameLangs[$language]) ? $profileNameLangs[$language] : $profileNameLangs['C'];
183
                    $value .= ' - ' . $langOrC;
184
                }
185
                $displayname->setValue($value);
186
                $displayname->setAttributes(['lang' => $language]);
187
                $objs[] = $displayname;
188
            }
189
        } else {
190
            $displayname = new DisplayName();
191
            $value = $attr['general:instname'][0];
192
            if ($attr['internal:profile_count'][0] > 1) {
193
                $value .= ' - ' . $attr['profile:name'][0];
194
            }
195
            $displayname->setValue($value);
196
            $objs[] = $displayname;
197
        }
198
        return $objs;
199
    }
200
201
    private function getProviderLogo() {
202
        $attr = $this->attributes;
203
        if (isset($attr['general:logo_file'][0])) {
204
            $logoString = base64_encode($attr['general:logo_file'][0]);
205
            $logoMime = 'image/' . $attr['internal:logo_file'][0]['mime'];
206
            $providerlogo = new ProviderLogo();
207
            $providerlogo->setAttributes(['mime' => $logoMime, 'encoding' => 'base64']);
208
            $providerlogo->setValue($logoString);
209
            return $providerlogo;
210
        }
211
    }
212
213
    private function getProviderInfo() {
214
        $providerinfo = new ProviderInfo();
215
        $providerinfo->setProperty('DisplayName', $this->getDisplayName());
216
        $providerinfo->setProperty('Description', $this->getSimpleMLAttribute('profile:description'));
217
        $providerinfo->setProperty('ProviderLocation', $this->getProvideLocation());
218
        $providerinfo->setProperty('ProviderLogo', $this->getProviderLogo());
219
        $providerinfo->setProperty('TermsOfUse', $this->getSimpleMLAttribute('support:info_file'));
220
        $providerinfo->setProperty('Helpdesk', $this->getHelpdesk());
221
        return $providerinfo;
222
    }
223
224
    private function getProvideLocation() {
225
        $attr = $this->attributes;
226
        if (isset($attr['general:geo_coordinates'])) {
227
            $attrCoordinates = $attr['general:geo_coordinates'];
228
            if (count($attrCoordinates) > 1) {
229
                $location = [];
230
                foreach ($attrCoordinates as $a) {
231
                    $providerlocation = new ProviderLocation();
232
                    $b = json_decode($a, true);
233
                    $providerlocation->setProperty('Longitude', $b['lon']);
234
                    $providerlocation->setProperty('Latitude', $b['lat']);
235
                    $location[] = $providerlocation;
236
                }
237
            } else {
238
                $providerlocation = new ProviderLocation();
239
                $b = json_decode($attrCoordinates[0], true);
240
                $providerlocation->setProperty('Longitude', $b['lon']);
241
                $providerlocation->setProperty('Latitude', $b['lat']);
242
                $location = $providerlocation;
243
            }
244
            return $location;
245
        }
246
    }
247
248
    private function getHelpdesk() {
249
        $helpdesk = new Helpdesk();
250
        $helpdesk->setProperty('EmailAddress', $this->getSimpleMLAttribute('support:email'));
251
        $helpdesk->setProperty('WebAddress', $this->getSimpleMLAttribute('support:url'));
252
        $helpdesk->setProperty('Phone', $this->getSimpleMLAttribute('support:phone'));
253
        return $helpdesk;
254
    }
255
256
/* This function is not currently used.
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
257
 * 
258
 *     private function getCompatibleUses() {
259
        $ssids = $this->attributes['internal:SSID'];
260
        $compatibleuses = new CompatibleUses();
261
        $ieee80211s = [];
262
        foreach ($ssids as $ssid => $ciph) {
263
            $ieee80211 = new IEEE80211();
264
            $ieee80211->setProperty('SSID', $ssid);
265
            $ieee80211->setProperty('MinRSNProto', $ciph == 'AES' ? 'CCMP' : 'TKIP');
266
            $ieee80211s[] = $ieee80211;
267
        }
268
        $compatibleuses->setProperty('IEEE80211', $ieee80211s);
269
        return($compatibleuses);
270
    }
271
272
*/
273
    private function getAuthenticationMethodParams($eap) {
274
        $inner = \core\common\EAP::innerAuth($eap);
275
        $outerMethod = $eap["OUTER"];
276
277
        if (isset($inner["METHOD"]) && $inner["METHOD"]) {
278
            $innerauthmethod = new InnerAuthenticationMethod();
279
            $typeOfInner = "\devices\xml\\" . ($inner["EAP"] ? 'EAPMethod' : 'NonEAPAuthMethod');
280
            $eapmethod = new $typeOfInner();
281
            $eaptype = new Type();
282
            $eaptype->setValue($inner['METHOD']);
283
            $eapmethod->setProperty('Type', $eaptype);
284
            $innerauthmethod->setProperty($typeOfInner, $eapmethod);
285
            return ['inner_method' => $innerauthmethod, 'methodID' => $outerMethod, 'inner_methodID' => $inner['METHOD']];
286
        } else {
287
            return ['inner_method' => 0, 'methodID' => $outerMethod, 'inner_methodID' => 0];
288
        }
289
    }
290
291
    private function getAuthMethod($eap) {
292
        $attr = $this->attributes;
293
        $eapParams = $this->getAuthenticationMethodParams($eap);
294
        $authmethod = new AuthenticationMethod();
295
        $eapmethod = new EAPMethod();
296
        $eaptype = new Type();
297
        $eaptype->setValue($eapParams['methodID']);
298
        $eapmethod->setProperty('Type', $eaptype);
299
        if (isset($this->VendorSpecific)) {
300
            $vendorspecifics = [];
301
            foreach ($this->VendorSpecific as $vs) {
302
                $vendorspecific = new VendorSpecific();
303
                $vs['value']->addAttribute('xsi:noNamespaceSchemaLocation', "xxx.xsd");
304
                $vendorspecific->setValue($vs['value']);
305
                $vendorspecific->setAttributes(['vendor' => $vs['vendor']]);
306
                $vendorspecifics[] = $vendorspecific;
307
            }
308
            $eapmethod->setProperty('VendorSpecific', $vendorspecifics);
309
        }
310
        $authmethod->setProperty('EAPMethod', $eapmethod);
311
312
// ServerSideCredentials
313
        $serversidecredential = new ServerSideCredential();
314
315
// Certificates and server names
316
317
        $cAlist = [];
318
        $attrCaList = $attr['internal:CAs'][0];
319
        foreach ($attrCaList as $ca) {
320
            $caObject = new CA();
321
            $caObject->setValue(base64_encode($ca['der']));
322
            $caObject->setAttributes(['format' => 'X.509', 'encoding' => 'base64']);
323
            $cAlist[] = $caObject;
324
        }
325
326
        $serverids = [];
327
        $servers = $attr['eap:server_name'];
328
        foreach ($servers as $server) {
329
            $serverid = new ServerID();
330
            $serverid->setValue($server);
331
            $serverids[] = $serverid;
332
        }
333
334
        $serversidecredential->setProperty('EAPType', $eaptype->getValue());
335
        $serversidecredential->setProperty('CA', $cAlist);
336
        $serversidecredential->setProperty('ServerID', $serverids);
337
        $authmethod->setProperty('ServerSideCredential', $serversidecredential);
338
339
// ClientSideCredentials
340
341
        $clientsidecredential = new ClientSideCredential();
342
343
// OuterIdentity 
344
        if ($attr['internal:use_anon_outer'] [0]) {
345
            $clientsidecredential->setProperty('OuterIdentity', $attr['internal:anon_local_value'][0] . '@' . $attr['internal:realm'][0]);
346
        }
347
        $clientsidecredential->setProperty('EAPType', $eapParams['inner_methodID'] ? $eapParams['inner_methodID'] : $eapParams['methodID']);
348
        
349
        // Client Certificate
350
        if ($this->selectedEap == \core\common\EAP::EAPTYPE_SILVERBULLET) {
351
            $clientCertificateObject = new ClientCertificate();
352
            $clientCertificateObject->setValue(base64_encode($this->clientCert["certdata"]));
353
            $clientCertificateObject->setAttributes(['format' => 'PKCS12', 'encoding' => 'base64']);
354
            
355
            $clientsidecredential->setProperty('ClientCertificate',$clientCertificateObject);
356
        }
357
        
358
        $authmethod->setProperty('ClientSideCredential', $clientsidecredential);
359
        if ($eapParams['inner_method']) {
360
            $authmethod->setProperty('InnerAuthenticationMethod', $eapParams['inner_method']);
361
        }
362
        return $authmethod;
363
    }
364
    
365
366
367
}
368