Package maqetta.server.orion.user

Source Code of maqetta.server.orion.user.LoginFixUpFilter$RequestWrapper

/*******************************************************************************
* Copyright (c) 2010, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package maqetta.server.orion.user;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.orion.internal.server.servlets.ProtocolConstants;
import org.eclipse.orion.server.servlets.OrionServlet;
import org.eclipse.orion.server.useradmin.IOrionCredentialsService;
import org.eclipse.orion.server.useradmin.User;
import org.eclipse.orion.server.useradmin.UserConstants;
import org.eclipse.orion.server.useradmin.UserServiceHelper;
import org.json.JSONException;
import org.json.JSONObject;

// POST /users/                 creates a new user
// POST /login/form             login user
// POST /useremailconfirmation  password reset
//
// Intercepts authentication requests and updates the request parameters for use by Orion.
//
// The Orion code expects the following parameters when registering a new user or handling login:
//        login: a unique, alphanumeric username
//        password:
//        email: (optional, registration only) unique email
//        name: (optional, registration only) display name
//
// For Maqetta, we don't want to use 2 different unique identifiers ("login" and "email"). Plus,
// we have existing users whose "login" is an email and have no value for "email".  Maqetta requests
// will come with the following parameters (as of M10):
//        email: unique email
//        password:
//        name: (optional, registration only) display name
//
// Here, we intercept these requests and properly set `login` for use by the Orion code.
//
// Also, if the 'name' parameter is not specified, we default to using the value of 'email'.  This
// differs from Orion, which sets the former to the value of 'login'.  In our case, that would
// result in 'name' containing a seemingly random alphanumeric sequence, which isn't very useful.
//
// Password reset for pre-M10 accounts won't work, since the email is stored in the 'login' value of
// the user's account, and the 'email' is blank. We fix that here.

@SuppressWarnings("restriction")
public class LoginFixUpFilter implements Filter {

  public static final String USERS_SERVLET_ALIAS = "/users";
  public static final String LOGIN_SERVLET_ALIAS = "/login";
  public static final String EMAILCONF_SERVLET_ALIAS = "/useremailconfirmation";

  static final private Logger theLogger = Logger.getLogger(LoginFixUpFilter.class.getName());

  public void init(FilterConfig filterConfig) throws ServletException {
  }

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;

    if ("POST".equals(httpRequest.getMethod())) { //$NON-NLS-1$
      String servletPath = httpRequest.getServletPath();
      String pathInfo = httpRequest.getPathInfo();
      if (servletPath.equals(USERS_SERVLET_ALIAS) && pathInfo == null) {
        if (handleRegistration(httpRequest, httpResponse, chain)) {
          return;
        }
      } else if (servletPath.equals(LOGIN_SERVLET_ALIAS) && pathInfo.equals("/form")) { //$NON-NLS-1$
        if (handleLogin(httpRequest, httpResponse, chain)) {
          return;
        }
      } else if (servletPath.equals(EMAILCONF_SERVLET_ALIAS) && pathInfo == null) {
        handleEmailConfig(httpRequest, httpResponse, chain);
        return;
      }
    }

    chain.doFilter(request, response);
  }

  public void destroy() {
  }

  private boolean handleRegistration(HttpServletRequest request, HttpServletResponse response,
      FilterChain chain) throws IOException, ServletException {
    String login = request.getParameter(UserConstants.KEY_LOGIN);
    if (login != null && login.length() > 0) {
      return false;
    }

    String email = request.getParameter(UserConstants.KEY_EMAIL);
    String name = request.getParameter(ProtocolConstants.KEY_NAME);

    IOrionCredentialsService userAdmin = getUserAdmin();

    // modify request with generated `login` parameter
    RequestWrapper modifiedRequest = new RequestWrapper(request);
    modifiedRequest.setParameter(UserConstants.KEY_LOGIN, generateUserId(userAdmin, email));

    // check if 'name' parameter is set
    if (name == null || name.length() == 0) {
      // If 'name' isn't set, default to 'email'. This differs from Orion, which defaults
      // to using 'login'.
      modifiedRequest.setParameter(ProtocolConstants.KEY_NAME, email);
    }

    // continue with filter chain
    chain.doFilter(modifiedRequest, response);
    return true;
  }

  private boolean handleLogin(HttpServletRequest request, HttpServletResponse response,
      FilterChain chain) throws IOException, ServletException {
    String login = request.getParameter(UserConstants.KEY_LOGIN);
    if (login != null && login.length() > 0) {
      return false;
    }

    String email = request.getParameter(UserConstants.KEY_EMAIL);
    IOrionCredentialsService userAdmin = getUserAdmin();
    User user = userAdmin.getUser(UserConstants.KEY_EMAIL, email);
    if (user == null) {
      // users registered before M10 will have an email for "login" and no value for "email"
      user = userAdmin.getUser(UserConstants.KEY_LOGIN, email);
      if (user != null) {
        user = fixOldUser(userAdmin, user);
      }

      if (user == null) {  // also checks for failure from `fixOldUser()`
        theLogger.finest("User object not found for " + email +
            ". Perhaps that user isn't registered yet.");
        return false;
      }
    }

    // modify request to add correct `login` parameter
    RequestWrapper modifiedRequest = new RequestWrapper(request);
    modifiedRequest.setParameter(UserConstants.KEY_LOGIN, user.getLogin());

    // continue with filter chain
    chain.doFilter(modifiedRequest, response);
    return true;
  }

  private void handleEmailConfig(HttpServletRequest request, HttpServletResponse response,
      FilterChain chain) throws IOException, ServletException {
    JSONObject data = null;
    try {
      data = OrionServlet.readJSONRequest(request);
      String email = data.getString(UserConstants.KEY_EMAIL);
      String login = data.getString(UserConstants.KEY_LOGIN);
     
      if (login != null && login.length() > 0) {
        return;
      }

      IOrionCredentialsService userAdmin = getUserAdmin();
      User user = userAdmin.getUser(UserConstants.KEY_EMAIL, email);
      if (user != null) {
        // a user exists with this email; let Orion handle the rest
        return;
      }

      // Pre-M10 accounts will store the email as 'login', while 'email' will be blank. Check
      // for that here.
      user = userAdmin.getUser(UserConstants.KEY_LOGIN, email);
      if (user == null) {
        // no such user; continue on to Orion
        return;
      }

      // let's fix up the user data now, so he/she has an 'email' value
      user = fixOldUser(userAdmin, user);
    } catch (JSONException e) {
      theLogger.log(Level.SEVERE, "Could not parse json request", e);
      return;
    } finally {
      // POST data can only be read once, which we did above.  Create a new request, set the
      // data and pass that on.
      RequestWrapper modifiedRequest = new RequestWrapper(request);
      modifiedRequest.setData(data != null ? data.toString() : "");

      // continue with filter chain
      chain.doFilter(modifiedRequest, response);
    }
  }

  private IOrionCredentialsService getUserAdmin() {
    return UserServiceHelper.getDefault().getUserStore();
  }

  public static String generateUserId(IOrionCredentialsService userAdmin, String email) {
    // Try to use the first part of user's email address, removing common non-alphanumeric
    // characters.
    String login = email.split("@", 2)[0];
    login = login.replaceAll("[.\\-_+]", "");
    if (login.length() > USERNAME_MAX_LENGTH) {
      login = login.substring(0, USERNAME_MAX_LENGTH);
    }

    // if it's still a valid login, then return one that doesn't collide with existing one
    if (validateLogin(login)) {
      int counter = 0;
      String candidate = login;
      while (userAdmin.getUser(UserConstants.KEY_LOGIN, candidate) != null) {
        candidate = login + ++counter;
      }
      return candidate;
    }

    // login still has some validation issues; just create a "random" login name
    int randlen = new Random().nextInt(USERNAME_MAX_LENGTH - USERNAME_MIN_LENGTH + 1) + USERNAME_MIN_LENGTH;
    do {
      login = UUID.randomUUID().toString().replaceAll("-","").substring(0, randlen);
    } while (userAdmin.getUser(UserConstants.KEY_LOGIN, login) != null);
    return login;
  }

  public User fixOldUser(IOrionCredentialsService userAdmin, User user) {
    // get old values
    String email = user.getLogin();
    String name = user.getName();
    String uid = user.getUid();

    // set new values
    user.setLogin(generateUserId(userAdmin, email));
    user.setEmail(email);
    if (name.length() == 0) {
      // default 'name' to same value as 'email'
      user.setName(email);
    }

    // update
    IStatus status = userAdmin.updateUser(uid, user)// errors logged by Orion
    if (!status.isOK()) {
      return null;
    }

    // Set email as confirmed -- pre-M10 users' emails were confirmed by Maqetta, so
    // should be fine setting it here for Orion.
    // Need to do a seperate updateUser() call unfortunately, since we changed the email above.
    user.confirmEmail();
    userAdmin.updateUser(uid, user)// errors logged by Orion
    if (!status.isOK()) {
      return null;
    }

    return user;
  }

  //============================================================================================//
  //  The following are copied from Orion's UserHandlerV1.java
  //============================================================================================//
  /**
   * The minimum length of a username.
   */
  private static final int USERNAME_MIN_LENGTH = 3;
  /**
   * The maximum length of a username.
   */
  private static final int USERNAME_MAX_LENGTH = 20;
  /**
   * Validates that the provided login is valid. Login must consistent of alphanumeric characters only for now.
   * @return <code>null</code> if the login is valid, and otherwise a string message stating the reason
   * why it is not valid.
   */
  private static boolean /*String*/ validateLogin(String login) {
    if (login == null || login.length() == 0)
      return false /*"User login not specified"*/;
    int length = login.length();
    if (length < USERNAME_MIN_LENGTH)
      return false /*NLS.bind("Username must contain at least {0} characters", USERNAME_MIN_LENGTH)*/;
    if (length > USERNAME_MAX_LENGTH)
      return false /*NLS.bind("Username must contain no more than {0} characters", USERNAME_MAX_LENGTH)*/;
    if (login.equals("ultramegatron"))
      return false /*"Nice try, Mark"*/;

    for (int i = 0; i < length; i++) {
      if (!Character.isLetterOrDigit(login.charAt(i)))
        return false /*NLS.bind("Username {0} contains invalid character ''{1}''", login, login.charAt(i))*/;
    }
    return true /*null*/;
  }

  //============================================================================================//
 
  class RequestWrapper extends HttpServletRequestWrapper {

    private HashMap<String, String[]> updatedMap = new HashMap<String, String[]>();
    private String data = null;

    public RequestWrapper(HttpServletRequest request) {
      super(request);
     
      updatedMap.putAll(request.getParameterMap());
    }

    /* (non-Javadoc)
     * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String)
     */
    @Override
    public String getParameter(String name) {
      String[] values = updatedMap.get(name);
      if (values != null && values.length > 0) {
        return values[0];
      }
      return null;
    }

    /* (non-Javadoc)
     * @see javax.servlet.ServletRequestWrapper#getParameterMap()
     */
    @Override
    public Map<String, String[]> getParameterMap() {
      return updatedMap;
    }

    /* (non-Javadoc)
     * @see javax.servlet.ServletRequestWrapper#getParameterNames()
     */
    @Override
    public Enumeration<String> getParameterNames() {
      return Collections.enumeration(updatedMap.keySet());
    }

    /* (non-Javadoc)
     * @see javax.servlet.ServletRequestWrapper#getParameterValues(java.lang.String)
     */
    @Override
    public String[] getParameterValues(String name) {
      return updatedMap.get(name);
    }

    /* (non-Javadoc)
     * @see javax.servlet.ServletRequestWrapper#getInputStream()
     */
    @Override
    public ServletInputStream getInputStream() throws IOException {
      if (data == null) {
        return super.getInputStream();
      }

      String charset = getRequest().getCharacterEncoding();
      if (charset == null) {
        charset = Charset.defaultCharset().name();
      }
      byte[] bytes = data.getBytes(charset);
      final ByteArrayInputStream in = new ByteArrayInputStream(bytes);

      return new ServletInputStream() {
       
        @Override
        public int read() throws IOException {
          return in.read();
        }
      };
    }

    /* (non-Javadoc)
     * @see javax.servlet.ServletRequestWrapper#getReader()
     */
    @Override
    public BufferedReader getReader() throws IOException {
      if (data == null) {
        return super.getReader();
      }
      return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    public void setParameter(String name, String value) {
      String[] values = { value };
      updatedMap.put(name, values);
    }
   
    public void setData(String newData) {
      data  = newData;
    }

  }
}
TOP

Related Classes of maqetta.server.orion.user.LoginFixUpFilter$RequestWrapper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.