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

Remove Remote Endpoint Code and Refactor Code #255

Merged
merged 21 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
61cf0c0
Remove remote endpoint support
dshanske Nov 4, 2023
50285d5
Serve the IndieAuth metadata header at the issuer URL
dshanske Nov 5, 2023
8ca588f
Have each endpoint handle its metadata
dshanske Nov 6, 2023
aab0d02
Make all endpoints children of the endpoint class
dshanske Nov 6, 2023
cf7aa1a
Remove local authorize and move around functions to reflect what they…
dshanske Nov 7, 2023
ab1550f
Add filters to allow for custom actions and grant types for the token…
dshanske Nov 11, 2023
ad4a5cb
Move header adding to the endpoint that needs the header
dshanske Nov 11, 2023
049985f
Standardize function for generating endpoint
dshanske Nov 11, 2023
b194644
Further standardize how headers are generated in endpoints
dshanske Nov 11, 2023
88a978b
Allow each endpoint to register its rest index entry
dshanske Nov 11, 2023
ed51231
ticket grant type is not supported yet
dshanske Nov 11, 2023
2457795
Expand serving of metadata header to all endpoints under the indieaut…
dshanske Nov 11, 2023
ad57c91
Have metadata global functions call class functions
dshanske Nov 11, 2023
c477f4e
Move function only used by token endpoint out of global scope.
dshanske Nov 11, 2023
9925680
PHPCS Fixes
dshanske Nov 11, 2023
eb7eb83
Forgot to load the combined class
dshanske Nov 11, 2023
8818b76
Fix reference to old class
dshanske Nov 11, 2023
2552ca9
Additional references
dshanske Nov 11, 2023
e160793
Remove extra line break
dshanske Nov 11, 2023
7a7aef5
Remove load that is no longer needed.
dshanske Nov 12, 2023
9685791
Merge branch 'trunk' into removeremote
dshanske Dec 1, 2023
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
54 changes: 54 additions & 0 deletions includes/class-indieauth-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,65 @@ public function settings() {
'show_in_rest' => true,
)
);
register_setting(
'indieauth',
'indieauth_expires_in',
array(
'type' => 'number',
'description' => __( 'IndieAuth Default Expiry Time', 'indieauth' ),
'show_in_rest' => true,
'default' => 1209600, // Two Weeks.
)
);
}


public function admin_init() {
add_settings_field( 'indieauth_general_settings', __( 'IndieAuth Settings', 'indieauth' ), array( $this, 'general_settings' ), 'general', 'default' );

add_settings_section(
'indieauth',
'IndieAuth Endpoint Settings',
array( $this, 'endpoint_settings' ),
'indieauth'
);
add_settings_field(
'indieauth_expires_in',
__( 'Default Token Expiration Time', 'indieauth' ),
array( $this, 'numeric_field' ),
'indieauth',
'indieauth',
array(
'label_for' => 'indieauth_expires_in',
'class' => 'widefat',
'description' => __( 'Set the Number of Seconds until a Token expires (Default is Two Weeks). 0 to Disable Expiration.', 'indieauth' ),
'default' => '',
'min' => 0,
)
);
}

public static function endpoint_settings() {
esc_html_e( 'These settings control the behavior of the endpoints', 'indieauth' );
}


public static function numeric_field( $args ) {
$props = array();
if ( array_key_exists( 'min', $args ) && is_numeric( $args['min'] ) ) {
$props[] = 'min=' . $args['min'];
}
if ( array_key_exists( 'max', $args ) && is_numeric( $args['max'] ) ) {
$props[] = 'max=' . $args['max'];
}
if ( array_key_exists( 'step', $args ) && is_numeric( $args['step'] ) ) {
$props[] = 'step=' . $args['step'];
}
$props = implode( ' ', $props );
printf( '<label for="%1$s"><input id="%1$s" name="%1$s" type="number" value="%2$s" %3$s />', esc_attr( $args['label_for'] ), esc_attr( get_option( $args['label_for'], $args['default'] ) ), esc_html( $props ) );
if ( array_key_exists( 'description', $args ) && ! empty( $args['description'] ) ) {
printf( '<p>%1$s</p>', esc_html( $args['description'] ) );
}
}

/**
Expand Down
66 changes: 56 additions & 10 deletions includes/class-indieauth-authorization-endpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,61 @@
* Implements IndieAuth Authorization Endpoint
*/

