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