diff --git a/src/Http/Handlers/AuthenticateHandler.php b/src/Http/Handlers/AuthenticateHandler.php index 0208bf3..44460fd 100644 --- a/src/Http/Handlers/AuthenticateHandler.php +++ b/src/Http/Handlers/AuthenticateHandler.php @@ -12,11 +12,27 @@ class AuthenticateHandler extends RequestHandler { private ConsentStorage $consent_storage; private array $clients; + /** + * Constructor for the ConsentManager class + * + * @param ConsentStorage $consent_storage The ConsentStorage object + * @param array $clients An array of clients + */ + public function __construct( ConsentStorage $consent_storage, array $clients ) { $this->consent_storage = $consent_storage; $this->clients = $clients; } + /** + * Handle the request for consent. + * + * @param Request $request The request object. + * @param Response $response The response object. + * + * @return Response The response object. + */ + public function handle( Request $request, Response $response ): Response { if ( ! is_user_logged_in() ) { auth_redirect(); @@ -59,6 +75,12 @@ public function handle( Request $request, Response $response ): Response { return $response; } + /** + * Render the no permission screen. + * + * @param array $data The data to be used to render the screen. + */ + private function render_no_permission_screen( $data ) { ?>
@@ -91,6 +113,12 @@ private function render_no_permission_screen( $data ) {
@@ -142,6 +170,12 @@ private function render_consent_screen( $data ) { server = $server; $this->consent_storage = $consent_storage; } + /** + * Handle an OIDC Authorize request. + * This function will check if the request is valid and if the user is logged in. If the user is not logged in, the + * user will be redirected to the login page. If the user is logged in, the request will be handled and the + * response will be returned. + * + * @param Request $request The request object. + * @param Response $response The response object. + * + * @return Response The response object. + */ + public function handle( Request $request, Response $response ): Response { // Our dependency bshaffer's OAuth library currently has a bug where it doesn't pick up nonce correctly if it's a POST request to the Authorize endpoint. // Fix has been contributed upstream (https://github.com/bshaffer/oauth2-server-php/pull/1032) but it doesn't look it would be merged anytime soon based on recent activity. diff --git a/src/Http/Handlers/ConfigurationHandler.php b/src/Http/Handlers/ConfigurationHandler.php index 2ea96ec..80a2793 100644 --- a/src/Http/Handlers/ConfigurationHandler.php +++ b/src/Http/Handlers/ConfigurationHandler.php @@ -8,6 +8,14 @@ use OpenIDConnectServer\Http\Router; class ConfigurationHandler extends RequestHandler { + /** + * Handle a Request and Response object + * + * @param Request $request The Request object + * @param Response $response The Response object + * + * @return Response The modified Response object + */ public function handle( Request $request, Response $response ): Response { $response->addHttpHeaders( array( @@ -21,6 +29,12 @@ public function handle( Request $request, Response $response ): Response { return $response; } + /** + * Configuration function to set up the OAuth2 server. + * + * @return array An array of configuration settings. + */ + private function configuration(): array { return array( 'issuer' => Router::make_url(), diff --git a/src/Http/Handlers/TokenHandler.php b/src/Http/Handlers/TokenHandler.php index 49aebd4..425aa7c 100644 --- a/src/Http/Handlers/TokenHandler.php +++ b/src/Http/Handlers/TokenHandler.php @@ -10,10 +10,25 @@ class TokenHandler extends RequestHandler { private OAuth2Server $server; + /** + * Constructor + * + * @param OAuth2Server $server The OAuth2 server instance + */ + public function __construct( OAuth2Server $server ) { $this->server = $server; } + /** + * Handles a request and returns a response. + * + * @param Request $request The request to handle + * @param Response $response The response to return + * + * @return Response The response + */ + public function handle( Request $request, Response $response ): Response { return $this->server->handleTokenRequest( $request ); } diff --git a/src/Http/Handlers/UserInfoHandler.php b/src/Http/Handlers/UserInfoHandler.php index 5e58bb6..670ac8c 100644 --- a/src/Http/Handlers/UserInfoHandler.php +++ b/src/Http/Handlers/UserInfoHandler.php @@ -10,10 +10,25 @@ class UserInfoHandler extends RequestHandler { private OAuth2Server $server; + /** + * Constructor + * + * @param OAuth2Server $server The OAuth2 server object + */ + public function __construct( OAuth2Server $server ) { $this->server = $server; } + /** + * Handles a Request and returns a Response + * + * @param Request $request The Request object + * @param Response $response The Response object + * + * @return Response The Response object + */ + public function handle( Request $request, Response $response ): Response { return $this->server->handleUserInfoRequest( $request ); } diff --git a/src/Http/Handlers/WebKeySetsHandler.php b/src/Http/Handlers/WebKeySetsHandler.php index cbadadf..dca171c 100644 --- a/src/Http/Handlers/WebKeySetsHandler.php +++ b/src/Http/Handlers/WebKeySetsHandler.php @@ -9,10 +9,25 @@ class WebKeySetsHandler extends RequestHandler { private string $public_key; + /** + * Constructor for the class + * + * @param string $public_key The public key to be used + */ + public function __construct( string $public_key ) { $this->public_key = $public_key; } + /** + * Handle the Request and Response objects + * + * @param Request $request The Request object + * @param Response $response The Response object + * + * @return Response The modified Response object + */ + public function handle( Request $request, Response $response ): Response { $response->addHttpHeaders( array( @@ -26,6 +41,12 @@ public function handle( Request $request, Response $response ): Response { return $response; } + /** + * Retrieve the key information + * + * @return array An array containing the key information (kty, use, alg, n, e) + */ + private function key_info(): array { $key = openssl_pkey_get_details( openssl_pkey_get_public( $this->public_key ) ); diff --git a/src/Http/Router.php b/src/Http/Router.php index 95f967b..413b93c 100644 --- a/src/Http/Router.php +++ b/src/Http/Router.php @@ -12,18 +12,49 @@ class Router { private array $rest_routes = array(); + /** + * Creates a URL from a given route. + * + * @param string $route The route to create the URL from. + * + * @return string The URL created from the given route. + */ + public static function make_url( string $route = '' ): string { return home_url( "/$route" ); } + /** + * Constructs a REST URL for the given route. + * + * @param string $route The route to construct the URL for. + * + * @return string The constructed REST URL. + */ + public static function make_rest_url( string $route ): string { return rest_url( self::PREFIX . "/$route" ); } + /** + * Constructor + * + * @return void + * @since 1.0.0 + * @access public + */ + public function __construct() { add_action( 'template_redirect', array( $this, 'handle_request' ) ); } + /** + * Add a route to the router + * + * @param string $route The route to add + * @param RequestHandler $handler The request handler for the route + */ + public function add_route( string $route, RequestHandler $handler ) { if ( isset( $this->rest_routes[ $route ] ) ) { return; @@ -32,6 +63,14 @@ public function add_route( string $route, RequestHandler $handler ) { $this->routes[ $route ] = $handler; } + /** + * Add a new REST route + * + * @param string $route The route to add + * @param RequestHandler $handler The handler for the route + * @param array $methods The HTTP methods to allow for the route (defaults to GET) + */ + public function add_rest_route( string $route, RequestHandler $handler, array $methods = array( 'GET' ), array $args = array() ) { $route_with_prefix = self::PREFIX . "/$route"; if ( isset( $this->rest_routes[ $route_with_prefix ] ) ) { @@ -57,6 +96,12 @@ function () use ( $route, $methods, $args ) { ); } + /** + * Get the current route of the request + * + * @return string The current route of the request + */ + private function get_current_route(): string { $wp_url = get_site_url(); $installed_dir = wp_parse_url( $wp_url, PHP_URL_PATH ); @@ -111,6 +156,14 @@ public function handle_rest_request( $wp_request ) { $this->do_handle_request( $handler ); } + /** + * Handles a request and sends a response + * + * @param RequestHandler $handler The request handler + * + * @return void + */ + private function do_handle_request( RequestHandler $handler ) { $request = Request::createFromGlobals(); $response = new Response(); diff --git a/src/OpenIDConnectServer.php b/src/OpenIDConnectServer.php index 76ed782..1ca27a8 100644 --- a/src/OpenIDConnectServer.php +++ b/src/OpenIDConnectServer.php @@ -25,6 +25,14 @@ class OpenIDConnectServer { private Router $router; private ConsentStorage $consent_storage; + /** + * Constructor for the class. + * + * @param string $public_key The public key. + * @param string $private_key The private key. + * @param array $clients An array of clients. + */ + public function __construct( string $public_key, string $private_key, array $clients ) { $this->public_key = $public_key; $this->clients = $clients; @@ -71,6 +79,13 @@ public function __construct( string $public_key, string $private_key, array $cli $this->setup_cron_hook(); } + /** + * Handles authentication requests + * + * @param Request $request The request object + * @param Response $response The response object + */ + public function authenticate_handler() { $request = Request::createFromGlobals(); $response = new Response(); @@ -80,6 +95,14 @@ public function authenticate_handler() { exit; } + /** + * Specifies the expected arguments for a given route. + * + * @param string $route The route to get the arguments for. + * + * @return array An array of arguments for the given route. + */ + private function expected_arguments_specification( $route ) { switch ( $route ) { case 'authorize': @@ -127,6 +150,12 @@ private function expected_arguments_specification( $route ) { } } + /** + * Sets up a cron hook to run weekly + * + * @return void + */ + public function setup_cron_hook() { if ( ! wp_next_scheduled( 'oidc_cron_hook' ) ) { wp_schedule_event( time(), 'weekly', 'oidc_cron_hook' ); @@ -135,7 +164,6 @@ public function setup_cron_hook() { /** * This function is invoked from uninstall.php - * * As of v1.0 we have two things that are being stored and should be removed on uninstall: * 1) Consent storage * 2) Auth code storage diff --git a/src/SiteStatusTests.php b/src/SiteStatusTests.php index 7770ec3..a8634f6 100644 --- a/src/SiteStatusTests.php +++ b/src/SiteStatusTests.php @@ -3,10 +3,24 @@ namespace OpenIDConnectServer; class SiteStatusTests { + /** + * Constructor for the class. + * + * @return void + * @since 1.0.0 + */ public function __construct() { add_filter( 'site_status_tests', array( $this, 'register_site_status_tests' ) ); } + /** + * Register site status tests for OpenID Connect + * + * @param array $tests An array of tests to be registered + * + * @return array An array of tests registered + */ + public function register_site_status_tests( $tests ): array { $tests['direct']['oidc-public-key'] = array( 'label' => __( 'The public key is defined and in the right format', 'wp-openid-connect-server' ), @@ -26,6 +40,12 @@ public function register_site_status_tests( $tests ): array { return $tests; } + /** + * Test the public key constant OIDC_PUBLIC_KEY. + * + * @return array An array containing the label, status, badge, description and test name. + */ + public function site_status_test_public_key(): array { if ( ! defined( 'OIDC_PUBLIC_KEY' ) ) { $label = __( 'The public key constant OIDC_PUBLIC_KEY is not defined.', 'wp-openid-connect-server' ); @@ -68,6 +88,13 @@ public function site_status_test_public_key(): array { ); } + /** + * This function checks if the OIDC_PRIVATE_KEY constant is defined and in the right format. + * + * @return array An array containing the label, status, badge, description and test of the OIDC_PRIVATE_KEY + * constant. + */ + public function site_status_test_private_key(): array { if ( ! defined( 'OIDC_PRIVATE_KEY' ) ) { $label = __( 'The private key constant OIDC_PRIVATE_KEY is not defined.', 'wp-openid-connect-server' ); @@ -110,6 +137,14 @@ public function site_status_test_private_key(): array { ); } + /** + * This function tests the status of the OpenID Connect Server clients. + * It checks if the clients have been defined, if the client id is a random string, if the redirect_uri is a HTTPS + * URL, and if the name is specified. + * + * @return array An array containing the label, status, badge, description, and test of the clients. + */ + public function site_status_test_clients(): array { $clients = apply_filters( 'oidc_registered_clients', array() ); if ( empty( $clients ) ) { diff --git a/src/Storage/AuthorizationCodeStorage.php b/src/Storage/AuthorizationCodeStorage.php index d8365e5..308b6f0 100644 --- a/src/Storage/AuthorizationCodeStorage.php +++ b/src/Storage/AuthorizationCodeStorage.php @@ -14,11 +14,23 @@ class AuthorizationCodeStorage implements AuthorizationCodeInterface { 'scope' => 'string', // scope as space-separated string. 'id_token' => 'string', // The OpenID Connect id_token. ); + /** + * Constructor for the class. + * Adds an action to the 'oidc_cron_hook' hook to call the 'cleanupOldCodes' method. + */ public function __construct() { add_action( 'oidc_cron_hook', array( $this, 'cleanupOldCodes' ) ); } + /** + * Retrieve the user ID associated with a given auth code. + * + * @param string $code The auth code to lookup. + * + * @return int|null The user ID associated with the auth code, or null if not found. + */ + private function getUserIdByCode( $code ) { if ( empty( $code ) ) { return null; @@ -45,6 +57,14 @@ private function getUserIdByCode( $code ) { return absint( $users[0]->ID ); } + /** + * Retrieve the authorization code for a given code. + * + * @param string $code The code to retrieve the authorization code for. + * + * @return array|null An array containing the authorization code data, or null if no code was found. + */ + public function getAuthorizationCode( $code ) { $user_id = $this->getUserIdByCode( $code ); if ( empty( $user_id ) ) { @@ -64,6 +84,18 @@ public function getAuthorizationCode( $code ) { return $authorization_code; } + /** + * Sets the authorization code for a user + * + * @param string $code The authorization code + * @param string $client_id The client ID + * @param string $user_id The user ID + * @param string $redirect_uri The redirect URI + * @param int $expires The expiration time + * @param string|null $scope The scope + * @param string|null $id_token The ID token + */ + public function setAuthorizationCode( $code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null ) { if ( empty( $code ) ) { return; @@ -84,6 +116,14 @@ public function setAuthorizationCode( $code, $client_id, $user_id, $redirect_uri } } + /** + * Expire an authorization code + * + * @param string $code The authorization code to expire + * + * @return null + */ + public function expireAuthorizationCode( $code ) { $user_id = $this->getUserIdByCode( $code ); if ( empty( $user_id ) ) { @@ -121,6 +161,11 @@ public function cleanupOldCodes() { } } + /** + * Uninstall function for the OIDC plugin. + * This function deletes all user meta data associated with the OIDC plugin. + */ + public static function uninstall() { global $wpdb; diff --git a/src/Storage/ClientCredentialsStorage.php b/src/Storage/ClientCredentialsStorage.php index b474545..7d3031d 100644 --- a/src/Storage/ClientCredentialsStorage.php +++ b/src/Storage/ClientCredentialsStorage.php @@ -7,10 +7,24 @@ class ClientCredentialsStorage implements ClientCredentialsInterface { private array $clients; + /** + * Constructor + * + * @param array $clients An array of clients + */ + public function __construct( array $clients ) { $this->clients = $clients; } + /** + * Get the details of a client. + * + * @param int $client_id The ID of the client. + * + * @return array|false An array of client details or false if the client does not exist. + */ + public function getClientDetails( $client_id ) { if ( ! $this->has( $client_id ) ) { return false; @@ -25,6 +39,14 @@ public function getClientDetails( $client_id ) { ); } + /** + * Retrieve the scope of a client. + * + * @param int $client_id The ID of the client to retrieve the scope of. + * + * @return string The scope of the client, or an empty string if the client does not exist or does not have a scope. + */ + public function getClientScope( $client_id ) { if ( ! $this->has( $client_id ) ) { return ''; @@ -39,6 +61,15 @@ public function getClientScope( $client_id ) { return $client['scope']; } + /** + * Checks if a given grant type is restricted for a given client + * + * @param string $client_id The ID of the client + * @param string $grant_type The grant type to check + * + * @return bool True if the grant type is restricted for the client, false otherwise + */ + public function checkRestrictedGrantType( $client_id, $grant_type ) { if ( ! $this->has( $client_id ) ) { return false; @@ -53,6 +84,15 @@ public function checkRestrictedGrantType( $client_id, $grant_type ) { return in_array( $grant_type, $client['grant_types'], true ); } + /** + * Checks the client credentials. + * + * @param string $client_id The client ID. + * @param string|null $client_secret The client secret (optional). + * + * @return bool True if the credentials are valid, false otherwise. + */ + public function checkClientCredentials( $client_id, $client_secret = null ) { if ( ! $this->has( $client_id ) ) { return false; @@ -67,6 +107,14 @@ public function checkClientCredentials( $client_id, $client_secret = null ) { return $client_secret === $client['secret']; } + /** + * Checks if the client is public or not. + * + * @param int $client_id The ID of the client to check. + * + * @return bool True if the client is public, false otherwise. + */ + public function isPublicClient( $client_id ) { if ( ! $this->has( $client_id ) ) { return false; @@ -77,6 +125,14 @@ public function isPublicClient( $client_id ) { return empty( $client['secret'] ); } + /** + * Retrieve a client by ID. + * + * @param int $client_id The ID of the client to retrieve. + * + * @return mixed|null The client object, or null if not found. + */ + private function get( $client_id ) { if ( ! $this->has( $client_id ) ) { return null; @@ -85,6 +141,14 @@ private function get( $client_id ) { return $this->clients[ $client_id ]; } + /** + * Checks if the given client ID exists in the clients array. + * + * @param int $client_id The ID of the client to check for. + * + * @return bool True if the client exists, false otherwise. + */ + private function has( $client_id ): bool { return isset( $this->clients[ $client_id ] ); } diff --git a/src/Storage/ConsentStorage.php b/src/Storage/ConsentStorage.php index 561b7e2..c95950b 100644 --- a/src/Storage/ConsentStorage.php +++ b/src/Storage/ConsentStorage.php @@ -7,10 +7,27 @@ class ConsentStorage { const META_KEY_PREFIX = 'oidc_consent_timestamp_'; + /** + * Get the meta key for a given client ID + * + * @param int $client_id The ID of the client + * + * @return string The meta key for the given client ID + */ + private function get_meta_key( $client_id ): string { return self::META_KEY_PREFIX . $client_id; } + /** + * Checks if a user needs to provide consent for a given client. + * + * @param int $user_id The ID of the user. + * @param int $client_id The ID of the client. + * + * @return bool True if the user needs to provide consent, false otherwise. + */ + public function needs_consent( $user_id, $client_id ): bool { $consent_timestamp = absint( get_user_meta( $user_id, $this->get_meta_key( $client_id ), true ) ); @@ -19,10 +36,23 @@ public function needs_consent( $user_id, $client_id ): bool { return empty( $consent_timestamp ) || $past_consent_expiry; } + /** + * Updates the timestamp for the given user and client. + * + * @param int $user_id The ID of the user to update the timestamp for. + * @param int $client_id The ID of the client to update the timestamp for. + */ + public function update_timestamp( $user_id, $client_id ) { update_user_meta( $user_id, $this->get_meta_key( $client_id ), time() ); } + /** + * Uninstall the plugin. + * + * @global wpdb $wpdb The WordPress Database Access Abstraction Object. + */ + public static function uninstall() { global $wpdb; diff --git a/src/Storage/PublicKeyStorage.php b/src/Storage/PublicKeyStorage.php index 06c3bef..4ad511a 100644 --- a/src/Storage/PublicKeyStorage.php +++ b/src/Storage/PublicKeyStorage.php @@ -8,19 +8,50 @@ class PublicKeyStorage implements PublicKeyInterface { private string $public_key; private string $private_key; + /** + * Constructor for the class + * + * @param string $public_key The public key + * @param string $private_key The private key + */ + public function __construct( string $public_key, string $private_key ) { $this->public_key = $public_key; $this->private_key = $private_key; } + /** + * Get the public key + * + * @param int|null $client_id The ID of the client + * + * @return string The public key + */ + public function getPublicKey( $client_id = null ) { return $this->public_key; } + /** + * Get the private key + * + * @param int|null $client_id The client id + * + * @return string The private key + */ + public function getPrivateKey( $client_id = null ) { return $this->private_key; } + /** + * Gets the encryption algorithm for the given client ID + * + * @param int $client_id The ID of the client + * + * @return string The encryption algorithm to use + */ + public function getEncryptionAlgorithm( $client_id = null ) { return 'RS256'; } diff --git a/src/Storage/UserClaimsStorage.php b/src/Storage/UserClaimsStorage.php index 4915ad7..1aa0715 100644 --- a/src/Storage/UserClaimsStorage.php +++ b/src/Storage/UserClaimsStorage.php @@ -7,6 +7,14 @@ use OAuth2\OpenID\Storage\UserClaimsInterface; class UserClaimsStorage implements UserClaimsInterface { + /** + * Get user claims for the given user ID and scope. + * + * @param string $user_id The user ID. + * @param string $scope The scope of the claims. + * + * @return array The user claims. + */ public function getUserClaims( $user_id, $scope ) { // We use WordPress user_login as the user identifier. $user_login = $user_id;