Passed
Push — master ( 706c3a...e4046b )
by Tomasz
07:16
created

Device_XML::setInnerIdentitySuffix()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
c 0
b 0
f 0
rs 9.4285
cc 3
eloc 7
nc 3
nop 2
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
use Exception;
23
require_once(dirname(__FILE__) . '/XML.inc.php');
24
25
/**
26
 * This class implements full functionality of the generic XML device
27
 * the only fuction of the extenstions of this class is to specify
28
 * supported EAP methods.
29
 * Instead of specifying supported EAPS an extension can set $all_eaps to true
30
 * this will cause the installer to configure all EAP methods supported by 
31
 * the current profile and declared by the given device.
32
 */
33
abstract class Device_XML extends \core\DeviceConfig {
34
35
    public function __construct() {
36
        parent::__construct();
37
    }
38
39
    /**
40
     * $lang_scope can be 'global' wheb all lang and all lang-specific information
41
     * is dumped or 'single' when only the selected lang (and defaults) are passed
42
     * NOTICE: 'global' is not yet supported
43
     */
44
    public $langScope;
45
    public $allEaps = FALSE;
46
    public $VendorSpecific;
47
48
    public function writeDeviceInfo() {
49
        $out = "<p>";
50
        $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");
51
        return $out;
52
    }
53
54
    public function writeInstaller() {
55
        $attr = $this->attributes;
56
        $NAMESPACE = 'urn:RFC4282:realm';
57
//EAPIdentityProvider  begin
58
        $eapIdp = new EAPIdentityProvider();
59
        $eapIdp->setProperty('CredentialApplicability', $this->getCredentialApplicability());
60
//    $eap_idp->setProperty('ValidUntil',$this->getValidUntil());
61
// ProviderInfo->
62
        $eapIdp->setProperty('ProviderInfo', $this->getProviderInfo());
63
// TODO    $eap_idp->setProperty('VendorSpecific',$this->getVendorSpecific());
64
//AuthenticationMethods
65
// TODO
66
//ID attribute
67
//lang attribute
68
        $methodList = [];
69
        if ($this->allEaps) {
70
            $eapmethods = [];
71
            foreach ($attr['all_eaps'] as $eap) {
72
                $eapRep = $eap->getArrayRep();
73
                if (in_array($eapRep, $this->supportedEapMethods)) {
74
                    $eapmethods[] = $eapRep;
75
                }
76
            }
77
        } else {
78
            $eapmethods = [$this->selectedEap];
79
        }
80
        foreach ($eapmethods as $eap) {
81
            $methodList[] = $this->getAuthMethod($eap);
82
        }
83
        $authMethods = new AuthenticationMethods();
84
        $authMethods->setProperty('AuthenticationMethods', $methodList);
85
        $eapIdp->setProperty('AuthenticationMethods', $authMethods);
86
        if (empty($attr['internal:realm'][0])) {
87
            $eapIdp->setAttribute('ID', 'undefined');
88
            $eapIdp->setAttribute('namespace', 'urn:undefined');
89
        } else {
90
            $eapIdp->setAttribute('ID', $attr['internal:realm'][0]);
91
            $eapIdp->setAttribute('namespace', $NAMESPACE);
92
        }
93
        if ($this->langScope === 'single') {
94
            $eapIdp->setAttribute('lang', $this->languageInstance->getLang());
95
        }
96
        $eapIdp->setAttribute('version', '1');
97
98
99
// EAPIdentityProvider end
100
// Generate XML
101
102
        $rootname = 'EAPIdentityProviderList';
103
        $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}>");
104
105
        marshalObject($root, $eapIdp);
106
        $dom = dom_import_simplexml($root)->ownerDocument;
107
        //TODO schema validation makes sense so probably should be used
108
        if ($dom->schemaValidate(ROOT . '/devices/xml/eap-metadata.xsd') === FALSE) {
109
            throw new Exception("Schema validation failed for eap-metadata");
110
        }
111
        file_put_contents($this->installerBasename . '.eap-config', $dom->saveXML());
112
        return($this->installerBasename . '.eap-config');
113
    }
114
115
    private $AttributeNames = [
116
        'support:email' => 'EmailAddress',
117
        'support:url' => 'WebAddress',
118
        'support:phone' => 'Phone',
119
        'profile:description' => 'Description',
120
        'support:info_file' => 'TermsOfUse',
121
        'general:logo_file' => 'ProviderLogo',
122
    ];
123
124
    /**
125
     * 
126
     * @param string $attrName
127
     * @return array of values for this attribute
128
     */
129
    private function getSimpleMLAttribute($attrName) {
130
        if (empty($this->attributes[$attrName][0])) {
131
            return([]);
132
        }
133
        $attributeList = $this->attributes[$attrName];
134
        if (!isset($this->AttributeNames[$attrName])) {
135
            $this->loggerInstance->debug(4, "Missing class definition for $attrName\n");
136
            return([]);
137
        }
138
        $className = "\devices\xml\\" . $this->AttributeNames[$attrName];
139
        $objs = [];
140
        if ($this->langScope === 'global') {
141
            foreach ($attributeList['langs'] as $language => $value) {
142
                $language = ($language === 'C' ? 'any' : $language);
143
                $obj = new $className();
144
                $obj->setValue($value);
145
                $obj->setAttributes(['lang' => $language]);
146
                $objs[] = $obj;
147
            }
148
        } else {
149
            $obj = new $className();
150
            $obj->setValue($attributeList[0]);
151
            $objs[] = $obj;
152
        }
153
        return($objs);
154
    }
155
156
    private function getDisplayName() {
157
        $attr = $this->attributes;
158
        $objs = [];
159
        if ($this->langScope === 'global') {
160
            $instNameLangs = $attr['general:instname']['langs'];
161
            if ($attr['internal:profile_count'][0] > 1) {
162
                $profileNameLangs = $attr['profile:name']['langs'];
163
            }
164
            foreach ($instNameLangs as $language => $value) {
165
                $language = ($language === 'C' ? 'any' : $language);
166
                $displayname = new DisplayName();
167
                if (isset($profileNameLangs)) {
168
                    $langOrC = isset($profileNameLangs[$language]) ? $profileNameLangs[$language] : $profileNameLangs['C'];
169
                    $value .= ' - ' . $langOrC;
170
                }
171
                $displayname->setValue($value);
172
                $displayname->setAttributes(['lang' => $language]);
173
                $objs[] = $displayname;
174
            }
175
        } else {
176
            $displayname = new DisplayName();
177
            $value = $attr['general:instname'][0];
178
            if ($attr['internal:profile_count'][0] > 1) {
179
                $value .= ' - ' . $attr['profile:name'][0];
180
            }
181
            $displayname->setValue($value);
182
            $objs[] = $displayname;
183
        }
184
        return $objs;
185
    }
186
187
    private function getProviderLogo() {
188
        $attr = $this->attributes;
189
        if (isset($attr['general:logo_file'][0])) {
190
            $logoString = base64_encode($attr['general:logo_file'][0]);
191
            $logoMime = 'image/' . $attr['internal:logo_file'][0]['mime'];
192
            $providerlogo = new ProviderLogo();
193
            $providerlogo->setAttributes(['mime' => $logoMime, 'encoding' => 'base64']);
194
            $providerlogo->setValue($logoString);
195
            return $providerlogo;
196
        }
197
    }
198
199
    private function getProviderInfo() {
200
        $providerinfo = new ProviderInfo();
201
        $providerinfo->setProperty('DisplayName', $this->getDisplayName());
202
        $providerinfo->setProperty('Description', $this->getSimpleMLAttribute('profile:description'));
203
        $providerinfo->setProperty('ProviderLocation', $this->getProvideLocation());
204
        $providerinfo->setProperty('ProviderLogo', $this->getProviderLogo());
205
        $providerinfo->setProperty('TermsOfUse', $this->getSimpleMLAttribute('support:info_file'));
206
        $providerinfo->setProperty('Helpdesk', $this->getHelpdesk());
207
        return $providerinfo;
208
    }