class IndieAuth_Authorization_Endpoint {
private $tokens;
class IndieAuth_Authorization_Endpoint extends IndieAuth_Endpoint {
private $codes;

public function __construct() {
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
add_action( 'login_form_indieauth', array( $this, 'login_form_indieauth' ) );
$this->tokens = new Token_User( '_indieauth_code_' );
add_filter( 'indieauth_metadata', array( $this, 'metadata' ) );
add_filter( 'rest_index_indieauth_endpoints', array( $this, 'rest_index' ) );

add_action( 'wp_head', array( $this, 'html_header' ) );
add_action( 'template_redirect', array( $this, 'http_header' ) );

$this->codes = new Token_User( '_indieauth_code_' );
}

public function http_header() {
if ( is_author() || is_front_page() ) {
$this->set_http_header( $this->get_endpoint(), 'authorization_endpoint' );
}
}

public function html_header() {
$kses = array(
'link' => array(
'href' => array(),
'rel' => array(),
),
);

if ( is_author() || is_front_page() ) {
echo wp_kses( $this->get_html_header( $this->get_endpoint(), 'authorization_endpoint' ), $kses );
}
}

public static function get_endpoint() {
return rest_url( '/indieauth/1.0/auth' );
}

public static function get_response_types() {
return array_unique( apply_filters( 'indieauth_response_types_supported', array( 'code' ) ) );
}

public function rest_index( $index ) {
$index['authorization'] = $this->get_endpoint();
return $index;
}

public function metadata( $metadata ) {
$metadata['authorization_endpoint'] = $this->get_endpoint();
$metadata['response_types_supported'] = $this->get_response_types();
$metadata['authorization_response_iss_parameter_supported'] = true;
return $metadata;
}


/**
* Register the Route.
*/
Expand Down Expand Up @@ -272,19 +318,19 @@ public function code( $params ) {
return new WP_REST_Response( array( 'url' => $url ), 302, array( 'Location' => $url ) );
}

public function set_code( $user_id, $token ) {
$this->tokens->set_user( $user_id );
return $this->tokens->set( $token, 600 );
public function set_code( $user_id, $code ) {
$this->codes->set_user( $user_id );
return $this->codes->set( $code, 600 );
}

public function get_code( $code, $hash = true ) {
$token = $this->tokens->get( $code, $hash );
return $token;
$code = $this->codes->get( $code, $hash );
return $code;
}

public function delete_code( $code, $user_id = null ) {
$this->tokens->set_user( $user_id );
return $this->tokens->destroy( $code );
$this->codes->set_user( $user_id );
return $this->codes->destroy( $code );
}

/*
Expand Down
130 changes: 61 additions & 69 deletions includes/class-indieauth-authorize.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
<?php
/**
* Authorize base class
* Helper functions for extracting tokens from the WP-API team Oauth2 plugin
* Authorize class
*/
abstract class IndieAuth_Authorize {
class IndieAuth_Authorize {

public $error = null;
public $scopes = array();
public $response = array();


public function __construct( $load = true ) {
// Load the hooks for this class only if true. This allows for debugging of the functions
if ( true === $load ) {
$this->load();
}
}

public function load() {
// do not call in CLI environment
if ( defined( 'WP_CLI' ) ) {
Expand All @@ -20,9 +27,6 @@ public function load() {
add_filter( 'determine_current_user', array( $this, 'determine_current_user' ), 15 );
add_filter( 'rest_authentication_errors', array( $this, 'rest_authentication_errors' ) );

add_action( 'template_redirect', array( $this, 'http_header' ) );
add_action( 'wp_head', array( $this, 'html_header' ) );

add_filter( 'indieauth_scopes', array( $this, 'get_indieauth_scopes' ), 9 );
add_filter( 'indieauth_response', array( $this, 'get_indieauth_response' ), 9 );
add_filter( 'wp_rest_server_class', array( $this, 'wp_rest_server_class' ) );
Expand All @@ -44,22 +48,6 @@ public static function return_oauth_error( $response, $handler, $request ) {
return $response;
}


/**
* Returns the URL for the authorization endpoint.
*
* @return string Authorization Endpoint.
**/
abstract public static function get_authorization_endpoint();

/**
* Returns the URL for the token endpoint.
*
* @return string Token Endpoint.
**/
abstract public static function get_token_endpoint();


/**
* Prevent caching of unauthenticated status. See comment below.
*
Expand Down Expand Up @@ -90,35 +78,6 @@ public function get_indieauth_response( $response ) {
return $response ? $response : $this->response;
}

public function http_header() {
$auth = static::get_authorization_endpoint();
$token = static::get_token_endpoint();
if ( empty( $auth ) || empty( $token ) ) {
return;
}
if ( is_author() || is_front_page() ) {
header( sprintf( 'Link: <%s>; rel="authorization_endpoint"', static::get_authorization_endpoint() ), false );
header( sprintf( 'Link: <%s>; rel="token_endpoint"', static::get_token_endpoint() ), false );
}
}
public static function html_header() {
$auth = static::get_authorization_endpoint();
$token = static::get_token_endpoint();
$kses = array(
'link' => array(
'href' => array(),
'rel' => array(),
),
);
if ( empty( $auth ) || empty( $token ) ) {
return;
}
if ( is_author() || is_front_page() ) {
echo wp_kses( sprintf( '<link rel="authorization_endpoint" href="%s" />' . PHP_EOL, $auth ), $kses );
echo wp_kses( sprintf( '<link rel="token_endpoint" href="%s" />' . PHP_EOL, $token ), $kses );
}
}

/**
* Report our errors, if we have any.
*
Expand Down Expand Up @@ -190,24 +149,6 @@ public function determine_current_user( $user_id ) {
return $user_id;
}

/**
* Verifies Access Token
*
* @param string $token The token to verify
*
* @return array|WP_OAuth_Response Return either the token information or an OAuth Error Object
**/
abstract public function verify_access_token( $token );

/**
* Verifies authorixation code.
*
* @param string $code Authorization Code
*
* @return array|WP_OAuth_Response Return either the code information or an OAuth Error object
**/
abstract public static function verify_authorization_code( $code );

/**
* Get the authorization header
*
Expand Down Expand Up @@ -289,4 +230,55 @@ public function get_token_from_request() {
}
return null;
}

/**
* Verifies Access Token
*
* @param string $token The token to verify
*
* @return array|WP_OAuth_Response Return either the token information or an OAuth Error Object
**/
public function verify_access_token( $token ) {
$tokens = new Token_User( '_indieauth_token_' );
$return = $tokens->get( $token );
if ( empty( $return ) ) {
return new WP_OAuth_Response(
'invalid_token',
__( 'Invalid access token', 'indieauth' ),
401
);
}
if ( is_oauth_error( $return ) ) {
return $return;
}
$return['last_accessed'] = time();
$return['last_ip'] = $_SERVER['REMOTE_ADDR'];
$tokens->update( $token, $return );
if ( array_key_exists( 'exp', $return ) ) {
$return['expires_in'] = $return['exp'] - time();
}
return $return;
}

/**
* Verifies authorixation code.
*
* @param string $code Authorization Code
*
* @return array|WP_OAuth_Response Return either the code information or an OAuth Error object
**/
public static function verify_authorization_code( $code ) {
$tokens = new Token_User( '_indieauth_code_' );
$return = $tokens->get( $code );
if ( empty( $return ) ) {
return new WP_OAuth_Response(
'invalid_code',
__( 'Invalid authorization code', 'indieauth' ),
401
);
}
// Once the code is verified destroy it
$tokens->destroy( $code );
return $return;
}
}
23 changes: 22 additions & 1 deletion includes/class-indieauth-endpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,35 @@
* Implements Endpoint Functionality
*/

class IndieAuth_Endpoint {
abstract class IndieAuth_Endpoint {
protected $tokens;
protected $refresh_tokens;
public function __construct() {
$this->tokens = new Token_User( '_indieauth_token_' );
$this->refresh_tokens = new Token_User( '_indieauth_refresh_' );
}

/*
* Outputs a marked up Http link header.
*
* @param string $url URL for the link
* @param string $rel Rel property for the link
* @param boolean $replace Passes the value of replace through to the header PHP
*/
public static function set_http_header( $url, $rel, $replace = false ) {
header( sprintf( 'Link: <%s>; rel="%s"', $url, $rel ), $replace );
}

/*
* Returns a marked up HTML link header.
*
* @param string $url URL for the link
* @param string $rel Rel property for the link
* @return string Marked up HTML link to add to head
*/
public static function get_html_header( $url, $rel ) {
return sprintf( '<link rel="%s" href="%s" />' . PHP_EOL, $rel, $url );
}

/**
* Extracts the token from the given authorization header.
Expand Down
21 changes: 21 additions & 0 deletions includes/class-indieauth-introspection-endpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ class IndieAuth_Introspection_Endpoint extends IndieAuth_Endpoint {
public function __construct() {
parent::__construct();
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
add_filter( 'indieauth_metadata', array( $this, 'metadata' ) );
add_filter( 'rest_index_indieauth_endpoints', array( $this, 'rest_index' ) );
}

public static function get_endpoint() {
return rest_url( '/indieauth/1.0/introspection' );
}

public function auth_methods_supported() {
return array_unique( apply_filters( 'indieauth_introspection_auth_methods_supported', array( 'none' ) ) );
}

public function metadata( $metadata ) {
$metadata['introspection_endpoint'] = $this->get_endpoint();
$metadata['introspection_auth_methods_supported'] = $this->auth_methods_supported();
return $metadata;
}

public function rest_index( $index ) {
$index['introspection'] = $this->get_endpoint();
return $index;
}

/**
Expand Down
Loading