Trim fat
- eliminate superfulous filter chaining - consolildate chained functions into simple if/then logic - add limited API role (add only) - slight restructure
This commit is contained in:
parent
63891d72dc
commit
a839b6474b
@ -13,45 +13,41 @@ if( !defined( 'YOURLS_ABSPATH' ) ) die();
|
|||||||
|
|
||||||
/****************** SET UP CONSTANTS ******************/
|
/****************** SET UP CONSTANTS ******************/
|
||||||
|
|
||||||
/**
|
|
||||||
* This plugin uses filter chains to evaluate whether specific actions
|
|
||||||
* should be allowed to proceed. The filter names are defined here.
|
|
||||||
*/
|
|
||||||
define( 'AUTHMGR_ALLOW', 'filter_authmgr_allow' );
|
|
||||||
define( 'AUTHMGR_HASROLE', 'filter_authmgr_hasrole' );
|
|
||||||
|
|
||||||
// Define constants used for naming roles (but they don't work in config.php)
|
|
||||||
class AuthmgrRoles {
|
class AuthmgrRoles {
|
||||||
const Administrator = 'Administrator';
|
const Administrator = 'Administrator';
|
||||||
const Editor = 'Editor';
|
const Editor = 'Editor';
|
||||||
const Contributor = 'Contributor';
|
const Contributor = 'Contributor';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define constants used for naming capabilities
|
|
||||||
class AuthmgrCapability {
|
class AuthmgrCapability {
|
||||||
const ShowAdmin = 'ShowAdmin'; // only display admin panel
|
const ShowAdmin = 'ShowAdmin';
|
||||||
const AddURL = 'AddURL';
|
const AddURL = 'AddURL';
|
||||||
const DeleteURL = 'DeleteURL';
|
const DeleteURL = 'DeleteURL';
|
||||||
const EditURL = 'EditURL';
|
const EditURL = 'EditURL';
|
||||||
const ManagePlugins = 'ManagePlugins';
|
const ManagePlugins = 'ManagePlugins';
|
||||||
const API = 'API';
|
const API = 'API';
|
||||||
|
const APIu = 'APIu';
|
||||||
const ViewStats = 'ViewStats';
|
const ViewStats = 'ViewStats';
|
||||||
}
|
}
|
||||||
|
|
||||||
/********** Add hooks to intercept functionality in CORE ********/
|
/********** Add hooks to intercept functionality in CORE **********/
|
||||||
|
|
||||||
yourls_add_action( 'load_template_infos', 'authmgr_intercept_stats' );
|
yourls_add_action( 'load_template_infos', 'authmgr_intercept_stats' );
|
||||||
function authmgr_intercept_stats() {
|
function authmgr_intercept_stats() {
|
||||||
if ( YOURLS_PRIVATE_INFOS === true ) {
|
if ( 'YOURLS_PRIVATE_INFOS' === true ) {
|
||||||
authmgr_require_capability( AuthmgrCapability::ViewStats );
|
authmgr_require_capability( AuthmgrCapability::ViewStats );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
yourls_add_action( 'api', 'authmgr_intercept_api' );
|
yourls_add_action( 'api', 'authmgr_intercept_api' );
|
||||||
function authmgr_intercept_api() {
|
function authmgr_intercept_api() {
|
||||||
if ( YOURLS_PRIVATE_API === true ) {
|
if ( 'YOURLS_PRIVATE_API' === true ) {
|
||||||
|
if ( isset( $_REQUEST['shorturl'] ) ) {
|
||||||
|
authmgr_require_capability( AuthmgrCapability::APIu );
|
||||||
|
} else {
|
||||||
authmgr_require_capability( AuthmgrCapability::API );
|
authmgr_require_capability( AuthmgrCapability::API );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -62,6 +58,8 @@ yourls_add_action( 'auth_successful', 'authmgr_intercept_admin' );
|
|||||||
* hook the admin page load itself, and try to figure out what action
|
* hook the admin page load itself, and try to figure out what action
|
||||||
* is intended.
|
* is intended.
|
||||||
*
|
*
|
||||||
|
* TODO: look for these hooks
|
||||||
|
*
|
||||||
* At this point, reasonably assume that the current request is for
|
* At this point, reasonably assume that the current request is for
|
||||||
* a rendering of the admin page.
|
* a rendering of the admin page.
|
||||||
*/
|
*/
|
||||||
@ -129,7 +127,7 @@ function authmgr_intercept_admin() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* This is a cosmetic filter that removes disallowed plugins from link list
|
* Cosmetic filter: removes disallowed plugins from link list
|
||||||
*/
|
*/
|
||||||
yourls_add_filter( 'admin_sublinks', 'authmgr_admin_sublinks' );
|
yourls_add_filter( 'admin_sublinks', 'authmgr_admin_sublinks' );
|
||||||
function authmgr_admin_sublinks( $links ) {
|
function authmgr_admin_sublinks( $links ) {
|
||||||
@ -146,27 +144,28 @@ function authmgr_admin_sublinks( $links ) {
|
|||||||
return $links;
|
return $links;
|
||||||
}
|
}
|
||||||
|
|
||||||
yourls_add_filter( 'logout_link', 'authmgr_html_append_roles' );
|
/*
|
||||||
/**
|
* Cosmetic filter: displays currently available roles
|
||||||
* This is a cosmetic filter that makes it possible to see which roles are
|
* by hovering mouse over the username in logout link.
|
||||||
* currently available, just by mousing over the username in the logout link.
|
|
||||||
*/
|
*/
|
||||||
|
yourls_add_filter( 'logout_link', 'authmgr_html_append_roles' );
|
||||||
function authmgr_html_append_roles( $original ) {
|
function authmgr_html_append_roles( $original ) {
|
||||||
$authenticated = yourls_is_valid_user();
|
$authenticated = yourls_is_valid_user();
|
||||||
if ( $authenticated === true ) {
|
if ( $authenticated === true ) {
|
||||||
$listcaps = implode(', ', authmgr_enumerate_current_capabilities());
|
$listcaps = implode(', ', authmgr_current_capabilities());
|
||||||
return '<div title="'.$listcaps.'">'.$original.'</div>';
|
return '<div title="'.$listcaps.'">'.$original.'</div>';
|
||||||
} else {
|
} else {
|
||||||
return $original;
|
return $original;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************** CAPABILITY TEST/ENUMERATION ****************/
|
/**************** CAPABILITY TESTING ****************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If capability is not permitted in current context, then abort.
|
* If capability is not permitted in current context, then abort.
|
||||||
* This is the most basic way to intercept unauthorized usage.
|
* This is the most basic way to intercept unauthorized usage.
|
||||||
*/
|
*/
|
||||||
|
// TODO: API responses!
|
||||||
function authmgr_require_capability( $capability ) {
|
function authmgr_require_capability( $capability ) {
|
||||||
if ( !authmgr_have_capability( $capability ) ) {
|
if ( !authmgr_have_capability( $capability ) ) {
|
||||||
// If the user can't view admin interface, return a plain error.
|
// If the user can't view admin interface, return a plain error.
|
||||||
@ -180,163 +179,57 @@ function authmgr_require_capability( $capability ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Heart of system
|
||||||
* Returns array of capabilities currently available.
|
|
||||||
*/
|
|
||||||
function authmgr_enumerate_current_capabilities() {
|
|
||||||
$current_capabilities = array();
|
|
||||||
$all_capabilities = authmgr_enumerate_all_capabilities();
|
|
||||||
|
|
||||||
foreach ( $all_capabilities as $cap ) {
|
|
||||||
if ( authmgr_have_capability( $cap ) ) {
|
|
||||||
$current_capabilities[] = $cap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $current_capabilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
function authmgr_enumerate_all_capabilities() {
|
|
||||||
$return = array(
|
|
||||||
AuthmgrCapability::ShowAdmin,
|
|
||||||
AuthmgrCapability::AddURL,
|
|
||||||
AuthmgrCapability::DeleteURL,
|
|
||||||
AuthmgrCapability::EditURL,
|
|
||||||
AuthmgrCapability::ManagePlugins,
|
|
||||||
AuthmgrCapability::API,
|
|
||||||
AuthmgrCapability::ViewStats,
|
|
||||||
);
|
|
||||||
// allow manipulation of this list ( be mindfull of extending the AuthmgrCapability class if needed )
|
|
||||||
yourls_apply_filter( 'authmgr_enumerate_all_capabilities', $return);
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is where everything comes together.
|
|
||||||
*
|
|
||||||
* Use the "allow" filter chain to see if the requested capability
|
|
||||||
* is permitted in the current context. Any function in the filter
|
|
||||||
* chain can change the response, but well-behaved functions will
|
|
||||||
* only change 'false' to 'true', never the other way around.
|
|
||||||
*/
|
|
||||||
function authmgr_have_capability( $capability ) {
|
function authmgr_have_capability( $capability ) {
|
||||||
return yourls_apply_filter( AUTHMGR_ALLOW, false, $capability);
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************* FILTERS THAT GRANT CAPABILITIES *****************************/
|
|
||||||
/* Whether an action is permitted is decided by running a filter chain. */
|
|
||||||
/*********************************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* What capabilities are always available, including anonymous users?
|
|
||||||
*/
|
|
||||||
yourls_add_filter( AUTHMGR_ALLOW, 'authmgr_check_anon_capability', 5 );
|
|
||||||
function authmgr_check_anon_capability( $original, $capability ) {
|
|
||||||
global $authmgr_anon_capabilities;
|
global $authmgr_anon_capabilities;
|
||||||
|
|
||||||
// Shortcut - trust approval given by earlier filters
|
|
||||||
if ( $original === true ) return true;
|
|
||||||
|
|
||||||
// Make sure the anon rights list has been setup
|
|
||||||
authmgr_env_check();
|
|
||||||
|
|
||||||
// Check list of capabilities that don't require authentication
|
|
||||||
return in_array( $capability, $authmgr_anon_capabilities );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* What capabilities are available through role assignments to the active user?
|
|
||||||
*/
|
|
||||||
yourls_add_filter( AUTHMGR_ALLOW, 'authmgr_check_user_capability', 10 );
|
|
||||||
function authmgr_check_user_capability( $original, $capability ) {
|
|
||||||
global $authmgr_role_capabilities;
|
global $authmgr_role_capabilities;
|
||||||
|
global $authmgr_admin_ipranges;
|
||||||
|
|
||||||
// Shortcut - trust approval given by earlier filters
|
// Make sure the environment has been setup
|
||||||
if ( $original === true ) return true;
|
|
||||||
|
|
||||||
// ensure $authmgr_role_capabilities has been set up
|
|
||||||
authmgr_env_check();
|
authmgr_env_check();
|
||||||
|
|
||||||
// If the user is not authenticated, then give up because only users have roles.
|
// Check anon capabilities
|
||||||
|
$return = in_array( $capability, $authmgr_anon_capabilities );
|
||||||
|
|
||||||
|
// Check user-role based auth
|
||||||
|
if( !$return ) {
|
||||||
|
// Only users have roles.
|
||||||
$authenticated = yourls_is_valid_user();
|
$authenticated = yourls_is_valid_user();
|
||||||
if ( $authenticated !== true )
|
if ( $authenticated !== true )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Enumerate the capabilities available to this user through roles
|
// List capabilities of particular user role
|
||||||
$user_caps = array();
|
$user_caps = array();
|
||||||
|
|
||||||
foreach ( $authmgr_role_capabilities as $rolename => $rolecaps ) {
|
foreach ( $authmgr_role_capabilities as $rolename => $rolecaps ) {
|
||||||
if ( authmgr_user_has_role( YOURLS_USER, $rolename ) ) {
|
if ( authmgr_user_has_role( YOURLS_USER, $rolename ) ) {
|
||||||
$user_caps = array_merge( $user_caps, $rolecaps );
|
$user_caps = array_merge( $user_caps, $rolecaps );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$user_caps = array_unique( $user_caps );
|
$user_caps = array_unique( $user_caps );
|
||||||
|
// Is the requested capability in this list?
|
||||||
// Is the desired capability in the enumerated list of capabilities?
|
$return = in_array( $capability, $user_caps );
|
||||||
return in_array( $capability, $user_caps );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the user is connecting from an IP address designated for admins,
|
|
||||||
* then all capabilities are automatically granted.
|
|
||||||
*
|
|
||||||
* By default, only 127.0.0.0/8 (localhost) is an admin range.
|
|
||||||
*/
|
|
||||||
yourls_add_filter( AUTHMGR_ALLOW, 'authmgr_check_admin_ipranges', 15 );
|
|
||||||
function authmgr_check_admin_ipranges( $original, $capability ) {
|
|
||||||
global $authmgr_admin_ipranges;
|
|
||||||
|
|
||||||
// Shortcut - trust approval given by earlier filters
|
|
||||||
if ( $original === true ) return true;
|
|
||||||
|
|
||||||
// ensure $authmgr_admin_ipranges is setup
|
|
||||||
authmgr_env_check();
|
|
||||||
|
|
||||||
foreach ($authmgr_admin_ipranges as $range) {
|
|
||||||
if ( authmgr_cidr_match( $_SERVER['REMOTE_ADDR'], $range ) )
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $original; // effectively returns false
|
// Is user connecting from an admin designated IP?
|
||||||
|
if( !$return ) {
|
||||||
|
// the array of ranges: '127.0.0.0/8' will always be admin
|
||||||
|
foreach ($authmgr_admin_ipranges as $range) {
|
||||||
|
$return = authmgr_cidr_match( $_SERVER['REMOTE_ADDR'], $range );
|
||||||
|
if( $return )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Determine whether a specific user has a role.
|
||||||
* What capabilities are available when making API requests without a username?
|
|
||||||
*/
|
|
||||||
yourls_add_filter( AUTHMGR_ALLOW, 'authmgr_check_apiuser_capability', 15 );
|
|
||||||
function authmgr_check_apiuser_capability( $original, $capability ) {
|
|
||||||
// Shortcut - trust approval given by earlier filters
|
|
||||||
if ( $original === true ) return true;
|
|
||||||
|
|
||||||
// In API mode and not using user/path authn? Let it go.
|
|
||||||
if ( yourls_is_API() && !isset($_REQUEST['username']) )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return $original;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************** ROLE TEST AND ENUMERATION ***********************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine whether a specific user has a role.
|
|
||||||
*/
|
|
||||||
function authmgr_user_has_role( $username, $rolename ) {
|
function authmgr_user_has_role( $username, $rolename ) {
|
||||||
return yourls_apply_filter( AUTHMGR_HASROLE, false, $username, $rolename );
|
|
||||||
}
|
|
||||||
|
|
||||||
// ******************* FILTERS THAT GRANT ROLE MEMBERSHIP *********************
|
|
||||||
// By filtering AUTHMGR_HASROLE, you can connect internal roles to something else.
|
|
||||||
// Any filter handlers should execute as quickly as possible.
|
|
||||||
|
|
||||||
/*
|
|
||||||
* What role memberships are defined for the user in user/config.php?
|
|
||||||
*/
|
|
||||||
yourls_add_filter( AUTHMGR_HASROLE, 'authmgr_user_has_role_in_config');
|
|
||||||
function authmgr_user_has_role_in_config( $original, $username, $rolename ) {
|
|
||||||
global $authmgr_role_assignment;
|
global $authmgr_role_assignment;
|
||||||
|
|
||||||
// if no role assignments are created, grant everything
|
// if no role assignments are created, grant everything FIXME: Make 'admin'
|
||||||
// so the site still works even if stuff is configured wrong
|
// so the site still works even if stuff is configured wrong
|
||||||
if ( empty( $authmgr_role_assignment ) )
|
if ( empty( $authmgr_role_assignment ) )
|
||||||
return true;
|
return true;
|
||||||
@ -354,7 +247,6 @@ function authmgr_user_has_role_in_config( $original, $username, $rolename ) {
|
|||||||
return in_array( $username, $users_in_role );
|
return in_array( $username, $users_in_role );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/********************* VALIDATE CONFIGURATION ************************/
|
/********************* VALIDATE CONFIGURATION ************************/
|
||||||
|
|
||||||
function authmgr_env_check() {
|
function authmgr_env_check() {
|
||||||
@ -377,6 +269,7 @@ function authmgr_env_check() {
|
|||||||
AuthmgrCapability::EditURL,
|
AuthmgrCapability::EditURL,
|
||||||
AuthmgrCapability::ManagePlugins,
|
AuthmgrCapability::ManagePlugins,
|
||||||
AuthmgrCapability::API,
|
AuthmgrCapability::API,
|
||||||
|
AuthmgrCapability::APIu,
|
||||||
AuthmgrCapability::ViewStats,
|
AuthmgrCapability::ViewStats,
|
||||||
),
|
),
|
||||||
AuthmgrRoles::Editor => array(
|
AuthmgrRoles::Editor => array(
|
||||||
@ -384,11 +277,13 @@ function authmgr_env_check() {
|
|||||||
AuthmgrCapability::AddURL,
|
AuthmgrCapability::AddURL,
|
||||||
AuthmgrCapability::EditURL,
|
AuthmgrCapability::EditURL,
|
||||||
AuthmgrCapability::DeleteURL,
|
AuthmgrCapability::DeleteURL,
|
||||||
|
AuthmgrCapability::APIu,
|
||||||
AuthmgrCapability::ViewStats,
|
AuthmgrCapability::ViewStats,
|
||||||
),
|
),
|
||||||
AuthmgrRoles::Contributor => array(
|
AuthmgrRoles::Contributor => array(
|
||||||
AuthmgrCapability::ShowAdmin,
|
AuthmgrCapability::ShowAdmin,
|
||||||
AuthmgrCapability::AddURL,
|
AuthmgrCapability::AddURL,
|
||||||
|
AuthmgrCapability::APIu,
|
||||||
AuthmgrCapability::ViewStats,
|
AuthmgrCapability::ViewStats,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -420,7 +315,8 @@ function authmgr_env_check() {
|
|||||||
$authmgr_role_assignment = $authmgr_role_assignment_lower;
|
$authmgr_role_assignment = $authmgr_role_assignment_lower;
|
||||||
unset($authmgr_role_assignment_lower);
|
unset($authmgr_role_assignment_lower);
|
||||||
|
|
||||||
// allow manipulation of env by other plugins ( be mindfull of extending AuthmgrCapability and AuthmgrRoles classes if needed )
|
// allow manipulation of env by other plugins
|
||||||
|
// be mindfull of extending AuthmgrCapability and AuthmgrRoles classes if needed
|
||||||
$a = $authmgr_anon_capabilities;
|
$a = $authmgr_anon_capabilities;
|
||||||
$b = $authmgr_role_capabilities;
|
$b = $authmgr_role_capabilities;
|
||||||
$c = $authmgr_role_assignment;
|
$c = $authmgr_role_assignment;
|
||||||
@ -432,12 +328,35 @@ function authmgr_env_check() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***************** GENERAL UTILITY FUNCTIONS ********************
|
/***************** HELPER FUNCTIONS ********************/
|
||||||
|
|
||||||
/*
|
// List currently available capabilities
|
||||||
* Borrowed from:
|
function authmgr_current_capabilities() {
|
||||||
* http://stackoverflow.com/questions/594112/matching-an-ip-to-a-cidr-mask-in-php5
|
$current_capabilities = array();
|
||||||
*/
|
$all_capabilities = array(
|
||||||
|
AuthmgrCapability::ShowAdmin,
|
||||||
|
AuthmgrCapability::AddURL,
|
||||||
|
AuthmgrCapability::DeleteURL,
|
||||||
|
AuthmgrCapability::EditURL,
|
||||||
|
AuthmgrCapability::ManagePlugins,
|
||||||
|
AuthmgrCapability::API,
|
||||||
|
AuthmgrCapability::APIu,
|
||||||
|
AuthmgrCapability::ViewStats,
|
||||||
|
);
|
||||||
|
// allow manipulation of this list ( be mindfull of extending the AuthmgrCapability class if needed )
|
||||||
|
yourls_apply_filter( 'authmgr_current_capabilities', $all_capabilities);
|
||||||
|
|
||||||
|
foreach ( $all_capabilities as $cap ) {
|
||||||
|
if ( authmgr_have_capability( $cap ) ) {
|
||||||
|
$current_capabilities[] = $cap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $current_capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for IP in a range
|
||||||
|
// from: http://stackoverflow.com/questions/594112/matching-an-ip-to-a-cidr-mask-in-php5
|
||||||
function authmgr_cidr_match($ip, $range) {
|
function authmgr_cidr_match($ip, $range) {
|
||||||
list ($subnet, $bits) = explode('/', $range);
|
list ($subnet, $bits) = explode('/', $range);
|
||||||
$ip = ip2long($ip);
|
$ip = ip2long($ip);
|
||||||
|
Loading…
Reference in New Issue
Block a user