package com.leanengine.server.auth;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserServiceFactory;
import com.leanengine.server.LeanEngineSettings;
import com.leanengine.server.LeanException;
import com.leanengine.server.appengine.AccountUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class OpenIdLoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String nextUrl = request.getParameter("next");
if (nextUrl == null) { // first part of the OpenID flow
String type = request.getParameter("type") == null ? "web" : request.getParameter("type");
String errorUrl;
if (request.getParameter("onerror") != null) {
errorUrl = request.getParameter("onerror");
} else {
errorUrl = "/loginerror";
}
// redirectUrl is composed so that it redirects twice:
// first to /openid for authentication
// second to the final destination URL
String redirectUrl;
if (type.equals("mobile")) {
redirectUrl = request.getRequestURI()+"?next=@mobile";
} else {
String redirectParam;
if (request.getParameter("onlogin") != null) {
redirectParam = request.getParameter("onlogin");
} else {
redirectParam = "/";
}
redirectUrl = request.getRequestURI()+ "?next=" + redirectParam + "@" + errorUrl;
}
// check if OpenID is enabled
if (!LeanEngineSettings.isOpenIdLoginEnabled()) {
Scheme scheme;
if (type.equals("mobile")) {
scheme = new MobileScheme(request.getServerName());
} else {
String hostname = request.getServerName();
if (request.getLocalPort() != 80 && request.getLocalPort() != 0) {
hostname = hostname + ":" + request.getLocalPort();
}
scheme = new WebScheme(request.getScheme(), hostname);
}
response.sendRedirect(
scheme.getErrorUrl(new LeanException(LeanException.Error.OpenIdAuthNotEnabled), errorUrl));
return;
}
// default OpenID provider is Google
String openIdProvider = request.getParameter("provider");
// is it a shortcut?
if (openIdProvider == null || openIdProvider.equals("google")) {
openIdProvider = "https://www.google.com/accounts/o8/id";
} else if (openIdProvider.equals("yahoo")) {
openIdProvider = "https://me.yahoo.com";
}
String loginUrl = UserServiceFactory.getUserService().createLoginURL(redirectUrl, null, openIdProvider, null);
response.sendRedirect(loginUrl);
} else { // second part of the OpenID flow
// type parameters tells us the type of redirect we should perform
Scheme scheme;
String redirectUrl = null;
String errorUrl = null;
if (nextUrl.equals("@mobile")) {
scheme = new MobileScheme(request.getServerName());
} else {
String hostname = request.getServerName();
if (request.getLocalPort() != 80 && request.getLocalPort() != 0) {
hostname = hostname + ":" + request.getLocalPort();
}
scheme = new WebScheme(request.getScheme(), hostname);
// extract the redirect URL
String[] stateItems = nextUrl.split("@");
redirectUrl = (stateItems.length == 2) ? stateItems[0] : null;
errorUrl = (stateItems.length == 2) ? stateItems[1] : null;
}
// get user
User currentUser = UserServiceFactory.getUserService().getCurrentUser();
//OpenID login did not succeed
if (currentUser == null) {
response.sendRedirect(
scheme.getErrorUrl(new LeanException(LeanException.Error.OpenIdAuthFailed), errorUrl));
return;
}
// get toke for this user
AuthToken authToken;
LeanAccount account = AccountUtils.findAccountByProvider(currentUser.getUserId(),
currentUser.getFederatedIdentity());
if (account == null) {
//todo this is one-to-one mapping between Account and User - change this in the future
Map<String, Object> props = new HashMap<String, Object>();
props.put("email", currentUser.getEmail());
// account does not yet exist - create it
account = new LeanAccount(
0,
currentUser.getNickname(),
currentUser.getUserId(),
currentUser.getFederatedIdentity(),
props
);
// saving the LeanAccount sets the 'id' on it
AccountUtils.saveAccount(account);
}
// create our own authentication token
authToken = AuthService.createAuthToken(account.id);
// save token in session
HttpSession session = request.getSession(true);
session.setAttribute("lean_token", authToken.token);
//send lean_token back to browser
try {
response.sendRedirect(scheme.getUrl(authToken.token, redirectUrl));
} catch (LeanException e) {
response.sendRedirect(scheme.getErrorUrl(e, errorUrl));
}
}
}
}