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

New Authentication Middleware using Wordpress #982

Closed
nkappler opened this issue Jul 26, 2023 · 11 comments
Closed

New Authentication Middleware using Wordpress #982

nkappler opened this issue Jul 26, 2023 · 11 comments
Assignees

Comments

@nkappler
Copy link
Contributor

nkappler commented Jul 26, 2023

Hi @mevdschee,

I'm currently trying to marry your api to the wordpress user session.
Unfortunately it is not as easy as pointing the api to the 'users' table, because WP uses neither the standard $_SESSION variable, nor standard password encryption (it uses some custom salt and appends an ID or something...)

So far I was able to write a custom script which checks if a wordpress session is available and which can verify a password from the database:

<?php
// Load the WordPress environment
define('WP_USE_THEMES', false);
require('path_to_wordpress_installation/wp-load.php'); // <- the base path needs to be configurable

// Function to check user's password
function verify_user_password($email, $plain_text_password)
{
    // Check if the user is logged in
    if (is_user_logged_in()) {
        // User is logged in, retrieve user ID and email
        $user = wp_get_current_user();
    
        // Do something useful here
        echo "User ID: $user->ID<br>";
        echo "User Email: $user->user_email<br>";
        echo "User Display Name: " . $user->display_name . "<br>";
        return;
    }

    // Retrieve the user data based on the provided email
    $user_data = get_user_by('email', $email);

    if (!$user_data) {
        echo "User not found with the provided email.";
        exit;
    }

    if (wp_check_password($plain_text_password, $user_data->user_pass)) {
        // do something useful here instead of echo...

        // Password is correct, display all user data
        echo "User ID: " . $user_data->ID . "<br>";
        echo "User Display Name: " . $user_data->display_name . "<br>";
        echo "User Email: " . $user_data->user_email . "<br>";
        // Add more fields as needed
    } else {
        echo "Password is incorrect.";
    }
}

// just for testing:
// Get user email and unhashed password from GET parameters
$email = isset($_GET['email']) ? $_GET['email'] : '';
$plain_text_password = isset($_GET['password']) ? $_GET['password'] : '';
verify_user_password($email, $plain_text_password);

I'd like to write a middleware similar to DBAuth and I would be happy to file a PR but I am not very good at php and I don't know where to start.

Any help is appreciated 🙂

@pottertech
Copy link

pottertech commented Jul 26, 2023

Once you load the required require('path_to_wordpress_installation/wp-load.php'); file, you should only have to add a global $current_user; line.

Then you can use the $current_user->ID to do a curl out to the API, something like this:

//Get User Info

$url = "http://IP_or_URL/CRUDAPI.php/records/users?filter=id,eq," . $current_user->ID;

$ch = curl_init($url);

curl_setopt($ch, CURLOPT_URL,$url);

curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);

$json = curl_exec($ch);

$user = json_decode($json, true);

@nkappler
Copy link
Contributor Author

@pottertech thanks for your reply, but I'm not trying to fetch a user from php-crud-api with the same ID as the wordpress user,
I wan't to use wordpress as an authentication/identity provider for the API.

I've got it partially working by modifying the DBAuth middleware, but I want to write a proper middleware for it, which I might be able to do by myself, but it's going to take some more time 😆

@mevdschee mevdschee self-assigned this Jul 29, 2023
@pottertech
Copy link

Good idea you have. I provided my code in hopes that it helps someone a little. Now that @mevdschee has tagged it as an enhancement, I am sure between it will get done and function well.

@nkappler
Copy link
Contributor Author

nkappler commented Aug 1, 2023

Now that @mevdschee has tagged it as an enhancement, I am sure between it will get done and function well.

Yep, I'm almost flabbergasted that it isn't done already 🤪

Jokes aside, @mevdschee do you expect me to prepare a PR? I don't have any estimate for how long it would take and I don't have a proper php dev setup.
I'd prefer to do a code review instead, if you have the capacity to develop it yourself...

@mevdschee
Copy link
Owner

Yep, I'm almost flabbergasted that it isn't done already zany_face

Ok.. I'll start now.. time me.. ;-)

@mevdschee
Copy link
Owner

mevdschee commented Aug 2, 2023

Stop the timer (<30 min)! The lines with bad indentation are added to make it work:

// file: src/index.php
namespace Tqdev\PhpCrudApi {

    use Tqdev\PhpCrudApi\Api;
    use Tqdev\PhpCrudApi\Config\Config;
    use Tqdev\PhpCrudApi\RequestFactory;
    use Tqdev\PhpCrudApi\ResponseUtils;

define( 'WP_USE_THEMES', false ); // Don't load theme support functionality
require( './wp-load.php' );

    $config = new Config([
        // 'driver' => 'mysql',
        // 'address' => 'localhost',
        // 'port' => '3306',
        'username' => 'php-crud-api',
        'password' => 'php-crud-api',
        'database' => 'php-crud-api',
'middlewares' => 'authorization',
'authorization.tableHandler' => function ($operation, $tableName) {
    return wp_get_current_user()->ID?true:false;
},
        // 'debug' => false
    ]);
    $request = RequestFactory::fromGlobals();
    $api = new Api($config);
    $response = $api->handle($request);
    ResponseUtils::output($response);

    //file_put_contents('request.log',RequestUtils::toString($request)."===\n",FILE_APPEND);
    //file_put_contents('request.log',ResponseUtils::toString($response)."===\n",FILE_APPEND);
}

We could put this into a middleware of some kind.

@nkappler I think Wordpress should verify the password, not our middleware. We only need to read the (session) cookie.

@pottertech I feel your approach should be implemented as a WordPress plugin, which would be nice-to-have.

mevdschee added a commit that referenced this issue Aug 2, 2023
@mevdschee
Copy link
Owner

mevdschee commented Aug 2, 2023

Okay.. @nkappler and @pottertech

WpAuthMiddleware is added to the main branch..

It supports:

  • /login
  • /logout
  • /me

It doesn't support:

  • /register
  • /password

Enable it as 'wpAuth' middleware, with config parameters:

  • wpAuth.wpDirectory
  • wpAuth.usernameFormField
  • wpAuth.passwordFormField
  • wpAuth.mode

In the authorization middleware you can use functions:

  • wp_get_current_user()
  • is_user_logged_in()
  • is_super_admin()
  • user_can(wp_get_current_user(),'edit_posts');

Play with it and let me know how you like it.. :-)

@nkappler
Copy link
Contributor Author

nkappler commented Aug 2, 2023

Works like a charm, thank you ❤️

Stop the timer (<30 min)!

Clues condense that you are, in fact, a robot 😀

One final remark:
Currently the returned object upon login contains the "user_pass" hash:
grafik

And the /me route returns it too...

I've made a few suggestions here: 8a424fe

@mevdschee
Copy link
Owner

mevdschee commented Aug 3, 2023

@nkappler Thank you for your review and your kind words. I'll merge your suggestions and release a new version with updated README. I do need one or two days as I'm a bit busy with some other things.

@nkappler
Copy link
Contributor Author

nkappler commented Aug 3, 2023

Take your time and thanks a lot.
I'll leave this issue open in case you want to link it with the next commit, but feel free to close it any time 🙂

mevdschee added a commit that referenced this issue Aug 3, 2023
@mevdschee
Copy link
Owner

mevdschee commented Aug 3, 2023

Released in v2.14.23

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants