// Copyright (C) 2008 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server;

import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.SignInDialog;
import com.google.gerrit.client.SignInDialog.Mode;
import com.google.gerrit.client.account.SignInResult;
import com.google.gerrit.client.openid.DiscoveryResult;
import com.google.gerrit.client.openid.OpenIdUtil;
import com.google.gerrit.client.reviewdb.Account;
import com.google.gerrit.client.reviewdb.AccountExternalId;
import com.google.gerrit.client.reviewdb.AccountExternalIdAccess;
import com.google.gerrit.client.reviewdb.ReviewDb;
import com.google.gerrit.client.rpc.Common;
import com.google.gwt.user.server.rpc.RPCServletUtils;
import com.google.gwtjsonrpc.server.JsonServlet;
import com.google.gwtjsonrpc.server.ValidToken;
import com.google.gwtjsonrpc.server.XsrfException;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.Transaction;

import com.dyuproject.openid.Constants;
import com.dyuproject.openid.DefaultDiscovery;
import com.dyuproject.openid.DiffieHellmanAssociation;
import com.dyuproject.openid.OpenIdContext;
import com.dyuproject.openid.OpenIdUser;
import com.dyuproject.openid.RelyingParty;
import com.dyuproject.openid.SimpleHttpConnector;
import com.dyuproject.openid.UrlEncodedParameterMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.GZIPOutputStream;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/** Handles the <code>/login</code> URL for web based single-sign-on. */
public class OpenIdLoginServlet extends HttpServlet {
  private static final Logger log =
      LoggerFactory.getLogger(OpenIdLoginServlet.class);
  private static final int LASTID_AGE = 365 * 24 * 60 * 60; // seconds
  private static final String AX_SCHEMA = "http://openid.net/srv/ax/1.0";
  private static final String OMODE_CANCEL = "cancel";
  private static final String GMODE_CHKCOOKIE = "gerrit.chkcookie";
  private static final String GMODE_SETCOOKIE = "gerrit.setcookie";

  private RelyingParty relyingParty;
  private GerritServer server;
  private Document pleaseSetCookieDoc;

  @Override
  public void init(final ServletConfig config) throws ServletException {
    super.init(config);

    try {
      server = GerritServer.getInstance();
    } catch (OrmException e) {
      throw new ServletException("Cannot load GerritServer", e);
    } catch (XsrfException e) {
      throw new ServletException("Cannot load GerritServer", e);
    }

    try {
      final OpenIdContext context = new OpenIdContext();
      context.setAssociation(new DiffieHellmanAssociation());
      context.setDiscovery(new DefaultDiscovery());
      context.setHttpConnector(new SimpleHttpConnector());
      relyingParty = new RelyingParty(context, new GerritOpenIdUserManager());
    } catch (Throwable e) {
      log.error("Cannot setup RelyingParty", e);
      throw new ServletException("Cannot setup RelyingParty", e);
    }

    final String scHtmlName = "com/google/gerrit/public/SetCookie.html";
    pleaseSetCookieDoc = HtmlDomUtil.parseFile(scHtmlName);
    if (pleaseSetCookieDoc == null) {
      log.error("No " + scHtmlName + " in CLASSPATH");
      throw new ServletException("No " + scHtmlName + " in CLASSPATH");
    }
  }

  @Override
  public void doGet(final HttpServletRequest req, final HttpServletResponse rsp)
      throws IOException {
    doPost(req, rsp);
  }

  @Override
  public void doPost(final HttpServletRequest req, final HttpServletResponse rsp)
      throws IOException {
    try {
      doAuth(req, rsp);
    } catch (Exception e) {
      getServletContext().log("Unexpected error during authentication", e);
      callback(req, rsp, SignInResult.CANCEL);
    }
  }

  private void doAuth(final HttpServletRequest req,
      final HttpServletResponse rsp) throws Exception {
    if (false) {
      System.out.println(req.getMethod() + " /login");
      for (final Enumeration e = req.getParameterNames(); e.hasMoreElements();) {
        final String n = (String) e.nextElement();
        for (final String v : req.getParameterValues(n)) {
          System.out.println("  " + n + "=" + v);
        }
      }
      System.out.println();
    }

    final String mode = req.getParameter(Constants.OPENID_MODE);
    if (OMODE_CANCEL.equals(mode)) {
      // Provider wants us to cancel the attempt.
      //
      callback(req, rsp, SignInResult.CANCEL);
      return;
    } else if (GMODE_CHKCOOKIE.equals(mode)) {
      modeChkSetCookie(req, rsp, true);
      return;
    } else if (GMODE_SETCOOKIE.equals(mode)) {
      modeChkSetCookie(req, rsp, false);
      return;
    }

    final OpenIdUser user;
    try {
      user = relyingParty.discover(req);
    } catch (UnknownHostException u) {
      // The remote host described in the OpenID doesn't exist, so we
      // can't try to perform discovery against it.
      //
      callback(req, rsp, SignInResult.CANCEL);
      return;
    }
    if (user == null) {
      // User isn't known, no provider is known.
      //
      callback(req, rsp, SignInResult.CANCEL);
      return;
    }

    if (user.isAssociated() && RelyingParty.isAuthResponse(req)) {
      if (!relyingParty.verifyAuth(user, req, rsp)) {
        // Failed verification... re-authenticate.
        //
        callback(req, rsp, SignInResult.CANCEL);
        return;
      }

      // Authentication was successful.
      //
      String fullname = req.getParameter("openid.sreg.fullname");
      String email = req.getParameter("openid.sreg.email");
      for (int i = 1;; i++) {
        final String nskey = "openid.ns.ext" + i;
        final String nsval = req.getParameter(nskey);
        if (nsval == null) {
          break;
        }

        final String ext = "openid.ext" + i + ".";
        if (AX_SCHEMA.equals(nsval)
            && "fetch_response".equals(req.getParameter(ext + "mode"))) {
          final String ax_fname = req.getParameter(ext + "value.fname");
          final String ax_email = req.getParameter(ext + "value.email");
          if (fullname == null && ax_fname != null) {
            fullname = ax_fname;
          }
          if (email == null && ax_email != null) {
            email = ax_email;
          }
          break;
        }
      }

      initializeAccount(req, rsp, user, fullname, email);
      return;
    }

    if (!relyingParty.getOpenIdContext().getAssociation().associate(user,
        relyingParty.getOpenIdContext())) {
      // Failed association. Try again.
      //
      callback(req, rsp, SignInResult.CANCEL);
      return;
    }

    // Authenticate user through his/her OpenID provider
    //
    final String realm = serverUrl(req);
    final UrlEncodedParameterMap retTo =
        new UrlEncodedParameterMap(req.getRequestURL().toString());
    save(retTo, req, OpenIdUtil.P_SIGNIN_CB);
    save(retTo, req, OpenIdUtil.P_SIGNIN_MODE);
    save(retTo, req, OpenIdUtil.P_REMEMBERID);
    final UrlEncodedParameterMap auth;

    auth = RelyingParty.getAuthUrlMap(user, realm, realm, retTo.toString());
    auth.put("openid.ns.ext1", AX_SCHEMA);
    final String ext1 = "openid.ext1.";
    auth.put(ext1 + "mode", "fetch_request");
    auth.put(ext1 + "type.fname", "http://example.com/schema/fullname");
    auth.put(ext1 + "type.email", "http://schema.openid.net/contact/email");
    auth.put(ext1 + "required", "email");
    auth.put(ext1 + "if_available", "fname");

    auth.put("openid.sreg.optional", "fullname,email");
    auth.put("openid.ns.sreg", "http://openid.net/extensions/sreg/1.1");

    relyingParty.getOpenIdUserManager().saveUser(user, req, rsp);
    sendJson(req, rsp, new DiscoveryResult(true, auth.getUrl(), auth), req
        .getParameter(OpenIdUtil.P_DISCOVERY_CB));
  }

  private static void save(UrlEncodedParameterMap b, HttpServletRequest r,
      String n) {
    final String v = r.getParameter(n);
    if (v != null) {
      b.put(n, v);
    }
  }

