File Coverage

blib/lib/XML/AppleConfigProfile.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             package XML::AppleConfigProfile;
2              
3 1     1   23536 use 5.14.4;
  1         5  
  1         47  
4 1     1   6 use strict;
  1         2  
  1         48  
5 1     1   6 use warnings FATAL => 'all';
  1         2  
  1         49  
6 1     1   5 use base qw(XML::AppleConfigProfile::Payload::Common);
  1         2  
  1         722  
7              
8             use Exporter::Easiest q(OK => $VERSION);
9             use Mac::PropertyList;
10             use Readonly;
11             use XML::AppleConfigProfile::Payload::Common;
12             use XML::AppleConfigProfile::Payload::Types qw(:all);
13             use XML::AppleConfigProfile::Targets qw(:all);
14              
15             our $VERSION = '0.00_001';
16              
17              
18             =head1 NAME
19              
20             XML::AppleConfigProfile - An OO interface to Apple Configuration Profiles.
21              
22              
23             =head1 SYNOPSIS
24              
25             use File::Temp;
26             use XML::AppleConfigProfile;
27             use XML::AppleConfigProfile::Payload::Certificate::PEM;
28             use XML::AppleConfigProfile::Payload::Wireless;
29              
30             my $cert = new XML::AppleConfigProfile::Payload::Certificate::PEM;
31             my $cert_payload = $cert->payload;
32             $cert_payload->{PayloadIdentifier} = 'com.example.group15.payload.cert';
33             $cert_payload->{PayloadCertificateFileName} = 'myCA.pem';
34             $cert_payload->{PayloadContent} = <
35             ----- BEGIN CERTIFICATE -----
36             dsfkldfsbnjksjkgnndbfjkdgnjdfkgjkndfg
37             # snip
38             dgkdfgldmklbgklmd==
39             ----- END CERTIFICATE -----
40             ENDCERT
41              
42             my $wifi = new XML::AppleConfigProfile::Payload::Wireless;
43             my $wifi_payload = $wifi->payload;
44             $wifi_payload->{PayloadIdentifier} = 'com.example.group15.payload.wireless';
45             $wifi_payload->{SSID_STR} = 'CorpNet Public';
46             $wifi_payload->{EncryptionType} = 'None';
47              
48             my $profile = new XML::AppleConfigProfile;
49             my $profile_payload = $profile->payload;
50             $profile_payload->{PayloadIdentifier} = 'com.example.group15.payload';
51             $profile_payload->{PayloadDisplayName} = "My Group's Profile";
52             push @{$profile_payload->{PayloadContent}}, $cert_payload, $wireless_payload;
53              
54             my ($fh, $file) = tempfile('CorpConfig',
55             SUFFIX => '.mobileconfig', UNLINK => 0);
56             print $fh $profile->export;
57             close $fh;
58             print "Configuration Profile written to $file\n";
59              
60              
61             =head1 DESCRIPTION
62              
63             Apple provides users with a way to configure Apple devices (running iOS or Mac
64             OS X) using ready-made configuration files, which Apple calls
65             B. This suite of Perl modules is intended to aid
66             people who would like to generate their own configuration profiles, without
67             having to mess around with the XML themselves.
68              
69             Configuration profiles can be used by iOS and Mac OS X to set a number of
70             general and user-specific items. Examples include:
71              
72             =over 4
73              
74             =item *
75              
76             Configuring an LDAP server, for directory search in Mail and Contacts.
77              
78             =item *
79              
80             Specifying password requirements to match company policy (and common sense).
81              
82             =item *
83              
84             Configuring an email account, with or without a user's credentials.
85              
86             =item *
87              
88             Adding new certificate authorities.
89              
90             =back
91              
92             Configuration profiles can be pre-made static files, or they can be
93             dynamically-generated with configurations (such as usernames and passwords)
94             that are specific to a user. Configuration profiles may be encrypted (so they
95             may only be read on a specific device) and signed (to verify that they have not
96             been modified by anyone other than the profile's creator).
97              
98             A configuration profile contains one or more B, in addition to some
99             header information. In Perl terms, a payload can be thought of as a Hash.
100             There are some keys of the "hash" that are common to all types of payloads,
101             and of course other keys that are payload-specific. Some keys are optinal,
102             and some keys are only optional on one platform or the other (iOS or Mac OS X).
103             In addition, there are some payloads that are only valid on one platform. For
104             example, the C payload can only be
105             used with a Mac OS X configuration profile.
106              
107             For a list of all payloads that Apple currently recognizes, refer to the
108             I linked below. Not all payloads are
109             implemented in this release. If you are interested in seeing more payloads
110             supported, please contribute! See the L section below for more info.
111              
112              
113             =head1 CLASS HIERARCHY
114              
115             Classes are laid out in the following hierarchy:
116              
117             XML::
118             AppleConfigProfile: <-- This file
119             AppleConfigProfile::
120             Payload:: <-- All payload-related classes are in here
121             Common.pm <-- Common payload elements are here
122             Certificate.pm <-- The Certificate payload type
123             Certificate:: <-- Certificate sub-types are here
124             Email.pm <-- The Email payload type
125             Tie:: <-- Internal support code
126             Encryption.pm <-- Profile encryption (TBI)
127             Signing.pm <-- Profile signing (TBI)
128              
129             Clients need only C the modules that directly provide the functionality
130             they are looking for.
131              
132             As an example, if you want to create a configuration profile that configures an
133             IMAP email account, an LDAP server, and a passcode policy, you would need the
134             following modules:
135              
136             * L would configure the email account.
137             * L would configure the LDAP server.
138             * L would configure the passcode
139             policy.
140             * This module would put everything together, and give you the final profile.
141              
142             =cut
143              
144              
145             =head1 CLASS METHODS
146              
147             =head2 new()
148              
149             Returns a new object.
150              
151             =cut
152              
153             # This call automatically goes up to XML::AppleConfigProfile::Payload::Common
154              
155              
156             =head1 INSTANCE METHODS
157              
158             =head2 INHERITED METHODS
159              
160             Most of the methods, including critical ones such as C and C,
161             are implemented in the module C,
162             and are not reimplemented here. See L.
163              
164              
165             =head2 export()
166              
167             export([C => C, ...])
168              
169             Return a string containing the profile, serialized as XML. The entire string
170             will already be encoded as UTF-8. This method is used when it is time to
171             output a profile.
172              
173             Several parameters can be provided, which will influence how this method runs.
174              
175             =over 4
176              
177             =item target
178              
179             If C (a value from L) is provided,
180             then this will be taken into account when exporting. Only payload keys that
181             are used on the specified target will be included in the output.
182              
183             The C option controls what happens if keys are excluded.
184              
185             =item version
186              
187             If C (a version string) is provided, then only payload keys that work
188             on the specified version will be included in the output.
189              
190             If C is provided, then C must also be set, but C can
191             be set without setting C.
192              
193             The C option controls what happens if keys are excluded.
194              
195             =item completeness
196              
197             If C is set to a true value, and keys are excluded because of
198             C or C, then C will throw an exception. If set to a
199             false value, or if not set at all, then no exceptions will be thrown, and a
200             less-than-complete (but still valid) plist will be returned.
201              
202             =back
203              
204             The following exceptions may be thrown:
205              
206             =over 4
207              
208             =item XML::AppleConfigProfile::Exception::KeyRequired
209              
210             Thrown if a required key has not been set.
211              
212             =item XML::AppleConfigProfile::Exception::Incomplete
213              
214             Thrown if payload keys are being excluded from the output because of C
215             or C.
216              
217             =back
218              
219             =cut
220              
221             sub export {
222             my $self = shift @_;
223            
224             my $plist = $self->plist(@_);
225             return Mac::PropertyList::plist_as_string($plist);
226             }
227              
228              
229             =head1 PAYLOAD KEYS
230              
231             Payload keys are the keys that you can use when manipulating the hash returned
232             by C.
233              
234             All of the payload keys defined in L
235             are used by this payload.
236              
237             This payload has the following additional keys:
238              
239             =head2 C
240              
241             I
242              
243             An array of C objects.
244              
245             =head2 C
246              
247             I
248              
249             Payload contents that are encrypted, such that only a single device may decrypt
250             and read it. This is a Data type, which is formed by first taking the contents
251             of C, and serializing them as a plist with an array as the root
252             element. Next, the contents are CMS-encrypted as enveloped data, then finally
253             DER-encoded.
254              
255             Until C is implemented, the following
256             OpenSSL command can be used to encrypt the plist.
257              
258             openssl cms -encrypt -in your.mobileconfig_fragment
259             -out your.mobileconfig_fragment.encrypted -outform der -cmsout
260             your_recipients_cert.pem
261              
262             OpenSSL 1 or later is required for the C command.
263              
264             =head2 C
265              
266             I
267              
268             Applies to Mac OS X only.
269              
270             Can be set to "System", in which case the profile will apply system-wide,
271             or "User", in which case the profile will only apply to the user installing
272             the profile.
273              
274             If not set, the default is "User".
275              
276             =head2 C
277              
278             I
279              
280             A dictionary of strings. The keys are locale identifiers, specifically
281             canonicalized IETF BCP 47 locale strings. Each value is a localized text string
282             containing a message that the user will see when installing the profile. This
283             is a place to put warnings, agreements, etc..
284              
285             An extra pair, with the key "default", may be included to provide a default
286             consent message. If no default is set, the "en" localization will be used as a
287             last resort.
288              
289             =head2 C
290              
291             I
292              
293             A boolean. If set to C, then the profile may only be removed if a
294             profile removal password is provided. To set such a password, include an object
295             from L as part of
296             C.
297              
298             =head2 C
299              
300             I
301              
302             A floating-point number, the number of seconds that the profile will remain on
303             the device before it is automatically removed.
304              
305             If C is set, this value will be ignored.
306              
307             =head2 C
308              
309             I
310              
311             A date. Once past, the profile will be automatically removed from the device.
312              
313             This value overrides C.
314              
315             =head2 C
316              
317             I
318              
319             A date. This only applies to payloads delivered over-the-air, using a mobile
320             device management (MDM) solution. Once past, this profile will be marked as
321             "expired", and will be eligible for updating over-the-air.
322              
323             =cut
324              
325             Readonly our %payloadKeys => (
326             # Bring in the certificate keys...
327             %XML::AppleConfigProfile::Payload::Common::payloadKeys,
328            
329             # Since we can't go any deeper, define the type and version!
330             'PayloadContent' => {
331             type => $ProfileArray,
332             description => 'The payloads to be delivered in this profile.',
333             targets => {
334             $TargetIOS => '5.0',
335             $TargetMACOSX => '10.7',
336             },
337             optional => 1,
338             },
339             'EncryptedPayloadContent' => {
340             type => $ProfileData,
341             description => 'Payload content that has been encrypted to a specific '
342             . 'user. The contents of "PayloadContent" must be serialized as '
343             . 'an array plist, then CMS-encrypted (as enveloped data), and '
344             . 'finally serialized in DER format.',
345             targets => {
346             $TargetIOS => '5.0',
347             $TargetMACOSX => '10.7',
348             },
349             optional => 1,
350             },
351             'PayloadExpirationDate' => {
352             type => $ProfileDate,
353             description => 'For profiles delivered via OTA, the date when the '
354             . 'profile has expired and can be updated (again via OTA).',
355             targets => {
356             $TargetIOS => '5.0',
357             $TargetMACOSX => '10.7',
358             },
359             optional => 1,
360             },
361             'PayloadRemovalDisallowed' => {
362             type => $ProfileBool,
363             description => 'If true, the profile may only be removed if a profile-'
364             . 'removal password has been set, and the password is provided '
365             . 'by the user.',
366             targets => {
367             $TargetIOS => '5.0',
368             $TargetMACOSX => '10.7',
369             },
370             optional => 1,
371             },
372             'PayloadScope' => {
373             type => $ProfileString,
374             description => 'Controls if the profile applies to the entire "System",'
375             . ' or if just to the specific "User". If one of those two values '
376             . 'is not provided, "User" will be used as the default.',
377             targets => {
378             # Desktop only, not for iOS
379             $TargetMACOSX => '10.7',
380             },
381             optional => 1,
382             },
383             'RemovalDate' => {
384             type => $ProfileDate,
385             description => 'The date when the profile will be automatically removed'
386             . ' from the device. Overrides DurationUntilRemoval.',
387             targets => {
388             $TargetIOS => '5.0',
389             $TargetMACOSX => '10.7',
390             },
391             optional => 1,
392             },
393             'DurationUntilRemoval' => {
394             type => $ProfileReal,
395             description => 'The number of seconds until the profile is '
396             . 'automatically removed from the device. The RemovalDate profile '
397             . 'key overrides this one.',
398             targets => {
399             $TargetIOS => '5.0',
400             $TargetMACOSX => '10.7',
401             },
402             optional => 1,
403             },
404             'ConsentText' => {
405             type => $ProfileDict,
406             description => 'A dictionary where the keys are canonicalized IETF BCP '
407             . '47 locale strings. The key "default" may be used as the '
408             . 'default entry. The values are localized messages that the user '
409             . 'must accept before the profile is installed.',
410             targets => {
411             $TargetIOS => '5.0',
412             $TargetMACOSX => '10.7',
413             },
414             optional => 1,
415             },
416             'PayloadType' => {
417             type => $ProfileString,
418             targets => {
419             $TargetIOS => '5.0',
420             $TargetMACOSX => '10.7',
421             },
422             value => 'Configuration',
423             },
424             'PayloadVersion' => {
425             type => $ProfileNumber,
426             value => 1,
427             },
428             ); # End of %payloadKeys
429              
430              
431             =head1 SEE ALSO
432              
433             =over 4
434              
435             =item * Apple's "Configuration Profile Reference".
436              
437             L
438              
439             =item * Apple's "Over-the-Air Profile Delivery and Configuration" document.
440              
441             L.
442              
443             =back
444              
445              
446             =head1 SUPPORT
447              
448             You can find documentation for this module with the perldoc command.
449              
450             perldoc XML::AppleConfigProfile
451              
452             All modules have some POD inside them. If you're not interested in using the
453             command-line, your IDE may have PerlDoc support, or you can go here:
454              
455             =over 4
456              
457             =item * MetaCPAN
458              
459             L
460              
461             =item * search.cpan.org
462              
463             L
464              
465             =item * AnnoCPAN: Annotated CPAN documentation
466              
467             L
468              
469             =back
470              
471             If you have found a bug, or want to request an enhancement of some sort, you
472             may do so here:
473              
474             =over 4
475              
476             =item * Github's issue section
477              
478             https://github.com/akkornel/XML-AppleConfigProfile/issues
479              
480             =item * RT: CPAN's request tracker (for people who don't use Github)
481              
482             L
483              
484             =back
485              
486             Finally, feel free to rate the release!
487              
488             =over 4
489              
490             =item * CPAN Ratings
491              
492             L
493              
494             =back
495              
496              
497             =head1 SOURCE
498              
499             This project is on GitHub:
500              
501             L
502              
503             The web site linked above has the most recently-pushed code, along with
504             information on how to get a copy to your computer.
505              
506             If you are interested in making a contribution, please make it in the form
507             of a GitHub pull request.
508              
509              
510             =head1 ACKNOWLEDGEMENTS
511              
512             Thanks are due to B (C) for the L
513             module, which is relied on heavily by this code!
514              
515              
516             =head1 AUTHOR
517              
518             A. Karl Kornel, C<< >>
519              
520              
521             =head1 COPYRIGHT AND LICENSE
522              
523             Copyright 2014 A. Karl Kornel.
524              
525             This program is free software; you can redistribute it and/or modify it
526             under the terms of either: the GNU General Public License as published
527             by the Free Software Foundation; or the Artistic License.
528              
529             See L for more information.
530              
531             =cut
532              
533             1;