Services/OpenId
This page discusses the implementation of an OpenID service.
Glossary
- OP: OpenId Provider. e.g. http://openid.ziade.org
- RP: Relying Party, the website that does an OpenID request
- FI: Firefox Identity Plugin
Flow
- FI detects forms that offer OpenID and inject a "Sign in using your Firefox Identity" in it so the user can use it to sign in.
- Clicking on the button initiates the process by sending the user's id to the RP
- the RP calls the OP "associate" API
- the RP calls the OP "checkid_setup" API
- FI intercepts the "checkid_setup" call and injects an Authentication header
- The OP redirects to the RP
Demo
You can try the current implementation by installing the custom account manager add-on here: http://ziade.org/account-manager-0.0.13-dev.xpi
This will work with my server at http://openid.ziade.org. The server uses a dummy authentication backend so it will always successfully authenticates you.
Once the add-on is installed, you can try connecting to websites that support openid.
Sites successfuly tested so far:
- http://pypi.python.org/pypi?:action=openid
- http://slashdot.org/my/login
- http://www.livejournal.com/identity/login.bml?type=openid
- https://bitbucket.org/account/signin
- http://stackoverflow.com/users/authenticate
The Identity Server
The server is a full OpenID 2.0 server that will authenticate the user against his Sync account.
The user identifier is: https://server/user-email
Where user-email is the user email used for Sync. The server will internally convert the email to a base32 hash to find the user.
Mine is currently: http://openid.ziade.org/tarek@mozilla.com
The other difference from a regular OpenId server is that authorizing EPs is done automatically in case the Sync Password is provided in an Authorization header, on the checkid_setup call. In that case, the server verifies the password and automatically adds the site, then performs the usual redirect.
If the add-on is deactivated for any reason, the user will still be able to use our openid provider, but will have to manually authorize sites through a screen that will display a "continue" button (after he has logged into our OP).
OpenID APIs
A user is identified by his e-mail.
GET or POST https://server/
Performs an OpenId operation. Depending on the openid_mode request parameter value, the server will perform a different process. * associate: creates an association with the EP. * check_authentication: checks that a given site is authorized * checkid_setup: checks if an EP owns the Claimed Identifier. * checkid_immediate: XXX points to checkid_setup for now See the OpenID doc for more details.
GET https://server/user_email
Discovery page for the user. Returns: * a Yadis page for clients that accept "application/xrds+xml" * an HTML page for other clients. If the user is logged in, and display his own page, he will get his list of active handles w/. associated sites.
Implementation details
The server prototype is here: http://bitbucket.org/tarek/server-openid
- The server is implemented using server-core, for the authentication APIs
- storage
- Users are stored in LDAP for Mozilla, but people can use alternative back-ends
- Association handles and Site tokens are stored in Redis, but people can use alternative back-ends
- The server uses the same node assignment library than Sync to associate a user to a server
- A new multi-value field is added in the LDAP User object: service-enabled
- to enable OpenID for the user, an OpenID value is added
- The Sync value is used to enable/disable Sync.
- The account-enabled field is kept for a global de-activation of a user
- Node assignment can be done on the first OpenID activation if Sync is disabled or not used yet.
The client prototype is here: http://hg.mozilla.org/labs/weave-identity/summary
See also, Account Manager specs: https://wiki.mozilla.org/Labs/Weave/Identity/Account_Manager/Spec/3
Performances
App profile:
- CPU intensive application (crypto)
- All storage in RAM (Redis)
- Storage: handles + sites associated w/ a handle
RAM Formula:
HANDLE_SIZE = maxsize(handle) + maxsize(secret) + 10 * avgsize(url) HANDLE_SIZE = 40 + 32 + 10 * 150 = 1572 octets USER_SIZE = 1572 * 10 = 15 ko
On a server w/ 8 gig for Redis, there's room for half a million openid.
An openid transaction is on average two requests:
- smart mode: association + checkid_setup
- dumb mode: checkid_setup + check_authentication
So a 8 gig. server can handle 250k transactions per hour: 70 req/seconds.
Draft on quotas:
- Max TTL for a handle: 3600 seconds.
- Max number of sites / handle : 10
- Max number of handles per user: 10
XXX: bench a server to see how much req/seconds it can handle. (cpu work)
Impact on Sync
- If a user tries to create a new account in Firefox Sync via the wizard but already has OpenID activated
- we tell the user that there's an existing account and redirect him to the regular user authentication screen.
- we add Sync in service-enabled in LDAP on the first sync
- If a user deletes his Sync account
- we remove Sync from service-enabled but don't remove the LDAP user
- If a user tries to create a new account in the OpenID UI, and already has Sync activated, we warn that an account exists for that e-mail and propose to the user to activate OpenID through the user account management panel
Impact on Mozilla websites
We need to implement OpenID in all of them.
Privacy concerns
XXX
- We store the authorized sites. We should hash them to avoid that.