  private void initializeAccount(final HttpServletRequest req,
      final HttpServletResponse rsp, final OpenIdUser user,
      final String fullname, final String email) throws IOException {
    final SignInDialog.Mode mode = signInMode(req);
    Account account = null;
    if (user != null) {
      try {
        final ReviewDb d = Common.getSchemaFactory().open();
        try {
          switch (mode) {
            case SIGN_IN:
              account = openAccount(d, user, fullname, email);
              break;
            case LINK_IDENTIY:
              account = linkAccount(req, d, user, email);
              break;
          }
        } finally {
          d.close();
        }
      } catch (OrmException e) {
        getServletContext().log("Account lookup failed", e);
        account = null;
      }
    }

    rsp.reset();

    String tok;
    try {
      final String idstr = String.valueOf(account.getId().get());
      tok = server.getAccountToken().newToken(idstr);
    } catch (XsrfException e) {
      getServletContext().log("Account cookie signature impossible", e);
      account = null;
      tok = "";
    }

    Cookie c = new Cookie(Gerrit.ACCOUNT_COOKIE, tok);
    c.setPath(req.getContextPath() + "/");

    if (account == null) {
      if (mode == SignInDialog.Mode.SIGN_IN) {
        c.setMaxAge(0);
        rsp.addCookie(c);
      }
      callback(req, rsp, SignInResult.CANCEL);
    } else {
      c.setMaxAge(server.getSessionAge());
      rsp.addCookie(c);

      final UrlEncodedParameterMap me =
          new UrlEncodedParameterMap(req.getRequestURL().toString());
      me.put(Constants.OPENID_MODE, GMODE_CHKCOOKIE);
      me.put(Gerrit.ACCOUNT_COOKIE, tok);
      save(me, req, OpenIdUtil.P_SIGNIN_CB);
      save(me, req, OpenIdUtil.P_SIGNIN_MODE);
      if ("on".equals(req.getParameter(OpenIdUtil.P_REMEMBERID))) {
        final String ident = saveLastId(req, rsp, user.getClaimedId());
        me.put(OpenIdUtil.LASTID_COOKIE, ident);
        save(me, req, OpenIdUtil.P_REMEMBERID);
      } else {
        c = new Cookie(OpenIdUtil.LASTID_COOKIE, "");
        c.setPath(req.getContextPath() + "/");
        c.setMaxAge(0);
        rsp.addCookie(c);
      }
      rsp.sendRedirect(me.toString());
    }
  }

  private String saveLastId(final HttpServletRequest req,
      final HttpServletResponse rsp, String ident) {
    final Cookie c = new Cookie(OpenIdUtil.LASTID_COOKIE, ident);
    c.setPath(req.getContextPath() + "/");
    c.setMaxAge(LASTID_AGE);
    rsp.addCookie(c);
    return ident;
  }

  private Account openAccount(final ReviewDb db, final OpenIdUser user,
      final String fullname, final String email) throws OrmException {
    Account account;
    final AccountExternalIdAccess extAccess = db.accountExternalIds();
    AccountExternalId acctExt = lookup(extAccess, user.getClaimedId());

    if (acctExt == null && email != null
        && server.isAllowGoogleAccountUpgrade() && isGoogleAccount(user)) {
      acctExt = lookupGoogleAccount(extAccess, email);
      if (acctExt != null) {
        // Legacy user from Gerrit 1? Attach the OpenID identity.
        //
        final AccountExternalId openidExt =
            new AccountExternalId(new AccountExternalId.Key(acctExt
                .getAccountId(), user.getClaimedId()));
        extAccess.insert(Collections.singleton(openidExt));
        acctExt = openidExt;
      }
    }

    if (acctExt != null) {
      // Existing user; double check the email is current.
      //
      if (email != null && !email.equals(acctExt.getEmailAddress())) {
        acctExt.setEmailAddress(email);
      }
      acctExt.setLastUsedOn();
      extAccess.update(Collections.singleton(acctExt));
      account = Common.getAccountCache().get(acctExt.getAccountId(), db);
    } else {
      account = null;
    }

    if (account == null) {
      // New user; create an account entity for them.
      //
      final Transaction txn = db.beginTransaction();

      account = new Account(new Account.Id(db.nextAccountId()));
      account.setFullName(fullname);
      account.setPreferredEmail(email);

      acctExt =
          new AccountExternalId(new AccountExternalId.Key(account.getId(), user
              .getClaimedId()));
      acctExt.setLastUsedOn();
      acctExt.setEmailAddress(email);

      db.accounts().insert(Collections.singleton(account), txn);
      extAccess.insert(Collections.singleton(acctExt), txn);
      txn.commit();
    }
    return account;
  }

  private Account linkAccount(final HttpServletRequest req, final ReviewDb db,
      final OpenIdUser user, final String email) throws OrmException {
    final Cookie[] cookies = req.getCookies();
    if (cookies == null) {
      return null;
    }
    Account.Id me = null;
    for (final Cookie c : cookies) {
      if (Gerrit.ACCOUNT_COOKIE.equals(c.getName())) {
        try {
          final ValidToken tok =
              server.getAccountToken().checkToken(c.getValue(), null);
          if (tok == null) {
            return null;
          }
          me = Account.Id.parse(tok.getData());
          break;
        } catch (XsrfException e) {
          return null;
        } catch (RuntimeException e) {
          return null;
        }
      }
    }
    if (me == null) {
      return null;
    }

    final Account account = Common.getAccountCache().get(me, db);
    if (account == null) {
      return null;
    }

    final AccountExternalId.Key idKey =
        new AccountExternalId.Key(account.getId(), user.getClaimedId());
    AccountExternalId id = db.accountExternalIds().get(idKey);
    if (id == null) {
      id = new AccountExternalId(idKey);
      id.setLastUsedOn();
      id.setEmailAddress(email);
      db.accountExternalIds().insert(Collections.singleton(id));
      Common.getGroupCache().invalidate(account.getId());
    } else {
      if (email != null && !email.equals(id.getEmailAddress())) {
        id.setEmailAddress(email);
      }
      id.setLastUsedOn();
      db.accountExternalIds().update(Collections.singleton(id));
    }
    return account;
  }

