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