Craig's second attempt:
- [yada yada, you pass a validation]
- Check all site properties to see if any match //properties/property[contents='openid']
- If there is a user, log in with that user
- If there is not a user: prompt to create.
- page needs to take proposed nickname and/or e-mail address from OpenID response XML and prepopulate form field
- form should post back to server and validate username before allowing submit
- there needs to be a salted hash to ensure you can't force a submit of the page if you haven't been through the OpenID process
- in order to add an OpenID to an existing account, set the site property on the UserPreferences screen [done]
Second Attempt Notes
- Create a new namespace for the openid usernames in site properties
- map openId usernames directly to a property to avoid looking up all openIds
- strip http? e.g. urn:john.openid.foobar.com?
- Do you have some sample openid usernames in various formats?
- If no user
- Save openId details in the $_SESSION and redirect to Special:CreateOpenId or something
- Handle createopenid by verifying information saved in $_SESSION against openid service?
- Alternatively, create unique hash against data that is salted with site salt?
- After finding an available username, create the user and associate in site properties
Access site properties in PHP
// @note guerrics: this is a step in the direction but I haven't tried it
class OpenIdProperties extends DekiSiteProperties
{
const NS_OPENID = 'urn:openid.draft#';
public function __construct()
{
parent::__construct();
}
/**
* @return string - false if not found
*/
public function getUsername($openIdUsername)
{
$name = $this->munge($openIdUsername);
return $this->get($name, false, self::NS_OPENID);
}
public function setUsername($openIdUsername, $mindtouchUsername)
{
$name = $this->munge($openIdUsername);
$this->set($name, $mindtouchUsername, self::NS_OPENID);
return parent::update();
}
protected function munge($u)
{
// TODO: what should this do?
return str_replace('http://', '', $u);
}
}
Craig's first attempt:
- User hits Special:UserLogin
- Hook injects an OpenID login block into the page
- GET is made to /deki/services/openid/authenticate?url=http://my.openid/
- authenticate function validates endpoint:
- you click the "yes I am that guy" button
- it redirects you to http://site/@api/deki/openid/validat...f-query-string
- validate function checks you are who you say you are
- failure: returns 400
- success: does a POST to users/authenticate with API key & gets auth token
- must then set your auth token and redirect you.. somewhere
Should return URL be a special page, which does a Plug post to users/authenticate, similar to how Special:UserLogin currently works?
Then we could have better error handling of the HTTP 400 cases, set cookie, and display a nice UI page etc - have the validate function only return the auth token
Refined by Max and Guerric
- User enters endpoint and hits submit
- POST to the special page
- server side: UI accepts address and posts to the c# open id service
- The c# service validates, and responds with xml containing the redirect URI with tokens, etc
- UI sees the status 200 response and the redirect uri, and issues a 302 to redirect the user
- Openid magic happens and the user is redirected to the login page with additional query params
- UI realizes this is a user coming back from openid and again posts to the C# service server side
- If the response is a 200 the UI does a POST:users/authenticate with an APIkey
To do:
- fix the http://foo:bar@baz vs. Authenticate: Base64(foo:bar) problem
- add this to the standard UserLogin workflow
- register the service somewhere consistent
- define the parameters better