package onlinefrontlines.auth;
import onlinefrontlines.Constants;
import onlinefrontlines.facebook.Facebook;
import onlinefrontlines.utils.GlobalProperties;
import onlinefrontlines.utils.Tools;
import java.security.*;
import java.util.Calendar;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Cookie;
/**
* Helper tools to automatically authenticate
*
* @author jorrit
*
* Copyright (C) 2009-2013 Jorrit Rouwe
*
* This file is part of Online Frontlines.
*
* Online Frontlines is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Online Frontlines is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Online Frontlines. If not, see <http://www.gnu.org/licenses/>.
*/
public class AutoAuth
{
/**
* Key pair changes with every restart. If key pair changed, user will have to login again.
*/
private static KeyPair keyPair;
/**
* Get existing or generate new key pair
*/
private static KeyPair getKeyPair()
{
try
{
if (keyPair == null)
{
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048, new SecureRandom());
keyPair = generator.generateKeyPair();
}
}
catch (Exception e)
{
Tools.logException(e);
}
return keyPair;
}
/**
* Generate string to automatically authenticate a user
*
* @param user User to authenticate
* @param timeValid How long this stays valid in milliseconds
* @return String that contains all information needed to authenticate a user
* @throws Exception
*/
public static String generateAuthenticationString(User user, long timeValid) throws Exception
{
long now = Calendar.getInstance().getTime().getTime();
String parameters = user.id + "-" + (now + timeValid);
String signature = AuthTools.sign(parameters, getKeyPair().getPrivate());
return parameters + "-" + signature;
}
/**
* Contains the result of parsing the authentication string
*/
public static class AuthResult
{
public User user;
public String facebookAccessToken;
}
/**
* Parse authentication string and return result
*
* @param authString Authentication string
* @return Result or null if not valid
* @throws Exception
*/
public static AuthResult parseAuthenticationString(String authString) throws Exception
{
// Validate that a string was passed
if (authString == null)
return null;
// Split string
String[] values = authString.split("-");
if (values.length != 3)
return null;
// Parse user id
int userId = Integer.parseInt(values[0]);
// Parse validity
long validUntil = Long.parseLong(values[1]);
// Check validity
long diff = validUntil - Calendar.getInstance().getTime().getTime();
if (diff < 0 || diff > Constants.AUTH_TIME_DEFAULT)
return null;
// Get the new user
User user = UserCache.getInstance().get(userId);
if (user == null)
return null;
// Check signature
StringBuilder valueToVerify = new StringBuilder();
valueToVerify.append(userId);
valueToVerify.append('-');
valueToVerify.append(validUntil);
if (!AuthTools.verifySignature(valueToVerify.toString(), values[2], getKeyPair().getPublic()))
return null;
// Return result
AuthResult result = new AuthResult();
result.user = user;
return result;
}
/**
* Get facebook access token from cookie
*
* @param cookie
* @return
*/
public static AuthResult parseFbAuthenticationCookie(String cookie) throws Exception
{
// Get user
Facebook.AuthenticatedUser fbUser = Facebook.getAuthenticatedUser(cookie);
if (fbUser == null)
return null;
// Find user
User user = UserCache.getInstance().getByFacebookId(fbUser.uid);
if (user == null)
{
// Get my data
Facebook.UserDetails result = Facebook.getMyDetails(fbUser.accessToken);
if (result == null)
return null;
// Create new user
user = new User();
user.facebookId = result.facebookId;
user.username = result.name;
user.realname = result.name;
user.website = result.website;
user.email = result.email;
user.determineArmy();
// Add to database
UserDAO.create(user);
// Register with cache
UserCache.getInstance().put(user.id, user);
}
// Return result
AuthResult result = new AuthResult();
result.user = user;
result.facebookAccessToken = fbUser.accessToken;
return result;
}
/**
* Generate cookies to automatically authenticate user
*
* @param response HTTP response
* @param user User to authenticate
* @param timeValid How long the login stays valid in milliseconds
* @param cookieMaxAge How long the cookie stays valid in seconds, 0 for forever, -1 for as long as the browser is active
* @throws Exception
*/
public static void generateAuthenticationCookies(HttpServletResponse response, User user, long timeValid, int cookieMaxAge) throws Exception
{
String auth = generateAuthenticationString(user, timeValid);
Cookie c = new Cookie(Constants.AUTH_STRING, auth);
c.setMaxAge(cookieMaxAge);
response.addCookie(c);
}
/**
* Removes the cookies to automatically authenticate a user
* @param response
*/
public static void removeAuthenticationCookies(HttpServletResponse response)
{
// Remove our authentication cookie
Cookie c = new Cookie(Constants.AUTH_STRING, "");
c.setMaxAge(0);
response.addCookie(c);
}
/**
* Validate authentication parameters and determine user
*
* @param request The HTTP request object
* @param response The HTTP response object
* @return User if request contains valid authentication info
*/
public static AuthResult getAuthenticatedUser(HttpServletRequest request, HttpServletResponse response)
{
try
{
// Get auth result from cookie
AuthResult cookieAuth = null;
AuthResult facebookAuth = null;
Cookie[] cookies = request.getCookies();
if (cookies != null)
for (Cookie c : cookies)
{
String name = c.getName();
if (name.equals(Constants.AUTH_STRING))
cookieAuth = parseAuthenticationString(c.getValue());
else if (name.equals("fbsr_" + GlobalProperties.getInstance().getString("facebook.api_key")))
facebookAuth = parseFbAuthenticationCookie(c.getValue());
}
// Determine which authentication to use
AuthResult auth;
if (cookieAuth != null)
auth = cookieAuth;
else if (facebookAuth != null)
auth = facebookAuth;
else
return null;
return auth;
}
catch (Exception e)
{
// Something went wrong, no authenticated user
Tools.logException(e);
return null;
}
}
}