diff --git a/.gitignore b/.gitignore index 7b3dea9..876025b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,7 @@ _book *.epub *.mobi *.pdf -.idea \ No newline at end of file +.idea +.vscode +vendor +composer.lock \ No newline at end of file diff --git a/inc/class-client.php b/inc/class-client.php index ddba759..31e588c 100644 --- a/inc/class-client.php +++ b/inc/class-client.php @@ -229,8 +229,8 @@ public function check_redirect_uri( $uri ) { * * @return Authorization_Code|WP_Error */ - public function generate_authorization_code( WP_User $user ) { - return Authorization_Code::create( $this, $user ); + public function generate_authorization_code( WP_User $user, $data ) { + return Authorization_Code::create( $this, $user, $data ); } /** diff --git a/inc/endpoints/class-token.php b/inc/endpoints/class-token.php index 6b24a82..54e28db 100644 --- a/inc/endpoints/class-token.php +++ b/inc/endpoints/class-token.php @@ -71,7 +71,7 @@ public function exchange_token( WP_REST_Request $request ) { return $auth_code; } - $is_valid = $auth_code->validate(); + $is_valid = $auth_code->validate( $request ); if ( is_wp_error( $is_valid ) ) { // Invalid request, but code itself exists, so we should delete // (and silently ignore errors). diff --git a/inc/tokens/class-authorization-code.php b/inc/tokens/class-authorization-code.php index e5f212e..d4e027f 100644 --- a/inc/tokens/class-authorization-code.php +++ b/inc/tokens/class-authorization-code.php @@ -108,6 +108,43 @@ public function get_expiration() { return (int) $value['expiration']; } + /** + * Validate whether the redirect_uri matches the one in the initial OAuth2 request + * + * @param String $redirect_uri + * @return Boolean|WP_Error + */ + protected function validate_redirect_uri( $redirect_uri ) { + $value = $this->get_value(); + + if ( ! empty( $value['redirect_uri'] ) && ! empty( $redirect_uri ) ) { + if ( $value['redirect_uri'] !== $redirect_uri ) { + return new WP_Error( + 'oauth2.tokens.authorization_code.redirect_uri.mismatch', + __( 'redirect_uri does not match the one in the initial request.', 'oauth2' ), + [ + 'status' => WP_Http::BAD_REQUEST, + ] + ); + } + } + + if ( ( empty( $value['redirect_uri'] ) && ! empty( $redirect_uri ) && ! $this->client->check_redirect_uri( $redirect_uri ) ) || + ( ! empty( $value['redirect_uri'] ) && empty( $redirect_uri ) ) ) { + return new WP_Error( + 'oauth2.tokens.authorization_code.redirect_uri.mismatch', + __( 'redirect_uri does not match the one in the initial request.', 'oauth2' ), + [ + 'status' => WP_Http::BAD_REQUEST, + 'expiration' => $expiration, + 'time' => $now, + ] + ); + } + + return true; + } + /** * Validate the code for use. * @@ -129,6 +166,11 @@ public function validate( $args = [] ) { ); } + $redirect_uri = $this->validate_redirect_uri( $args['redirect_uri'] ); + if ( is_wp_error( $redirect_uri ) ) { + return $redirect_uri; + } + return true; } @@ -183,12 +225,13 @@ public static function get_by_code( Client $client, $code ) { * * @return Authorization_Code|WP_Error Authorization code instance, or error on failure. */ - public static function create( Client $client, WP_User $user ) { + public static function create( Client $client, WP_User $user, $redirect_uri = '' ) { $code = wp_generate_password( static::KEY_LENGTH, false ); $meta_key = static::KEY_PREFIX . $code; $data = [ - 'user' => (int) $user->ID, - 'expiration' => time() + static::MAX_AGE, + 'user' => (int) $user->ID, + 'expiration' => time() + static::MAX_AGE, + 'redirect_uri' => $redirect_uri, ]; $result = add_post_meta( $client->get_post_id(), wp_slash( $meta_key ), wp_slash( $data ), true ); if ( ! $result ) { diff --git a/inc/types/class-authorization-code.php b/inc/types/class-authorization-code.php index cff7e86..446556c 100644 --- a/inc/types/class-authorization-code.php +++ b/inc/types/class-authorization-code.php @@ -33,7 +33,8 @@ protected function handle_authorization_submission( $submit, Client $client, $da case 'authorize': // Generate authorization code and redirect back. $user = wp_get_current_user(); - $code = $client->generate_authorization_code( $user ); + $code = $client->generate_authorization_code( $user, $redirect_uri ); + if ( is_wp_error( $code ) ) { return $code; } diff --git a/inc/types/class-base.php b/inc/types/class-base.php index cde81a1..2dc8bcb 100644 --- a/inc/types/class-base.php +++ b/inc/types/class-base.php @@ -52,9 +52,12 @@ public function handle_authorisation() { } // Validate the redirection URI. - $redirect_uri = $this->validate_redirect_uri( $client, $redirect_uri ); - if ( is_wp_error( $redirect_uri ) ) { - return $redirect_uri; + if ( ! empty( $redirect_uri ) ) { + $redirect_uri = $this->validate_redirect_uri( $client, $redirect_uri ); + + if ( is_wp_error( $redirect_uri ) ) { + return $redirect_uri; + } } // Valid parameters, ensure the user is logged in. @@ -69,8 +72,7 @@ public function handle_authorisation() { } // Check nonce. - $nonce_action = $this->get_nonce_action( $client ); - if ( ! wp_verify_nonce( wp_unslash( $_POST['_wpnonce'] ), $none_action ) ) { + if ( ! wp_verify_nonce( wp_unslash( $_POST['_wpnonce'] ), $this->get_nonce_action( $client ) ) ) { return new WP_Error( 'oauth2.types.authorization_code.handle_authorisation.invalid_nonce', __( 'Invalid nonce.', 'oauth2' ) @@ -105,24 +107,11 @@ public function handle_authorisation() { * @return string|WP_Error Valid redirect URI on success, error otherwise. */ protected function validate_redirect_uri( Client $client, $redirect_uri = null ) { - if ( empty( $redirect_uri ) ) { - $registered = $client->get_redirect_uris(); - if ( count( $registered ) !== 1 ) { - // Either none registered, or more than one, so error. - return new WP_Error( - 'oauth2.types.authorization_code.handle_authorisation.missing_redirect_uri', - __( 'Redirect URI was required, but not found.', 'oauth2' ) - ); - } - - $redirect_uri = $registered[0]; - } else { - if ( ! $client->check_redirect_uri( $redirect_uri ) ) { - return new WP_Error( - 'oauth2.types.authorization_code.handle_authorisation.invalid_redirect_uri', - __( 'Specified redirect URI is not valid for this client.', 'oauth2' ) - ); - } + if ( ! $client->check_redirect_uri( $redirect_uri ) ) { + return new WP_Error( + 'oauth2.types.authorization_code.handle_authorisation.invalid_redirect_uri', + __( 'Specified redirect URI is not valid for this client.', 'oauth2' ) + ); } return $redirect_uri;