-
Notifications
You must be signed in to change notification settings - Fork 92
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
Fix Implicit login handling #426
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, presume still going through your extensive manual testing?
@cocojoe - as usual 😄 working on a Docker setup now to make life a little easier. |
WP_Auth0.php
Outdated
} | ||
|
||
public function render_form( $html ) { | ||
if ( isset( $_GET['action'] ) && $_GET['action'] == 'lostpassword' ) { | ||
if ( ( isset( $_GET['action'] ) && $_GET['action'] == 'lostpassword' ) || ! empty( $_GET[ 'auth0' ] ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does this change represent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the auth0
URL param is set, don't load the form. It's only sent when coming back from an implicit grant. Auth code grant goes straight to index.php?auth0=1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I load the form, I get a new state
set so I don't want to do that ... also, no need to load the form at all since we're just passing through.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, I remember the auth0
param now. Are you planning to refactor this "auth0 hack" anytime soon?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The param can show up on the login page and on the index.php
entry point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not loading the form in this case does solve the problem of re-setting a state cookie but we don't need to load the login form at all if this is a response from Auth0. So, I would say that the URL parameter check will stay but state checking will evolve to handle this better (by abstracting that WP_Auth0_Nonce_Handler
class to handle both scenarios)
assets/js/implicit-login.js
Outdated
@@ -0,0 +1,35 @@ | |||
document.addEventListener( 'DOMContentLoaded', function() { | |||
if ( ! window.location.hash || window.location.hash.indexOf('id_token') < 0 ) { | |||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the token is missing you return. Does that mean that you are ignoring a possible auth error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question and I don't know if I have a good answer. The core login page processing does not use anchors at all and I don't want this to run unless I have something to do here. I'm not sure of another situation where we would have a hash and want to do something with it. I don't see anything else in the implicit grant doc.
Is there an error message that I might get back? error
or error_description
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. You might receive error
and error_description
in the hash/query params. There are a few knowns errors, I'll share privately a reference.
assets/js/implicit-login.js
Outdated
return; | ||
} | ||
|
||
var hash = window.location.hash; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know how much resources you are saving, but this line could be the first one and hash
used on the if
assets/js/implicit-login.js
Outdated
} | ||
|
||
var hash = window.location.hash; | ||
if (hash[0] === '#') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will this work fine if hash=""
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it can't be empty because we've escaped already if that's the case
if ( ! empty( $state_decoded->interim ) ) { | ||
include WPA0_PLUGIN_DIR . 'templates/login-interim.php'; | ||
} else { | ||
$redirect_to = ! empty( $state_decoded->redirect_to ) ? $state_decoded->redirect_to : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this the same, or you need an explicit null
later?
$redirect_to = $state_decoded->redirect_to
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$state_decoded->redirect_to
will throw an error if it does not exist, so I'm checking whether it's there or not with empty()
lib/WP_Auth0_LoginManager.php
Outdated
@@ -551,7 +561,7 @@ protected function get_state( $decoded = FALSE ) { | |||
|
|||
if ( empty( $this->state ) ) { | |||
// Get and store base64 encoded state | |||
$state_val = $this->query_vars( 'state' ); | |||
$state_val = $_REQUEST[ 'state' ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why, did the previous stop working?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$this->query_vars()
is not explicit enough, makes for confusion around how these vars are handled. I want state
from either POST or GET (aka $_REQUEST
), I don't want anything else.
public function generateNonce() { | ||
return function_exists( 'random_bytes' ) ? bin2hex( random_bytes( 32 ) ) : md5( uniqid( rand(), true ) ); | ||
public function generateNonce( $bytes = 32 ) { | ||
$nonce_bytes = function_exists( 'random_bytes' ) ? random_bytes( $bytes ) : openssl_random_pseudo_bytes( $bytes ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will openssl_random_pseudo_bytes
always exist?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This plugin is tagged PHP 5.3, which is when this function was introduced:
https://secure.php.net/manual/en/function.openssl-random-pseudo-bytes.php
b3443fe
to
a21333c
Compare
@@ -123,6 +123,10 @@ public function init() { | |||
|
|||
$this->check_signup_status(); | |||
|
|||
if ( $this->a0_options->get( 'auto_login' ) ) { | |||
WP_Auth0_Nonce_Handler::getInstance()->setCookie(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this well indented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like, correct whitespace? Yes. This project mixes tabs and spaces, as well as how many spaces for each. I'll do an automated whitespace cleanup before I start the next release.
92253c9
to
7561602
Compare
form.appendChild( createHiddenField( 'token', data.id_token ) ); | ||
form.appendChild( createHiddenField( 'state', data.state ) ); | ||
} else { | ||
redirectWithoutQuery(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a valid path? When will it happen? Do you have an example? If you don't have one but still want to catch it, would be nice to log that query somewhere to debug and understand it I guess. If the authentication was initiated for "implicit flow" and the token is not there, there must be an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's valid as in it exists but without a hash we don't have much to do. The param triggers this JS to load and for the form to be excluded (param tells us that we need to process something from Auth0). If we don't have the information we need, then we need to cease processing, hence the redirect.
If we have the Auth0 param but no error
or no state
, that could be an intermittent problem, in which case showing the login form to try again seems reasonable. I'm not sure I want to catch and log every possible outcome here, I think it's best to get someone back to a place where they can try again.
@@ -150,9 +150,10 @@ public function init_auth0() { | |||
|
|||
// Catch any incoming errors and stop the login process | |||
// See https://auth0.com/docs/libraries/error-messages | |||
if ( $this->query_vars( 'error_description' ) ) { | |||
if ( $this->query_vars( 'error' ) || $this->query_vars( 'error_description' ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the error_description
might be missing sometimes (AFAIK is optional). In any case, because error
is always present that condition should suffice.
Move the JS that POSTs auth data back to the WP site to it's own file. Better enqueuing for login JS and CSS.
7561602
to
971021a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aaaand done!
openssl_random_pseudo_bytes()
)