209
210
    private function getProvideLocation() {
211
        $attr = $this->attributes;
212
        if (isset($attr['general:geo_coordinates'])) {
213
            $attrCoordinates = $attr['general:geo_coordinates'];
214
            if (count($attrCoordinates) > 1) {
215
                $location = [];
216
                foreach ($attrCoordinates as $a) {
217
                    $providerlocation = new ProviderLocation();
218
                    $b = json_decode($a, true);
219
                    $providerlocation->setProperty('Longitude', $b['lon']);
220
                    $providerlocation->setProperty('Latitude', $b['lat']);
221
                    $location[] = $providerlocation;
222
                }
223
            } else {
224
                $providerlocation = new ProviderLocation();
225
                $b = json_decode($attrCoordinates[0], true);
226
                $providerlocation->setProperty('Longitude', $b['lon']);
227
                $providerlocation->setProperty('Latitude', $b['lat']);
228
                $location = $providerlocation;
229
            }
230
            return $location;
231
        }
232
    }
233
234
    private function getHelpdesk() {
235
        $helpdesk = new Helpdesk();
236
        $helpdesk->setProperty('EmailAddress', $this->getSimpleMLAttribute('support:email'));
237
        $helpdesk->setProperty('WebAddress', $this->getSimpleMLAttribute('support:url'));
238
        $helpdesk->setProperty('Phone', $this->getSimpleMLAttribute('support:phone'));
239
        return $helpdesk;
240
    }
241
242
   private function getCredentialApplicability() {
243
        $ssids = $this->attributes['internal:SSID'];
244
        $credentialapplicability = new CredentialApplicability();
245
        $ieee80211s = [];
246
        foreach ($ssids as $ssid => $ciph) {
247
            $ieee80211 = new IEEE80211();
248
            $ieee80211->setProperty('SSID', $ssid);
249
            $ieee80211->setProperty('MinRSNProto', $ciph == 'AES' ? 'CCMP' : 'TKIP');
250
            $ieee80211s[] = $ieee80211;
251
        }
252
        $credentialapplicability->setProperty('IEEE80211', $ieee80211s);
253
        return($credentialapplicability);
254
    }
255
256
    private function getAuthenticationMethodParams($eap) {
257
        $inner = \core\common\EAP::innerAuth($eap);
258
        $outerMethod = $eap["OUTER"];
259
260
        if (isset($inner["METHOD"]) && $inner["METHOD"]) {
261
            $innerauthmethod = new InnerAuthenticationMethod();
262
            $typeOfInner = "\devices\xml\\" . ($inner["EAP"] ? 'EAPMethod' : 'NonEAPAuthMethod');
263
            $eapmethod = new $typeOfInner();
264
            $eaptype = new Type();
265
            $eaptype->setValue($inner['METHOD']);
266
            $eapmethod->setProperty('Type', $eaptype);
267
            $innerauthmethod->setProperty($typeOfInner, $eapmethod);
268
            return ['inner_method' => $innerauthmethod, 'methodID' => $outerMethod, 'inner_methodID' => $inner['METHOD']];
269
        } else {
270
            return ['inner_method' => 0, 'methodID' => $outerMethod, 'inner_methodID' => 0];
271
        }
272
    }
273
274
    private function setServerSideCredentials($eaptype) {
275
        $attr = $this->attributes;
276
        $serversidecredential = new ServerSideCredential();
277
// Certificates and server names
278
        $cAlist = [];
279
        $attrCaList = $attr['internal:CAs'][0];
280
        foreach ($attrCaList as $ca) {
281
            $caObject = new CA();
282
            $caObject->setValue(base64_encode($ca['der']));
283
            $caObject->setAttributes(['format' => 'X.509', 'encoding' => 'base64']);
284
            $cAlist[] = $caObject;
285
        }
286
        $serverids = [];
287
        $servers = $attr['eap:server_name'];
288
        foreach ($servers as $server) {
289
            $serverid = new ServerID();
290
            $serverid->setValue($server);
291
            $serverids[] = $serverid;
292
        }
293
        $serversidecredential->setProperty('EAPType', $eaptype->getValue());
294
        $serversidecredential->setProperty('CA', $cAlist);
295
        $serversidecredential->setProperty('ServerID', $serverids);
296
        return($serversidecredential);
297
    }