  private static Mode signInMode(final HttpServletRequest req) {
    final String p = req.getParameter(OpenIdUtil.P_SIGNIN_MODE);
    if (p == null || p.length() == 0) {
      return SignInDialog.Mode.SIGN_IN;
    }
    try {
      return SignInDialog.Mode.valueOf(p);
    } catch (RuntimeException e) {
      return SignInDialog.Mode.SIGN_IN;
    }
  }

  private static AccountExternalId lookup(
      final AccountExternalIdAccess extAccess, final String id)
      throws OrmException {
    final List<AccountExternalId> extRes = extAccess.byExternal(id).toList();
    switch (extRes.size()) {
      case 0:
        return null;
      case 1:
        return extRes.get(0);
      default:
        throw new OrmException("More than one account matches: " + id);
    }
  }

  private static boolean isGoogleAccount(final OpenIdUser user) {
    return user.getClaimedId().startsWith(OpenIdUtil.URL_GOOGLE + "?");
  }

  private static AccountExternalId lookupGoogleAccount(
      final AccountExternalIdAccess extAccess, final String email)
      throws OrmException {
    // We may have multiple records which match the email address, but
    // all under the same account. This happens when the user does a
    // login through different server hostnames, as Google issues
    // unique OpenID tokens per server.
    //
    // Match to an existing account only if there is exactly one record
    // for this email using the generic Google identity.
    //
    final List<AccountExternalId> m = new ArrayList<AccountExternalId>();
    for (final AccountExternalId e : extAccess.byEmailAddress(email)) {
      if (e.getExternalId().equals("Google Account " + email)) {
        m.add(e);
      }
    }
    return m.size() == 1 ? m.get(0) : null;
  }

  private void modeChkSetCookie(final HttpServletRequest req,
      final HttpServletResponse rsp, final boolean isCheck) throws IOException {
    final String exp = req.getParameter(Gerrit.ACCOUNT_COOKIE);
    final ValidToken chk;
    try {
      chk = server.getAccountToken().checkToken(exp, null);
      if (chk == null) {
        callback(req, rsp, SignInResult.CANCEL);
        return;
      }
    } catch (XsrfException e) {
      getServletContext().log("Cannot validate cookie token", e);
      callback(req, rsp, SignInResult.CANCEL);
      return;
    }

    final Account.Id id;
    try {
      id = new Account.Id(Integer.parseInt(chk.getData()));
    } catch (NumberFormatException e) {
      callback(req, rsp, SignInResult.CANCEL);
      return;
    }

    final String act = getCookie(req, Gerrit.ACCOUNT_COOKIE);
    if (isCheck && !exp.equals(act)) {
      // Cookie won't set without "user interaction" (thanks Safari). Lets
      // send an HTML page to the browser and ask the user to click to let
      // us set the cookie.
      //
      sendSetCookieHtml(req, rsp, exp);
      return;
    }

    Cookie c = new Cookie(Gerrit.ACCOUNT_COOKIE, exp);
    c.setPath(req.getContextPath() + "/");
    c.setMaxAge(server.getSessionAge());
    rsp.addCookie(c);

    if ("on".equals(req.getParameter(OpenIdUtil.P_REMEMBERID))) {
      saveLastId(req, rsp, req.getParameter(OpenIdUtil.LASTID_COOKIE));
    } else {
      c = new Cookie(OpenIdUtil.LASTID_COOKIE, "");
      c.setPath(req.getContextPath() + "/");
      c.setMaxAge(0);
      rsp.addCookie(c);
    }
    callback(req, rsp, new SignInResult(SignInResult.Status.SUCCESS));
  }

