Passed
Push — master ( e870f9...8e19b6 )
by Stefan
06:30
created

DevicePPOSUXML   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 158
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 9
eloc 46
dl 0
loc 158
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
B writeInstaller() 0 130 7
A __construct() 0 3 1
A writeDeviceInfo() 0 4 1
1
<?php
2
3
/*
4
 * ******************************************************************************
5
 * Copyright 2011-2017 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 
6
 * and GN4-2 consortia
7
 *
8
 * License: see the web/copyright.php file in the file structure
9
 * ******************************************************************************
10
 */
11
12
/**
13
 * This file contains the TestModule class
14
 *
15
 * This is a very basic example of using the CAT API.  
16
 *
17
 * The module contains two files
18
 * in the Files directory. They will illustrate the use of the {@link DeviceConfig::copyFile()} method.
19
 * One fille will be coppied without the name change, for the second we will provide a new name.
20
 * The API also contains a similar {@link DeviceConfig::translateFile()} method, which is special to Windows installers and not used in this example.
21
 *
22
 * This module will collect all certificate files stored in the database for a given profile and will copy them to the working directory.
23
 *
24
 * If, for the given profile, an information file is available, this will also be copied to the working directory.
25
 *
26
 * The installer will collect all available configuration attributes and save them to a file in the form of the PHP print_r output.
27
 *
28
 * Finally, the installer will create a zip archive containing all above files and this file 
29
 * will be sent to the user as the configurator file.
30
 *
31
 * Go to the {@link DeviceTestModule} and {@link DeviceConfig} class definitions to learn more.
32
 *  
33
 * @package ModuleWriting
34
 */
35
36
namespace devices\PP_OSU_XML;
37
38
use Exception;
39
40
/**
41
 * This is the main implementation class of the module
42
 *
43
 * The name of the class must the the 'Device' followed by the name of the module file
44
 * (without the '.php' extension), so in this case the file is "TestModule.php" and
45
 * the class is DeviceTestModule.
46
 *
47
 * The class MUST define the constructor method and one additional 
48
 * public method: {@link writeInstaller()}.
49
 *
50
 * All other methods and properties should be private. This example sets zipInstaller method to protected, so that it can be seen in the documentation.
51
 *
52
 * It is important to understand how the device module fits into the whole picture, so here is s short descrption.
53
 * An external caller (for instance {@link GUI::generateInstaller()}) creates the module device instance and prepares
54
 * its environment for a given user profile by calling {@link DeviceConfig::setup()} method.
55
 *      this will:
56
 *       - create the temporary directory and save its path as $this->FPATH
57
 *       - process the CA certificates and store results in $this->attributes['internal:CAs'][0]
58
 *            $this->attributes['internal:CAs'][0] is an array of processed CA certificates
59
 *            a processed certifincate is an array 
60
 *               'pem' points to pem feromat certificate
61
 *               'der' points to der format certificate
62
 *               'md5' points to md5 fingerprint
63
 *               'sha1' points to sha1 fingerprint
64
 *               'name' points to the certificate subject
65
 *               'root' can be 1 for self-signed certificate or 0 otherwise
66
 *       - save the info_file (if exists) and put the name in $this->attributes['internal:info_file_name'][0]
67
 * Finally, the module {@link DeviceConfig::writeInstaller ()} is called and the returned path name is used for user download.
68
 *
69
 * @package ModuleWriting
70
 */
