Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

Archive /

Our old forums are still available as a read-only archive.

Moderators: martimiz, Sean, biapar, Willr, Ingo, simon_w

OpenID authentication - login form


Reply


7 Posts   2361 Views

Avatar
Markus

Google Summer of Code Hacker, 152 Posts

6 June 2007 at 3:45am

Edited: 06/06/2007 3:50am

Hello,

since Hayden and Sigurd seem to be very busy at the moment I'll use this forum to discuss with you the implementation of OpenID.

Currently the login form consists of an email and password field with a submit and "lost password" button.. for my gsoc project I'll add support for OpenID authentication which means that there is need for another field (OpenID user) and a button (login with OpenID).

I'm unsure what would be the better way to implement it:
- add a second form on the existing login page (maybe in a 2nd column)
- or create a link "login with OpenID" with a special form

I'd prefer the first option since there is 1 click and 1 page less than in the second one, but e.g. with the new black candy theme there will be a space problem since on the login page is rendered by default also a site tree.
Maybe that tree should be removed, since the tabs on the top show the same links.

Another question: I couldn't figure out how I can add a second form to the existing one (1st option). In sapphire/security/Security.php on line ~106 the form is rendered, but how can I add a second form there (or in sapphire/security/LoginForm.php)?

I wish you all the best for your projects!

Avatar
Sam

Administrator, 685 Posts

6 June 2007 at 10:21am

First off: the forum is the best place to write technical questions of this sort, so that the whole team can respond to issues as appropriate :-)

We want to let site developers create the best user experience possible on their site. I don't think that a link off to a separate form provides this. For sites that support OpenID, it should be included in the default log-in form - perhaps with a radio button that switches between email/password and openid authentication. Of course, for sites that don't support openid, the login form should be left as-is.

Log would look roughly as follows:

(o) Regular login
Email: [_________]
Password: [_________]

( ) OpenID

And would change to this when you click the radio button. The SelectionGroup field type can help create this kind of UI.

( ) Regular login
(o) OpenID
OpenID URL: [___________]

I would recommend setting up a configuration method such as LoginForm::allow_openid() that triggered the changing of the behaviour. Alternatively, you could use the authenticator classess mentioned below to go Security::allow_auth('OpenIDAuthenticator').

Another other thing that you're going to have to mess with is the authentication mechanism. Currently LoginForm::performLogin() calls Security::authenticate() to check a username/password in the database.

Perhaps you should have a number of authenticator classes, and the log-in form specifies which of these authenticators is being used.

abstract class Authenticator
* abstract function authenticate();
* abstract function getLoginFields();
* abstract function getMethodTitle();

class MemberAuthenticator extends Authenticator
* implement authenticate as currently defined in Security::authenticate()
* have getLoginFields() return username and password
* have getMethodTitle() return "Reular Login";

class OpenIDAuthenticator extends Authenticator
* Put your authentication code here. There will probably be some redirection to the OpenID provider, and redirection back; you may need to make class OpenIDAuthenticator_Controller extends Controller to handle the responses (this will be accessible as http://www.yoursite.com/OpenIDAuthenticator_Controller)
* use getLoginFields() and getLoginTitle() to provide the changes to the log-in form

class LDAPAuthenticator extends Authenticator
* This would be another good one to implement

For this to work most appropriately, I would suggest creating a new method on Security that was an array of form data instead of the username and password variables. To preserve backward compatability you'll want to keep Security::authenticate() working.

I would suggest that you create a "stub" Member object for anyone who logs in via OpenID. Perhaps you need to add a Username or OpenIDURL field to the Member object. Username would probably be more widely usable - we don't want to add lots of fields to the core database that are only used in the minority of cases.

You'll also note that I've suggested that you re-structure the log-in form to make use of a getLoginFields() method on each active authenticator. This would be a bit more work, but will make it easy to add new authentication mechanisms to the system. This will be particularly useful for people wanting to do this like integrate in, say, a phpBB forum by using phpBB's login scheme.

Avatar
Willr

Forum Moderator, 5513 Posts

6 June 2007 at 1:52pm

Edited: 06/06/2007 3:23pm

I really like how icon buffet has done their OpenID dual login screen - https://www.iconbuffet.com/people;login, From a design point of view its quite nice.

Avatar
Markus

Google Summer of Code Hacker, 152 Posts

6 June 2007 at 9:29pm

First off all thank you Sam and Will for your suggestions.

The login form on iconbuffet.com looks good, no question, but I don't like the idea of that additional (and unnecessary) click and without javascript that login form doesn't work at all.

So I'd prefer the option where the OpenID form is on the same page than the default login form, but not with radio buttons as Sam suggested because it creates new problems than. What should the "I've lost my password" button do when I use OpenID to login?
Maybe a better option would then be to use a form like http://www.sudokular.com/signin/, but that doesn't scale... I mean I can't add other login methods.

So in my opinion the best option would be to create different forms. One for the default method, one for OpenID and so on... In that way the different authentication methods can be easily turned on or off in the administration GUI and each of the Authenticator classes could simple implement a method getLoginForm()

Regarding the database layout I would suggest to leave the database as it is at the moment and use new tables to map the OpenID URLs to the CMS. So every authentication method is completely encapsulated. Another reason for that is that I need some more tables for OpenID anyway to prevent replay attacks.

Can you give me a hint how I can add quickly a second login form to the current one so that I can concentrate on the implementation of the various classes. I will implement the GUI then at the end when all the code behind works.

Avatar
Sam

Administrator, 685 Posts

6 June 2007 at 10:56pm

Separate forms sounds like a good idea, an iconbuffet-style layout could be achieved by adding some javascript/css tabs on with a form on each tab. The tab engine in jsparty/tabstrip is designed to show all tabs with # links in cases where javascript is disabled.

You are probably going to need to have Member records in the database, otherwise you won't know which groups the OpenID user belongs to, and therefore which permissions they have.

That said, you will need to be careful about saving the openid data into the member table. If the email address given by the OpenID provider matches an email address already in the system, the current Member class will merge the two records together - to enforce uniqueness of Emails. This means that someone could set up an OpenID provider that said you had the same email address as the site's provider, and therefore get administrative privileges!

I would suggest that if you tried to log in with OpenID, and the email address given matched a member in the system that has a password set, that it either rejected the log-in, or didn't fill out the Email field in the member table.

Avatar
Markus

Google Summer of Code Hacker, 152 Posts

7 June 2007 at 3:22am

I will not change the member table, but instead I will create a new one that maps the OpenID URL to an entry in the member table. The only thing that maybe should be added is a flag like *deactivate_member_login* so that that user can't login like a normal user (to reduce the possible attack surface).

I will use the email address you mentioned just for the registration of new users (in the backend). So the mapping is just between the (trusted) OpenID URL and the member object and that should not create any security holes.

Avatar
Sam

Administrator, 685 Posts

7 June 2007 at 2:53pm

Regarding deactivation of member log-in, the convention is that any member without a password can't log in. So just make sure that password field is blank :-)