  private void sendSetCookieHtml(final HttpServletRequest req,
      final HttpServletResponse rsp, final String exp) throws IOException {
    final Document doc = HtmlDomUtil.clone(pleaseSetCookieDoc);
    final Element set_form = HtmlDomUtil.find(doc, "set_form");
    set_form.setAttribute("action", req.getRequestURL().toString());
    HtmlDomUtil.addHidden(set_form, Constants.OPENID_MODE, GMODE_SETCOOKIE);
    HtmlDomUtil.addHidden(set_form, Gerrit.ACCOUNT_COOKIE, exp);
    save(set_form, req, OpenIdUtil.LASTID_COOKIE);
    save(set_form, req, OpenIdUtil.P_REMEMBERID);
    save(set_form, req, OpenIdUtil.P_SIGNIN_CB);
    save(set_form, req, OpenIdUtil.P_SIGNIN_MODE);
    sendHtml(req, rsp, HtmlDomUtil.toString(doc));
  }

  private static void save(Element f, HttpServletRequest r, String n) {
    final String v = r.getParameter(n);
    if (v != null) {
      HtmlDomUtil.addHidden(f, n, v);
    }
  }

  private static String getCookie(final HttpServletRequest req,
      final String name) {
    final Cookie[] allCookies = req.getCookies();
    if (allCookies != null) {
      for (final Cookie c : allCookies) {
        if (name.equals(c.getName())) {
          return c.getValue();
        }
      }
    }
    return null;
  }

  private void callback(final HttpServletRequest req,
      final HttpServletResponse rsp, final SignInResult result)
      throws IOException {
    final String dcb = req.getParameter(OpenIdUtil.P_DISCOVERY_CB);
    if (dcb != null) {
      // We're in the middle of a discovery request; we need to use
      // the discovery request callback and not the sign in callback.
      //
      sendJson(req, rsp, new DiscoveryResult(false), dcb);
      return;
    }

    // We're not in an OpenID transaction so try to clear out the
    // OpenID management cookie.
    //
    relyingParty.getOpenIdUserManager().invalidate(req, rsp);

    final String cb = req.getParameter(OpenIdUtil.P_SIGNIN_CB);
    if (cb != null && cb.startsWith("history:")) {
      final StringBuffer rdr = req.getRequestURL();
      rdr.setLength(rdr.lastIndexOf("/"));
      rdr.append("/Gerrit");
      rdr.append('#');
      rdr.append(cb.substring("history:".length()));
      rsp.sendRedirect(rdr.toString());
      return;
    }
    sendJson(req, rsp, result, cb);
  }

  private void sendJson(final HttpServletRequest req,
      final HttpServletResponse rsp, final Object result, final String cb)
      throws IOException {
    final StringWriter body = new StringWriter();
    body.write("<html>");
    body.append("<body>");
    if (JsonServlet.SAFE_CALLBACK.matcher(cb).matches()) {
      body.write("<script><!--\n");
      body.write(cb);
      body.write("(");
      JsonServlet.defaultGsonBuilder().create().toJson(result, body);
      body.write(");\n");
      body.write("// -->\n");
      body.write("</script>");
      body.write("<p>Loading ...</p>");
    } else {
      body.append("Unsafe JSON callback requested; refusing to execute it.");
    }
    body.append("</body>");
    body.write("</html>");
    sendHtml(req, rsp, body.toString());
  }

  private void sendHtml(final HttpServletRequest req,
      final HttpServletResponse rsp, final String bodystr) throws IOException {
    final byte[] raw = bodystr.getBytes(HtmlDomUtil.ENC);
    final byte[] tosend;
    if (RPCServletUtils.acceptsGzipEncoding(req)) {
      rsp.setHeader("Content-Encoding", "gzip");
      final ByteArrayOutputStream compressed = new ByteArrayOutputStream();
      final GZIPOutputStream gz = new GZIPOutputStream(compressed);
      gz.write(raw);
      gz.finish();
      gz.flush();
      tosend = compressed.toByteArray();
    } else {
      tosend = raw;
    }

    rsp.setCharacterEncoding(HtmlDomUtil.ENC);
    rsp.setContentType("text/html");
    rsp.setHeader("Expires", "Fri, 01 Jan 1980 00:00:00 GMT");
    rsp.setHeader("Pragma", "no-cache");
    rsp.setHeader("Cache-Control", "no-cache, must-revalidate");
    rsp.setContentLength(tosend.length);
    final OutputStream out = rsp.getOutputStream();
    try {
      out.write(tosend);
    } finally {
      out.close();
    }
  }

  static String serverUrl(final HttpServletRequest req) {
    // Assume this servlet is in the context with a simple name like "login"
    // and we were accessed without any path info. Clipping the last part of
    // the name from the URL should generate the web application's root path.
    //
    final String uri = req.getRequestURL().toString();
    final int s = uri.lastIndexOf('/');
    return s >= 0 ? uri.substring(0, s + 1) : uri;
  }
}
