// Copyright 2011 Google Inc. All Rights Reserved.
//
// 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.enterprise.adaptor;

import com.google.enterprise.apis.client.GsaClient;
import com.google.gdata.util.AuthenticationException;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;

import java.io.IOException;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Require GSA-Administrator authentication before allowing requests.
 */
class AdministratorSecurityHandler implements HttpHandler {
  private static final Logger log
      = Logger.getLogger(AdministratorSecurityHandler.class.getName());
  /** Key used to store the fact the user has been authenticated. */
  private static final String SESSION_ATTR_NAME = "dashboard-authned";
  /** Page to display when prompting for user credentials. */
  private static final String LOGIN_PAGE = "resources/login.html";
  /** Page to display when the user credentials are invalid. */
  private static final String LOGIN_FAILED_PAGE = "resources/login-failed.html";
  /** Page to display when the user credentials were not able to be verified. */
  private static final String LOGIN_INDETERMINATE_PAGE
      = "resources/login-indeterminate.html";

  /** Wrapped handler, for when the user is authenticated. */
  private final HttpHandler handler;
  /** Manager that handles keeping track of authenticated users. */
  private final SessionManager<HttpExchange> sessionManager;
  /** Trusted entity for performing authentication of user credentials. */
  private final AuthnClient authnClient;

  AdministratorSecurityHandler(HttpHandler handler,
      SessionManager<HttpExchange> sessionManager, AuthnClient authnClient) {
    this.handler = handler;
    this.sessionManager = sessionManager;
    this.authnClient = authnClient;
  }

  public AdministratorSecurityHandler(HttpHandler handler,
      SessionManager<HttpExchange> sessionManager, String gsaHostname,
      boolean useHttps) {
    this(handler, sessionManager, new GsaAuthnClient(gsaHostname, useHttps));
  }

  private void meteredHandle(HttpExchange ex) throws IOException {
    String pageToDisplay = LOGIN_PAGE;

    if ("POST".equals(ex.getRequestMethod())) {
      AuthzStatus authn = validUsernameAndPassword(ex);
      if (authn == AuthzStatus.PERMIT) {
        // Need the client to access the page via GET since the only reason the
        // request method was POST was because of submitting our login form.
        HttpExchanges.sendRedirect(ex, HttpExchanges.getRequestUri(ex));
        return;
      } else if (authn == AuthzStatus.INDETERMINATE) {
        pageToDisplay = LOGIN_INDETERMINATE_PAGE;
      } else {
        pageToDisplay = LOGIN_FAILED_PAGE;
      }
    }

    // Send login page.
    InputStream is = this.getClass().getResourceAsStream(pageToDisplay);
    if (is == null) {
      throw new IOException("Could not load login page");
    }
    byte[] page;
    try {
      page = IOHelper.readInputStreamToByteArray(is);
    } finally {
      is.close();
    }
    HttpExchanges.respond(
        ex, HttpURLConnection.HTTP_FORBIDDEN, "text/html", page);
  }

  /**
   * Check POST data to see if the user can be authenticated by the GSA. This
   * abuses the {@code AuthzStatus} class, using it for Authn, but it was
   * convenient.
   *
   * @return {@code PERMIT} if user authenticated, {@code DENY} if invalid
   *   credentials, and {@code INDETERMINATE} otherwise
   */
  private AuthzStatus validUsernameAndPassword(HttpExchange ex)
      throws IOException {
    log.fine("Not already authenticated");
    // Check to see if they provided a username and password.
    String username = null;
    String password = null;
    try {
      String request = IOHelper.readInputStreamToString(
          ex.getRequestBody(), Charset.forName("US-ASCII"));
      for (String pair : request.split("&")) {
        String[] splitPair = pair.split("=", 2);
        if (splitPair.length != 2) {
          continue;
        }
        splitPair[0] = URLDecoder.decode(splitPair[0], "UTF-8");
        splitPair[1] = URLDecoder.decode(splitPair[1], "UTF-8");
        if ("username".equals(splitPair[0])) {
          username = splitPair[1];
        } else if ("password".equals(splitPair[0])) {
          password = splitPair[1];
        }
        if (username != null && password != null) {
          break;
        }
      }
    } catch (Exception e) {
      log.log(Level.FINE, "Processing POST caused exception", e);
      // Assume that they were POSTing to a different page, since they didn't
      // provide the expected input.
      username = null;
      password = null;
    }
    if (username == null || password == null) {
      log.fine("Username or password is null. Not authenticated");
      // Must not have been from our login page.
      return AuthzStatus.INDETERMINATE;
    }

    // Check to see if provided username and password are valid.
    AuthzStatus result = authnClient.authn(username, password);
    if (result == AuthzStatus.INDETERMINATE) {
      log.fine("Failed communicating with the GSA");
      return result;
    } else if (result != AuthzStatus.PERMIT) {
      log.fine("GSA login was not successful");
      return result;
    }

    // We have a winner. Store in the session that they are a valid user.
    log.fine("GSA login successful");
    Session session = sessionManager.getSession(ex);
    session.setAttribute(SESSION_ATTR_NAME, true);
    return AuthzStatus.PERMIT;
  }

  @Override
  public void handle(HttpExchange ex) throws IOException {
    // Clickjacking defence.
    ex.getResponseHeaders().set("X-Frame-Options", "deny");

    // This comment is no longer true and exists from before logging was done in
    // a filter. TODO(ejona): split into a separate filter and handler.
    // Perform fast-path checking here to prevent double-logging most requests.
    Session session = sessionManager.getSession(ex, false);
    if (session != null && session.getAttribute(SESSION_ATTR_NAME) != null) {
      handler.handle(ex);
      return;
    }
    meteredHandle(ex);
  }

  interface AuthnClient {
    public AuthzStatus authn(String username, String password);
  }

  static class GsaAuthnClient implements AuthnClient {
    private String gsaHostname;
    private boolean useHttps;

    public GsaAuthnClient(String gsaHostname, boolean useHttps) {
      this.gsaHostname = gsaHostname;
      this.useHttps = useHttps;
    }

    @Override
    public AuthzStatus authn(String username, String password) {
      String protocol = useHttps ? "https" : "http";
      int port = useHttps ? 8443 : 8000;
      try {
        new GsaClient(protocol, gsaHostname, port, username, password);
      } catch (AuthenticationException e) {
        log.log(Level.FINE, "AuthenticationException", e);
        if (e.getCause() instanceof ConnectException) {
          return AuthzStatus.INDETERMINATE;
        } else if (e.getCause() instanceof UnknownHostException) {
          return AuthzStatus.INDETERMINATE;
        }
        return AuthzStatus.DENY;
      }
      return AuthzStatus.PERMIT;
    }
  }
}