298
    
299
    private function setInnerIdentitySuffix($attr, $realm) {
300
        if (\core\common\Entity::getAttributeValue($attr, 'internal:verify_userinput_suffix', 0) !== 1) {
301
            return(NULL);
302
        }
303
        $suffix = new InnerIdentitySuffix();
304
        $suffix->setValue($realm);
305
        if (\core\common\Entity::getAttributeValue($attr, 'internal:hint_userinput_suffix', 0) === 1) {
306
            $suffix->setAttribute('hint', "true");
307
        }
308
        return($suffix);
309
    }
310
311
    private function setClientSideCredentials($eapParams) {
312
        $attr = $this->attributes;
313
        $clientsidecredential = new ClientSideCredential();
314
// OuterIdentity 
315
        $realm = \core\common\Entity::getAttributeValue($attr, 'internal:realm', 0);
316
        if ($realm !== NULL) {
317
            $outerId = \core\common\Entity::getAttributeValue($attr, 'internal:anon_local_value', 0);
318
            if ($outerId !== NULL) { 
319
                $clientsidecredential->setProperty('OuterIdentity', $outerId . '@' . $realm);
320
            }
321
            $suffix = $this->setInnerIdentitySuffix($attr, $realm);
322
            if ($suffix !== NULL) {
323
                $clientsidecredential->setProperty('InnerIdentitySuffix', $suffix);
324
            }
325
        }
326
        
327
        $clientsidecredential->setProperty('EAPType', $eapParams['inner_methodID'] ? $eapParams['inner_methodID'] : $eapParams['methodID']);
328
                
329
        // Client Certificate
330
        if ($this->selectedEap == \core\common\EAP::EAPTYPE_SILVERBULLET) {
331
            $clientCertificateObject = new ClientCertificate();
332
            $clientCertificateObject->setValue(base64_encode($this->clientCert["certdata"]));
333
            $clientCertificateObject->setAttributes(['format' => 'PKCS12', 'encoding' => 'base64']);
334
            $clientsidecredential->setProperty('ClientCertificate', $clientCertificateObject);
335
        }
336
        return($clientsidecredential);
337
    }
338
    
339
    private function setEapMethod($eaptype) {
340
        $eapmethod = new EAPMethod();
341
        $eapmethod->setProperty('Type', $eaptype);
342
        if (isset($this->VendorSpecific)) {
343
            $vendorspecifics = [];
344
            foreach ($this->VendorSpecific as $vs) {
345
                $vendorspecific = new VendorSpecific();
346
                $vs['value']->addAttribute('xsi:noNamespaceSchemaLocation', "xxx.xsd");
347
                $vendorspecific->setValue($vs['value']);
348
                $vendorspecific->setAttributes(['vendor' => $vs['vendor']]);
349
                $vendorspecifics[] = $vendorspecific;
350
            }
351
            $eapmethod->setProperty('VendorSpecific', $vendorspecifics);
352
        }
353
        return($eapmethod);
354
    }
355
    
356
    private function getAuthMethod($eap) {
357
 //       $attr = $this->attributes;
358
        $authmethod = new AuthenticationMethod();
359
        $eapParams = $this->getAuthenticationMethodParams($eap);
360
        $eaptype = new Type();
361
        $eaptype->setValue($eapParams['methodID']);
362
// Type
363
        $authmethod->setProperty('EAPMethod', $this->setEapMethod($eaptype));
364
365
// ServerSideCredentials
366
        $authmethod->setProperty('ServerSideCredential', $this->setServerSideCredentials($eaptype));
367
368
// ClientSideCredentials
369
        $authmethod->setProperty('ClientSideCredential', $this->setClientSideCredentials($eapParams));
370
        
371
        if ($eapParams['inner_method']) {
372
            $authmethod->setProperty('InnerAuthenticationMethod', $eapParams['inner_method']);
373
        }
374
        return $authmethod;
375
376
377
    }
378
    
379
380
381
}
382