Let’s dive right into /keyring.php
, which is the “guts” of Keyring and see what we’ve got.
Configuration Constants
There are a few constants which you can use to alter the way that Keyring works. All of these constants may be defined in your wp-config.php
file so that they won’t be affected by plugin upgrades. If you don’t define them then they will default to their own settings:
KEYRING__DEBUG_MODE: define this constant as true
to enable very verbose output that will be included in your error_log. You can grep for “Keyring:” which is prepended to all lines output by Keyring. Default is false
KEYRING__TOKEN_STORE: The full PHP class name of the Token Store to use for handling Keyring Tokens. Default is Keyring_SingleStore
KEYRING__HEADLESS_MODE: Depending on your WordPress install, you may or may not want/need users to be able to access the default Keyring admin interface. Defining this constant as true
will disable all built in user interface, and require you to implement your own. Default value is false
(built in admin UI will be loaded).
Bootstrap + Request Handling
OK, once you’ve got things configured, it’s time to look at what the rest of this file provides. The best way to learn about most of it is to just walk through a typical Keyring-handled request and see what happens:
- As WordPress is loaded, the
plugins_loaded
action is fired, which triggersKeyring::plugins_loaded()
. Note that this is pretty early in the WordPress bootstrap. /store.php
is then loaded, which automatically loads all PHP files in/includes/store/
- Once all the Store files are loaded, the
keyring_load_token_stores
action is fired and thenKEYRING__TOKEN_STORE
is checked to make sure it exists and is a validKeyring_Store
. - Now
/token.php
is loaded, and then/service.php
is loaded (which triggers a load of all core + extended services) - With everytihng involved in the core of Keyring loaded, 2 things are hooked onto the
init
action — Keyring’s ownKeyring::init()
method, and a small closure that just fires thekeyring_load_services
action. - The
keyring_load_services
action is where all core Services hook in to load, and it’s where you should hook any custom Services in as well. - Since Keyring is intended to only operate within the admin area of WordPress,
Keyring::request_handlers()
are hooked intoadmin_init
(and will conditionally handle Keyring-specific requests)
At this point, we’ve loaded Keyring and all core services, stores, etc. Now we get to actually handling requests.
Keyring::request_handlers()
, which is hooked intoadmin_init
handles all Keyring requests, provided a series of parameters exist.- If an admin request contains the following
$_REQUEST
parameters, then Keyring will intercept and handle it:page
(and it matches theKeyring->admin_page
var),action
andservice
. Note thataction
andservice
are also restricted to known values. - Assuming Keyring is going to handle this request, it will fire a ‘pre’ action (
pre_keyring_{$service}_{$action}
), then it will verify thekr_nonce
parameter to avoid replay and involuntary requests. - If the nonce is valid, Keyring will then fire the “main” action —
keyring_{$service}_{$action}
- If this is a
delete
request (action=delete), then an addition action,keyring_connection_deleted
, will be fired for the specified service.
Auth Flow
The general idea of the auth flow in Keyring is modeled most closely on OAuth, where an initial request is made to the remove service, then the user is redirected to the service to grant permissions, then another request is made to get an authenicated token of some sort. Using this as a mental model, everything in Keyring works roughly like this:
- The user indicates they would like to connect to a service (either directly, or by attempting to use a feature which required a connection)
- They will be directed to the ‘request’ phase of the process (Phase 1)
- If
KEYRING__HEADLESS_MODE
is set tofalse
and something is hooked into thekeyring_{$service}_request_ui
action, that action will be fired and whatever is attached to it should render a UI to work with this first part of the flow (e.g. for HTTP Basic, this is where we ask the user for a username/password). - If a custom request UI doesn’t intercept, then the
request_token()
method will automatically be called (note that this method must be defined for all Services). - Depending on how this particular auth protocol works, the user may be redirected to an external site at this point, or automated requests may be made behind the scenes. Either way, the user will be directed to the next phase, called ‘verify’.
- The ‘verify’ phase works the same as the ‘request’ phase, calling the
keyring_{$service}_verify_ui
action if defined, and then theverify_token()
method if control has not been short-circuited already. - During
verify_token()
, external requests or internal checks may be made to ensure the token received is valid, has the correct permissions etc. - Once
verify_token()
is complete, it will callverified()
, which if not intercepted will just redirect the user back to the Keyring admin with a message telling them that they created a connection.