OpenID, the challenge Attributes

11 12 2008

So what’s the fuss about openID? Well the idea are to have one id provider for all the sites that require authentication.

And if you go a bit further and you do at sometime, you’ll want to get some details about the user, like email or full name. So the guys at openID implemented something called attribute exchange. And if you are in the java world like I am you want something simple, so I turned to openID4Java. The idea are that you let the user put in the id on your web page just something like johndoe.openid.org and then you forward the user to openid.org and lets openid.org validate your user and then openid.org will forward the user back to you using an url you specified. And if you really need some properties, you can add a sreg (OpenID Simple Registration Extension) for each property to make the user enter it at the provider ( however not all providers supports these things ).

Well onto the code :

Code for requesting the provider

// --- placing the authentication request ---
public String authRequest(String userSuppliedString,
HttpServletRequest httpReq, HttpServletResponse httpResp,
String returnToUrl) throws IOException, ServletException {
try {
// configure the return_to URL where your application will receive
// the authentication responses from the OpenID provider

// perform discovery on the user-supplied identifier
List discoveries = manager.discover(userSuppliedString);

// attempt to associate with the OpenID provider
// and retrieve one service endpoint for authentication
DiscoveryInformation discovered = manager.associate(discoveries);

// store the discovery information in the user's session
httpReq.getSession().setAttribute("openid-disc", discovered);

// obtain a AuthRequest message to be sent to the OpenID provider
AuthRequest authReq = manager.authenticate(discovered, returnToUrl);
FetchRequest fetch = FetchRequest.createFetchRequest();

//
// SRegRequest sregReq = SRegRequest.createFetchRequest();
//
// sregReq.addAttribute("fullname", true);
// sregReq.addAttribute("nickname", true);
// sregReq.addAttribute("email", true);
fetch.addAttribute("Fullname", "http://axschema.org/namePerson/",
true);
fetch.addAttribute("Email", "http://axschema.org/contact/email",
true);

// tell the email coint
fetch.setCount("Email", 1);
AuthRequest req = manager.authenticate(discovered, returnToUrl);
req.addExtension(fetch);
// authReq.addExtension(sregReq);
if (!discovered.isVersion2()) {
// Option 1: GET HTTP-redirect to the OpenID Provider endpoint
// The only method supported in OpenID 1.x
// redirect-URL usually limited ~2048 bytes
httpResp.sendRedirect(authReq.getDestinationUrl(true));
return null;

} else {
httpResp.sendRedirect(authReq.getDestinationUrl(true));
return null;
// // Option 2: HTML FORM Redirection (Allows payloads >2048
// bytes)
// RequestDispatcher dispatcher =
// httpReq.getRequestDispatcher(OpenIdSignInPage.MOUNTPATH);
// httpReq.setAttribute("parameterMap",
// authReq.getParameterMap());
// httpReq.setAttribute("destinationUrl",
// authReq.getDestinationUrl(false));
// dispatcher.forward(httpReq, httpResp);
}
} catch (OpenIDException e) {
// present error to the user
}

return null;
}

The code that recieves the response from the provider:

// --- processing the authentication response ---
public User verifyResponse(HttpServletRequest httpReq) {
try {
// extract the parameters from the authentication response
// (which comes in as a HTTP request from the OpenID provider)
ParameterList response = new ParameterList(httpReq
.getParameterMap());

// retrieve the previously stored discovery information
DiscoveryInformation discovered = (DiscoveryInformation) httpReq
.getSession().getAttribute("openid-disc");

// extract the receiving URL from the HTTP request
StringBuffer receivingURL = httpReq.getRequestURL();
String queryString = httpReq.getQueryString();
if (queryString != null && queryString.length() > 0)
receivingURL.append("?").append(httpReq.getQueryString());

// verify the response; ConsumerManager needs to be the same
// (static) instance used to place the authentication request
VerificationResult verification = manager.verify(receivingURL
.toString(), response, discovered);

// examine the verification result and extract the verified
// identifier
Identifier verified = verification.getVerifiedId();
if (verified != null) {
AuthSuccess authSuccess = (AuthSuccess) verification
.getAuthResponse();
if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
FetchResponse fetchResp = (FetchResponse) authSuccess
.getExtension(AxMessage.OPENID_NS_AX);
return filluser(fetchResp);
}

if (authSuccess.hasExtension(OPENID_NS_SREG1_1)) {
log.info("got info:"
+ authSuccess
.getParameterValue("openid.sreg.email"));
log.info("got info:"
+ authSuccess
.getParameterValue("openid.sreg.fullname"));

User user = new User();
user.setEmail(authSuccess
.getParameterValue("openid.sreg.email"));
user.setName(authSuccess
.getParameterValue("openid.sreg.fullname"));
return user;

}

// return verified; // success
}
} catch (OpenIDException e) {
// present error to the user
}

