package org.molgenis.auth;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.expressme.openid.Association;
import org.expressme.openid.Authentication;
import org.expressme.openid.Endpoint;
import org.expressme.openid.OpenIdException;
import org.expressme.openid.OpenIdManager;
import org.molgenis.framework.db.Database;
import org.molgenis.framework.db.DatabaseException;
import org.molgenis.framework.server.TokenFactory;
/**
* OpenIdLogin is a DatabaseLogin that authenticates via OpenId while
* authorization is done via the database
*
* @author robert wagner
*
*/
public class OpenIdLogin extends DatabaseLogin
{
private static final long serialVersionUID = 1L;
static final long ONE_HOUR = 3600000L;
static final long TWO_HOUR = ONE_HOUR * 2L;
static final String ATTR_MAC = "openid_mac";
static final String ATTR_ALIAS = "openid_alias";
protected final transient Logger logger = Logger.getLogger(this.getClass().getSimpleName());
public OpenIdLogin(TokenFactory tm)
{
super(tm);
logger.debug("OpenIdLogin()");
}
public OpenIdLogin(Database db, TokenFactory tm) throws Exception
{
super(db, tm);
}
public OpenIdLogin(Database db, String redirect, TokenFactory tm) throws Exception
{
super(db, tm);
super.redirect = redirect;
}
/**
*
* @param db
* @param request
* @param response
* @param returnURL
* @param op
* @throws Exception
*/
public void authenticate(Database db, HttpServletRequest request, HttpServletResponse response, String returnURL,
String op) throws Exception
{
OpenIdManager manager = new OpenIdManager();
if ("authenticated".equals(op))
{
// check nonce:
checkNonce(request.getParameter("openid.response_nonce"));
// get authentication:
byte[] mac_key = (byte[]) request.getSession().getAttribute(ATTR_MAC);
String alias = (String) request.getSession().getAttribute(ATTR_ALIAS);
Authentication authentication = manager.getAuthentication(request, mac_key, alias);
this.user = this.getMolgenisUser(db, authentication);
this.reload(db);
}
else if ("Google".equals(op) || "Yahoo".equals(op))
{
// manager.setRealm("http://localhost:8080");
manager.setReturnTo(returnURL);
// redirect to Google||Yahoo sign on page:
Endpoint endpoint = manager.lookupEndpoint(op);
Association association = manager.lookupAssociation(endpoint);
request.getSession().setAttribute(ATTR_MAC, association.getRawMacKey());
request.getSession().setAttribute(ATTR_ALIAS, endpoint.getAlias());
String url = manager.getAuthenticationUrl(endpoint, association);
response.sendRedirect(url);
}
else
{
throw new IOException("Bad parameter op=" + op);
}
}
/**
*
* @param nonce
*/
private void checkNonce(String nonce)
{
// check response_nonce to prevent replay-attack:
if (nonce == null || nonce.length() < 20) throw new OpenIdException("Verify failed.");
long nonceTime = getNonceTime(nonce);
long diff = System.currentTimeMillis() - nonceTime;
if (diff < 0) diff = (-diff);
if (diff > ONE_HOUR) throw new OpenIdException("Bad nonce time.");
if (isNonceExist(nonce)) throw new OpenIdException("Verify nonce failed.");
storeNonce(nonce, nonceTime + TWO_HOUR);
}
private boolean isNonceExist(String nonce)
{
// TODO: check if nonce is exist in database:
return false;
}
private void storeNonce(String nonce, long expires)
{
// TODO: store nonce in database:
}
private long getNonceTime(String nonce)
{
try
{
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(nonce.substring(0, 19) + "+0000").getTime();
}
catch (ParseException e)
{
throw new OpenIdException("Bad nonce time.");
}
}
// public void setUser(MolgenisUser molgenisUser) {
// this.user = molgenisUser;
//
// }
/**
*
*/
private MolgenisUser getMolgenisUser(Database db, Authentication authentication) throws DatabaseException,
ParseException, IOException
{
// check if already in database
List<MolgenisUser> users = db.query(MolgenisUser.class).eq(MolgenisUser.NAME, authentication.getEmail()).find();
if (users.size() == 0)
{
MolgenisUser user = new MolgenisUser();
user.setName(authentication.getEmail());
user.setFirstName(authentication.getFirstname());
user.setLastName(authentication.getLastname());
user.setEmail(authentication.getEmail());
user.setPassword(UUID.randomUUID().toString());
db.beginTx();
db.add(user);
db.commitTx();
return user;
}
else
{
return users.get(0); // safe because name is unique
}
}
}