Passed
Push — master ( 8e1554...ffe3d0 )
by Stefan
10:51
created

Device_PP_OSU_XML   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 159
Duplicated Lines 0 %

Importance

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

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
B writeInstaller() 0 131 7
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 Device_TestModule} 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 Device_TestModule.
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 Device_PP_OSU_XML 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
';
167
        $content_encoded = base64_encode($content);
168
        // sigh... we need to construct a MIME envelope for the payload and the cert data
169
        $content_encoded = 'Content-Type: multipart/mixed; boundary={boundary}
170
Content-Transfer-Encoding: base64
171
172
--{boundary}
173
Content-Type: application/x-passpoint-profile
174
Content-Transfer-Encoding: base64
175
176
'.$content_encoded.'
177
--{boundary}';
178
        // then, another MIME body for each CA certificate we referenced earlier
179
        // only leaves me to wonder what the "URL" for those is...
180
        foreach ($this->attributes['internal:CAs'][0] as $oneCert) {
181
            $content_encoded .= '
182
Content-Type: application/x-x509-ca-cert
183
Content-Transfer-Encoding: base64
184
185
'.base64_encode($oneCert['der']).
186
'--{boundary}';
187
            
188
        }
189
        // and our own client cert - what about intermediates?
190
        $content_encoded .= '
191
Content-Type: application/x-pkcs12
192
Content-Transfer-Encoding: base64
193
194
'.base64_encode($this->clientCert['certdata']). // is PKCS#12, with encrypted key
195
'--{boundary}';
196
197
        // trail this with a double slash
198
        $content_encoded .= "--";
199
        // strangely enough, now encode ALL OF THIS in base64 again. Whatever.
200
        file_put_contents('installer_profile', base64_encode($content_encoded));
201
202
        $fileName = $this->installerBasename . '.bin';
203
204
        if (!$this->sign) {
205
            rename("installer_profile", $fileName);
206
            return $fileName;
207
        }
208
209
        // still here? We are signing. That actually can't be - ONC does not
210
        // have the notion of signing
211
        // but if they ever change their mind, we are prepared
212
213
        $outputFromSigning = system($this->sign . " installer_profile '$fileName' > /dev/null");
214
        if ($outputFromSigning === FALSE) {
215
            $this->loggerInstance->debug(2, "Signing the ONC installer $fileName FAILED!\n");
216
        }
217
218
        return $fileName;
219
    }
220
221
    /**
222
     * prepare module desctiption and usage information
223
     * 
224
     * @return string HTML text to be displayed in the information window
225
     */
226
    public function writeDeviceInfo() {
227
        $out = "<p>";
228
        $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.");
229
        return $out;
230
    }
231
232
}
233