[3733] | 1 | <?php |
---|
| 2 | /** |
---|
| 3 | * CalDAV Server - handle MKTICKET method in line with defunct proposed RFC |
---|
| 4 | * from: http://tools.ietf.org/html/draft-ito-dav-ticket-00 |
---|
| 5 | * |
---|
| 6 | * Why are we using a defunct RFC? Well, we want to support some kind of system |
---|
| 7 | * for providing a URI to people to give out for granting privileged access |
---|
| 8 | * without requiring logins. Using a defunct proposed spec seems better than |
---|
| 9 | * inventing our own. As well as Xythos, Cosmo follows this specification, |
---|
| 10 | * with some documented variations, which we will also follow. In particular |
---|
| 11 | * we use the xmlns="http://www.xythos.com/namespaces/StorageServer" rather |
---|
| 12 | * than the DAV: namespace. |
---|
| 13 | * |
---|
| 14 | * @package davical |
---|
| 15 | * @subpackage caldav |
---|
| 16 | * @author Andrew McMillan <andrew@mcmillan.net.nz> |
---|
| 17 | * @copyright Morphoss Ltd - http://www.morphoss.com/ |
---|
| 18 | * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later |
---|
| 19 | */ |
---|
| 20 | dbg_error_log('MKTICKET', 'method handler'); |
---|
| 21 | require_once('DAVResource.php'); |
---|
| 22 | |
---|
| 23 | $request->NeedPrivilege('DAV::bind'); |
---|
| 24 | |
---|
| 25 | require_once('XMLDocument.php'); |
---|
| 26 | $reply = new XMLDocument(array( 'DAV:' => '', 'http://www.xythos.com/namespaces/StorageServer' => 'T' )); |
---|
| 27 | |
---|
| 28 | $target = new DAVResource( $request->path ); |
---|
| 29 | if ( ! $target->Exists() ) { |
---|
| 30 | $request->XMLResponse( 404, new XMLElement( 'error', new XMLElement('resource-must-not-be-null'), $reply->GetXmlNsArray() ) ); |
---|
| 31 | } |
---|
| 32 | |
---|
| 33 | if ( ! isset($request->xml_tags) ) { |
---|
| 34 | $request->XMLResponse( 400, new XMLElement( 'error', new XMLElement('missing-xml-for-request'), $reply->GetXmlNsArray() ) ); |
---|
| 35 | } |
---|
| 36 | |
---|
| 37 | $xmltree = BuildXMLTree( $request->xml_tags, $position); |
---|
| 38 | if ( $xmltree->GetTag() != 'http://www.xythos.com/namespaces/StorageServer:ticketinfo' && |
---|
| 39 | $xmltree->GetTag() != 'DAV::ticketinfo' ) { |
---|
| 40 | $request->XMLResponse( 400, new XMLElement( 'error', new XMLElement('invalid-xml-for-request'), $reply->GetXmlNsArray() ) ); |
---|
| 41 | } |
---|
| 42 | |
---|
| 43 | $ticket_timeout = 'Seconds-3600'; |
---|
| 44 | $ticket_privs_array = array('read-free-busy'); |
---|
| 45 | foreach( $xmltree->GetContent() AS $k => $v ) { |
---|
| 46 | // <!ELEMENT ticketinfo (id?, owner?, timeout, visits, privilege)> |
---|
| 47 | switch( $v->GetTag() ) { |
---|
| 48 | case 'DAV::timeout': |
---|
| 49 | case 'http://www.xythos.com/namespaces/StorageServer:timeout': |
---|
| 50 | $ticket_timeout = $v->GetContent(); |
---|
| 51 | break; |
---|
| 52 | |
---|
| 53 | case 'DAV::privilege': |
---|
| 54 | case 'http://www.xythos.com/namespaces/StorageServer:privilege': |
---|
| 55 | $ticket_privs_array = $v->GetElements(); // Ensure we always get an array back |
---|
| 56 | $ticket_privileges = 0; |
---|
| 57 | foreach( $ticket_privs_array AS $k1 => $v1 ) { |
---|
| 58 | $ticket_privileges |= privilege_to_bits( $v1->GetTag() ); |
---|
| 59 | } |
---|
| 60 | if ( $ticket_privileges & privilege_to_bits('write') ) $ticket_privileges |= privilege_to_bits( 'read' ); |
---|
| 61 | if ( $ticket_privileges & privilege_to_bits('read') ) $ticket_privileges |= privilege_to_bits( array('read-free-busy', 'read-current-user-privilege-set') ); |
---|
| 62 | if ( $ticket_privileges & privilege_to_bits('read-free-busy') ) $ticket_privileges |= privilege_to_bits( 'schedule-query-freebusy'); |
---|
| 63 | break; |
---|
| 64 | } |
---|
| 65 | } |
---|
| 66 | |
---|
| 67 | if ( $ticket_timeout == 'infinity' ) { |
---|
| 68 | $sql_timeout = null; |
---|
| 69 | } |
---|
| 70 | else if ( preg_match( '{^([a-z]+)-(\d+)$}i', $ticket_timeout, $matches ) ) { |
---|
| 71 | /** It isn't specified, but timeout seems to be 'unit-number' like 'Seconds-3600', so we make it '3600 Seconds' which PostgreSQL understands */ |
---|
| 72 | $sql_timeout = $matches[2] . ' ' . $matches[1]; |
---|
| 73 | } |
---|
| 74 | else { |
---|
| 75 | $sql_timeout = $ticket_timeout; |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | $collection_id = $target->GetProperty('collection_id'); |
---|
| 79 | $resource_id = $target->GetProperty('dav_id'); |
---|
| 80 | |
---|
| 81 | $i = 0; |
---|
| 82 | do { |
---|
| 83 | $ticket_id = substr( str_replace('/', '', str_replace('+', '',base64_encode(sha1(date('r') .rand(0,2100000000) . microtime(true),true)))), 7, 8); |
---|
| 84 | $qry = new AwlQuery( |
---|
| 85 | 'INSERT INTO access_ticket ( ticket_id, dav_owner_id, privileges, target_collection_id, target_resource_id, expires ) |
---|
| 86 | VALUES( :ticket_id, :owner, :privs::INT::BIT(24), :collection, :resource, (current_timestamp + :expires::interval) )', |
---|
| 87 | array( |
---|
| 88 | ':ticket_id' => $ticket_id, |
---|
| 89 | ':owner' => $session->principal_id, |
---|
| 90 | ':privs' => $ticket_privileges, |
---|
| 91 | ':collection' => $collection_id, |
---|
| 92 | ':resource' => $resource_id, |
---|
| 93 | ':expires' => $sql_timeout, |
---|
| 94 | ) |
---|
| 95 | ); |
---|
| 96 | $result = $qry->Exec('MKTICKET', __LINE__, __FILE__); |
---|
| 97 | } while( !$result && $i++ < 2 ); |
---|
| 98 | |
---|
| 99 | $privs = new XMLElement('privilege'); |
---|
| 100 | foreach( bits_to_privilege($ticket_privileges) AS $k => $v ) { |
---|
| 101 | $reply->NSElement($privs, $v); |
---|
| 102 | } |
---|
| 103 | |
---|
| 104 | $ticketinfo = new XMLElement( 'T:ticketinfo', array( |
---|
| 105 | new XMLElement( 'T:id', $ticket_id), |
---|
| 106 | new XMLElement( 'owner', $reply->href( ConstructURL('/'.$session->username.'/') ) ), |
---|
| 107 | $privs, |
---|
| 108 | new XMLElement( 'T:timeout', $ticket_timeout), |
---|
| 109 | new XMLElement( 'T:visits', 'infinity') |
---|
| 110 | ) |
---|
| 111 | ); |
---|
| 112 | |
---|
| 113 | $prop = new XMLElement( "prop", new XMLElement('T:ticketdiscovery', $ticketinfo), $reply->GetXmlNsArray() ); |
---|
| 114 | header('Ticket: '.$ticket_id); |
---|
| 115 | $request->XMLResponse( 200, $prop ); |
---|