diff --git a/authmgr/plugin.php b/authmgr/plugin.php
index 6c01704..c351c35 100644
--- a/authmgr/plugin.php
+++ b/authmgr/plugin.php
@@ -13,44 +13,40 @@ if( !defined( 'YOURLS_ABSPATH' ) ) die();
/****************** 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 {
const Administrator = 'Administrator';
const Editor = 'Editor';
const Contributor = 'Contributor';
}
-// Define constants used for naming capabilities
class AuthmgrCapability {
- const ShowAdmin = 'ShowAdmin'; // only display admin panel
+ const ShowAdmin = 'ShowAdmin';
const AddURL = 'AddURL';
const DeleteURL = 'DeleteURL';
const EditURL = 'EditURL';
const ManagePlugins = 'ManagePlugins';
const API = 'API';
+ const APIu = 'APIu';
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' );
function authmgr_intercept_stats() {
- if ( YOURLS_PRIVATE_INFOS === true ) {
+ if ( 'YOURLS_PRIVATE_INFOS' === true ) {
authmgr_require_capability( AuthmgrCapability::ViewStats );
}
}
yourls_add_action( 'api', 'authmgr_intercept_api' );
function authmgr_intercept_api() {
- if ( YOURLS_PRIVATE_API === true ) {
- authmgr_require_capability( AuthmgrCapability::API );
+ if ( 'YOURLS_PRIVATE_API' === true ) {
+ if ( isset( $_REQUEST['shorturl'] ) ) {
+ authmgr_require_capability( AuthmgrCapability::APIu );
+ } else {
+ 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
* is intended.
*
+ * TODO: look for these hooks
+ *
* At this point, reasonably assume that the current request is for
* 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' );
function authmgr_admin_sublinks( $links ) {
@@ -146,27 +144,28 @@ function authmgr_admin_sublinks( $links ) {
return $links;
}
-yourls_add_filter( 'logout_link', 'authmgr_html_append_roles' );
-/**
- * This is a cosmetic filter that makes it possible to see which roles are
- * currently available, just by mousing over the username in the logout link.
+/*
+ * Cosmetic filter: displays currently available roles
+ * by hovering mouse over the username in logout link.
*/
+yourls_add_filter( 'logout_link', 'authmgr_html_append_roles' );
function authmgr_html_append_roles( $original ) {
$authenticated = yourls_is_valid_user();
if ( $authenticated === true ) {
- $listcaps = implode(', ', authmgr_enumerate_current_capabilities());
+ $listcaps = implode(', ', authmgr_current_capabilities());
return '
'.$original.'
';
} else {
return $original;
}
}
-/**************** CAPABILITY TEST/ENUMERATION ****************/
+/**************** CAPABILITY TESTING ****************/
/*
* If capability is not permitted in current context, then abort.
* This is the most basic way to intercept unauthorized usage.
*/
+// TODO: API responses!
function authmgr_require_capability( $capability ) {
if ( !authmgr_have_capability( $capability ) ) {
// If the user can't view admin interface, return a plain error.
@@ -180,163 +179,57 @@ function authmgr_require_capability( $capability ) {
}
}
-/*
- * Returns array of capabilities currently available.
- */
-function authmgr_enumerate_current_capabilities() {
- $current_capabilities = array();
- $all_capabilities = authmgr_enumerate_all_capabilities();
+// Heart of system
+function authmgr_have_capability( $capability ) {
- foreach ( $all_capabilities as $cap ) {
- if ( authmgr_have_capability( $cap ) ) {
- $current_capabilities[] = $cap;
+ global $authmgr_anon_capabilities;
+ global $authmgr_role_capabilities;
+ global $authmgr_admin_ipranges;
+
+ // Make sure the environment has been setup
+ authmgr_env_check();
+
+ // 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();
+ if ( $authenticated !== true )
+ return false;
+
+ // List capabilities of particular user role
+ $user_caps = array();
+ foreach ( $authmgr_role_capabilities as $rolename => $rolecaps ) {
+ if ( authmgr_user_has_role( YOURLS_USER, $rolename ) ) {
+ $user_caps = array_merge( $user_caps, $rolecaps );
+ }
}
+ $user_caps = array_unique( $user_caps );
+ // Is the requested capability in this list?
+ $return = in_array( $capability, $user_caps );
}
- 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);
+ // 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;
}
-/*
- * 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 ) {
- 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;
-
- // 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;
-
- // Shortcut - trust approval given by earlier filters
- if ( $original === true ) return true;
-
- // ensure $authmgr_role_capabilities has been set up
- authmgr_env_check();
-
- // If the user is not authenticated, then give up because only users have roles.
- $authenticated = yourls_is_valid_user();
- if ( $authenticated !== true )
- return false;
-
- // Enumerate the capabilities available to this user through roles
- $user_caps = array();
-
- foreach ( $authmgr_role_capabilities as $rolename => $rolecaps ) {
- if ( authmgr_user_has_role( YOURLS_USER, $rolename ) ) {
- $user_caps = array_merge( $user_caps, $rolecaps );
- }
- }
- $user_caps = array_unique( $user_caps );
-
- // Is the desired capability in the enumerated list of capabilities?
- 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
-}
-
-/*
- * 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.
- */
+// Determine whether a specific user has a role.
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;
- // 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
if ( empty( $authmgr_role_assignment ) )
return true;
@@ -354,7 +247,6 @@ function authmgr_user_has_role_in_config( $original, $username, $rolename ) {
return in_array( $username, $users_in_role );
}
-
/********************* VALIDATE CONFIGURATION ************************/
function authmgr_env_check() {
@@ -377,6 +269,7 @@ function authmgr_env_check() {
AuthmgrCapability::EditURL,
AuthmgrCapability::ManagePlugins,
AuthmgrCapability::API,
+ AuthmgrCapability::APIu,
AuthmgrCapability::ViewStats,
),
AuthmgrRoles::Editor => array(
@@ -384,11 +277,13 @@ function authmgr_env_check() {
AuthmgrCapability::AddURL,
AuthmgrCapability::EditURL,
AuthmgrCapability::DeleteURL,
+ AuthmgrCapability::APIu,
AuthmgrCapability::ViewStats,
),
AuthmgrRoles::Contributor => array(
AuthmgrCapability::ShowAdmin,
AuthmgrCapability::AddURL,
+ AuthmgrCapability::APIu,
AuthmgrCapability::ViewStats,
),
);
@@ -420,7 +315,8 @@ function authmgr_env_check() {
$authmgr_role_assignment = $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;
$b = $authmgr_role_capabilities;
$c = $authmgr_role_assignment;
@@ -432,12 +328,35 @@ function authmgr_env_check() {
return true;
}
-// ***************** GENERAL UTILITY FUNCTIONS ********************
+/***************** HELPER FUNCTIONS ********************/
-/*
- * Borrowed from:
- * http://stackoverflow.com/questions/594112/matching-an-ip-to-a-cidr-mask-in-php5
- */
+// List currently available capabilities
+function authmgr_current_capabilities() {
+ $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) {
list ($subnet, $bits) = explode('/', $range);
$ip = ip2long($ip);