return null;
}

private User filluser(FetchResponse fetchResp) {

List emails = fetchResp.getAttributeValues("email");
String email = emails.get(0);
List names = fetchResp.getAttributeValues("name");
String name = names.get(0);

User user = new User();
user.setEmail(email);
user.setName(name);
return user;

}

So the idea are good and the authentication works, but my problem are that I cannot get the providers to provide the ax properties. So I’ll be following up on howto do this in this post. I hope I succeed at some point, because for me openid without ax are almost worthless. At this point I dont know if it’s the openID4java implementation or the openID providers. If you have any pointers on howto do this please comment

Advertisements

Actions

Information

6 responses

13 12 2008
David Leangen

Hi, Nino,

You can get info about how to discover which extensions an OP supports here:

http://openid.net/specs/openid-authentication-2_0.html#extensions

Note that Attribute Exchange is just an extension: there is no obligation for an OP to provide it. Unfortunately, it indeed seems to be the case that many of the OPs do not seem to provide ax. Also, the big players (Yahoo, Google…) are OPs, but won’t let you log into their systems with OpenIDs from other domains. So, they’re not really using OpenID like it was intended to be.

As you said in one of your posts, “the situation sux”.

13 12 2008
ninomartinez

Hi David

Thanks a lot. I was hoping that were just doing something wrongly 😦 I’ll continue my quest though. But I guess just listing which OP’s you support in your web app sort of ruin the idea though..
iI
I hate the fact though that you can say your system are openId compliant which should really mean that you can log in with any openID, but then have to tell people that their provider are unsupported if it dont support AX or SREG, I guess I could then just require the user to enter email and name if their OP dont support transfering..

11 06 2009
sreenagesh

This information is pretty useful and one that I have been looking around for.
Thanks alot.

2 04 2012
Suraj Chandran

I am facing the same problem i.e. unable to get the ax attributes. The statement “authSuccess.hasExtension(AxMessage.OPENID_NS_AX)” always returns false. This is really discouraging. I wonder how sites liek Stackoverflow do it then.

2 04 2012
Suraj Chandran

OK, 2 mins after posting the above comment, I stumbled upon the solution. And this one really works:

private String yahooEndpoint = “https://me.yahoo.com”;
private String googleEndpoint = “https://www.google.com/accounts/o8/id”;
FetchRequest fetch = FetchRequest.createFetchRequest();
if (userSuppliedString.equals(googleEndpoint)) {
fetch.addAttribute(“email”, “http://axschema.org/contact/email”, true);
fetch.addAttribute(“firstName”, “http://axschema.org/namePerson/first”, true);
fetch.addAttribute(“lastName”, “http://axschema.org/namePerson/last”, true);
} else if (userSuppliedString.equals(yahooEndpoint)) {
fetch.addAttribute(“email”, “http://axschema.org/contact/email”, true);
fetch.addAttribute(“fullname”, “http://axschema.org/namePerson”, true);
} else { //works for myOpenID
fetch.addAttribute(“fullname”, “http://schema.openid.net/namePerson”, true);
fetch.addAttribute(“email”, “http://schema.openid.net/contact/email”, true);
}

7 04 2012
Suraj Chandran

BTW, in the above code, the yahooEndPoint may not match the userSuppliedString, so take care of that.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: