Discussion:
Exemplary code for web single sign-on plugin
Robert Lowe
2013-07-30 16:22:46 UTC
Permalink
I am attempting to create a plugin that causes WordPress to use an external
site for authentication using a custom single sign-on protocol.

Essentially, the plugin will need to redirect users to the external site
when they need to log in. After authenticating the user, the external site
will redirect them back to WordPress, passing a username, along with a
message authentication code, which my plugin will need to validate.

I see a number of plugins in the official directory that claim to provide
various forms of single sign-on. However, looking at the code for these
plugins I see little commonality in the approaches taken.

Can anyone point me to code that they would consider exemplary for
implementing web single sign-on in a plugin?
--
Best regards,

Robert Lowe
http://notability.rmlowe.com/
Ryan McCue
2013-07-30 21:22:06 UTC
Permalink
Post by Robert Lowe
Can anyone point me to code that they would consider exemplary for
implementing web single sign-on in a plugin?
Depending on what exactly you want, Keyring is probably a good start:
http://wordpress.org/plugins/keyring/

You may even be able to write your own service definition for it and
avoid reinventing the whole wheel.

As for the relevant cookie parts, I'm not sure if they're handled by
Keyring, but they're fairly trivial once you've got a WP_User.
--
Ryan McCue
<http://ryanmccue.info/>
Otto
2013-07-30 23:28:58 UTC
Permalink
Post by Ryan McCue
As for the relevant cookie parts, I'm not sure if they're handled by
Keyring, but they're fairly trivial once you've got a WP_User.
You don't need to handle the cookie parts yourself. Using the
"authenticate" filter correctly will do it for you.

Short version: Hook a filter function to "authenticate". It should
look like this:

add_filter('authenticate', 'example', 40, 3);

function example($user, $username, $password) {
if ( is_a($user, 'WP_User') ) { return $user; }
... do your auth stuff here ...
return ...something...
}

- If the function wants to login a user (after whatever verification
process), it should return a valid WP_User object.
- If the function wants to make a user *not* logged in (say the
verification was invalid or failed), it should return a WP_Error
object with a valid error message to display to the user.
- If the function wants to not affect the normal auth process in any
way, it should return the $user value unchanged.

When a valid WP_User is returned, the correct cookies for that user
will be set automatically by the normal process, and the next time
authentication is needed, those cookies will be used (they hook in to
this same filter, but at priority 30). Because of this, you can hook
in at priority 40, and that first is_a line will cause your auth to
not have to happen every time, since the cookie auth will be passing
you a WP_User and you can thus just skip it.

-Otto
Ryan McCue
2013-07-31 00:58:00 UTC
Permalink
Post by Otto
You don't need to handle the cookie parts yourself. Using the
"authenticate" filter correctly will do it for you.
From my own experience, simply filtering authenticate is *not* enough.
The cookie check will happen before authenticate gets called in some
cases, and cause the user to be logged out.

I had to work around this:
https://github.com/rmccue/WordPressOAuthProvider/commit/4b779059fd352c9086aef31b6b3c817ea3229388

It may be the case that I was doing this incorrectly, but a simple
filter on authenticate wasn't enough for me.
--
Ryan McCue
<http://ryanmccue.info/>
Otto
2013-07-31 14:29:06 UTC
Permalink
Post by Otto
Post by Otto
You don't need to handle the cookie parts yourself. Using the
"authenticate" filter correctly will do it for you.
From my own experience, simply filtering authenticate is *not* enough.
The cookie check will happen before authenticate gets called in some
cases, and cause the user to be logged out.
https://github.com/rmccue/WordPressOAuthProvider/commit/4b779059fd352c9086aef31b6b3c817ea3229388
It may be the case that I was doing this incorrectly, but a simple
filter on authenticate wasn't enough for me.
Think you must have been doing it wrong somehow. The cookie check
happens in wp_authenticate_cookie(), which is actually hooked to the
authenticate filter at priority 30.

Cookies can be cleared if something causes reauth to get set, but
that's separate, really.

Also, your workaround is incomplete. You're not setting up the
userdata globals quite properly. You might consider calling
wp_set_current_user() instead of just setting the global
$current_user.

-Otto
Robert Lowe
2013-07-31 16:09:37 UTC
Permalink
Post by Otto
You don't need to handle the cookie parts yourself. Using the
"authenticate" filter correctly will do it for you.
Thanks Otto. I guess the implication here is that I'd still be sending the
user to wp-login.php to handle the authentication, even though they would
never see an actual WordPress login page.
--
Best regards,

Robert Lowe
http://notability.rmlowe.com/
Robert Lowe
2013-08-01 06:47:32 UTC
Permalink
Post by Ryan McCue
Post by Robert Lowe
Can anyone point me to code that they would consider exemplary for
implementing web single sign-on in a plugin?
http://wordpress.org/plugins/keyring/
You may even be able to write your own service definition for it and
avoid reinventing the whole wheel.
Thanks Ryan.

I don't think Keyring is exactly what I'm looking for however.

Perhaps I'm misunderstanding, but it looks like Keyring associates OAuth
credentials from other sites with WordPress user accounts, and makes those
available for authenticated API calls to those sites, but doesn't perform
single sign-on as such.

What I'm looking to do is replace the standard WordPress login with login
via an external site, and it doesn't look as if Keyring does that.
--
Best regards,

Robert Lowe
http://crepuscular.rmlowe.com/
Loading...