71
class DevicePPOSUXML extends \core\DeviceConfig {
72
73
    /**
74
     * Constructs a Device object.
75
     *
76
     * @final not to be redefined
77
     */
78
    final public function __construct() {
79
        parent::__construct();
80
        $this->setSupportedEapMethods([\core\common\EAP::EAPTYPE_SILVERBULLET]);
81
    }
82
    
83
    /**
84
     * prepare a ONC file
85
     *
86
     * @return string installer path name
87
     */
88
    public function writeInstaller() {
89
        $this->loggerInstance->debug(4, "HS20 PerProviderSubscription Managed Object Installer start\n");
90
        $now = new \DateTime();
91
        $content = '<MgmtTree xmlns="syncml:dmddf1.2">
92
  <VerDTD>1.2</VerDTD>
93
  <Node>
94
    <NodeName>PerProviderSubscription</NodeName>
95
    <RTProperties>
96
      <Type>
97
        <DDFName>urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0</DDFName>
98
      </Type>
99
    </RTProperties>
100
    <Node>
101
      <NodeName>CATPasspointSetting</NodeName>
102
      <Node>
103
        <NodeName>AAAServerTrustRoot</NodeName>';
104
      foreach ($this->attributes['internal:CAs'][0] as $oneCert) {
105
          $content .= '<Node>
106
                         <NodeName>'.$oneCert['uuid'].'</NodeName>
107
                             <Node>
108
                               <NodeName>CertSHA256Fingerprint</NodeName>
109
                               <Value>'.$oneCert['sha256'].'</Value>
110
                             </Node>
111
                       </Node>
112
                  ';
113
      }
114
      $content .= '</Node>
115
      <Node>
116
        <NodeName>Credential</NodeName>
117
        <Node>
118
          <NodeName>CreationDate</NodeName>
119
          <Value>'.$now->format("Y-m-d") . "T" . $now->format("H:i:s") . "Z".'</Value>
120
        </Node>
121
        <Node>
122
          <NodeName>DigitalCertificate</NodeName>
123
          <Node>
124
            <NodeName>CertificateType</NodeName>
125
            <Value>x509v3</Value>
126
          </Node>
127
          <Node>
128
            <NodeName>CertSHA256Fingerprint</NodeName>
129
            <Value>'.$this->clientCert["sha256"] /* the actual cert has to go... where? */.'</Value>
130
          </Node>
131
        </Node>
132
        <Node>
133
          <NodeName>Realm</NodeName>
134
          <Value>'.$this->attributes['internal:realm'][0].'</Value>
135
        </Node>
136
      </Node>
137
      <Node>
138
        <NodeName>HomeSP</NodeName>
139
        <Node>
140
          <NodeName>FriendlyName</NodeName>
141
          <Value>'.sprintf(_("%s via Passpoint"),CONFIG_CONFASSISTANT['CONSORTIUM']['display_name']).'</Value>
142
        </Node>
143
        <Node>
144
          <NodeName>FQDN</NodeName>
145
          <Value>'.$this->attributes['eap:server_name'][0] /* what, only one FQDN allowed? */.'</Value>
146
        </Node>
147
        <Node>
148
          <NodeName>RoamingConsortiumOI</NodeName>
149
          <Value>';
150
        $oiList = "";
151
        $numberOfOi = count(CONFIG_CONFASSISTANT['CONSORTIUM']['interworking-consortium-oi']);
152
        foreach (CONFIG_CONFASSISTANT['CONSORTIUM']['interworking-consortium-oi'] as $index => $oneOi) {
153
            // according to spec, must be lowercase ASCII without dashes
154
            $oiList .= str_replace("-","",trim(strtolower($oneOi)));
155
            if ($index < $numberOfOi - 1) {
156
                // according to spec, comma-separated
157
                $oiList .= ",";
158
            }
159
        }
160
        $content .= $oiList.'</Value>
161
        </Node>
162
      </Node>
163
    </Node>
164
  </Node>
165
</MgmtTree>';
166
        $content_encoded = chunk_split(base64_encode($content), 76, "\n");
167
        // sigh... we need to construct a MIME envelope for the payload and the cert data
168
        $content_encoded = 'Content-Type: multipart/mixed; boundary={boundary}
169
Content-Transfer-Encoding: base64
170
171
--{boundary}
172
Content-Type: application/x-passpoint-profile
173
Content-Transfer-Encoding: base64
174
175
'.$content_encoded.'--{boundary}';
176
        // then, another MIME body for each CA certificate we referenced earlier
177
        // only leaves me to wonder what the "URL" for those is...
178
        foreach ($this->attributes['internal:CAs'][0] as $oneCert) {
179
            $content_encoded .= '
180
Content-Type: application/x-x509-ca-cert
181
Content-Transfer-Encoding: base64
182
183
'.chunk_split(base64_encode($oneCert['der']), 76, "\n").
184
'--{boundary}';
185
            
186
        }
187
        // and our own client cert - what about intermediates?
188
        $content_encoded .= '
189
Content-Type: application/x-pkcs12
190
Content-Transfer-Encoding: base64
191
192
'.chunk_split(base64_encode($this->clientCert['certdataclear']), 76, "\n"). // is PKCS#12, with encrypted key
193
'--{boundary}';
194
195
        // trail this with a double slash and a newline
196
        $content_encoded .= "--\n";
197
        // strangely enough, now encode ALL OF THIS in base64 again. Whatever.
198
        file_put_contents('installer_profile', chunk_split(base64_encode($content_encoded), 76, "\n"));
199
200
        // $fileName = $this->installerBasename . '.bin';
201
        $fileName = "passpoint.config";
202
203
        if (!$this->sign) {
204
            rename("installer_profile", $fileName);
205
            return $fileName;
206
        }
207
208
        // still here? We are signing. That actually can't be - ONC does not
209
        // have the notion of signing
210
        // but if they ever change their mind, we are prepared
211
212
        $outputFromSigning = system($this->sign . " installer_profile '$fileName' > /dev/null");
213
        if ($outputFromSigning === FALSE) {
214
            $this->loggerInstance->debug(2, "Signing the ONC installer $fileName FAILED!\n");
215
        }
216
217
        return $fileName;
218
    }
219
220
    /**
221
     * prepare module desctiption and usage information
222
     * 
223
     * @return string HTML text to be displayed in the information window
224
     */
225
    public function writeDeviceInfo() {
226
        $out = "<p>";
227
        $out .= _("This installer is an example only. It produces a zip file containig the IdP certificates, info and logo files (if such have been defined by the IdP administrator) and a dump of all available attributes.");
228
        return $out;
229
    }
230
231
}
232