1 <?php
2 
3 namespace Sabre\DAVACL\Xml\Property;
4 
5 use Sabre\DAV;
6 use Sabre\DAV\Browser\HtmlOutput;
7 use Sabre\DAV\Browser\HtmlOutputHelper;
8 use Sabre\Xml\Element;
9 use Sabre\Xml\Reader;
10 use Sabre\Xml\Writer;
11 
12 /**
13  * This class represents the {DAV:}acl property.
14  *
15  * The {DAV:}acl property is a full list of access control entries for a
16  * resource.
17  *
18  * {DAV:}acl is used as a WebDAV property, but it is also used within the body
19  * of the ACL request.
20  *
21  * See:
22  * http://tools.ietf.org/html/rfc3744#section-5.5
23  *
24  * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/).
25  * @author Evert Pot (http://evertpot.com/)
26  * @license http://sabre.io/license/ Modified BSD License
27  */
28 class Acl implements Element, HtmlOutput {
29 
30     /**
31      * List of privileges
32      *
33      * @var array
34      */
35     protected $privileges;
36 
37     /**
38      * Whether or not the server base url is required to be prefixed when
39      * serializing the property.
40      *
41      * @var bool
42      */
43     protected $prefixBaseUrl;
44 
45     /**
46      * Constructor
47      *
48      * This object requires a structure similar to the return value from
49      * Sabre\DAVACL\Plugin::getACL().
50      *
51      * Each privilege is a an array with at least a 'privilege' property, and a
52      * 'principal' property. A privilege may have a 'protected' property as
53      * well.
54      *
55      * The prefixBaseUrl should be set to false, if the supplied principal urls
56      * are already full urls. If this is kept to true, the servers base url
57      * will automatically be prefixed.
58      *
59      * @param array $privileges
60      * @param bool $prefixBaseUrl
61      */
62     function __construct(array $privileges, $prefixBaseUrl = true) {
63 
64         $this->privileges = $privileges;
65         $this->prefixBaseUrl = $prefixBaseUrl;
66 
67     }
68 
69     /**
70      * Returns the list of privileges for this property
71      *
72      * @return array
73      */
74     function getPrivileges() {
75 
76         return $this->privileges;
77 
78     }
79 
80     /**
81      * The xmlSerialize metod is called during xml writing.
82      *
83      * Use the $writer argument to write its own xml serialization.
84      *
85      * An important note: do _not_ create a parent element. Any element
86      * implementing XmlSerializble should only ever write what's considered
87      * its 'inner xml'.
88      *
89      * The parent of the current element is responsible for writing a
90      * containing element.
91      *
92      * This allows serializers to be re-used for different element names.
93      *
94      * If you are opening new elements, you must also close them again.
95      *
96      * @param Writer $writer
97      * @return void
98      */
99     function xmlSerialize(Writer $writer) {
100 
101         foreach ($this->privileges as $ace) {
102 
103             $this->serializeAce($writer, $ace);
104 
105         }
106 
107     }
108 
109     /**
110      * Generate html representation for this value.
111      *
112      * The html output is 100% trusted, and no effort is being made to sanitize
113      * it. It's up to the implementor to sanitize user provided values.
114      *
115      * The output must be in UTF-8.
116      *
117      * The baseUri parameter is a url to the root of the application, and can
118      * be used to construct local links.
119      *
120      * @param HtmlOutputHelper $html
121      * @return string
122      */
123     function toHtml(HtmlOutputHelper $html) {
124 
125         ob_start();
126         echo "<table>";
127         echo "<tr><th>Principal</th><th>Privilege</th><th></th></tr>";
128         foreach ($this->privileges as $privilege) {
129 
130             echo '<tr>';
131             // if it starts with a {, it's a special principal
132             if ($privilege['principal'][0] === '{') {
133                 echo '<td>', $html->xmlName($privilege['principal']), '</td>';
134             } else {
135                 echo '<td>', $html->link($privilege['principal']), '</td>';
136             }
137             echo '<td>', $html->xmlName($privilege['privilege']), '</td>';
138             echo '<td>';
139             if (!empty($privilege['protected'])) echo '(protected)';
140             echo '</td>';
141             echo '</tr>';
142 
143         }
144         echo "</table>";
145         return ob_get_clean();
146 
147     }
148 
149     /**
150      * The deserialize method is called during xml parsing.
151      *
152      * This method is called statictly, this is because in theory this method
153      * may be used as a type of constructor, or factory method.
154      *
155      * Often you want to return an instance of the current class, but you are
156      * free to return other data as well.
157      *
158      * Important note 2: You are responsible for advancing the reader to the
159      * next element. Not doing anything will result in a never-ending loop.
160      *
161      * If you just want to skip parsing for this element altogether, you can
162      * just call $reader->next();
163      *
164      * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
165      * the next element.
166      *
167      * @param Reader $reader
168      * @return mixed
169      */
170     static function xmlDeserialize(Reader $reader) {
171 
172         $elementMap = [
173             '{DAV:}ace'       => 'Sabre\Xml\Element\KeyValue',
174             '{DAV:}privilege' => 'Sabre\Xml\Element\Elements',
175             '{DAV:}principal' => 'Sabre\DAVACL\Xml\Property\Principal',
176         ];
177 
178         $privileges = [];
179 
180         foreach ((array)$reader->parseInnerTree($elementMap) as $element) {
181 
182             if ($element['name'] !== '{DAV:}ace') {
183                 continue;
184             }
185             $ace = $element['value'];
186 
187             if (empty($ace['{DAV:}principal'])) {
188                 throw new DAV\Exception\BadRequest('Each {DAV:}ace element must have one {DAV:}principal element');
189             }
190             $principal = $ace['{DAV:}principal'];
191 
192             switch ($principal->getType()) {
193                 case Principal::HREF :
194                     $principal = $principal->getHref();
195                     break;
196                 case Principal::AUTHENTICATED :
197                     $principal = '{DAV:}authenticated';
198                     break;
199                 case Principal::UNAUTHENTICATED :
200                     $principal = '{DAV:}unauthenticated';
201                     break;
202                 case Principal::ALL :
203                     $principal = '{DAV:}all';
204                     break;
205 
206             }
207 
208             $protected = array_key_exists('{DAV:}protected', $ace);
209 
210             if (!isset($ace['{DAV:}grant'])) {
211                 throw new DAV\Exception\NotImplemented('Every {DAV:}ace element must have a {DAV:}grant element. {DAV:}deny is not yet supported');
212             }
213             foreach ($ace['{DAV:}grant'] as $elem) {
214                 if ($elem['name'] !== '{DAV:}privilege') {
215                     continue;
216                 }
217 
218                 foreach ($elem['value'] as $priv) {
219                     $privileges[] = [
220                         'principal' => $principal,
221                         'protected' => $protected,
222                         'privilege' => $priv,
223                     ];
224                 }
225 
226             }
227 
228         }
229 
230         return new self($privileges);
231 
232     }
233 
234     /**
235      * Serializes a single access control entry.
236      *
237      * @param Writer $writer
238      * @param array $ace
239      * @return void
240      */
241     private function serializeAce(Writer $writer, array $ace) {
242 
243         $writer->startElement('{DAV:}ace');
244 
245         switch ($ace['principal']) {
246             case '{DAV:}authenticated' :
247                 $principal = new Principal(Principal::AUTHENTICATED);
248                 break;
249             case '{DAV:}unauthenticated' :
250                 $principal = new Principal(Principal::UNAUTHENTICATED);
251                 break;
252             case '{DAV:}all' :
253                 $principal = new Principal(Principal::ALL);
254                 break;
255             default:
256                 $principal = new Principal(Principal::HREF, $ace['principal']);
257                 break;
258         }
259 
260         $writer->writeElement('{DAV:}principal', $principal);
261         $writer->startElement('{DAV:}grant');
262         $writer->startElement('{DAV:}privilege');
263 
264         $writer->writeElement($ace['privilege']);
265 
266         $writer->endElement(); // privilege
267         $writer->endElement(); // grant
268 
269         if (!empty($ace['protected'])) {
270             $writer->writeElement('{DAV:}protected');
271         }
272 
273         $writer->endElement(); // ace
274 
275     }
276 
277 }
278