Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save Oauth2 Access Token in User Meta #155

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Save Oauth2 Access Token in User Meta
Now, the Access Token and Refresh Token are stored in the database. After login, the tokens are encrypted using the login key of the WordPress system and stored as usermeta in the database as “encrypted_token”.
Before logout, the corresponding entry is removed from the metadata.
The token can then be used by other plugins, e.g., for calling APIs.
  • Loading branch information
ChristianMaidhof committed Jul 21, 2024
commit 99d7d75082d565ac1698ba6f78a185e3c12ca655
2 changes: 2 additions & 0 deletions authorizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
require_once __DIR__ . '/src/authorizer/class-authentication.php';
require_once __DIR__ . '/src/authorizer/class-authorization.php';
require_once __DIR__ . '/src/authorizer/class-login-form.php';
require_once __DIR__ . '/src/authorizer/class-save-secure.php';

require_once __DIR__ . '/src/authorizer/class-dashboard-widget.php';
require_once __DIR__ . '/src/authorizer/class-ajax-endpoints.php';
require_once __DIR__ . '/src/authorizer/class-sync-userdata.php';
Expand Down
27 changes: 27 additions & 0 deletions src/authorizer/class-authentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Authorizer\Helper;
use Authorizer\Options;
use Authorizer\Authorization;
use Authorizer\Save_Secure;

/**
* Implements the authentication (is user who they say they are?) features of
Expand Down Expand Up @@ -137,6 +138,7 @@ public function custom_authenticate( $user, $username, $password ) {
$externally_authenticated_emails = array();
$authenticated_by = '';
$result = null;
$encrypted_token = '';

// Try OAuth2 authentication if it's enabled and we don't have a
// successful login yet.
Expand All @@ -153,6 +155,10 @@ public function custom_authenticate( $user, $username, $password ) {
$externally_authenticated_emails[] = $result['email'];
}
$authenticated_by = $result['authenticated_by'];

if (isset($result['encrypted_token'])){
$encrypted_token = $result['encrypted_token'];
}
}
}

Expand Down Expand Up @@ -294,6 +300,10 @@ public function custom_authenticate( $user, $username, $password ) {
$user = $result;
}

if ($encrypted_token != ''){
update_user_meta( $user->ID, 'encrypted_token', $encrypted_token );
}

// If we haven't exited yet, we have a valid/approved user, so authenticate them.
return $user;
}
Expand All @@ -309,6 +319,9 @@ public function custom_authenticate( $user, $username, $password ) {
* or null if not attempting an oauth2 login.
*/
protected function custom_authenticate_oauth2( $auth_settings ) {
$encrypted_token = ''; //Maybe the access token from oauth2 service, encrypted


// Move on if oauth2 hasn't been requested here.
// phpcs:ignore WordPress.Security.NonceVerification
if ( empty( $_GET['external'] ) || 'oauth2' !== $_GET['external'] ) {
Expand Down Expand Up @@ -563,6 +576,14 @@ function ( $entry ) {
$token = $provider->getAccessToken( 'authorization_code', array(
'code' => $_REQUEST['code'],
) );

$token_json_prepared = $token->jsonSerialize();
$token_json = json_encode($token_json_prepared);

$save_secure = new Save_Secure;
$encrypted_token = $save_secure->encrypt($token_json);


} catch ( \Exception $e ) {
// Failed to get token; try again from the beginning.
$auth_url = $provider->getAuthorizationUrl(
Expand Down Expand Up @@ -663,6 +684,7 @@ function ( $entry ) {
'authenticated_by' => 'oauth2',
'oauth2_provider' => $auth_settings['oauth2_provider'],
'oauth2_attributes' => $attributes,
'encrypted_token' => $encrypted_token,
);
}

Expand Down Expand Up @@ -1397,6 +1419,11 @@ public function pre_logout() {
if ( empty( self::$authenticated_by ) && ! empty( $_REQUEST['external'] ) ) {
self::$authenticated_by = $_REQUEST['external'];
}

$user_id = get_current_user_id();
//Delete token from usermeta
delete_user_meta( $user_id, 'encrypted_token');

}

/**
Expand Down
99 changes: 99 additions & 0 deletions src/authorizer/class-save-secure.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

namespace Authorizer;

/**
* This is an edited copied excerpt from the Wordpress Plugin “Google-Site-Kit” (https://wordpress.org/plugins/google-site-kit/). Used according to the explanation at https://felix-arntz.me/blog/storing-confidential-data-in-wordpress/.
* Edited by christianmaidhof
* No guarantee!!
*/


/**
* Helper class to store encrypted data in WordPress database.
*/

class Save_Secure
{

private $key;
private $salt;

public function __construct()
{
$this->key = $this->get_default_key();
$this->salt = $this->get_default_salt();
}

// encrypt and decrypt methods omitted for readability.

private function get_default_key()
{

if (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) {
return LOGGED_IN_KEY;
}

// If this is reached, you're either not on a live site or have a serious security issue.
return 'no-secret-key';
}

private function get_default_salt()
{

if (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) {
return LOGGED_IN_SALT;
}

// If this is reached, you're either not on a live site or have a serious security issue.
return 'no-secret-salt';
}


/**
* Encypts a value for storing in database
*/
public function encrypt($value)
{
if (!extension_loaded('openssl')) {
return $value;
}

$method = 'aes-256-ctr';
$ivlen = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($ivlen);

$raw_value = openssl_encrypt($value . $this->salt, $method, $this->key, 0, $iv);
if (!$raw_value) {
return false;
}

return base64_encode($iv . $raw_value);
}


/**
* Decrypts a value
*/
public function decrypt($raw_value)
{
if (!extension_loaded('openssl')) {
return $raw_value;
}

$raw_value = base64_decode($raw_value, true);

$method = 'aes-256-ctr';
$ivlen = openssl_cipher_iv_length($method);
$iv = substr($raw_value, 0, $ivlen);

$raw_value = substr($raw_value, $ivlen);

$value = openssl_decrypt($raw_value, $method, $this->key, 0, $iv);
if (!$value || substr($value, -strlen($this->salt)) !== $this->salt) {
return false;
}

return substr($value, 0, -strlen($this->salt));
}
}