openid-connect-generic
openid-connect-generic copied to clipboard
Add filters for contextualization
All Submissions:
- [x] Have you followed the plugin Contributing guideline?
- [x] Does your code follow the WordPress' coding standards?
- [x] Have you checked to ensure there aren't other open Pull Requests for the same update/change?
Changes proposed in this Pull Request:
We needed a way to dynamically use openid details of multiple companies based on an external identifier. In detail, the new filters allow modifying the settings used to create the login button.
In our setup, we are storing the openid credentials as post meta and identify the post to load by a url parameter. To identify the post used we store it inside the state which is why we implemented the filter.
In general the filters do not intervene with the current functionality, but allow for more usecases.
How to test the changes in this Pull Request:
Here is our full custom implementation:
use OpenID_Connect_Generic_Option_Settings;
/**
* This class is responsible for dynamically setting OpenID Connect Generic settings
* It works by first modifying the settings based on a url parameter to identify the post.
* After that it adds the post id to the state so that the login redirect can identify the post.
*/
class DynamicClient {
/**
* Adds the callbacks to openid filter.
*/
public function __construct() {
add_filter( 'openid-connect-generic-settings', array( $this, 'dynamic_settings' ) );
add_filter( 'openid-connect-generic-new-state-value', array( $this, 'add_post_id_to_state' ) );
}
/**
* Whenever the shortcode or the automatic login redirect is called we need to overwrite the settings since they are used
* for further logic.
*
* @param OpenID_Connect_Generic_Option_Settings $settings OpenId Settings built on every request.
* @return OpenID_Connect_Generic_Option_Settings
*/
public function dynamic_settings( OpenID_Connect_Generic_Option_Settings $settings ): OpenID_Connect_Generic_Option_Settings {
$post_id = false;
if ( ! empty( $_GET['state'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$state = wp_kses( wp_unslash( $_GET['state'] ), array() ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$state = get_transient( 'openid-connect-generic-state--' . $state );
if ( ! empty( $state ) && ! empty( $state['post_id'] ) ) {
$post_id = $state['post_id'];
}
}
// If post id was not determined from state we try to get it from the url param
if ( ! $post_id ) {
$post_id = $this->get_post_by_param();
}
// If post id still not determine we return the settings and stop further processing
if ( ! $post_id ) {
return $settings;
}
$post_settings = $this->get_post_settings( $post_id );
if ( ! $post_settings ) {
return $settings;
}
// Overwrite settings
$settings->client_id = $post_settings['client_id'];
$settings->client_secret = $post_settings['client_secret'];
$settings->endpoint_login = $post_settings['authorize_endpoint'];
$settings->endpoint_userinfo = $post_settings['userinfo_endpoint'];
$settings->endpoint_token = $post_settings['token_endpoint'];
return $settings;
}
/**
* To identify the post we get our settings from throughout the request process we add the post id to the state.
*
* @param array<string, mixed> $state_value Value that is going to be set as state.
* @return array<string, mixed>
*/
public function add_post_id_to_state( array $state_value ): array {
// State is set during the same request the settings are set. We can assume the url param is still available.
$post_id = $this->get_post_by_param();
if ( ! $post_id ) {
return $state_value;
}
$state_value['post_id'] = $post_id;
return $state_value;
}
/**
* Get the post id from the request. The request is expected to have a partner parameter which is the slug of the post.
*
* @return int|false
*/
private function get_post_by_param(): int|false {
if ( ! isset( $_GET['partner'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return false;
}
$partner = wp_kses( wp_unslash( $_GET['partner'] ), array() ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
// If we reach this point we are not logged in and have a partner
$post = get_page_by_path( $partner, OBJECT, 'unternehmen' );
if ( ! $post ) {
return false;
}
return $post->ID;
}
/**
* Get the openid settings from the post.
*
* @param int $post_id Id of the post to get the settings from.
* @return array{'client_id': string, 'client_secret': string, 'authorize_endpoint': string, 'userinfo_endpoint': string, 'token_endpoint': string}|false
*/
private function get_post_settings( int $post_id ): bool|array {
// Get our fields
// phpcs:disable Universal.Operators.DisallowShortTernary.Found
$client_id = get_field( 'openid_company_client_id', $post_id ) ?: '';
$client_secret = get_field( 'openid_company_client_secret', $post_id ) ?: '';
$authorize_endpoint = get_field( 'openid_company_authorize', $post_id ) ?: '';
$userinfo_endpoint = get_field( 'openid_company_userinfo', $post_id ) ?: '';
$token_endpoint = get_field( 'openid_company_token', $post_id ) ?: '';
// phpcs:enable
// Check all fields are set
if ( empty( $client_id ) || empty( $client_secret ) || empty( $authorize_endpoint ) || empty( $userinfo_endpoint ) || empty( $token_endpoint ) ) {
return false;
}
return array(
'client_id' => $client_id,
'client_secret' => $client_secret,
'authorize_endpoint' => $authorize_endpoint,
'userinfo_endpoint' => $userinfo_endpoint,
'token_endpoint' => $token_endpoint,
);
}
}
Other information:
- [x] Have you added an explanation of what your changes do and why you'd like us to include them?
- [ ] Have you written new tests for your changes, as applicable?
- [ ] Have you successfully run tests with your changes locally?
Changelog entry
- Added new filter that allows modifying settings
- Added filter to allow modifying state value
This looks quite nice, would love to see this feature in an upcoming release.