|
|
|
@ -50,6 +50,8 @@ class OpenID_Connect_Generic {
|
|
|
|
|
'no_sslverify' => 0,
|
|
|
|
|
'enforce_privacy' => 0,
|
|
|
|
|
'identity_key' => 'sub',
|
|
|
|
|
'enable_logging' => 0,
|
|
|
|
|
'log_limit' => 1000,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// storage for plugin settings
|
|
|
|
@ -60,6 +62,8 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
private $redirect_uri;
|
|
|
|
|
|
|
|
|
|
private $logs = null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialize the plugin
|
|
|
|
|
*/
|
|
|
|
@ -98,6 +102,58 @@ class OpenID_Connect_Generic {
|
|
|
|
|
return $this->settings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Retrieve all log messages
|
|
|
|
|
*/
|
|
|
|
|
public function get_logs(){
|
|
|
|
|
if ( is_null( $this->logs ) ) {
|
|
|
|
|
$this->logs = get_option( 'openid_connect_generic_logs', array() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->logs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
public function log( $data, $type = 'error' ){
|
|
|
|
|
if ( (bool) $this->settings['enable_logging'] ) {
|
|
|
|
|
$this->add_log_message( $data, $type );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a new message to the log
|
|
|
|
|
*
|
|
|
|
|
* @param $data array - extra data about the message
|
|
|
|
|
* @param $type string - simple message type string, defaults to error
|
|
|
|
|
*/
|
|
|
|
|
public function add_log_message( $data = array(), $type = 'error' ){
|
|
|
|
|
// construct our message
|
|
|
|
|
$message = array(
|
|
|
|
|
'type' => $type,
|
|
|
|
|
'time' => time(),
|
|
|
|
|
'user_ID' => get_current_user_id(),
|
|
|
|
|
'data' => is_array( $data ) ? $data : array( $data ),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// add our message to the logs
|
|
|
|
|
$logs = $this->get_logs();
|
|
|
|
|
$logs[] = $message;
|
|
|
|
|
|
|
|
|
|
// keep our log count under the limit
|
|
|
|
|
$items_to_remove = count( $logs ) - (int) $this->settings['log_limit'];
|
|
|
|
|
|
|
|
|
|
while ( $items_to_remove > 0 ) {
|
|
|
|
|
array_shift( $logs );
|
|
|
|
|
$items_to_remove--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// save our logs
|
|
|
|
|
$this->logs = $logs;
|
|
|
|
|
update_option( 'openid_connect_generic_logs', $logs, false );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Implements hook init
|
|
|
|
|
* - hook plugin into WP as needed
|
|
|
|
@ -182,12 +238,12 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
// look for an existing error of some kind
|
|
|
|
|
if ( isset( $_GET['error'] ) ) {
|
|
|
|
|
$this->error_redirect( 99 );
|
|
|
|
|
$this->error( 99 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// make sure we have a legitimate authentication code and valid state
|
|
|
|
|
if ( !isset( $_GET['code'] ) || !isset( $_GET['state'] ) || !$this->check_state( $_GET['state'] ) ) {
|
|
|
|
|
$this->error_redirect( 1 );
|
|
|
|
|
$this->error( 1 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we have an authorization code, make sure it is good by
|
|
|
|
@ -196,7 +252,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
// ensure the token is not an error generated by wp
|
|
|
|
|
if ( is_wp_error( $token_result ) ){
|
|
|
|
|
$this->error_redirect( 2 );
|
|
|
|
|
$this->error( 2, $token_result );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// extract token response from token
|
|
|
|
@ -207,7 +263,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
if ( ! isset( $token_response['id_token'] ) || ! isset( $token_response['access_token'] ) ||
|
|
|
|
|
! isset( $token_response['token_type'] ) || $token_response['token_type'] !== 'Bearer' )
|
|
|
|
|
{
|
|
|
|
|
$this->error_redirect( 4 );
|
|
|
|
|
$this->error( 4 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// - end authentication
|
|
|
|
@ -225,7 +281,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
// make sure we can find our identification data and that it has a value
|
|
|
|
|
if ( ! isset( $id_token_claim[ $settings['identity_key'] ] ) || empty( $id_token_claim[ $settings['identity_key'] ] ) ) {
|
|
|
|
|
$this->error_redirect( 5 );
|
|
|
|
|
$this->error( 5 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if desired, admins can use regex to determine if the identity value is valid
|
|
|
|
@ -233,7 +289,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
if ( isset( $settings['allowed_regex'] ) && !empty( $settings['allowed_regex'] ) &&
|
|
|
|
|
preg_match( $settings['allowed_regex'], $id_token_claim[ $settings['identity_key'] ] ) !== 1)
|
|
|
|
|
{
|
|
|
|
|
$this->error_redirect( 5 );
|
|
|
|
|
$this->error( 5 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// send a userinfo request to get user claim
|
|
|
|
@ -241,14 +297,14 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
// 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'] ) ) {
|
|
|
|
|
$this->error_redirect( 3 );
|
|
|
|
|
$this->error( 3, $user_claim_result );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$user_claim = json_decode( $user_claim_result['body'], true );
|
|
|
|
|
|
|
|
|
|
// make sure the id_token sub === user_claim sub, according to spec
|
|
|
|
|
if ( $id_token_claim[ $settings['identity_key'] ] !== $user_claim['sub'] ) {
|
|
|
|
|
$this->error_redirect( 4 );
|
|
|
|
|
$this->error( 4 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// retrieve the identity from the id_token
|
|
|
|
@ -262,7 +318,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
$login_user = apply_filters( 'openid-connect-generic-user-login-test', true, $user_claim );
|
|
|
|
|
|
|
|
|
|
if ( ! $login_user ){
|
|
|
|
|
$this->error_redirect( 8 );
|
|
|
|
|
$this->error( 8 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// look for user by their openid-connect-generic-user-identity value
|
|
|
|
@ -298,7 +354,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
// make sure we didn't get an error
|
|
|
|
|
if ( is_wp_error( $user_claim_result ) ) {
|
|
|
|
|
$this->error_redirect( 3 );
|
|
|
|
|
$this->error( 3, $user_claim_result );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$user_claim = json_decode( $user_claim_result['body'], true );
|
|
|
|
@ -314,7 +370,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
$create_user = apply_filters( 'openid-connect-generic-user-creation-test', true, $user_claim );
|
|
|
|
|
|
|
|
|
|
if ( ! $create_user ) {
|
|
|
|
|
$this->error_redirect( 9 );
|
|
|
|
|
$this->error( 9 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create the new user
|
|
|
|
@ -322,9 +378,13 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
// make sure we didn't fail in creating the user
|
|
|
|
|
if ( is_wp_error( $uid ) ) {
|
|
|
|
|
$this->error_redirect( 6 );
|
|
|
|
|
$this->error( 6, $uid );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->log(array(
|
|
|
|
|
'message' => 'New user created: '. $uid
|
|
|
|
|
), 'success' );
|
|
|
|
|
|
|
|
|
|
$user = get_user_by( 'id', $uid );
|
|
|
|
|
|
|
|
|
|
// save some meta data about this new user for the future
|
|
|
|
@ -337,7 +397,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
// ensure our found user is a real WP_User
|
|
|
|
|
if ( ! is_a( $user, 'WP_User' ) || ! $user->exists() ) {
|
|
|
|
|
$this->error_redirect( 7 );
|
|
|
|
|
$this->error( 7, $user );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// hey, we made it!
|
|
|
|
@ -352,6 +412,11 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
// get a cookie and go home!
|
|
|
|
|
wp_set_auth_cookie( $user->ID, false );
|
|
|
|
|
|
|
|
|
|
$this->log(array(
|
|
|
|
|
'message' => "Successful login for: {$user->user_login} ({$user->ID})"
|
|
|
|
|
), 'success' );
|
|
|
|
|
|
|
|
|
|
wp_redirect( home_url() );
|
|
|
|
|
// - end user handling
|
|
|
|
|
}
|
|
|
|
@ -500,7 +565,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
// errors and auto login can't happen at the same time
|
|
|
|
|
if ( isset( $_GET['login-error'] ) ) {
|
|
|
|
|
$message = $this->error_message( $_GET['login-error'] );
|
|
|
|
|
$message = $this->get_error_message( $_GET['login-error'] );
|
|
|
|
|
}
|
|
|
|
|
else if ( $settings['login_type'] == 'auto' ) {
|
|
|
|
|
wp_redirect( $this->make_authentication_url() );
|
|
|
|
@ -519,11 +584,27 @@ class OpenID_Connect_Generic {
|
|
|
|
|
* Handle errors by redirecting the user to the login form
|
|
|
|
|
* along with an error code
|
|
|
|
|
*
|
|
|
|
|
* @param $error_number
|
|
|
|
|
* @param $error_number - required
|
|
|
|
|
*/
|
|
|
|
|
function error_redirect( $error_number ){
|
|
|
|
|
function error( $error_number ) {
|
|
|
|
|
$args = func_get_args();
|
|
|
|
|
$error_number = array_shift($args);
|
|
|
|
|
$url = wp_login_url() . '?login-error=' . $error_number;
|
|
|
|
|
|
|
|
|
|
$error = array(
|
|
|
|
|
'error id' => $error_number,
|
|
|
|
|
'error message' => $this->errors[ $error_number ],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// allow for additional error details
|
|
|
|
|
if ( !empty( $args ) ){
|
|
|
|
|
$error['details'] = $args;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// attempt to log the error
|
|
|
|
|
$this->log( $error );
|
|
|
|
|
|
|
|
|
|
// redirect user back to login page
|
|
|
|
|
wp_redirect( $url );
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
@ -534,7 +615,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
* @param $error_number
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
function error_message( $error_number ){
|
|
|
|
|
function get_error_message( $error_number ){
|
|
|
|
|
// fallback to unknown error
|
|
|
|
|
if ( ! isset( $this->errors[ $error_number ] ) ) {
|
|
|
|
|
$error_number = 99;
|
|
|
|
|