Domanda

So far I have been unable to successfully implement ACLs (permissions) in SabreDAV.

I have implemented SabreDAV in Code Igniter with my own Auth, Principal and CalDAV backend. This the actual code from the controller:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class CalDAV extends CI_Controller {

    public function _remap() {
        $this->load->library('SabreDAV');

        $authBackend = new SabreDAV_DAV_Auth_Backend_Tank_Auth;
        $principalBackend = new Sabre_DAVACL_PrincipalBackend_Click4Time;
        $calendarBackend = new Sabre_CalDAV_Backend_Click4Time;

        // Directory tree
        $tree = array(
            new Sabre_DAVACL_PrincipalCollection($principalBackend),
            new Sabre_CalDAV_CalendarRootNode($principalBackend, $calendarBackend)
        );      

        // The object tree needs in turn to be passed to the server class
        $server = new Sabre_DAV_Server($tree);

        // You are highly encouraged to set your WebDAV server base url. Without it,
        // SabreDAV will guess, but the guess is not always correct. Putting the
        // server on the root of the domain will improve compatibility. 
        $server->setBaseUri('/caldav/');

        // Authentication plugin
        $authPlugin = new Sabre_DAV_Auth_Plugin($authBackend, 'SabreDAV');
        $server->addPlugin($authPlugin);

        // CalDAV plugin
        $caldavPlugin = new Sabre_CalDAV_Plugin();
        $server->addPlugin($caldavPlugin);

        // ACL plugin
        $aclPlugin = new Sabre_DAVACL_Custom;
        $server->addPlugin($aclPlugin);

        // Support for html frontend
        $browser = new Sabre_DAV_Browser_Plugin();
        $server->addPlugin($browser);

        $server->exec();
    }
}

My current attempt at implementing permissions has been through my custom ACL Plugin:

<?php

class Sabre_DAVACL_Custom extends Sabre_DAVACL_Plugin {

    public $allowAccessToNodesWithoutACL = false;

    private function _getCurrentUserName() {
        $authPlugin = $this->server->getPlugin('auth');
        if (is_null($authPlugin)) return null;

        return $authPlugin->getCurrentUser();
    }

    public function getACL($node) {
        $user = $this->_getCurrentUserName();
        $path = $node->getName();

        if ($path == 'calendars' || $path == 'principals' || $path == 'root') {
            return array(
                array(
                    'privilege' => '{DAV:}read',
                    'principal' => 'principals/' . $user,
                    'protected' => true,
                )
            );
        }
        else if ($path == 'calendars/' . $user) {
            return array(
                array(
                    'privilege' => '{DAV:}read',
                    'principal' => 'principals/' . $user,
                    'protected' => true,
                )
            );
        }

        return array();
    }
}

This code pretty much works except the second check which should authorize the user to see his or her own calendar(s). I am unable to get the full path name for $node.

This may be the wrong way to implement but I have been unable to find any documentation to confirm that this is the way to implement ACLs.

È stato utile?

Soluzione

i'm using a different attempt, i extended the plugin, just like you did but then i replaced getSupportedPrivilegeSet($node) instead.

in sabredav 1.8.6 it looks like this:

public function getSupportedPrivilegeSet($node) {

    if (is_string($node)) {
        $node = $this->server->tree->getNodeForPath($node);
    }

    if ($node instanceof IACL) {
        $result = $node->getSupportedPrivilegeSet();

        if ($result)
            return $result;
    }

    return self::getDefaultSupportedPrivilegeSet();

}

now you can use the classes instead of the path which i found more usefull, i.e.:

class DavCalAcl extends \Sabre\DAVACL\Plugin {

public function getSupportedPrivilegeSet($node) {       
    if (is_string($node)) {
        $node = $this->server->tree->getNodeForPath($node);
    }

    if($node instanceof \Sabre\CalDAV\Calendar || $node instanceof \Sabre\CalDAV\CalendarObject) {
        return array(
            array(
                'privilege'  => '{DAV:}read',
                'aggregates' => array(
                    array(
                        'privilege' => '{DAV:}read-acl',
                        'abstract'  => true,
                    ),
                    array(
                        'privilege' => '{DAV:}read-current-user-privilege-set',
                        'abstract'  => true,
                    ),
                ),
            )
        );
    }

    if ($node instanceof \Sabre\DAVACL\IACL) {
        $result = $node->getSupportedPrivilegeSet();
        if ($result)
            return $result;
    }

    return self::getDefaultSupportedPrivilegeSet();
}

}

this is my current attempt to get iCal to recognize a calendar as read-only... i'm not quite there yet but maybe this will help you in better identifying the objects

if you want the absolute path of a node i guess you could always go to the root search it for your current node and by doing so recording the path which took you there. as far as i checked the nodes in sabredav do not support a parent or a root property.

[UPDATE]

the best way seems to be to override getACL in the plugin. here you can test for the node's class and return what you really want on instead of the stuff which is returned by the default objects (for instance look at UserCalendars->getACL().

here's my working solution for read-only enforcement based on the object types:

class DavCalAcl extends \Sabre\DAVACL\Plugin {

    /**
     * Returns the full ACL list.
     *
     * Either a uri or a DAV\INode may be passed.
     *
     * null will be returned if the node doesn't support ACLs.
     *
     * @param string|DAV\INode $node
     * @return array
     */
    public function getACL($node) {

        if (is_string($node)) {
            $node = $this->server->tree->getNodeForPath($node);
        }
        if (!$node instanceof \Sabre\DAVACL\IACL) {
            return null;
        }

        if( $node instanceof \Sabre\CalDAV\Calendar ||
            $node instanceof \Sabre\CalDAV\CalendarObject ||
            $node instanceof \Sabre\CalDAV\UserCalendars
        ) {
            $acl = array(
                array(
                    'privilege' => '{DAV:}read',
                    'principal' => $node->getOwner(),
                    'protected' => true,
                ),
            );
        } else {
            $acl = $node->getACL();         
        }

        foreach($this->adminPrincipals as $adminPrincipal) {
            $acl[] = array(
                'principal' => $adminPrincipal,
                'privilege' => '{DAV:}all',
                'protected' => true,
            );
        }
        return $acl;

    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top