Current state of coding standards and analysis fixes.

isekai
Tim Nolte 5 years ago
parent ec2e37ace6
commit 139791a75c
No known key found for this signature in database
GPG Key ID: 33E7CA1AD448F3B3

@ -4,27 +4,49 @@ class OpenID_Connect_Generic_Client_Wrapper {
private $client; private $client;
// settings object /**
* The settings object.
*
* @var OpenID_Connect_Generic_Option_Settings
*/
private $settings; private $settings;
// logger object /**
* The logger object.
*
* @var OpenID_Connect_Generic_Option_Logger
*/
private $logger; private $logger;
// token refresh info cookie key /**
* The token refresh info cookie key.
*
* @var string
*/
private $cookie_token_refresh_key = 'openid-connect-generic-refresh'; private $cookie_token_refresh_key = 'openid-connect-generic-refresh';
// user redirect cookie key /**
* The user redirect cookie key.
*
* @var string
*/
public $cookie_redirect_key = 'openid-connect-generic-redirect'; public $cookie_redirect_key = 'openid-connect-generic-redirect';
// WP_Error if there was a problem, or false if no error /**
* The return error onject.
*
* @example WP_Error if there was a problem, or false if no error
*
* @var bool|WP_Error
*/
private $error = false; private $error = false;
/** /**
* Inject necessary objects and services into the client * Inject necessary objects and services into the client.
* *
* @param \OpenID_Connect_Generic_Client $client * @param OpenID_Connect_Generic_Client $client A plugin client object instance.
* @param \OpenID_Connect_Generic_Option_Settings $settings * @param OpenID_Connect_Generic_Option_Settings $settings A plugin settings object instance.
* @param \OpenID_Connect_Generic_Option_Logger $logger * @param OpenID_Connect_Generic_Option_Logger $logger A plugin logger object instance.
*/ */
function __construct( OpenID_Connect_Generic_Client $client, OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) { function __construct( OpenID_Connect_Generic_Client $client, OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) {
$this->client = $client; $this->client = $client;
@ -33,18 +55,18 @@ class OpenID_Connect_Generic_Client_Wrapper {
} }
/** /**
* Hook the client into WP * Hook the client into WordPress.
* *
* @param \OpenID_Connect_Generic_Client $client * @param \OpenID_Connect_Generic_Client $client The plugin client instance.
* @param \OpenID_Connect_Generic_Option_Settings $settings * @param \OpenID_Connect_Generic_Option_Settings $settings The plugin settings instance.
* @param \OpenID_Connect_Generic_Option_Logger $logger * @param \OpenID_Connect_Generic_Option_Logger $logger The plugin logger instance.
* *
* @return \OpenID_Connect_Generic_Client_Wrapper * @return \OpenID_Connect_Generic_Client_Wrapper
*/ */
static public function register( OpenID_Connect_Generic_Client $client, OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) { static public function register( OpenID_Connect_Generic_Client $client, OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) {
$client_wrapper = new self( $client, $settings, $logger ); $client_wrapper = new self( $client, $settings, $logger );
// integrated logout // Integrated logout.
if ( $settings->endpoint_end_session ) { if ( $settings->endpoint_end_session ) {
add_filter( 'allowed_redirect_hosts', array( $client_wrapper, 'update_allowed_redirect_hosts' ), 99, 1 ); add_filter( 'allowed_redirect_hosts', array( $client_wrapper, 'update_allowed_redirect_hosts' ), 99, 1 );
add_filter( 'logout_redirect', array( $client_wrapper, 'get_end_session_logout_redirect_url' ), 99, 3 ); add_filter( 'logout_redirect', array( $client_wrapper, 'get_end_session_logout_redirect_url' ), 99, 3 );

@ -1,34 +1,115 @@
<?php <?php
/**
* Plugin OIDC/oAuth client class.
*
* @package OpenID_Connect_Generic
* @category Authentication
* @author Jonathan Daggerhart <jonathan@daggerhart.com>
* @copyright 2015-2020 daggerhart
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
*/
/**
* OpenID_Connect_Generic_Client class.
*
* Plugin OIDC/oAuth client class.
*
* @package OpenID_Connect_Generic
* @category Authentication
*/
class OpenID_Connect_Generic_Client { class OpenID_Connect_Generic_Client {
/**
* The OIDC/oAuth client ID.
*
* @see OpenID_Connect_Generic_Option_Settings::client_id
*
* @var string
*/
private $client_id; private $client_id;
/**
* The OIDC/oAuth client secret.
*
* @see OpenID_Connect_Generic_Option_Settings::client_secret
*
* @var string
*/
private $client_secret; private $client_secret;
/**
* The OIDC/oAuth scopes.
*
* @see OpenID_Connect_Generic_Option_Settings::scope
*
* @var string
*/
private $scope; private $scope;
/**
* The OIDC/oAuth authorization endpoint URL.
*
* @see OpenID_Connect_Generic_Option_Settings::endpoint_login
*
* @var string
*/
private $endpoint_login; private $endpoint_login;
/**
* The OIDC/oAuth User Information endpoint URL.
*
* @see OpenID_Connect_Generic_Option_Settings::endpoint_userinfo
*
* @var string
*/
private $endpoint_userinfo; private $endpoint_userinfo;
/**
* The OIDC/oAuth token validation endpoint URL.
*
* @see OpenID_Connect_Generic_Option_Settings::endpoint_token
*
* @var string
*/
private $endpoint_token; private $endpoint_token;
// login flow "ajax" endpoint /**
* The login flow "ajax" endpoint URI.
*
* @see OpenID_Connect_Generic_Option_Settings::redirect_uri
*
* @var string
*/
private $redirect_uri; private $redirect_uri;
// states are only valid for 3 minutes /**
* The state time limit. States are only valid for 3 minutes.
*
* @see OpenID_Connect_Generic_Option_Settings::state_time_limit
*
* @var int
*/
private $state_time_limit = 180; private $state_time_limit = 180;
// logger object /**
* The logger object instance.
*
* @var OpenID_Connect_Generic_Option_Logger
*/
private $logger; private $logger;
/** /**
* Client constructor * Client constructor.
* *
* @param $client_id * @param string $client_id @see OpenID_Connect_Generic_Option_Settings::client_id for description.
* @param $client_secret * @param string $client_secret @see OpenID_Connect_Generic_Option_Settings::client_secret for description.
* @param $scope * @param string $scope @see OpenID_Connect_Generic_Option_Settings::scope for description.
* @param $endpoint_login * @param string $endpoint_login @see OpenID_Connect_Generic_Option_Settings::endpoint_login for description.
* @param $endpoint_userinfo * @param string $endpoint_userinfo @see OpenID_Connect_Generic_Option_Settings::endpoint_userinfo for description.
* @param $endpoint_token * @param string $endpoint_token @see OpenID_Connect_Generic_Option_Settings::endpoint_token for description.
* @param $redirect_uri * @param string $redirect_uri @see OpenID_Connect_Generic_Option_Settings::redirect_uri for description.
* @param $state_time_limit time states are valid in seconds * @param int $state_time_limit @see OpenID_Connect_Generic_Option_Settings::state_time_limit for description.
* @param OpenID_Connect_Generic_Option_Logger $logger The plugin logging object instance.
*/ */
function __construct( $client_id, $client_secret, $scope, $endpoint_login, $endpoint_userinfo, $endpoint_token, $redirect_uri, $state_time_limit, $logger ) { function __construct( $client_id, $client_secret, $scope, $endpoint_login, $endpoint_userinfo, $endpoint_token, $redirect_uri, $state_time_limit, $logger ) {
$this->client_id = $client_id; $this->client_id = $client_id;
@ -77,22 +158,22 @@ class OpenID_Connect_Generic_Client {
/** /**
* Validate the request for login authentication * Validate the request for login authentication
* *
* @param $request * @param array $request The authentication request results.
* *
* @return array|\WP_Error * @return array|WP_Error
*/ */
function validate_authentication_request( $request ) { function validate_authentication_request( $request ) {
// look for an existing error of some kind // Look for an existing error of some kind.
if ( isset( $request['error'] ) ) { if ( isset( $request['error'] ) ) {
return new WP_Error( 'unknown-error', 'An unknown error occurred.', $request ); return new WP_Error( 'unknown-error', 'An unknown error occurred.', $request );
} }
// make sure we have a legitimate authentication code and valid state // Make sure we have a legitimate authentication code and valid state.
if ( ! isset( $request['code'] ) ) { if ( ! isset( $request['code'] ) ) {
return new WP_Error( 'no-code', 'No authentication code present in the request.', $request ); return new WP_Error( 'no-code', 'No authentication code present in the request.', $request );
} }
// check the client request state // Check the client request state.
if ( ! isset( $request['state'] ) ) { if ( ! isset( $request['state'] ) ) {
do_action( 'openid-connect-generic-no-state-provided' ); do_action( 'openid-connect-generic-no-state-provided' );
return new WP_Error( 'missing-state', __( 'Missing state.' ), $request ); return new WP_Error( 'missing-state', __( 'Missing state.' ), $request );
@ -108,24 +189,24 @@ class OpenID_Connect_Generic_Client {
/** /**
* Get the authorization code from the request * Get the authorization code from the request
* *
* @param $request array * @param array $request The authentication request results.
* *
* @return string|\WP_Error * @return string|WP_Error
*/ */
function get_authentication_code( $request ) { function get_authentication_code( $request ) {
return $request['code']; return $request['code'];
} }
/** /**
* Using the authorization_code, request an authentication token from the idp * Using the authorization_code, request an authentication token from the IDP.
* *
* @param $code - authorization_code * @param string $code The authorization code.
* *
* @return array|\WP_Error * @return array|WP_Error
*/ */
function request_authentication_token( $code ) { function request_authentication_token( $code ) {
// Add Host header - required for when the openid-connect endpoint is behind a reverse-proxy // Add Host header - required for when the openid-connect endpoint is behind a reverse-proxy.
$parsed_url = parse_url( $this->endpoint_token ); $parsed_url = parse_url( $this->endpoint_token );
$host = $parsed_url['host']; $host = $parsed_url['host'];
@ -141,10 +222,10 @@ class OpenID_Connect_Generic_Client {
'headers' => array( 'Host' => $host ), 'headers' => array( 'Host' => $host ),
); );
// allow modifications to the request // Allow modifications to the request.
$request = apply_filters( 'openid-connect-generic-alter-request', $request, 'get-authentication-token' ); $request = apply_filters( 'openid-connect-generic-alter-request', $request, 'get-authentication-token' );
// call the server and ask for a token // Call the server and ask for a token.
$this->logger->log( $this->endpoint_token, 'request_authentication_token' ); $this->logger->log( $this->endpoint_token, 'request_authentication_token' );
$response = wp_remote_post( $this->endpoint_token, $request ); $response = wp_remote_post( $this->endpoint_token, $request );
@ -158,9 +239,9 @@ class OpenID_Connect_Generic_Client {
/** /**
* Using the refresh token, request new tokens from the idp * Using the refresh token, request new tokens from the idp
* *
* @param $refresh_token - refresh token previously obtained from token response. * @param string $refresh_token The refresh token previously obtained from token response.
* *
* @return array|\WP_Error * @return array|WP_Error
*/ */
function request_new_tokens( $refresh_token ) { function request_new_tokens( $refresh_token ) {
$request = array( $request = array(
@ -172,10 +253,10 @@ class OpenID_Connect_Generic_Client {
), ),
); );
// allow modifications to the request // Allow modifications to the request.
$request = apply_filters( 'openid-connect-generic-alter-request', $request, 'refresh-token' ); $request = apply_filters( 'openid-connect-generic-alter-request', $request, 'refresh-token' );
// call the server and ask for new tokens // Call the server and ask for new tokens.
$this->logger->log( $this->endpoint_token, 'request_new_tokens' ); $this->logger->log( $this->endpoint_token, 'request_new_tokens' );
$response = wp_remote_post( $this->endpoint_token, $request ); $response = wp_remote_post( $this->endpoint_token, $request );
@ -189,17 +270,23 @@ class OpenID_Connect_Generic_Client {
/** /**
* Extract and decode the token body of a token response * Extract and decode the token body of a token response
* *
* @param $token_result * @param array $token_result The token response.
* @return array|mixed|object *
* @return array|WP_Error|null
*/ */
function get_token_response( $token_result ) { function get_token_response( $token_result ) {
if ( ! isset( $token_result['body'] ) ) { if ( ! isset( $token_result['body'] ) ) {
return new WP_Error( 'missing-token-body', __( 'Missing token body.' ), $token_result ); return new WP_Error( 'missing-token-body', __( 'Missing token body.' ), $token_result );
} }
// extract token response from token // Extract the token response from token.
$token_response = json_decode( $token_result['body'], true ); $token_response = json_decode( $token_result['body'], true );
// Check that the token response body was able to be parsed.
if ( is_null( $token_response ) ) {
return new WP_Error( 'invalid-token', __( 'Invalid token.' ), $token_result );
}
if ( isset( $token_response['error'] ) ) { if ( isset( $token_response['error'] ) ) {
$error = $token_response['error']; $error = $token_response['error'];
$error_description = $error; $error_description = $error;
@ -212,27 +299,28 @@ class OpenID_Connect_Generic_Client {
return $token_response; return $token_response;
} }
/** /**
* Exchange an access_token for a user_claim from the userinfo endpoint * Exchange an access_token for a user_claim from the userinfo endpoint
* *
* @param $access_token * @param string $access_token The access token supplied from authentication user claim.
* *
* @return array|\WP_Error * @return array|WP_Error
*/ */
function request_userinfo( $access_token ) { function request_userinfo( $access_token ) {
// allow modifications to the request // Allow modifications to the request.
$request = apply_filters( 'openid-connect-generic-alter-request', array(), 'get-userinfo' ); $request = apply_filters( 'openid-connect-generic-alter-request', array(), 'get-userinfo' );
// section 5.3.1 of the spec recommends sending the access token using the authorization header /*
// a filter may or may not have already added headers - make sure they exist then add the token * Section 5.3.1 of the spec recommends sending the access token using the authorization header
* a filter may or may not have already added headers - make sure they exist then add the token.
*/
if ( ! array_key_exists( 'headers', $request ) || ! is_array( $request['headers'] ) ) { if ( ! array_key_exists( 'headers', $request ) || ! is_array( $request['headers'] ) ) {
$request['headers'] = array(); $request['headers'] = array();
} }
$request['headers']['Authorization'] = 'Bearer ' . $access_token; $request['headers']['Authorization'] = 'Bearer ' . $access_token;
// Add Host header - required for when the openid-connect endpoint is behind a reverse-proxy // Add Host header - required for when the openid-connect endpoint is behind a reverse-proxy.
$parsed_url = parse_url( $this->endpoint_userinfo ); $parsed_url = parse_url( $this->endpoint_userinfo );
$host = $parsed_url['host']; $host = $parsed_url['host'];
@ -242,7 +330,7 @@ class OpenID_Connect_Generic_Client {
$request['headers']['Host'] = $host; $request['headers']['Host'] = $host;
// attempt the request including the access token in the query string for backwards compatibility // Attempt the request including the access token in the query string for backwards compatibility.
$this->logger->log( $this->endpoint_userinfo, 'request_userinfo' ); $this->logger->log( $this->endpoint_userinfo, 'request_userinfo' );
$response = wp_remote_post( $this->endpoint_userinfo, $request ); $response = wp_remote_post( $this->endpoint_userinfo, $request );
@ -254,13 +342,12 @@ class OpenID_Connect_Generic_Client {
} }
/** /**
* Generate a new state, save it as a transient, * Generate a new state, save it as a transient, and return the state hash.
* and return the state hash.
* *
* @return string * @return string
*/ */
function new_state() { function new_state() {
// new state w/ timestamp // New state w/ timestamp.
$state = md5( mt_rand() . microtime( true ) ); $state = md5( mt_rand() . microtime( true ) );
set_transient( 'openid-connect-generic-state--' . $state, $state, $this->state_time_limit ); set_transient( 'openid-connect-generic-state--' . $state, $state, $this->state_time_limit );
@ -270,7 +357,7 @@ class OpenID_Connect_Generic_Client {
/** /**
* Check the existence of a given state transient. * Check the existence of a given state transient.
* *
* @param $state * @param string $state The state hash to validate.
* *
* @return bool * @return bool
*/ */
@ -293,15 +380,17 @@ class OpenID_Connect_Generic_Client {
} }
/** /**
* Ensure that the token meets basic requirements * Ensure that the token meets basic requirements.
* *
* @param $token_response * @param array $token_response The token response.
* *
* @return bool|\WP_Error * @return bool|WP_Error
*/ */
function validate_token_response( $token_response ) { function validate_token_response( $token_response ) {
// we need to ensure 2 specific items exist with the token response in order /*
// to proceed with confidence: id_token and token_type == 'Bearer' * Ensure 2 specific items exist with the token response in order
* to proceed with confidence: id_token and token_type == 'Bearer'
*/
if ( ! isset( $token_response['id_token'] ) || if ( ! isset( $token_response['id_token'] ) ||
! isset( $token_response['token_type'] ) || strcasecmp( $token_response['token_type'], 'Bearer' ) ! isset( $token_response['token_type'] ) || strcasecmp( $token_response['token_type'], 'Bearer' )
) { ) {
@ -312,29 +401,29 @@ class OpenID_Connect_Generic_Client {
} }
/** /**
* Extract the id_token_claim from the token_response * Extract the id_token_claim from the token_response.
* *
* @param $token_response * @param array $token_response The token response.
* *
* @return array|\WP_Error * @return array|WP_Error
*/ */
function get_id_token_claim( $token_response ) { function get_id_token_claim( $token_response ) {
// name sure we have an id_token // Validate there is an id_token.
if ( ! isset( $token_response['id_token'] ) ) { if ( ! isset( $token_response['id_token'] ) ) {
return new WP_Error( 'no-identity-token', __( 'No identity token' ), $token_response ); return new WP_Error( 'no-identity-token', __( 'No identity token' ), $token_response );
} }
// break apart the id_token in the response for decoding // Break apart the id_token in the response for decoding.
$tmp = explode( '.', $token_response['id_token'] ); $tmp = explode( '.', $token_response['id_token'] );
if ( ! isset( $tmp[1] ) ) { if ( ! isset( $tmp[1] ) ) {
return new WP_Error( 'missing-identity-token', __( 'Missing identity token' ), $token_response ); return new WP_Error( 'missing-identity-token', __( 'Missing identity token' ), $token_response );
} }
// Extract the id_token's claims from the token // Extract the id_token's claims from the token.
$id_token_claim = json_decode( $id_token_claim = json_decode(
base64_decode( base64_decode(
str_replace( // because token is encoded in base64 URL (and not just base64) str_replace( // Because token is encoded in base64 URL (and not just base64).
array( '-', '_' ), array( '-', '_' ),
array( '+', '/' ), array( '+', '/' ),
$tmp[1] $tmp[1]
@ -347,18 +436,18 @@ class OpenID_Connect_Generic_Client {
} }
/** /**
* Ensure the id_token_claim contains the required values * Ensure the id_token_claim contains the required values.
* *
* @param $id_token_claim * @param array $id_token_claim The ID token claim.
* *
* @return bool|\WP_Error * @return bool|WP_Error
*/ */
function validate_id_token_claim( $id_token_claim ) { function validate_id_token_claim( $id_token_claim ) {
if ( ! is_array( $id_token_claim ) ) { if ( ! is_array( $id_token_claim ) ) {
return new WP_Error( 'bad-id-token-claim', __( 'Bad ID token claim' ), $id_token_claim ); return new WP_Error( 'bad-id-token-claim', __( 'Bad ID token claim' ), $id_token_claim );
} }
// make sure we can find our identification data and that it has a value // Validate the identification data and it's value.
if ( ! isset( $id_token_claim['sub'] ) || empty( $id_token_claim['sub'] ) ) { if ( ! isset( $id_token_claim['sub'] ) || empty( $id_token_claim['sub'] ) ) {
return new WP_Error( 'no-subject-identity', __( 'No subject identity' ), $id_token_claim ); return new WP_Error( 'no-subject-identity', __( 'No subject identity' ), $id_token_claim );
} }
@ -367,17 +456,17 @@ class OpenID_Connect_Generic_Client {
} }
/** /**
* Attempt to exchange the access_token for a user_claim * Attempt to exchange the access_token for a user_claim.
* *
* @param $token_response * @param array $token_response The token response.
* *
* @return array|mixed|object|\WP_Error * @return array|WP_Error|null
*/ */
function get_user_claim( $token_response ) { function get_user_claim( $token_response ) {
// send a userinfo request to get user claim // Send a userinfo request to get user claim.
$user_claim_result = $this->request_userinfo( $token_response['access_token'] ); $user_claim_result = $this->request_userinfo( $token_response['access_token'] );
// make sure we didn't get an error, and that the response body exists // Make sure we didn't get an error, and that the response body exists.
if ( is_wp_error( $user_claim_result ) || ! isset( $user_claim_result['body'] ) ) { if ( is_wp_error( $user_claim_result ) || ! isset( $user_claim_result['body'] ) ) {
return new WP_Error( 'bad-claim', __( 'Bad user claim' ), $user_claim_result ); return new WP_Error( 'bad-claim', __( 'Bad user claim' ), $user_claim_result );
} }
@ -391,18 +480,18 @@ class OpenID_Connect_Generic_Client {
* Make sure the user_claim has all required values, and that the subject * Make sure the user_claim has all required values, and that the subject
* identity matches of the id_token matches that of the user_claim. * identity matches of the id_token matches that of the user_claim.
* *
* @param $user_claim * @param array $user_claim The authentication user claim.
* @param $id_token_claim * @param array $id_token_claim The ID token claim.
* *
* @return \WP_Error * @return bool|WP_Error
*/ */
function validate_user_claim( $user_claim, $id_token_claim ) { function validate_user_claim( $user_claim, $id_token_claim ) {
// must be an array // Validate the user claim.
if ( ! is_array( $user_claim ) ) { if ( ! is_array( $user_claim ) ) {
return new WP_Error( 'invalid-user-claim', __( 'Invalid user claim' ), $user_claim ); return new WP_Error( 'invalid-user-claim', __( 'Invalid user claim' ), $user_claim );
} }
// allow for errors from the IDP // Allow for errors from the IDP.
if ( isset( $user_claim['error'] ) ) { if ( isset( $user_claim['error'] ) ) {
$message = __( 'Error from the IDP' ); $message = __( 'Error from the IDP' );
if ( ! empty( $user_claim['error_description'] ) ) { if ( ! empty( $user_claim['error_description'] ) ) {
@ -411,12 +500,12 @@ class OpenID_Connect_Generic_Client {
return new WP_Error( 'invalid-user-claim-' . $user_claim['error'], $message, $user_claim ); return new WP_Error( 'invalid-user-claim-' . $user_claim['error'], $message, $user_claim );
} }
// make sure the id_token sub === user_claim sub, according to spec // Make sure the id_token sub equals the user_claim sub, according to spec.
if ( $id_token_claim['sub'] !== $user_claim['sub'] ) { if ( $id_token_claim['sub'] !== $user_claim['sub'] ) {
return new WP_Error( 'incorrect-user-claim', __( 'Incorrect user claim' ), func_get_args() ); return new WP_Error( 'incorrect-user-claim', __( 'Incorrect user claim' ), func_get_args() );
} }
// allow for other plugins to alter the login success // Allow for other plugins to alter the login success.
$login_user = apply_filters( 'openid-connect-generic-user-login-test', true, $user_claim ); $login_user = apply_filters( 'openid-connect-generic-user-login-test', true, $user_claim );
if ( ! $login_user ) { if ( ! $login_user ) {
@ -427,13 +516,14 @@ class OpenID_Connect_Generic_Client {
} }
/** /**
* Retrieve the subject identity from the id_token * Retrieve the subject identity from the id_token.
* *
* @param $id_token_claim array * @param array $id_token_claim The ID token claim.
* *
* @return mixed * @return mixed
*/ */
function get_subject_identity( $id_token_claim ) { function get_subject_identity( $id_token_claim ) {
return $id_token_claim['sub']; return $id_token_claim['sub'];
} }
} }

@ -1,35 +1,67 @@
<?php <?php
/**
* Login form and login button handlong class.
*
* @package OpenID_Connect_Generic
* @category Login
* @author Jonathan Daggerhart <jonathan@daggerhart.com>
* @copyright 2015-2020 daggerhart
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
*/
/**
* OpenID_Connect_Generic_Login_Form class.
*
* Login form and login button handlong.
*
* @package OpenID_Connect_Generic
* @category Login
*/
class OpenID_Connect_Generic_Login_Form { class OpenID_Connect_Generic_Login_Form {
/**
* Plugin settings object.
*
* @var OpenID_Connect_Generic_Option_Settings
*/
private $settings; private $settings;
/**
* Plugin client wrapper instance.
*
* @var OpenID_Connect_Generic_Client_Wrapper
*/
private $client_wrapper; private $client_wrapper;
/** /**
* @param $settings * The class constructor.
* @param $client_wrapper *
* @param OpenID_Connect_Generic_Option_Settings $settings A plugin settings object instance.
* @param OpenID_Connect_Generic_Client_Wrapper $client_wrapper A plugin client wrapper object instance.
*/ */
function __construct( $settings, $client_wrapper ) { function __construct( $settings, $client_wrapper ) {
$this->settings = $settings; $this->settings = $settings;
$this->client_wrapper = $client_wrapper; $this->client_wrapper = $client_wrapper;
// maybe set redirect cookie on formular page // Handle setting the redirect cookie on a formu page.
add_action( 'login_form_login', array( $this, 'handle_redirect_cookie' ) ); add_action( 'login_form_login', array( $this, 'handle_redirect_cookie' ) );
} }
/** /**
* @param $settings * Create an instance of the OpenID_Connect_Generic_Login_Form class.
* @param $client_wrapper *
* @param OpenID_Connect_Generic_Option_Settings $settings A plugin settings object instance.
* @param OpenID_Connect_Generic_Client_Wrapper $client_wrapper A plugin client wrapper object instance.
* *
* @return \OpenID_Connect_Generic_Login_Form * @return OpenID_Connect_Generic_Login_Form
*/ */
static public function register( $settings, $client_wrapper ) { static public function register( $settings, $client_wrapper ) {
$login_form = new self( $settings, $client_wrapper ); $login_form = new self( $settings, $client_wrapper );
// alter the login form as dictated by settings // Alter the login form as dictated by settings.
add_filter( 'login_message', array( $login_form, 'handle_login_page' ), 99 ); add_filter( 'login_message', array( $login_form, 'handle_login_page' ), 99 );
// add a shortcode for the login button // Add a shortcode for the login button.
add_shortcode( 'openid_connect_generic_login_button', array( $login_form, 'make_login_button' ) ); add_shortcode( 'openid_connect_generic_login_button', array( $login_form, 'make_login_button' ) );
$login_form->handle_redirect_login_type_auto(); $login_form->handle_redirect_login_type_auto();
@ -38,12 +70,15 @@ class OpenID_Connect_Generic_Login_Form {
} }
/** /**
* Auto Login redirect * Auto Login redirect.
*
* @return void
*/ */
function handle_redirect_login_type_auto() { function handle_redirect_login_type_auto() {
if ( $GLOBALS['pagenow'] == 'wp-login.php'
&& ( $this->settings->login_type == 'auto' || ! empty( $_GET['force_redirect'] ) ) if ( 'wp-login.php' == $GLOBALS['pagenow']
&& ( ! isset( $_GET['action'] ) || $_GET['action'] !== 'logout' ) && ( 'auto' == $this->settings->login_type || ! empty( $_GET['force_redirect'] ) )
&& ( ! isset( $_GET['action'] ) || 'logout' !== $_GET['action'] )
&& ! isset( $_POST['wp-submit'] ) ) { && ! isset( $_POST['wp-submit'] ) ) {
if ( ! isset( $_GET['login-error'] ) ) { if ( ! isset( $_GET['login-error'] ) ) {
$this->handle_redirect_cookie(); $this->handle_redirect_cookie();
@ -53,25 +88,28 @@ class OpenID_Connect_Generic_Login_Form {
add_action( 'login_footer', array( $this, 'remove_login_form' ), 99 ); add_action( 'login_footer', array( $this, 'remove_login_form' ), 99 );
} }
} }
} }
/** /**
* Handle login related redirects * Handle login related redirects.
*
* @return void
*/ */
function handle_redirect_cookie() { function handle_redirect_cookie() {
if ( $GLOBALS['pagenow'] == 'wp-login.php' && isset( $_GET['action'] ) && $_GET['action'] === 'logout' ) { if ( isset( $GLOBALS['pagenow'] ) && 'wp-login.php' == $GLOBALS['pagenow'] && isset( $_GET['action'] ) && 'logout' === $_GET['action'] ) {
return; return;
} }
// record the URL of this page if set to redirect back to origin page // Record the URL of this page if set to redirect back to origin page.
if ( $this->settings->redirect_user_back ) { if ( $this->settings->redirect_user_back ) {
$redirect_expiry = current_time( 'timestamp' ) + DAY_IN_SECONDS; $redirect_expiry = current_time( 'timestamp' ) + DAY_IN_SECONDS;
// default redirect to the homepage // Default redirect to the homepage.
$redirect_url = home_url( esc_url( add_query_arg( null, null ) ) ); $redirect_url = home_url( esc_url( add_query_arg( null, null ) ) );
if ( $GLOBALS['pagenow'] == 'wp-login.php' ) { if ( isset( $GLOBALS['pagenow'] ) && 'wp-login.php' == $GLOBALS['pagenow'] ) {
// if using the login form, default redirect to the admin dashboard // If using the login form, default redirect to the admin dashboard.
$redirect_url = admin_url(); $redirect_url = admin_url();
if ( isset( $_REQUEST['redirect_to'] ) ) { if ( isset( $_REQUEST['redirect_to'] ) ) {
@ -86,9 +124,10 @@ class OpenID_Connect_Generic_Login_Form {
} }
/** /**
* Implements filter login_message * Implements filter login_message.
*
* @param string $message The text message to display on the login page.
* *
* @param $message
* @return string * @return string
*/ */
function handle_login_page( $message ) { function handle_login_page( $message ) {
@ -97,15 +136,17 @@ class OpenID_Connect_Generic_Login_Form {
$message .= $this->make_error_output( $_GET['login-error'], $_GET['message'] ); $message .= $this->make_error_output( $_GET['login-error'], $_GET['message'] );
} }
// login button is appended to existing messages in case of error // Login button is appended to existing messages in case of error.
$message .= $this->make_login_button(); $message .= $this->make_login_button();
return $message; return $message;
} }
/** /**
* Display an error message to the user * Display an error message to the user.
* *
* @param $error_code * @param string $error_code The error code.
* @param string $error_message The error message test.
* *
* @return string * @return string
*/ */
@ -122,7 +163,7 @@ class OpenID_Connect_Generic_Login_Form {
} }
/** /**
* Create a login button (link) * Create a login button (link).
* *
* @param array $atts Array of optional attributes to override login buton * @param array $atts Array of optional attributes to override login buton
* functionality when used by shortcode. * functionality when used by shortcode.
@ -147,8 +188,10 @@ class OpenID_Connect_Generic_Login_Form {
return ob_get_clean(); return ob_get_clean();
} }
/* /**
* Removes the login form from the HTML DOM * Removes the login form from the HTML DOM
*
* @return void
*/ */
function remove_login_form() { function remove_login_form() {
?> ?>
@ -161,4 +204,5 @@ class OpenID_Connect_Generic_Login_Form {
</script> </script>
<?php <?php
} }
} }

@ -1,44 +1,81 @@
<?php <?php
/** /**
* Simple class for logging messages to the options table * Plugin logging class.
*
* @package OpenID_Connect_Generic
* @category Logging
* @author Jonathan Daggerhart <jonathan@daggerhart.com>
* @copyright 2015-2020 daggerhart
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
*/
/**
* OpenID_Connect_Generic_Option_Logger class.
*
* Simple class for logging messages to the options table.
*
* @package OpenID_Connect_Generic
* @category Logging
*/ */
class OpenID_Connect_Generic_Option_Logger { class OpenID_Connect_Generic_Option_Logger {
// wp option name/key /**
* Thw WordPress option name/key.
*
* @var string
*/
private $option_name; private $option_name;
// default message type /**
* The default message type.
*
* @var string
*/
private $default_message_type; private $default_message_type;
// the number of items to keep in the log /**
* The number of items to keep in the log.
*
* @var int
*/
private $log_limit; private $log_limit;
// whether or not the /**
* Whether or not logging is enabled.
*
* @var bool
*/
private $logging_enabled; private $logging_enabled;
// internal cache of logs /**
* Internal cache of logs.
*
* @var array
*/
private $logs; private $logs;
/** /**
* Setup the logger according to the needs of the instance * Setup the logger according to the needs of the instance.
* *
* @param string $option_name * @param string $option_name The plugin log WordPress option name.
* @param string $default_message_type * @param string $default_message_type The log message type.
* @param bool|TRUE $logging_enabled * @param bool|TRUE $logging_enabled Whether logging is enabled.
* @param int $log_limit * @param int $log_limit The log entry limit.
*/ */
function __construct( $option_name, $default_message_type = 'none', $logging_enabled = true, $log_limit = 1000 ) { function __construct( $option_name, $default_message_type = 'none', $logging_enabled = true, $log_limit = 1000 ) {
$this->option_name = $option_name; $this->option_name = $option_name;
$this->default_message_type = $default_message_type; $this->default_message_type = $default_message_type;
$this->logging_enabled = (bool) $logging_enabled; $this->logging_enabled = boolval( $logging_enabled );
$this->log_limit = (int) $log_limit; $this->log_limit = intval( $log_limit );
} }
/** /**
* Subscribe logger to a set of filters * Subscribe logger to a set of filters.
*
* @param array|string $filter_names The array, or string, of the name(s) of an filter(s) to hook the logger into.
* @param int $priority The WordPress filter priority level.
* *
* @param $filter_names * @return void
* @param int $priority
*/ */
function log_filters( $filter_names, $priority = 10 ) { function log_filters( $filter_names, $priority = 10 ) {
if ( ! is_array( $filter_names ) ) { if ( ! is_array( $filter_names ) ) {
@ -51,10 +88,12 @@ class OpenID_Connect_Generic_Option_Logger {
} }
/** /**
* Subscribe logger to a set of actions * Subscribe logger to a set of actions.
*
* @param array|string $action_names The array, or string, of the name(s) of an action(s) to hook the logger into.
* @param int $priority The WordPress action priority level.
* *
* @param $action_names * @return void
* @param $priority
*/ */
function log_actions( $action_names, $priority ) { function log_actions( $action_names, $priority ) {
if ( ! is_array( $action_names ) ) { if ( ! is_array( $action_names ) ) {
@ -67,10 +106,11 @@ class OpenID_Connect_Generic_Option_Logger {
} }
/** /**
* Log the data * Log the data.
* *
* @param null $arg1 * @param mixed $arg1 The hook argument.
* @return null *
* @return mixed
*/ */
function log_hook( $arg1 = null ) { function log_hook( $arg1 = null ) {
$this->log( func_get_args(), current_filter() ); $this->log( func_get_args(), current_filter() );
@ -78,13 +118,15 @@ class OpenID_Connect_Generic_Option_Logger {
} }
/** /**
* Save an array of data to the logs * Save an array of data to the logs.
*
* @param mixed $data The data to be logged.
* @param mixed $type The type of log message.
* *
* @param $data mixed
* @return bool * @return bool
*/ */
public function log( $data, $type = null ) { public function log( $data, $type = null ) {
if ( (bool) $this->logging_enabled ) { if ( boolval( $this->logging_enabled ) ) {
$logs = $this->get_logs(); $logs = $this->get_logs();
$logs[] = $this->make_message( $data, $type ); $logs[] = $this->make_message( $data, $type );
$logs = $this->upkeep_logs( $logs ); $logs = $this->upkeep_logs( $logs );
@ -95,12 +137,12 @@ class OpenID_Connect_Generic_Option_Logger {
} }
/** /**
* Retrieve all log messages * Retrieve all log messages.
* *
* @return array * @return array
*/ */
public function get_logs() { public function get_logs() {
if ( is_null( $this->logs ) ) { if ( empty( $this->logs ) ) {
$this->logs = get_option( $this->option_name, array() ); $this->logs = get_option( $this->option_name, array() );
} }
@ -108,7 +150,7 @@ class OpenID_Connect_Generic_Option_Logger {
} }
/** /**
* Get the name of the option where this log is stored * Get the name of the option where this log is stored.
* *
* @return string * @return string
*/ */
@ -117,17 +159,17 @@ class OpenID_Connect_Generic_Option_Logger {
} }
/** /**
* Create a message array containing the data and other information * Create a message array containing the data and other information.
* *
* @param $data mixed * @param mixed $data The log message data.
* @param $type * @param mixed $type The log message type.
* *
* @return array * @return array
*/ */
private function make_message( $data, $type ) { private function make_message( $data, $type ) {
// determine the type of message // Determine the type of message.
if ( empty( $type ) ) { if ( empty( $type ) ) {
$this->default_message_type; $type = $this->default_message_type;
if ( is_array( $data ) && isset( $data['type'] ) ) { if ( is_array( $data ) && isset( $data['type'] ) ) {
$type = $data['type']; $type = $data['type'];
@ -136,7 +178,7 @@ class OpenID_Connect_Generic_Option_Logger {
} }
} }
// construct our message // Construct the message.
$message = array( $message = array(
'type' => $type, 'type' => $type,
'time' => time(), 'time' => time(),
@ -149,16 +191,17 @@ class OpenID_Connect_Generic_Option_Logger {
} }
/** /**
* Keep our log count under the limit * Keep the log count under the limit.
*
* @param array $logs The plugin logs.
* *
* @param $message array - extra data about the message
* @return array * @return array
*/ */
private function upkeep_logs( $logs ) { private function upkeep_logs( $logs ) {
$items_to_remove = count( $logs ) - $this->log_limit; $items_to_remove = count( $logs ) - $this->log_limit;
if ( $items_to_remove > 0 ) { if ( $items_to_remove > 0 ) {
// keep only the last $log_limit messages from the end // Only keep the last $log_limit messages from the end.
$logs = array_slice( $logs, ( $items_to_remove * -1 ) ); $logs = array_slice( $logs, ( $items_to_remove * -1 ) );
} }
@ -166,28 +209,32 @@ class OpenID_Connect_Generic_Option_Logger {
} }
/** /**
* Save the log messages * Save the log messages.
*
* @param array $logs The array of log messages.
* *
* @param $logs
* @return bool * @return bool
*/ */
private function save_logs( $logs ) { private function save_logs( $logs ) {
// save our logs // Save the logs.
$this->logs = $logs; $this->logs = $logs;
return update_option( $this->option_name, $logs, false ); return update_option( $this->option_name, $logs, false );
} }
/** /**
* Clear all log messages * Clear all log messages.
*
* @return void
*/ */
public function clear_logs() { public function clear_logs() {
$this->save_logs( array() ); $this->save_logs( array() );
} }
/** /**
* Get a simple html table of all the logs * Get a simple html table of all the logs.
*
* @param array $logs The array of log messages.
* *
* @param array $logs
* @return string * @return string
*/ */
public function get_logs_table( $logs = array() ) { public function get_logs_table( $logs = array() ) {
@ -220,7 +267,7 @@ class OpenID_Connect_Generic_Option_Logger {
</div> </div>
<div> <div>
<label><?php _e( 'Date' ); ?>: </label> <label><?php _e( 'Date' ); ?>: </label>
<?php print date( 'Y-m-d H:i:s', $log['time'] ); ?> <?php print gmdate( 'Y-m-d H:i:s', $log['time'] ); ?>
</div> </div>
<div> <div>
<label><?php _e( 'User' ); ?>: </label> <label><?php _e( 'User' ); ?>: </label>

@ -1,22 +1,91 @@
<?php <?php
/** /**
* Class OpenId_Connect_Generic_Option_Settings * WordPress options handling class.
*
* @package OpenID_Connect_Generic
* @category Settings
* @author Jonathan Daggerhart <jonathan@daggerhart.com>
* @copyright 2015-2020 daggerhart
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
*/
/**
* OpenId_Connect_Generic_Option_Settings class.
*
* WordPress options handling.
*
* @package OpenID_Connect_Generic
* @category Settings
*
* Legacy Settings:
*
* @property string $ep_login The login endpoint.
* @property string $ep_token The token endpoint.
* @property string $ep_userinfo The userinfo endpoint.
*
* OAuth Client Settings:
*
* @property string $login_type How the client (login form) should provide login options.
* @property string $client_id The ID the client will be recognized as when connecting the to Identity provider server.
* @property string $client_secret The secret key the IDP server expects from the client.
* @property string $scope The list of scopes this client should access.
* @property string $endpoint_login The IDP authorization endpoint URL.
* @property string $endpoint_userinfo The IDP User information endpoint URL.
* @property string $endpoint_token The IDP token validation endpoint URL.
* @property string $endpoint_end_session The IDP logout endpoint URL.
*
* Non-standard Settings:
*
* @property bool $no_sslverify The flag to enable/disable SSL verification during authorization.
* @property int $http_request_timeout The timeout for requests made to the IDP. Default value is 5.
* @property string $identity_key The key in the user claim array to find the user's identification data.
* @property string $nickname_key The key in the user claim array to find the user's nickname.
* @property string $email_format The key(s) in the user claim array to formulate the user's email address.
* @property string $displayname_format The key(s) in the user claim array to formulate the user's display name.
* @property bool $identify_with_username The flag which indicates how the user's identity will be determined.
* @property int $state_time_limit The valid time limit of the state, in seconds. Defaults to 180 seconds.
*
* Plugin Settings:
*
* @property bool $enforce_privacy The flag to indicates whether a user us required to be authenticated to access the site.
* @property bool $alternate_redirect_uri The flag to indicate whether to use the alternative redirect URI.
* @property bool $token_refresh_enable The flag whether to support refresh tokens by IDPs.
* @property bool $link_existing_users The flag to indicate whether to link to existing WordPress-only accounts or greturn an error.
* @property bool $create_if_does_not_exist The flag to indicate whether to create new users or not.
* @property bool $redirect_user_back The flag to indicate whether to redirect the user back to the page on which they started.
* @property bool $redirect_on_logout The flag to indicate whether to redirect to the login screen on session expiration.
* @property bool $enable_logging The flag to enable/disable logging.
* @property int $log_limit The maximum number of log entries to keep.
*/ */
class OpenID_Connect_Generic_Option_Settings { class OpenID_Connect_Generic_Option_Settings {
// wp option name/key /**
* WordPress option name/key.
*
* @var string
*/
private $option_name; private $option_name;
// stored option values array /**
* Stored option values array.
*
* @var array
*/
private $values; private $values;
// default plugin settings values /**
* Default plugin settings values.
*
* @var array
*/
private $default_settings; private $default_settings;
/** /**
* @param $option_name * The class constructor.
* @param array $default_settings *
* @param bool|TRUE $granular_defaults * @param string $option_name The option name/key.
* @param array $default_settings The default plugin settings values.
* @param bool|TRUE $granular_defaults The granular defaults.
*/ */
function __construct( $option_name, $default_settings = array(), $granular_defaults = true ) { function __construct( $option_name, $default_settings = array(), $granular_defaults = true ) {
$this->option_name = $option_name; $this->option_name = $option_name;
@ -28,32 +97,76 @@ class OpenID_Connect_Generic_Option_Settings {
} }
} }
/**
* Magic getter for settings.
*
* @param string $key The array key/option name.
*
* @return mixed
*/
function __get( $key ) { function __get( $key ) {
if ( isset( $this->values[ $key ] ) ) { if ( isset( $this->values[ $key ] ) ) {
return $this->values[ $key ]; return $this->values[ $key ];
} }
} }
/**
* Magic setter for settings.
*
* @param string $key The array key/option name.
* @param mixed $value The option value.
*
* @return void
*/
function __set( $key, $value ) { function __set( $key, $value ) {
$this->values[ $key ] = $value; $this->values[ $key ] = $value;
} }
/**
* Magic method to check is an attribute isset.
*
* @param string $key The array key/option name.
*
* @return bool
*/
function __isset( $key ) { function __isset( $key ) {
return isset( $this->values[ $key ] ); return isset( $this->values[ $key ] );
} }
/**
* Magic method to clear an attribute.
*
* @param string $key The array key/option name.
*
* @return void
*/
function __unset( $key ) { function __unset( $key ) {
unset( $this->values[ $key ] ); unset( $this->values[ $key ] );
} }
/**
* Get the plugin settings array.
*
* @return array
*/
function get_values() { function get_values() {
return $this->values; return $this->values;
} }
/**
* Get the plugin WordPress options name.
*
* @return string
*/
function get_option_name() { function get_option_name() {
return $this->option_name; return $this->option_name;
} }
/**
* Save the plugin options to the WordPress options table.
*
* @return void
*/
function save() { function save() {
update_option( $this->option_name, $this->values ); update_option( $this->option_name, $this->values );
} }

@ -1,35 +1,207 @@
<?php <?php
/**
* Plugin Admin settings page class.
*
* @package OpenID_Connect_Generic
* @category Settings
* @author Jonathan Daggerhart <jonathan@daggerhart.com>
* @copyright 2015-2020 daggerhart
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
*/
/** /**
* Class OpenID_Connect_Generic_Settings_Page. * OpenID_Connect_Generic_Settings_Page class.
*
* Admin settings page. * Admin settings page.
*
* @package OpenID_Connect_Generic
* @category Settings
*/ */
class OpenID_Connect_Generic_Settings_Page { class OpenID_Connect_Generic_Settings_Page {
// local copy of the settings provided by the base plugin /**
* Local copy of the settings provided by the base plugin.
*
* @var OpenID_Connect_Generic_Option_Settings
*/
private $settings; private $settings;
// The controlled list of settings & associated /**
// defined during construction for i18n reasons * Instance of the plugin logger.
*
* @var OpenID_Connect_Generic_Option_Logger
*/
private $logger;
/**
* The controlled list of settings & associated defined during
* construction for i18n reasons.
*
* @var array
*/
private $settings_fields = array(); private $settings_fields = array();
// options page slug /**
* Options page slug.
*
* @var string
*/
private $options_page_name = 'openid-connect-generic-settings'; private $options_page_name = 'openid-connect-generic-settings';
// options page settings group name /**
* Options page settings group name.
*
* @var string
*/
private $settings_field_group; private $settings_field_group;
/** /**
* @param OpenID_Connect_Generic_Option_Settings $settings * Settings page class constructor.
* @param OpenID_Connect_Generic_Option_Logger $logger *
* @param OpenID_Connect_Generic_Option_Settings $settings The plugin settings object.
* @param OpenID_Connect_Generic_Option_Logger $logger The plugin logging class object.
*/ */
function __construct( OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) { function __construct( OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) {
$this->settings = $settings; $this->settings = $settings;
$this->logger = $logger; $this->logger = $logger;
$this->settings_field_group = $this->settings->get_option_name() . '-group'; $this->settings_field_group = $this->settings->get_option_name() . '-group';
/* $fields = $this->get_settings_fields();
* Simple settings fields simply have:
// Some simple pre-processing.
foreach ( $fields as $key => &$field ) {
$field['key'] = $key;
$field['name'] = $this->settings->get_option_name() . '[' . $key . ']';
}
// Allow alterations of the fields.
$this->settings_fields = $fields;
}
/**
* Hook the settings page into WordPress.
*
* @param OpenID_Connect_Generic_Option_Settings $settings A plugin settings object instance.
* @param OpenID_Connect_Generic_Option_Logger $logger A plugin logger object instance.
*
* @return \OpenID_Connect_Generic_Settings_Page
*/
static public function register( OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) {
$settings_page = new self( $settings, $logger );
// Add our options page the the admin menu.
add_action( 'admin_menu', array( $settings_page, 'admin_menu' ) );
// Register our settings.
add_action( 'admin_init', array( $settings_page, 'admin_init' ) );
return $settings_page;
}
/**
* Implements hook admin_menu to add our options/settings page to the
* dashboard menu.
*
* @return void
*/
public function admin_menu() {
add_options_page(
__( 'OpenID Connect - Generic Client' ),
__( 'OpenID Connect Client' ),
'manage_options',
$this->options_page_name,
array( $this, 'settings_page' )
);
}
/**
* Implements hook admin_init to register our settings.
*
* @return void
*/
public function admin_init() {
register_setting(
$this->settings_field_group,
$this->settings->get_option_name(),
array(
$this,
'sanitize_settings',
)
);
add_settings_section(
'client_settings',
__( 'Client Settings' ),
array( $this, 'client_settings_description' ),
$this->options_page_name
);
add_settings_section(
'user_settings',
__( 'WordPress User Settings' ),
array( $this, 'user_settings_description' ),
$this->options_page_name
);
add_settings_section(
'authorization_settings',
__( 'Authorization Settings' ),
array( $this, 'authorization_settings_description' ),
$this->options_page_name
);
add_settings_section(
'log_settings',
__( 'Log Settings' ),
array( $this, 'log_settings_description' ),
$this->options_page_name
);
// Preprocess fields and add them to the page.
foreach ( $this->settings_fields as $key => $field ) {
// Make sure each key exists in the settings array.
if ( ! isset( $this->settings->{ $key } ) ) {
$this->settings->{ $key } = null;
}
// Determine appropriate output callback.
switch ( $field['type'] ) {
case 'checkbox':
$callback = 'do_checkbox';
break;
case 'select':
$callback = 'do_select';
break;
case 'text':
default:
$callback = 'do_text_field';
break;
}
// Add the field.
add_settings_field(
$key,
$field['title'],
array( $this, $callback ),
$this->options_page_name,
$field['section'],
$field
);
}
}
/**
* Get the plugin settings fields definition.
*
* @return array
*/
private function get_settings_fields() {
/**
* Simple settings fields have:
* *
* - title * - title
* - description * - description
@ -205,137 +377,21 @@ class OpenID_Connect_Generic_Settings_Page {
), ),
); );
$fields = apply_filters( 'openid-connect-generic-settings-fields', $fields ); return apply_filters( 'openid-connect-generic-settings-fields', $fields );
// some simple pre-processing
foreach ( $fields as $key => &$field ) {
$field['key'] = $key;
$field['name'] = $this->settings->get_option_name() . '[' . $key . ']';
}
// allow alterations of the fields
$this->settings_fields = $fields;
}
/**
* @param \OpenID_Connect_Generic_Option_Settings $settings
* @param \OpenID_Connect_Generic_Option_Logger $logger
*
* @return \OpenID_Connect_Generic_Settings_Page
*/
static public function register( OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) {
$settings_page = new self( $settings, $logger );
// add our options page the the admin menu
add_action( 'admin_menu', array( $settings_page, 'admin_menu' ) );
// register our settings
add_action( 'admin_init', array( $settings_page, 'admin_init' ) );
return $settings_page;
}
/**
* Implements hook admin_menu to add our options/settings page to the
* dashboard menu
*/
public function admin_menu() {
add_options_page(
__( 'OpenID Connect - Generic Client' ),
__( 'OpenID Connect Client' ),
'manage_options',
$this->options_page_name,
array( $this, 'settings_page' )
);
}
/**
* Implements hook admin_init to register our settings
*/
public function admin_init() {
register_setting(
$this->settings_field_group,
$this->settings->get_option_name(),
array(
$this,
'sanitize_settings',
)
);
add_settings_section(
'client_settings',
__( 'Client Settings' ),
array( $this, 'client_settings_description' ),
$this->options_page_name
);
add_settings_section(
'user_settings',
__( 'WordPress User Settings' ),
array( $this, 'user_settings_description' ),
$this->options_page_name
);
add_settings_section(
'authorization_settings',
__( 'Authorization Settings' ),
array( $this, 'authorization_settings_description' ),
$this->options_page_name
);
add_settings_section(
'log_settings',
__( 'Log Settings' ),
array( $this, 'log_settings_description' ),
$this->options_page_name
);
// preprocess fields and add them to the page
foreach ( $this->settings_fields as $key => $field ) {
// make sure each key exists in the settings array
if ( ! isset( $this->settings->{ $key } ) ) {
$this->settings->{ $key } = null;
}
// determine appropriate output callback
switch ( $field['type'] ) {
case 'checkbox':
$callback = 'do_checkbox';
break;
case 'select':
$callback = 'do_select';
break;
case 'text':
default:
$callback = 'do_text_field';
break;
}
// add the field
add_settings_field(
$key,
$field['title'],
array( $this, $callback ),
$this->options_page_name,
$field['section'],
$field
);
}
} }
/** /**
* Sanitization callback for settings/option page * Sanitization callback for settings/option page.
* *
* @param $input - submitted settings values * @param array $input The submitted settings values.
* *
* @return array * @return array
*/ */
public function sanitize_settings( $input ) { public function sanitize_settings( $input ) {
$options = array(); $options = array();
// loop through settings fields to control what we're saving // Loop through settings fields to control what we're saving.
foreach ( $this->settings_fields as $key => $field ) { foreach ( $this->settings_fields as $key => $field ) {
if ( isset( $input[ $key ] ) ) { if ( isset( $input[ $key ] ) ) {
$options[ $key ] = sanitize_text_field( trim( $input[ $key ] ) ); $options[ $key ] = sanitize_text_field( trim( $input[ $key ] ) );
@ -348,7 +404,9 @@ class OpenID_Connect_Generic_Settings_Page {
} }
/** /**
* Output the options/settings page * Output the options/settings page.
*
* @return void
*/ */
public function settings_page() { public function settings_page() {
$redirect_uri = admin_url( 'admin-ajax.php?action=openid-connect-authorize' ); $redirect_uri = admin_url( 'admin-ajax.php?action=openid-connect-authorize' );
@ -366,7 +424,7 @@ class OpenID_Connect_Generic_Settings_Page {
do_settings_sections( $this->options_page_name ); do_settings_sections( $this->options_page_name );
submit_button(); submit_button();
// simple debug to view settings array // Simple debug to view settings array.
if ( isset( $_GET['debug'] ) ) { if ( isset( $_GET['debug'] ) ) {
var_dump( $this->settings->get_values() ); var_dump( $this->settings->get_values() );
} }
@ -400,9 +458,11 @@ class OpenID_Connect_Generic_Settings_Page {
} }
/** /**
* Output a standard text field * Output a standard text field.
*
* @param array $field The settings field definition array.
* *
* @param $field * @return void
*/ */
public function do_text_field( $field ) { public function do_text_field( $field ) {
?> ?>
@ -416,10 +476,12 @@ class OpenID_Connect_Generic_Settings_Page {
} }
/** /**
* Output a checkbox for a boolean setting * Output a checkbox for a boolean setting.
* - hidden field is default value so we don't have to check isset() on save * - hidden field is default value so we don't have to check isset() on save.
* *
* @param $field * @param array $field The settings field definition array.
*
* @return void
*/ */
public function do_checkbox( $field ) { public function do_checkbox( $field ) {
?> ?>
@ -434,7 +496,11 @@ class OpenID_Connect_Generic_Settings_Page {
} }
/** /**
* @param $field * Output a select control.
*
* @param array $field The settings field definition array.
*
* @return void
*/ */
function do_select( $field ) { function do_select( $field ) {
$current_value = isset( $this->settings->{ $field['key'] } ) ? $this->settings->{ $field['key'] } : ''; $current_value = isset( $this->settings->{ $field['key'] } ) ? $this->settings->{ $field['key'] } : '';
@ -449,9 +515,11 @@ class OpenID_Connect_Generic_Settings_Page {
} }
/** /**
* Simply output the field description, and example if present * Output the field description, and example if present.
*
* @param array $field The settings field definition array.
* *
* @param $field * @return void
*/ */
public function do_field_description( $field ) { public function do_field_description( $field ) {
?> ?>
@ -465,18 +533,38 @@ class OpenID_Connect_Generic_Settings_Page {
<?php <?php
} }
/**
* Output the 'Client Settings' plugin setting section description.
*
* @return void
*/
public function client_settings_description() { public function client_settings_description() {
_e( 'Enter your OpenID Connect identity provider settings' ); _e( 'Enter your OpenID Connect identity provider settings' );
} }
/**
* Output the 'WordPress User Settings' plugin setting section description.
*
* @return void
*/
public function user_settings_description() { public function user_settings_description() {
_e( 'Modify the interaction between OpenID Connect and WordPress users' ); _e( 'Modify the interaction between OpenID Connect and WordPress users' );
} }
/**
* Output the 'Authorization Settings' plugin setting section description.
*
* @return void
*/
public function authorization_settings_description() { public function authorization_settings_description() {
_e( 'Control the authorization mechanics of the site' ); _e( 'Control the authorization mechanics of the site' );
} }
/**
* Output the 'Log Settings' plugin setting section description.
*
* @return void
*/
public function log_settings_description() { public function log_settings_description() {
_e( 'Log information about login attempts through OpenID Connect Generic' ); _e( 'Log information about login attempts through OpenID Connect Generic' );
} }

@ -5,8 +5,8 @@
* This plugin provides the ability to authenticate users with Identity * This plugin provides the ability to authenticate users with Identity
* Providers using the OpenID Connect OAuth2 API with Authorization Code Flow. * Providers using the OpenID Connect OAuth2 API with Authorization Code Flow.
* *
* @category Authentication
* @package OpenID_Connect_Generic * @package OpenID_Connect_Generic
* @category General
* @author Jonathan Daggerhart <jonathan@daggerhart.com> * @author Jonathan Daggerhart <jonathan@daggerhart.com>
* @copyright 2015-2020 daggerhart * @copyright 2015-2020 daggerhart
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+ * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
@ -67,9 +67,11 @@ Notes
/** /**
* OpenID_Connect_Generic class. * OpenID_Connect_Generic class.
*
* Defines plugin initialization functionality. * Defines plugin initialization functionality.
* *
* @package OpenID_Connect_Generic * @package OpenID_Connect_Generic
* @category General
*/ */
class OpenID_Connect_Generic { class OpenID_Connect_Generic {
@ -104,7 +106,7 @@ class OpenID_Connect_Generic {
/** /**
* Settings admin page. * Settings admin page.
* *
* @var OpenID_Connect_Generic_Option_Settings * @var OpenID_Connect_Generic_Settings_Page
*/ */
private $settings_page; private $settings_page;
@ -115,6 +117,13 @@ class OpenID_Connect_Generic {
*/ */
private $login_form; private $login_form;
/**
* Client wrapper.
*
* @var OpenID_Connect_Generic_Client_Wrapper
*/
private $client_wrapper;
/** /**
* Setup the plugin * Setup the plugin
* *
@ -129,7 +138,9 @@ class OpenID_Connect_Generic {
} }
/** /**
* WP Hook 'init' * WordPress Hook 'init'.
*
* @return void
*/ */
function init() { function init() {
@ -163,10 +174,10 @@ class OpenID_Connect_Generic {
$this->login_form = OpenID_Connect_Generic_Login_Form::register( $this->settings, $this->client_wrapper ); $this->login_form = OpenID_Connect_Generic_Login_Form::register( $this->settings, $this->client_wrapper );
// add a shortcode to get the auth url // Add a shortcode to get the auth URL.
add_shortcode( 'openid_connect_generic_auth_url', array( $this->client_wrapper, 'get_authentication_url' ) ); add_shortcode( 'openid_connect_generic_auth_url', array( $this->client_wrapper, 'get_authentication_url' ) );
// add actions to our scheduled cron jobs // Add actions to our scheduled cron jobs.
add_action( 'openid-connect-generic-cron-daily', array( $this, 'cron_states_garbage_collection' ) ); add_action( 'openid-connect-generic-cron-daily', array( $this, 'cron_states_garbage_collection' ) );
$this->upgrade(); $this->upgrade();
@ -182,17 +193,17 @@ class OpenID_Connect_Generic {
*/ */
function enforce_privacy_redirect() { function enforce_privacy_redirect() {
if ( $this->settings->enforce_privacy && ! is_user_logged_in() ) { if ( $this->settings->enforce_privacy && ! is_user_logged_in() ) {
// our client endpoint relies on the wp admind ajax endpoint // The client endpoint relies on the wp admind ajax endpoint.
if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX || ! isset( $_GET['action'] ) || $_GET['action'] != 'openid-connect-authorize' ) { if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX || ! isset( $_GET['action'] ) || 'openid-connect-authorize' != $_GET['action'] ) {
auth_redirect(); auth_redirect();
} }
} }
} }
/** /**
* Enforce privacy settings for rss feeds * Enforce privacy settings for rss feeds.
* *
* @param $content * @param string $content The content.
* *
* @return mixed * @return mixed
*/ */
@ -211,7 +222,7 @@ class OpenID_Connect_Generic {
$settings = $this->settings; $settings = $this->settings;
if ( version_compare( self::VERSION, $last_version, '>' ) ) { if ( version_compare( self::VERSION, $last_version, '>' ) ) {
// upgrade required // An upgrade is required.
self::setup_cron_jobs(); self::setup_cron_jobs();
// @todo move this to another file for upgrade scripts // @todo move this to another file for upgrade scripts
@ -224,7 +235,7 @@ class OpenID_Connect_Generic {
$settings->save(); $settings->save();
} }
// update the stored version number // Update the stored version number.
update_option( 'openid-connect-generic-plugin-version', self::VERSION ); update_option( 'openid-connect-generic-plugin-version', self::VERSION );
} }
} }
@ -269,9 +280,9 @@ class OpenID_Connect_Generic {
} }
/** /**
* Simple autoloader * Simple autoloader.
* *
* @param $class * @param string $class The class name.
*/ */
static public function autoload( $class ) { static public function autoload( $class ) {
$prefix = 'OpenID_Connect_Generic_'; $prefix = 'OpenID_Connect_Generic_';
@ -282,7 +293,7 @@ class OpenID_Connect_Generic {
$filename = $class . '.php'; $filename = $class . '.php';
// internal files are all lowercase and use dashes in filenames // Internal files are all lowercase and use dashes in filenames.
if ( false === strpos( $filename, '\\' ) ) { if ( false === strpos( $filename, '\\' ) ) {
$filename = strtolower( str_replace( '_', '-', $filename ) ); $filename = strtolower( str_replace( '_', '-', $filename ) );
} else { } else {
@ -304,9 +315,9 @@ class OpenID_Connect_Generic {
$settings = new OpenID_Connect_Generic_Option_Settings( $settings = new OpenID_Connect_Generic_Option_Settings(
'openid_connect_generic_settings', 'openid_connect_generic_settings',
// default settings values // Default settings values.
array( array(
// oauth client settings // OAuth client settings.
'login_type' => 'button', 'login_type' => 'button',
'client_id' => '', 'client_id' => '',
'client_secret' => '', 'client_secret' => '',
@ -316,7 +327,7 @@ class OpenID_Connect_Generic {
'endpoint_token' => '', 'endpoint_token' => '',
'endpoint_end_session' => '', 'endpoint_end_session' => '',
// non-standard settings // Non-standard settings.
'no_sslverify' => 0, 'no_sslverify' => 0,
'http_request_timeout' => 5, 'http_request_timeout' => 5,
'identity_key' => 'preferred_username', 'identity_key' => 'preferred_username',
@ -325,7 +336,7 @@ class OpenID_Connect_Generic {
'displayname_format' => '', 'displayname_format' => '',
'identify_with_username' => false, 'identify_with_username' => false,
// plugin settings // Plugin settings.
'enforce_privacy' => 0, 'enforce_privacy' => 0,
'alternate_redirect_uri' => 0, 'alternate_redirect_uri' => 0,
'token_refresh_enable' => 1, 'token_refresh_enable' => 1,
@ -344,7 +355,7 @@ class OpenID_Connect_Generic {
add_action( 'init', array( $plugin, 'init' ) ); add_action( 'init', array( $plugin, 'init' ) );
// privacy hooks // Privacy hooks.
add_action( 'template_redirect', array( $plugin, 'enforce_privacy_redirect' ), 0 ); add_action( 'template_redirect', array( $plugin, 'enforce_privacy_redirect' ), 0 );
add_filter( 'the_content_feed', array( $plugin, 'enforce_privacy_feeds' ), 999 ); add_filter( 'the_content_feed', array( $plugin, 'enforce_privacy_feeds' ), 999 );
add_filter( 'the_excerpt_rss', array( $plugin, 'enforce_privacy_feeds' ), 999 ); add_filter( 'the_excerpt_rss', array( $plugin, 'enforce_privacy_feeds' ), 999 );

Loading…
Cancel
Save