PageRenderTime 218ms CodeModel.GetById 122ms app.highlight 36ms RepoModel.GetById 51ms app.codeStats 1ms

/system/classes/acl.php

https://github.com/HabariMag/habarimag-old
PHP | 850 lines | 525 code | 94 blank | 231 comment | 103 complexity | 7500ff621cdb7d172f8d926fef1b6d58 MD5 | raw file
  1<?php
  2/**
  3 * @package Habari
  4 *
  5 */
  6
  7/**
  8 * Access Control List class
  9 *
 10 * The default Habari ACL class implements groups, and group permissions
 11 * Users are assigned to one or more groups.
 12 * Groups are assigned one or more permissions.
 13 * Membership in any group that grants a permission
 14 * means you have that permission.  Membership in any group that denies
 15 * that permission denies the user that permission, even if another group
 16 * grants that permission.
 17 *
 18 */
 19class ACL
 20{
 21	/**
 22	 * How to handle a permission request for a permission that is not in the permission list.
 23	 * For example, if you request $user->can('some non-existent permission') then this value is returned.
 24	 */
 25	const ACCESS_NONEXISTENT_PERMISSION = 0;
 26	const CACHE_NULL = -1;
 27
 28	public static $access_names = array( 'read', 'edit', 'delete', 'create' );
 29	private static $token_cache = null;
 30
 31	/**
 32	 * Check a permission bitmask for a particular access type.
 33	 * @param Bitmask $bitmask The permission bitmask
 34	 * @param mixed $access The name of the access to check against (read, write, full)
 35	 * @return bool Returns true if the given access meets exceeds the access to check against
 36	 */
 37	public static function access_check( $bitmask, $access )
 38	{
 39		if ( $access instanceof Bitmask ) {
 40			return ( $bitmask->value & $access->value ) == $access->value;
 41		}
 42
 43		switch ( $access ) {
 44			case 'full':
 45				return $bitmask->value == $bitmask->full;
 46			case 'any':
 47				return $bitmask->value != 0;
 48			case 'deny':
 49				return $bitmask->value == 0;
 50			default:
 51				return $bitmask->$access;
 52		}
 53	}
 54
 55	/**
 56	 * Get a Bitmask object representing the supplied access integer
 57	 *
 58	 * @param integer $mask The access mask, usually stored in the database
 59	 * @return Bitmask An object representing the access value
 60	 */
 61	public static function get_bitmask( $mask )
 62	{
 63		$bitmask = new Bitmask( self::$access_names, $mask );
 64		return $bitmask;
 65	}
 66
 67	/**
 68	 * Create a new permission token, and save it to the permission tokens table
 69	 * @param string $name The name of the permission
 70	 * @param string $description The description of the permission
 71	 * @param string $group The token group for organizational purposes
 72	 * @param bool $crud Indicates if the token is a CRUD or boolean type token (default is boolean)
 73	 * @return mixed the ID of the newly created permission, or boolean false
 74	 */
 75	public static function create_token( $name, $description, $group, $crud = false )
 76	{
 77		$name = self::normalize_token( $name );
 78		$crud = ( $crud ) ? 1 : 0;
 79		// first, make sure this isn't a duplicate
 80		if ( ACL::token_exists( $name ) ) {
 81			return false;
 82		}
 83		$allow = true;
 84		// Plugins have the opportunity to prevent adding this token
 85		$allow = Plugins::filter( 'token_create_allow', $allow, $name, $description, $group, $crud );
 86		if ( ! $allow ) {
 87			return false;
 88		}
 89		Plugins::act( 'token_create_before', $name, $description, $group, $crud );
 90
 91		$result = DB::query( 'INSERT INTO {tokens} (name, description, token_group, token_type) VALUES (?, ?, ?, ?)', array( $name, $description, $group, $crud ) );
 92
 93		if ( ! $result ) {
 94			// if it didn't work, don't bother trying to log it
 95			return false;
 96		}
 97
 98		self::clear_caches();
 99
100		// Add the token to the admin group
101		$token = ACL::token_id( $name );
102		$admin = UserGroup::get( 'admin' );
103		if ( $admin ) {
104			ACL::grant_group( $admin->id, $token, 'full' );
105		}
106
107		EventLog::log( 'New permission token created: ' . $name, 'info', 'default', 'habari' );
108		Plugins::act( 'permission_create_after', $name, $description, $group, $crud );
109		return $result;
110	}
111
112	/**
113	 * Remove a permission token, and any assignments of it
114	 * @param mixed $permission a permission ID or name
115	 * @return bool whether the permission was deleted or not
116	 */
117	public static function destroy_token( $token )
118	{
119		// make sure the permission exists, first
120		if ( ! self::token_exists( $token ) ) {
121			return false;
122		}
123
124		// grab token ID
125		$token_id = self::token_id( $token );
126
127		$allow = true;
128		// plugins have the opportunity to prevent deletion
129		$allow = Plugins::filter( 'token_destroy_allow', $allow, $token_id );
130		if ( ! $allow ) {
131			return false;
132		}
133		Plugins::act( 'token_destroy_before', $token_id );
134		// capture the token name
135		$name = DB::get_value( 'SELECT name FROM {tokens} WHERE id=?', array( $token_id ) );
136		// remove all references to this permissions
137		$result = DB::query( 'DELETE FROM {group_token_permissions} WHERE token_id=?', array( $token_id ) );
138		$result = DB::query( 'DELETE FROM {user_token_permissions} WHERE token_id=?', array( $token_id ) );
139		$result = DB::query( 'DELETE FROM {post_tokens} WHERE token_id=?', array( $token_id ) );
140		ACL::clear_caches();
141		// remove this token
142		$result = DB::query( 'DELETE FROM {tokens} WHERE id=?', array( $token_id ) );
143		if ( ! $result ) {
144			// if it didn't work, don't bother trying to log it
145			return false;
146		}
147		EventLog::log( sprintf( _t( 'Permission token deleted: %s' ), $name ), 'info', 'default', 'habari' );
148		Plugins::act( 'token_destroy_after', $token_id );
149		return $result;
150	}
151
152	/**
153	 * Get an array of QueryRecord objects containing all permission tokens
154	 * @param string $order the order in which to sort the returning array
155	 * @return array an array of QueryRecord objects containing all tokens
156	 */
157	public static function all_tokens( $order = 'id' )
158	{
159		$order = strtolower( $order );
160		if ( ( 'id' != $order ) && ( 'name' != $order ) && ( 'description' != $order ) ) {
161			$order = 'id';
162		}
163		$tokens = DB::get_results( 'SELECT id, name, description, token_group, token_type FROM {tokens} ORDER BY ' . $order );
164		return $tokens ? $tokens : array();
165	}
166
167	/**
168	 * Get a permission token's name by its ID
169	 * @param int $id a token ID
170	 * @return string the name of the permission, or boolean false
171	 */
172	public static function token_name( $id )
173	{
174		if ( ! is_int( $id ) ) {
175			return false;
176		}
177		else {
178			$tokens = ACL::cache_tokens();
179			return isset( $tokens[ $id ] ) ? $tokens[ $id ] : false;
180		}
181	}
182
183	/**
184	 * Get an associative array of token ids and their name.
185	 *
186	 * @return array an array in the form id => name
187	 */
188	private static function cache_tokens()
189	{
190		if ( ACL::$token_cache == null ) {
191			ACL::$token_cache = DB::get_keyvalue( 'SELECT id, name FROM {tokens}' );
192		}
193		return ACL::$token_cache;
194	}
195
196	/**
197	 * Get a permission token's ID by its name
198	 * @param string $name the name of the permission
199	 * @return int the permission's ID
200	 */
201	public static function token_id( $name )
202	{
203		if ( is_numeric( $name ) ) {
204			return intval( $name );
205		}
206		$name = self::normalize_token( $name );
207		if ( $token = array_search( $name, ACL::cache_tokens() ) ) {
208			return $token;
209		}
210		return false;
211	}
212
213	/**
214	 * Fetch a permission token's description from the DB
215	 * @param mixed $permission a permission name or ID
216	 * @return string the description of the permission
217	 */
218	public static function token_description( $permission )
219	{
220		if ( is_int( $permission ) ) {
221			$query = 'id';
222		}
223		else {
224			$query = 'name';
225			$permission = self::normalize_token( $permission );
226		}
227		return DB::get_value( "SELECT description FROM {tokens} WHERE $query=?", array( $permission ) );
228	}
229
230	/**
231	 * Determine whether a permission token exists
232	 * @param mixed $permission a permission name or ID
233	 * @return bool whether the permission exists or not
234	 */
235	public static function token_exists( $permission )
236	{
237		if ( is_numeric( $permission ) ) {
238			$query = 'id';
239		}
240		else {
241			$query = 'name';
242			$permission = self::normalize_token( $permission );
243		}
244		return ( (int) DB::get_value( "SELECT COUNT(id) FROM {tokens} WHERE $query=?", array( $permission ) ) > 0 );
245	}
246
247	/**
248	 * Determine whether a group can perform a specific action
249	 * @param mixed $group A group ID or name
250	 * @param mixed $token_id A permission token ID or name
251	 * @param string $access Check for 'create', 'read', 'update', 'delete', or 'full' access
252	 * @return bool Whether the group can perform the action
253	 */
254	public static function group_can( $group, $token_id, $access = 'full' )
255	{
256		$bitmask = self::get_group_token_access( $group, $token_id );
257
258		if ( isset( $bitmask ) && self::access_check( $bitmask, $access ) ) {
259			// the permission has been granted to this group
260			return true;
261		}
262		// either the permission hasn't been granted, or it's been
263		// explicitly denied.
264		return false;
265	}
266
267	/**
268	 * Determine whether a group is explicitly denied permission to perform a specific action
269	 * This function does not return true if the group is merely not granted a permission
270	 * @param mixed $user A group ID or a group name
271	 * @param mixed $token_id A permission ID or name
272	 * @return bool True if access to the token is denied to the group
273	 */
274	public static function group_cannot( $group, $token_id )
275	{
276
277		$result = self::get_group_token_access( $group, $token_id );
278		if ( isset( $result ) && self::access_check( $result, 'deny' ) ) {
279			return true;
280		}
281
282		// The permission has been granted, or it hasn't been explicitly denied.
283		return false;
284	}
285
286	/**
287	 * Determine whether a user can perform a specific action
288	 * @param mixed $user A user object, user ID or a username
289	 * @param mixed $token_id A permission ID or name
290	 * @param string $access Check for 'create', 'read', 'update', 'delete', or 'full' access
291	 * @return bool Whether the user can perform the action
292	 */
293	public static function user_can( $user, $token_id, $access = 'full' )
294	{
295
296		$result = self::get_user_token_access( $user, $token_id );
297
298		if ( isset( $result ) && self::access_check( $result, $access ) ) {
299			return true;
300		}
301
302		$super_user_access = self::get_user_token_access( $user, 'super_user' );
303		if ( isset( $super_user_access ) && self::access_check( $super_user_access, 'any' ) ) {
304			return true;
305		}
306
307		// either the permission hasn't been granted, or it's been
308		// explicitly denied.
309		return false;
310	}
311
312	/**
313	 * Determine whether a user is explicitly denied permission to perform a specific action
314	 * This function does not return true if the user is merely not granted a permission
315	 * @param mixed $user A User object, user ID or a username
316	 * @param mixed $token_id A permission ID or name
317	 * @return bool True if access to the token is denied to the user
318	 */
319	public static function user_cannot( $user, $token_id )
320	{
321
322		$result = self::get_user_token_access( $user, $token_id );
323		if ( isset( $result ) && self::access_check( $result, 'deny' ) ) {
324			return true;
325		}
326
327		// The permission has been granted, or it hasn't been explicitly denied.
328		return false;
329	}
330
331	/**
332	 * Return the access bitmask to a specific token for a specific user
333	 *
334	 * @param mixed $user A User object instance or user id
335	 * @param mixed $token_id A permission token name or token ID
336	 * @return integer An access bitmask
337	 */
338	public static function get_user_token_access( $user, $token )
339	{
340		// Use only numeric ids internally
341		$token_id = self::token_id( $token );
342
343		/**
344		 * Do we allow perms that don't exist?
345		 * When ACL is functional ACCESS_NONEXISTENT_PERMISSION should be false by default.
346		 */
347		if ( is_null( $token_id ) ) {
348			return self::get_bitmask( self::ACCESS_NONEXISTENT_PERMISSION );
349		}
350
351		// if we were given a user ID, use that to fetch the group membership from the DB
352		if ( is_numeric( $user ) ) {
353			$user_id = $user;
354		}
355		else {
356			// otherwise, make sure we have a User object, and get
357			// the groups from that
358			if ( ! $user instanceof User ) {
359				$user = User::get( $user );
360			}
361			$user_id = $user->id;
362		}
363
364		if ( defined( 'LOCKED_OUT_SUPER_USER' ) && $token == 'super_user' ) {
365			$su = User::get( LOCKED_OUT_SUPER_USER );
366			if ( $su->id == $user_id ) {
367				return new Bitmask( self::$access_names, 'read');
368			}
369		}
370
371		// check the cache first for the user's access_mask on the token
372		if ( isset( $_SESSION[ 'user_token_access' ][ $user_id ][ $token_id ] ) ) {
373//			Utils::debug($token, $_SESSION['user_token_access'][$token_id]);
374			if ( $_SESSION[ 'user_token_access' ][ $user_id ][ $token_id ] == ACL::CACHE_NULL ) {
375				return null;
376			}
377			else {
378				return self::get_bitmask( $_SESSION[ 'user_token_access' ][ $user_id ][ $token_id ] );
379			}
380		}
381
382		/**
383		 * Jay Pipe's explanation of the following SQL
384		 * 1) Look into user_permissions for the user and the token.
385		 * If exists, use that permission flag for the check. If not,
386		 * go to 2)
387		 *
388		 * 2) Look into the group_permissions joined to
389		 * users_groups for the user and the token.  Order the results
390		 * by the access bitmask. The lower the mask value, the
391		 * fewest permissions that group has. Use the first record's
392		 * access mask to check the ACL.
393		 *
394		 * This gives the system very fine grained control and grabbing
395		 * the permission flag and can be accomplished in a single SQL
396		 * call.
397		 */
398
399		$exceptions = '';
400		$default_groups = array();
401		$default_groups = Plugins::filter( 'user_default_groups', $default_groups, $user_id );
402		$default_groups = array_filter( array_map( 'intval', $default_groups ) );
403		switch ( count( $default_groups ) ) {
404			case 0: // do nothing
405				break;
406			case 1: // single argument
407				$exceptions = 'OR ug.group_id = ' . reset( $default_groups );
408				break;
409			default: // multiple arguments
410				$exceptions = 'OR ug.group_id IN (' . implode( ',', $default_groups ) . ')';
411				break;
412		}
413
414		$sql = <<<SQL
415SELECT access_mask
416	FROM {user_token_permissions}
417	WHERE user_id = ?
418	AND token_id = ?
419UNION ALL
420SELECT gp.access_mask
421	FROM {users_groups} ug
422	INNER JOIN {group_token_permissions} gp
423	ON ((ug.group_id = gp.group_id
424	AND ug.user_id = ?)
425	{$exceptions})
426	AND gp.token_id = ?
427	ORDER BY access_mask ASC
428SQL;
429
430		if ( $token_id == '' ) { $token_id = '0'; }
431
432		$accesses = DB::get_column( $sql, array( $user_id, $token_id, $user_id, $token_id ) );
433
434		$accesses = Plugins::filter( 'user_token_access', $accesses, $user_id, $token_id );
435
436		if ( count( $accesses ) == 0 ) {
437			$_SESSION[ 'user_token_access' ][ $user_id ][ $token_id ] = ACL::CACHE_NULL;
438			return null;
439		}
440		else {
441			$result = 0;
442			foreach ( (array) $accesses as $access ) {
443				if ( $access == 0 ) {
444					$result = 0;
445					break;
446				}
447				else {
448					$result |= $access;
449				}
450			}
451
452			$_SESSION[ 'user_token_access' ][ $user_id ][ $token_id ] = $result;
453			return self::get_bitmask( $result );
454		}
455	}
456
457	/**
458	 * Get all the tokens for a given user with a particular kind of access
459	 * @param mixed $user A user object, user ID or a username
460	 * @param string $access Check for 'create' or 'read', 'update', or 'delete' access
461	 * @return array of token IDs
462	 */
463	public static function user_tokens( $user, $access = 'full', $posts_only = false )
464	{
465		static $post_tokens = null;
466
467		$bitmask = new Bitmask ( self::$access_names );
468		$tokens = array();
469
470		// convert $user to an ID
471		if ( is_numeric( $user ) ) {
472			$user_id = $user;
473		}
474		else {
475			if ( ! $user instanceof User ) {
476				$user = User::get( $user );
477			}
478			$user_id = $user->id;
479		}
480
481		// Implement cache RIGHT HERE
482		if ( isset( $_SESSION[ 'user_tokens' ][ $user_id ][ $access ] ) ) {
483			return $_SESSION[ 'user_tokens' ][ $user_id ][ $access ];
484		}
485
486		$super_user_access = self::get_user_token_access( $user, 'super_user' );
487		if ( isset( $super_user_access ) && self::access_check( $super_user_access, 'any' ) ) {
488			$token_ids = DB::get_column( 'SELECT id as token_id FROM {tokens}' );
489			$result = array();
490			foreach ( $token_ids as $id ) {
491				$result_row = new StdClass();
492				$result_row->token_id = $id;
493				$result_row->access_mask = $bitmask->full;
494				$result[] = $result_row;
495			}
496		}
497		else {
498
499			$sql = <<<SQL
500SELECT token_id, access_mask
501	FROM {user_token_permissions}
502	WHERE user_id = :user_id
503UNION ALL
504SELECT gp.token_id, gp.access_mask
505	FROM {users_groups} ug
506	INNER JOIN {group_token_permissions} gp
507	ON ug.group_id = gp.group_id
508	AND ug.user_id = :user_id
509	ORDER BY token_id ASC
510SQL;
511			$result = DB::get_results( $sql, array( ':user_id' => $user_id ) );
512		}
513
514		if ( $posts_only && !isset( $post_tokens ) ) {
515			$post_tokens = DB::get_column( 'SELECT token_id FROM {post_tokens} GROUP BY token_id' );
516		}
517
518		foreach ( (array) $result as $token ) {
519			$bitmask->value = $token->access_mask;
520			if ( $access === 'deny' ) {
521				if ( $bitmask->value === 0 ) {
522					$tokens[] = $token->token_id;
523				}
524			}
525			elseif ( $bitmask->$access ) {
526				$tokens[] = $token->token_id;
527			}
528		}
529
530		if ( $posts_only ) {
531			$tokens = array_intersect( $tokens, $post_tokens );
532		}
533
534		$_SESSION[ 'user_tokens' ][ $user_id ][ $access ] = $tokens;
535		return $tokens;
536	}
537
538	/**
539	 * Get the access bitmask of a group for a specific permission token
540	 * @param integer $group The group ID
541	 * @param mixed $token_id A permission name or ID
542	 * @return an access bitmask
543	 */
544	public static function get_group_token_access( $group, $token_id )
545	{
546		// Use only numeric ids internally
547		$group = UserGroup::id( $group );
548		$token_id = self::token_id( $token_id );
549		$sql = 'SELECT access_mask FROM {group_token_permissions} WHERE
550			group_id=? AND token_id=?;';
551
552		$result = DB::get_value( $sql, array( $group, $token_id ) );
553
554		if ( isset( $result ) ) {
555			return self::get_bitmask( $result );
556		}
557		return null;
558	}
559
560	/**
561	 * Grant a permission to a group
562	 * @param integer $group_id The group ID
563	 * @param mixed $token_id The name or ID of the permission token to grant
564	 * @param string $access The kind of access to assign the group
565	 * @return Result of the DB query
566	 */
567	public static function grant_group( $group_id, $token_id, $access = 'full' )
568	{
569		$token_id = self::token_id( $token_id );
570		$results = DB::get_column( 'SELECT access_mask FROM {group_token_permissions} WHERE group_id=? AND token_id=?', array( $group_id, $token_id ) );
571		$access_mask = 0;
572		$row_exists = false;
573		if ( $results ) {
574			$row_exists = true;
575			if ( in_array( 0, $results ) ) {
576					$access_mask = 0;
577				}
578			else {
579				$access_mask = Utils::array_or( $results );
580			}
581		}
582
583		$bitmask = self::get_bitmask( $access_mask );
584		$orig_value = $bitmask->value;
585
586		if ( $access instanceof Bitmask ) {
587			$bitmask->value = $access->value;
588		}
589		elseif ( $access == 'full' ) {
590			$bitmask->value = $bitmask->full;
591		}
592		elseif ( $access == 'deny' ) {
593			$bitmask->value = 0;
594		}
595		else {
596			$bitmask->$access = true;
597		}
598
599		// Only update if the value is changed
600		if ( $orig_value != $bitmask->value || ( $orig_value == 0 && !$row_exists && $bitmask->value == 0 ) ) {
601			// DB::update will insert if the token is not already in the group tokens table
602			$result = DB::update(
603				'{group_token_permissions}',
604				array( 'access_mask' => $bitmask->value ),
605				array( 'group_id' => $group_id, 'token_id' => $token_id )
606			);
607			ACL::clear_caches();
608
609			$ug = UserGroup::get_by_id( $group_id );
610			$ug->clear_permissions_cache();
611			$msg = _t( 'Group %1$s: Access to %2$s changed to %3$s', array( $ug->name, ACL::token_name( $token_id ), $bitmask ) );
612			EventLog::log( $msg, 'notice', 'user', 'habari' );
613		}
614		else {
615			$result = true;
616		}
617
618		return $result;
619	}
620
621	/**
622	 * Grant a permission to a user
623	 * @param integer $user_id The user ID
624	 * @param integer $token_id The name or ID of the permission token to grant
625	 * @param string $access The kind of access to assign the group
626	 * @return Result of the DB query
627	 */
628	public static function grant_user( $user_id, $token_id, $access = 'full' )
629	{
630		$token_id = self::token_id( $token_id );
631		$access_mask = DB::get_value( 'SELECT access_mask FROM {user_token_permissions} WHERE user_id=? AND token_id=?',
632			array( $user_id, $token_id ) );
633		if ( $access_mask ===  false ) {
634			$permission_bit = 0; // default is 'deny' (bitmask 0)
635		}
636
637		$bitmask = self::get_bitmask( $access_mask );
638
639		if ( $access == 'full' ) {
640			$bitmask->value= $bitmask->full;
641		}
642		elseif ( $access == 'deny' ) {
643			$bitmask->value = 0;
644		}
645		else {
646			$bitmask->$access = true;
647		}
648
649		$result = DB::update(
650			'{user_token_permissions}',
651			array( 'access_mask' => $bitmask->value ),
652			array( 'user_id' => $user_id, 'token_id' => $token_id )
653		);
654
655		ACL::clear_caches();
656
657		return $result;
658	}
659
660	/**
661	 * Deny permission to a group
662	 * @param integer $group_id The group ID
663	 * @param mixed $token_id The name or ID of the permission token
664	 * @return Result of the DB query
665	 */
666	public static function deny_group( $group_id, $token_id )
667	{
668		self::grant_group( $group_id, $token_id, 'deny' );
669	}
670
671	/**
672	 * Deny permission to a user
673	 * @param integer $user_id The user ID
674	 * @param mixed $token_id The name or ID of the permission token
675	 * @return Result of the DB query
676	 */
677	public static function deny_user( $user_id, $token_id )
678	{
679		self::grant_user( $group_id, $token_id, 'deny' );
680	}
681
682	/**
683	 * Remove a permission token from the group permissions table
684	 * @param integer $group_id The group ID
685	 * @param mixed $token_id The name or ID of the permission token
686	 * @return the result of the DB query
687	 */
688	public static function revoke_group_token( $group_id, $token_id )
689	{
690		$token_id = self::token_id( $token_id );
691		$ug = UserGroup::get_by_id( $group_id );
692
693		$access = self::get_group_token_access( $group_id, $token_id );
694
695		if ( empty( $access ) ) {
696			$result = true;
697		}
698		else {
699			$result = DB::delete( '{group_token_permissions}',
700				array( 'group_id' => $group_id, 'token_id' => $token_id ) );
701			EventLog::log( _t( 'Group %1$s: Permission to %2$s revoked.', array( $ug->name, ACL::token_name( $token_id ) ) ), 'notice', 'user', 'habari' );
702		}
703
704		$ug->clear_permissions_cache();
705		ACL::clear_caches();
706
707		return $result;
708	}
709
710	/**
711	 * Remove a permission token from the user permissions table
712	 * @param integer $user_id The user ID
713	 * @param mixed $token_id The name or ID of the permission token
714	 * @return the result of the DB query
715	 */
716	public static function revoke_user_token( $user_id, $token_id )
717	{
718		$token_id = self::token_id( $token_id );
719		$result = DB::delete( '{user_token_permissions}',
720			array( 'user_id' => $user_id, 'token_id' => $token_id ) );
721
722		ACL::clear_caches();
723
724		return $result;
725	}
726
727	/**
728	 * Convert a token name into a valid format
729	 *
730	 * @param string $name The name of a permission
731	 * @return string The permission with spaces converted to underscores and all lowercase
732	 */
733	public static function normalize_token( $name )
734	{
735		return strtolower( preg_replace( '/\s+/u', '_', trim( $name ) ) );
736	}
737
738	/**
739	 * Clears all caches used to hold permissions
740	 *
741	 */
742	public static function clear_caches()
743	{
744		if ( isset( $_SESSION[ 'user_token_access' ] ) ) {
745			unset( $_SESSION[ 'user_token_access' ] );
746
747		}
748		if ( isset( $_SESSION[ 'user_tokens' ] ) ) {
749			unset( $_SESSION[ 'user_tokens' ] );
750		}
751		self::$token_cache = null;
752	}
753
754	/**
755	 * Creates the default set of permissions.
756	 */
757	public static function create_default_tokens()
758	{
759		// super user token
760		self::create_token( 'super_user', 'Permissions for super users', 'Super User' );
761
762		// admin tokens
763		self::create_token( 'manage_all_comments', _t( 'Manage comments on all posts' ), 'Administration' );
764		self::create_token( 'manage_own_post_comments', _t( 'Manage comments on one\'s own posts' ), 'Administration' );
765		self::create_token( 'manage_tags', _t( 'Manage tags' ), 'Administration' );
766		self::create_token( 'manage_options', _t( 'Manage options' ), 'Administration' );
767		self::create_token( 'manage_theme', _t( 'Change theme' ), 'Administration' );
768		self::create_token( 'manage_theme_config', _t( 'Configure the active theme' ), 'Administration' );
769		self::create_token( 'manage_plugins', _t( 'Activate/deactivate plugins' ), 'Administration' );
770		self::create_token( 'manage_plugins_config', _t( 'Configure active plugins' ), 'Administration' );
771		self::create_token( 'manage_import', _t( 'Use the importer' ), 'Administration' );
772		self::create_token( 'manage_users', _t( 'Add, remove, and edit users' ), 'Administration' );
773		self::create_token( 'manage_self', _t( 'Edit own profile' ), 'Administration' );
774		self::create_token( 'manage_groups', _t( 'Manage groups and permissions' ), 'Administration' );
775		self::create_token( 'manage_logs', _t( 'Manage logs' ), 'Administration' );
776
777		// content tokens
778		self::create_token( 'own_posts', _t( 'Permissions on one\'s own posts' ), _t( 'Content' ), true );
779		self::create_token( 'post_any', _t( 'Permissions to all posts' ), _t( 'Content' ), true );
780		self::create_token( 'post_unpublished', _t( "Permissions to other users' unpublished posts" ), _t( 'Content' ), true );
781		foreach ( Post::list_active_post_types() as $name => $posttype ) {
782			self::create_token( 'post_' . Utils::slugify( $name ), _t( 'Permissions to posts of type "%s"', array( $name ) ), _t( 'Content' ), true );
783		}
784
785		// comments tokens
786		self::create_token( 'comment', 'Make comments on any post', _t( 'Comments' ) );
787	}
788
789	/**
790	 * Reset premissions to their default state
791	 */
792	public static function rebuild_permissions( $user = null )
793	{
794		// Clear out all permission-related values
795		DB::query( 'DELETE FROM {tokens}' );
796		DB::query( 'DELETE FROM {group_token_permissions}' );
797		//DB::query( 'DELETE FROM {groups}' );
798		DB::query( 'DELETE FROM {post_tokens}' );
799		DB::query( 'DELETE FROM {user_token_permissions}' );
800		//DB::query('DELETE FROM {users_groups}');
801
802		// Create initial groups if they don't already exist
803		$admin_group = UserGroup::get_by_name( _t( 'admin' ) );
804		if ( ! $admin_group instanceof UserGroup ) {
805			$admin_group = UserGroup::create( array( 'name' => _t( 'admin' ) ) );
806		}
807
808		$anonymous_group = UserGroup::get_by_name( _t( 'anonymous' ) );
809		if ( ! $anonymous_group instanceof UserGroup ) {
810			$anonymous_group = UserGroup::create( array( 'name' => _t( 'anonymous' ) ) );
811		}
812
813		// Add all users or the passed user to the admin group
814		if ( empty($user) ) {
815			$users = Users::get_all();
816			$ids = array();
817			foreach ( $users as $user ) {
818				$ids[] = $user->id;
819			}
820			$admin_group->add( $ids );
821		}
822		else {
823			$admin_group->add( $user );
824		}
825
826		// create default permissions
827		self::create_default_tokens();
828		// Make the admin group all superusers
829		$admin_group->grant( 'super_user' );
830		// Add entry and page read access to the anonymous group
831		$anonymous_group->grant( 'post_entry', 'read' );
832		$anonymous_group->grant( 'post_page', 'read' );
833		$anonymous_group->grant( 'comment' );
834
835		// Add the anonymous user to the anonymous group
836		$anonymous_group->add( 0 );
837
838		// Create the default authenticated group
839		$authenticated_group = UserGroup::get_by_name( _t( 'authenticated' ) );
840		if ( ! $authenticated_group instanceof UserGroup ) {
841			$authenticated_group = UserGroup::create( array( 'name' => _t( 'authenticated' ) ) );
842		}
843		$authenticated_group->grant( 'post_entry', 'read' );
844		$authenticated_group->grant( 'post_page', 'read' );
845		$authenticated_group->grant( 'comment' );
846
847	}
848
849}
850?>