I feel your pain, and I do know there are a lot of people that would like to do the same thing.
Unfortunately, this is kinda out of the scope of this forum since signing on using facebook credentials is delegated authentication, and OAuth is about delegated access. There's a significant difference.
Having said that, I can give you some code that I used for delegated authentication with Google credentials. Basically I implemented my own AuthenticationFilter:
Code:
package org.springframework.security.oauth.examples.tonr.servlet;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
/**
* @author Ryan Heaton
*/
public class GoogleAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public GoogleAuthenticationFilter() {
super("/googleauth");
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
String responseCode = request.getParameter("openid.mode");
if (responseCode == null) {
//initiate google login by sending the user to the google login endpoint with all the openid parameters that it needs.
//we know that this is the google login endpoint. If we were afraid that google might change it on us, we'd want to first ask
//for it by making a request to the xml document located at https://www.google.com/accounts/o8/id
//or at least make it configurable. For now, we'll just hard-code it.
String googleLoginEndpoint = "https://www.google.com/accounts/o8/ud";
String loginUrl = new StringBuilder(googleLoginEndpoint)
//standard required google openid parameters.
.append("?openid.ns=http://specs.openid.net/auth/2.0&openid.mode=checkid_setup&openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select&openid.identity=http://specs.openid.net/auth/2.0/identifier_select")
//we want to decide what to ask google to send back to use about the user
//for now, we'll just ask for the e-mail and pretend that's enough for us to let google users use our site.
//but there are other things you can ask for, like firstname, lastname, country, and language
//here's how to ask for the e-mail:
.append("&openid.ns.ax=http://openid.net/srv/ax/1.0&openid.ax.mode=fetch_request&openid.ax.type.email=http://axschema.org/contact/email&openid.ax.required=email")
//tell google what url the user needs to return to in order to finish login
//for now, we'll just send them back to this url.
.append("&openid.return_to=").append(request.getRequestURL()).append("&openid.realm=").append(request.getRequestURL())
.toString();
response.sendRedirect(loginUrl);
return null;
}
else if ("id_res".equals(responseCode)) { //this is how we know that the login succeeded, per openid spec.
//there has to be a decision made as to what roles to grant users who log-in using google creds. For now, we'll just hard-code "ROLE_USER"
List<GrantedAuthority> authorities = Arrays.asList((GrantedAuthority) new GrantedAuthorityImpl("ROLE_USER"));
String email = findEmail(request); //find the e-mail.
if (email == null) {
//we require at least the e-mail.
throw new AuthenticationServiceException("no email supplied from Google.");
}
return new UsernamePasswordAuthenticationToken(new User(email, "", true, true, true, true, authorities), null, authorities);
}
else {
//otherwise, login failed.
throw new AuthenticationServiceException("Google login failed.");
}
}
private String findEmail(HttpServletRequest request) {
//the openid parameters that google sends back are namespaced.
//we're looking for the "openid.NAMESPACE_ID.value.email" parameter
//where "NAMESPACE_ID" is the id of the "http://openid.net/srv/ax/1.0" namespace.
//first build up the map of namespaces to namespace ids.
Enumeration paramNames = request.getParameterNames();
Map<String, String> namespaceIds = new HashMap<String, String>();
while (paramNames.hasMoreElements()) {
String name = (String) paramNames.nextElement();
if (name.startsWith("openid.ns.")) {
namespaceIds.put(request.getParameter(name), name.substring("openid.ns.".length()));
}
}
//now look up the id for the attribute exchange namespace.
String attributeExchangeId = namespaceIds.get("http://openid.net/srv/ax/1.0");
if (attributeExchangeId != null) {
//return the value
return request.getParameter("openid." + attributeExchangeId + ".value.email");
}
return null;
}
}
created a bean in the application context:
Code:
<beans:bean id="googleAuthFilter" class="org.springframework.security.oauth.examples.tonr.servlet.GoogleAuthenticationFilter">
<beans:property name="authenticationManager" ref="authMan"/>
<beans:property name="rememberMeServices" ref="rememberMeServices"/>
</beans:bean>
and introduced it into the filter chain as a custom filter:
Code:
<http ...>
...
<custom-filter ref="googleAuthFilter" after="FORM_LOGIN_FILTER"/>
...
</http>
This is according to the instructions of the Google federated login API:
http://code.google.com/apis/accounts/docs/OpenID.html
Hope that helps.