|
|
|
@ -62,7 +62,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
private $redirect_uri;
|
|
|
|
|
|
|
|
|
|
private $logs = null;
|
|
|
|
|
private $logs = NULL;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialize the plugin
|
|
|
|
@ -99,6 +99,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->settings = wp_parse_args( get_option( OPENID_CONNECT_GENERIC_SETTINGS_NAME, array() ), $this->default_settings );
|
|
|
|
|
|
|
|
|
|
return $this->settings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -151,7 +152,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
// save our logs
|
|
|
|
|
$this->logs = $logs;
|
|
|
|
|
update_option( 'openid_connect_generic_logs', $logs, false );
|
|
|
|
|
update_option( 'openid_connect_generic_logs', $logs, FALSE );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -172,14 +173,23 @@ class OpenID_Connect_Generic {
|
|
|
|
|
add_filter( 'login_message', array( $this, 'login_message' ), 99 );
|
|
|
|
|
|
|
|
|
|
// alter the requests according to settings
|
|
|
|
|
add_filter( 'openid-connect-generic-alter-request', array( $this, 'alter_request' ), 10, 3 );
|
|
|
|
|
add_filter( 'openid-connect-generic-alter-request', array(
|
|
|
|
|
$this,
|
|
|
|
|
'alter_request'
|
|
|
|
|
), 10, 3 );
|
|
|
|
|
|
|
|
|
|
// administration yo!
|
|
|
|
|
if ( is_admin() ) {
|
|
|
|
|
// use the ajax url to handle processing authorization without any html output
|
|
|
|
|
// this callback will occur when then IDP returns with an authenticated value
|
|
|
|
|
add_action( 'wp_ajax_openid-connect-authorize', array( $this, 'auth_callback' ) );
|
|
|
|
|
add_action( 'wp_ajax_nopriv_openid-connect-authorize', array( $this, 'auth_callback' ) );
|
|
|
|
|
add_action( 'wp_ajax_openid-connect-authorize', array(
|
|
|
|
|
$this,
|
|
|
|
|
'auth_callback'
|
|
|
|
|
) );
|
|
|
|
|
add_action( 'wp_ajax_nopriv_openid-connect-authorize', array(
|
|
|
|
|
$this,
|
|
|
|
|
'auth_callback'
|
|
|
|
|
) );
|
|
|
|
|
|
|
|
|
|
// initialize the settings page
|
|
|
|
|
require_once OPENID_CONNECT_GENERIC_DIR . '/admin/openid-connect-generic-settings.php';
|
|
|
|
@ -199,8 +209,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
// avoid redirects on cron or ajax
|
|
|
|
|
( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) &&
|
|
|
|
|
( ! defined( 'DOING_CRON' ) || ! DOING_CRON )
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
) {
|
|
|
|
|
global $pagenow;
|
|
|
|
|
|
|
|
|
|
// avoid redirect loop
|
|
|
|
@ -220,7 +229,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
* Check the user's cookie
|
|
|
|
|
*/
|
|
|
|
|
function check_user_token() {
|
|
|
|
|
$is_openid_connect_user = get_user_meta( wp_get_current_user()->ID, 'openid-connect-generic-user', true );
|
|
|
|
|
$is_openid_connect_user = get_user_meta( wp_get_current_user()->ID, 'openid-connect-generic-user', TRUE );
|
|
|
|
|
|
|
|
|
|
if ( is_user_logged_in() && ! empty( $is_openid_connect_user ) && ! isset( $_COOKIE[ $this->cookie_id_key ] ) ) {
|
|
|
|
|
wp_logout();
|
|
|
|
@ -256,13 +265,13 @@ class OpenID_Connect_Generic {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// extract token response from token
|
|
|
|
|
$token_response = json_decode( $token_result['body'], true );
|
|
|
|
|
$token_response = json_decode( $token_result['body'], TRUE );
|
|
|
|
|
|
|
|
|
|
// we need to ensure 3 specific items exist with the token response in order
|
|
|
|
|
// to proceed with confidence: id_token, access_token, and token_type == 'Bearer'
|
|
|
|
|
if ( ! isset( $token_response['id_token'] ) || ! isset( $token_response['access_token'] ) ||
|
|
|
|
|
! isset( $token_response['token_type'] ) || $token_response['token_type'] !== 'Bearer' )
|
|
|
|
|
{
|
|
|
|
|
! isset( $token_response['token_type'] ) || $token_response['token_type'] !== 'Bearer'
|
|
|
|
|
) {
|
|
|
|
|
$this->error( 4 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -277,7 +286,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
$tmp = explode( '.', $token_response['id_token'] );
|
|
|
|
|
|
|
|
|
|
// Extract the id_token's claims from the token
|
|
|
|
|
$id_token_claim = json_decode( base64_decode( $tmp[1] ), true );
|
|
|
|
|
$id_token_claim = json_decode( base64_decode( $tmp[1] ), TRUE );
|
|
|
|
|
|
|
|
|
|
// 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'] ] ) ) {
|
|
|
|
@ -287,8 +296,8 @@ class OpenID_Connect_Generic {
|
|
|
|
|
// if desired, admins can use regex to determine if the identity value is valid
|
|
|
|
|
// according to their own standards expectations
|
|
|
|
|
if ( isset( $settings['allowed_regex'] ) && ! empty( $settings['allowed_regex'] ) &&
|
|
|
|
|
preg_match( $settings['allowed_regex'], $id_token_claim[ $settings['identity_key'] ] ) !== 1)
|
|
|
|
|
{
|
|
|
|
|
preg_match( $settings['allowed_regex'], $id_token_claim[ $settings['identity_key'] ] ) !== 1
|
|
|
|
|
) {
|
|
|
|
|
$this->error( 5 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -300,7 +309,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
$this->error( 3, $user_claim_result );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$user_claim = json_decode( $user_claim_result['body'], true );
|
|
|
|
|
$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'] ) {
|
|
|
|
@ -315,7 +324,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
// allow plugins / themes to halt the login process early
|
|
|
|
|
// based on the user_claim
|
|
|
|
|
$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 ) {
|
|
|
|
|
$this->error( 8 );
|
|
|
|
@ -335,8 +344,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
if ( $user_query->get_total() > 0 ) {
|
|
|
|
|
$users = $user_query->get_results();
|
|
|
|
|
$user = $users[0];
|
|
|
|
|
}
|
|
|
|
|
// otherwise, user does not exist and we'll need to create it
|
|
|
|
|
} // otherwise, user does not exist and we'll need to create it
|
|
|
|
|
else {
|
|
|
|
|
// default username & email to the user identity, since that is the only
|
|
|
|
|
// thing we can be sure to have
|
|
|
|
@ -347,8 +355,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
if ( isset( $user_claim['email'] ) ) {
|
|
|
|
|
$email = $user_claim['email'];
|
|
|
|
|
$username = $this->get_username_from_claim( $user_claim );
|
|
|
|
|
}
|
|
|
|
|
// if no name exists, attempt another request for userinfo
|
|
|
|
|
} // if no name exists, attempt another request for userinfo
|
|
|
|
|
else if ( isset( $token_response['access_token'] ) ) {
|
|
|
|
|
$user_claim_result = $this->request_userinfo( $token_response['access_token'] );
|
|
|
|
|
|
|
|
|
@ -357,7 +364,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
$this->error( 3, $user_claim_result );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$user_claim = json_decode( $user_claim_result['body'], true );
|
|
|
|
|
$user_claim = json_decode( $user_claim_result['body'], TRUE );
|
|
|
|
|
|
|
|
|
|
if ( isset( $user_claim['email'] ) ) {
|
|
|
|
|
$email = $user_claim['email'];
|
|
|
|
@ -367,14 +374,14 @@ class OpenID_Connect_Generic {
|
|
|
|
|
|
|
|
|
|
// allow other plugins / themes to determine authorization
|
|
|
|
|
// of new accounts based on the returned user claim
|
|
|
|
|
$create_user = apply_filters( 'openid-connect-generic-user-creation-test', true, $user_claim );
|
|
|
|
|
$create_user = apply_filters( 'openid-connect-generic-user-creation-test', TRUE, $user_claim );
|
|
|
|
|
|
|
|
|
|
if ( ! $create_user ) {
|
|
|
|
|
$this->error( 9 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create the new user
|
|
|
|
|
$uid = wp_create_user( $username, wp_generate_password( 32, true, true ), $email );
|
|
|
|
|
$uid = wp_create_user( $username, wp_generate_password( 32, TRUE, TRUE ), $email );
|
|
|
|
|
|
|
|
|
|
// make sure we didn't fail in creating the user
|
|
|
|
|
if ( is_wp_error( $uid ) ) {
|
|
|
|
@ -388,8 +395,8 @@ class OpenID_Connect_Generic {
|
|
|
|
|
$user = get_user_by( 'id', $uid );
|
|
|
|
|
|
|
|
|
|
// save some meta data about this new user for the future
|
|
|
|
|
add_user_meta( $user->ID, 'openid-connect-generic-user', true, true );
|
|
|
|
|
add_user_meta( $user->ID, 'openid-connect-generic-user-identity', (string) $user_identity, true );
|
|
|
|
|
add_user_meta( $user->ID, 'openid-connect-generic-user', TRUE, TRUE );
|
|
|
|
|
add_user_meta( $user->ID, 'openid-connect-generic-user-identity', (string) $user_identity, TRUE );
|
|
|
|
|
|
|
|
|
|
// allow plugins / themes to take action on new user creation
|
|
|
|
|
do_action( 'openid-connect-generic-user-create', $user, $user_claim );
|
|
|
|
@ -407,11 +414,11 @@ class OpenID_Connect_Generic {
|
|
|
|
|
update_user_meta( $user->ID, 'openid-connect-generic-last-user-claim', $user_claim );
|
|
|
|
|
|
|
|
|
|
// save our authorization cookie for the response expiration
|
|
|
|
|
$oauth_expiry = $token_response['expires_in'] + current_time( 'timestamp', true );
|
|
|
|
|
setcookie( $this->cookie_id_key, $user_identity, $oauth_expiry, COOKIEPATH, COOKIE_DOMAIN, true );
|
|
|
|
|
$oauth_expiry = $token_response['expires_in'] + current_time( 'timestamp', TRUE );
|
|
|
|
|
setcookie( $this->cookie_id_key, $user_identity, $oauth_expiry, COOKIEPATH, COOKIE_DOMAIN, TRUE );
|
|
|
|
|
|
|
|
|
|
// get a cookie and go home!
|
|
|
|
|
wp_set_auth_cookie( $user->ID, false );
|
|
|
|
|
wp_set_auth_cookie( $user->ID, FALSE );
|
|
|
|
|
|
|
|
|
|
$this->log( array(
|
|
|
|
|
'message' => "Successful login for: {$user->user_login} ({$user->ID})"
|
|
|
|
@ -425,6 +432,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
* Using the authorization_code, request an authentication token from the idp
|
|
|
|
|
*
|
|
|
|
|
* @param $code - authorization_code
|
|
|
|
|
*
|
|
|
|
|
* @return array|\WP_Error
|
|
|
|
|
*/
|
|
|
|
|
function request_authentication_token( $code ) {
|
|
|
|
@ -454,6 +462,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
* Using an access_token, request the userinfo from the idp
|
|
|
|
|
*
|
|
|
|
|
* @param $access_token
|
|
|
|
|
*
|
|
|
|
|
* @return array|\WP_Error
|
|
|
|
|
*/
|
|
|
|
|
function request_userinfo( $access_token ) {
|
|
|
|
@ -474,11 +483,12 @@ class OpenID_Connect_Generic {
|
|
|
|
|
* @param $request
|
|
|
|
|
* @param $settings
|
|
|
|
|
* @param $op
|
|
|
|
|
*
|
|
|
|
|
* @return mixed
|
|
|
|
|
*/
|
|
|
|
|
function alter_request( $request, $settings, $op ) {
|
|
|
|
|
if ( isset( $settings['no_sslverify'] ) && $settings['no_sslverify'] ) {
|
|
|
|
|
$request['sslverify'] = false;
|
|
|
|
|
$request['sslverify'] = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $request;
|
|
|
|
@ -527,11 +537,12 @@ class OpenID_Connect_Generic {
|
|
|
|
|
* Check the validity of a given state
|
|
|
|
|
*
|
|
|
|
|
* @param $state
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
function check_state( $state ) {
|
|
|
|
|
$states = get_option( 'openid-connect-generic-valid-states', array() );
|
|
|
|
|
$valid = false;
|
|
|
|
|
$valid = FALSE;
|
|
|
|
|
|
|
|
|
|
// remove any expired states
|
|
|
|
|
foreach ( $states as $code => $timestamp ) {
|
|
|
|
@ -545,7 +556,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
// state is valid, remove it
|
|
|
|
|
unset( $states[ $state ] );
|
|
|
|
|
|
|
|
|
|
$valid = true;
|
|
|
|
|
$valid = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// save our altered states
|
|
|
|
@ -558,6 +569,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
* Implements filter login_message
|
|
|
|
|
*
|
|
|
|
|
* @param $message
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
function login_message( $message ) {
|
|
|
|
@ -613,6 +625,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
* Display an error message to the user
|
|
|
|
|
*
|
|
|
|
|
* @param $error_number
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
function get_error_message( $error_number ) {
|
|
|
|
@ -652,13 +665,14 @@ class OpenID_Connect_Generic {
|
|
|
|
|
* Remove cookies
|
|
|
|
|
*/
|
|
|
|
|
function wp_logout() {
|
|
|
|
|
setcookie( $this->cookie_id_key , '1', 0, COOKIEPATH, COOKIE_DOMAIN, true );
|
|
|
|
|
setcookie( $this->cookie_id_key, '1', 0, COOKIEPATH, COOKIE_DOMAIN, TRUE );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Avoid user_login collisions by incrementing
|
|
|
|
|
*
|
|
|
|
|
* @param $user_claim array
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
function get_username_from_claim( $user_claim ) {
|
|
|
|
@ -674,7 +688,7 @@ class OpenID_Connect_Generic {
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// nothing to build a name from
|
|
|
|
|
return false;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// normalize the data a bit
|
|
|
|
|