Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * JBoss, a division of Red Hat
   * Copyright 2013, Red Hat Middleware, LLC, and individual
   * contributors as indicated by the @authors tag. See the
   * copyright.txt in the distribution for a full listing of
   * individual contributors.
   *
   * This is free software; you can redistribute it and/or modify it
   * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software 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
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
 
 package org.gatein.web.security.impersonation;
 
 
 import java.util.List;
 import java.util.Map;

Servlet, which handles impersonation and impersonalization (de-impersonation) of users

Author(s):
Marek Posolda
 
 public class ImpersonationServlet extends AbstractHttpServlet {

    
Request parameter to track if we want to start new impersonation session or stop existing impersonation session
 
     public static final String PARAM_ACTION = "_impersonationAction";
     public static final String PARAM_ACTION_START_IMPERSONATION = "startImpersonation";
     public static final String PARAM_ACTION_STOP_IMPERSONATION = "stopImpersonation";

    
Request parameter with name of user, who will be impersonated
 
     public static final String PARAM_USERNAME = "_impersonationUsername";

    
Request parameter where is stored URI, which will be used after impersonation session will be finished The point is that admin user will be redirected to same page (navigation node) from which original impersonation session was started
 
     public static final String PARAM_RETURN_IMPERSONATION_URI = "_returnImpersonationURI";

    
Session attribute where return impersonation URI will be saved
 
     public static final String ATTR_RETURN_IMPERSONATION_URI = "_returnImpersonationURI";

    
Impersonation suffix (Actually path of this servlet)
 
     public static final String IMPERSONATE_URL_SUFIX = "/impersonate";

    
Session attribute, which will be used to backup existing session of root user
 
     private static final String BACKUP_ATTR = "_impersonation.bck";
 
     private static final Logger log = LoggerFactory.getLogger(ImpersonationServlet.class);
 
     @Override
     protected void doGet(HttpServletRequest reqHttpServletResponse respthrows ServletExceptionIOException {
         try {
             // We set the character encoding now to UTF-8 before obtaining parameters
             req.setCharacterEncoding("UTF-8");
         } catch (UnsupportedEncodingException e) {
             .error("Encoding not supported"e);
         }
 
         String action = req.getParameter();
         if (action == null) {
             .error("Parameter '" +  + "' not provided");
            resp.sendError(.);
        } else if (.equals(action)) {
            startImpersonation(reqresp);
        } else if (.equals(action)) {
            stopImpersonation(reqresp);
        } else {
            .error("Unknown impersonation action: " + action);
            resp.sendError(.);
        }
    }
    protected void startImpersonation(HttpServletRequest reqHttpServletResponse respthrows ServletExceptionIOException {
        // Obtain username
        String usernameToImpersonate = req.getParameter();
        if (usernameToImpersonate == null) {
            .error("Parameter '" +  + "' not provided");
            resp.sendError(.);
            return;
        }
        // Find user to impersonate
        User userToImpersonate;
        try {
            userToImpersonate = orgService.getUserHandler().findUserByName(usernameToImpersonate.);
        } catch (Exception e) {
            throw new ServletException(e);
        }
        if (userToImpersonate == null) {
            .error("User '" + usernameToImpersonate + "' not found!");
            resp.sendError(.);
            return;
        }
        ConversationState currentConversationState = ConversationState.getCurrent();
        Identity currentIdentity = currentConversationState.getIdentity();
        if (currentIdentity instanceof ImpersonatedIdentity) {
            .error("Already impersonated as identity: " + currentIdentity);
            resp.sendError(.);
            return;
        }
        if (!checkPermission(userToImpersonate)) {
            .error("Current user represented by identity " + currentIdentity.getUserId() + " doesn't have permission to impersonate as "
                    + userToImpersonate);
            resp.sendError(.);
            return;
        }
        .debug("Going to impersonate as user: " + usernameToImpersonate);
        // Backup and clear current HTTP session
        backupAndClearCurrentSession(req);
        // Obtain URI where we need to redirect after finish impersonation session. Save it to current HTTP session
        String returnImpersonationURI = req.getParameter();
        if (returnImpersonationURI == null) {
            returnImpersonationURI = req.getContextPath();
        }
        req.getSession().setAttribute(returnImpersonationURI);
        if (.isTraceEnabled()) {
            .trace("Saved URI " + returnImpersonationURI + " which will be used after finish of impersonation");
        }
        // Real impersonation done here
        boolean success = impersonate(reqcurrentConversationStateusernameToImpersonate);
        if (success) {
            // Redirect to portal for now
            resp.sendRedirect(req.getContextPath());
        } else {
        }
    }


    
Check if current user has permission to impersonate as user 'userToImpersonate'

Parameters:
userToImpersonate user to check
Returns:
true if current user has permission to impersonate as user 'userToImpersonate'
    protected boolean checkPermission(User userToImpersonate) {
        UserACL userACL = (UserACL)getContainer().getComponentInstanceOfType(UserACL.class);
        return userACL.hasImpersonateUserPermission(userToImpersonate);
    }


    
Backup all session attributes of admin user as we will have new session for "impersonated" user

Parameters:
req http servlet request
    protected void backupAndClearCurrentSession(HttpServletRequest req) {
        HttpSession session = req.getSession(false);
        if (session != null) {
            String sessionId = session.getId();
            // Backup attributes in sessions of portal and all portlet applications
            ServletContainerFactory.getServletContainer().visit(new SessionTaskVisitor(sessionIdnew SessionTask(){
                @Override
                public boolean executeTask(HttpSession session) {
                    if (.isTraceEnabled()) {
                        .trace("Starting with backup attributes for context: " + session.getServletContext().getContextPath());
                    }
                    // Create a copy just to make sure that attrNames is transient
                    List<StringattrNames = offlineCopy(session.getAttributeNames());
                    Map<StringObjectbackup = new HashMap<StringObject>();
                    for (String attrName : attrNames) {
                        Object attrValue = session.getAttribute(attrName);
                        session.removeAttribute(attrName);
                        backup.put(attrNameattrValue);
                        if (.isTraceEnabled()) {
                            .trace("Finished backup of attribute: " + attrName);
                        }
                    }
                    session.setAttribute(backup);
                    return true;
                }
            }));
        }
    }

    
Start impersonation session and update ConversationRegistry with new impersonated Identity

Parameters:
req servlet request
currentConvState current Conversation State. It will be wrapped inside impersonated identity, so we can later restore it
usernameToImpersonate
Returns:
true if impersonation was successful
    protected boolean impersonate(HttpServletRequest reqConversationState currentConvStateString usernameToImpersonate) {
        // Create new identity for user, who will be impersonated
        Identity newIdentity = createIdentity(usernameToImpersonate);
        if (newIdentity == null) {
            return false;
        }
        ImpersonatedIdentity impersonatedIdentity = new ImpersonatedIdentity(newIdentitycurrentConvState);
        // Create new entry to ConversationState
        .debug("Set ConversationState with current session. Admin user "
                + impersonatedIdentity.getParentConversationState().getIdentity().getUserId()
                + " will use identity of user " + impersonatedIdentity.getUserId());
        ConversationState impersonatedConversationState = new ConversationState(impersonatedIdentity);
        registerConversationState(reqimpersonatedConversationState);
        return true;
    }


    
Stop impersonation session and restore previous Conversation State

Parameters:
req servlet request
resp servlet response
    protected void stopImpersonation(HttpServletRequest reqHttpServletResponse respthrows IOException {
        Identity currentIdentity = ConversationState.getCurrent().getIdentity();
        if (!(currentIdentity instanceof ImpersonatedIdentity)) {
            .error("Can't stop impersonation session. Current identity is not instance of Impersonated Identity! Current identity: " + currentIdentity);
            resp.sendError(.);
            return;
        }
        ImpersonatedIdentity impersonatedIdentity = (ImpersonatedIdentity)currentIdentity;
        .debug("Cancel impersonation session. Impersonated user was: " + impersonatedIdentity.getUserId()
                + ", Admin user is: " + impersonatedIdentity.getParentConversationState().getIdentity().getUserId());
        // Restore old conversation state
        restoreConversationState(reqimpersonatedIdentity);
        // Restore return URI from session
        String returnURI = getReturnURI(req);
        // Restore session attributes of root user
        restoreOldSessionAttributes(req);
        if (.isTraceEnabled()) {
            .trace("Impersonation finished. Redirecting to " + returnURI);
        }
        resp.sendRedirect(returnURI);
    }
    protected void restoreConversationState(HttpServletRequest reqImpersonatedIdentity impersonatedIdentity) {
        ConversationState adminConvState = impersonatedIdentity.getParentConversationState();
        registerConversationState(reqadminConvState);
        // Possibly restore identity if it's not available anymore in IdentityRegistry. This could happen during parallel logout of admin user from another session
        String adminUsername = adminConvState.getIdentity().getUserId();
        Identity adminIdentity = identityRegistry.getIdentity(adminUsername);
        if (adminIdentity == null) {
            .debug("Restore of identity of user " + adminUsername + " in IdentityRegistry");
            adminIdentity = createIdentity(adminUsername);
            identityRegistry.register(adminIdentity);
        }
    }
    protected void restoreOldSessionAttributes(HttpServletRequest req) {
        HttpSession session = req.getSession(false);
        if (session != null) {
            String sessionId = session.getId();
            // Restore attributes in sessions of portal and all portlet applications
            ServletContainerFactory.getServletContainer().visit(new SessionTaskVisitor(sessionIdnew SessionTask(){
                @Override
                public boolean executeTask(HttpSession session) {
                    if (.isTraceEnabled()) {
                        .trace("Starting with restoring attributes for context: " + session.getServletContext().getContextPath());
                    }
                    // Retrieve backup of previous attributes
                    Map<StringObjectbackup = (Map<StringObject>)session.getAttribute();
                    // Iteration 1 -- Remove all session attributes of current (impersonated) user.
                    List<StringattrNames = offlineCopy(session.getAttributeNames());
                    for (String attrName : attrNames) {
                        session.removeAttribute(attrName);
                        if (.isTraceEnabled()) {
                            .trace("Removed attribute: " + attrName);
                        }
                    }
                    // Iteration 2 -- Restore all session attributes of admin user
                    if (backup == null) {
                        if (.isTraceEnabled()) {
                            .trace("No session attributes found in previous impersonated session. Ignoring");
                        }
                    } else {
                        for (Map.Entry<StringObjectattr : backup.entrySet()) {
                            session.setAttribute(attr.getKey(), attr.getValue());
                            if (.isTraceEnabled()) {
                                .trace("Finished restore of attribute: " + attr.getKey());
                            }
                        }
                    }
                    return true;
                }
            }));
        }
    }
    // Register given conversationState into ConversationRegistry. Key will be current Http session
    private void registerConversationState(HttpServletRequest reqConversationState conversationState) {
        HttpSession httpSession = req.getSession();
        StateKey stateKey = new HttpSessionStateKey(httpSession);
        conversationRegistry.register(stateKeyconversationState);
    }
    private Identity createIdentity(String username) {
        try {
            return authenticator.createIdentity(username);
        } catch (Exception e) {
            .error("New identity for user: " + username + " not created."e);
            return null;
        }
    }
    private String getReturnURI(HttpServletRequest req) {
        String returnURI = null;
        HttpSession session = req.getSession(false);
        if (session != null) {
            returnURI = (String)session.getAttribute();
        }
        if (returnURI == null) {
            returnURI = req.getContextPath();
        }
        return returnURI;
    }
    private List<StringofflineCopy(Enumeration<Stringe) {
        List<Stringlist = new LinkedList<String>();
        while (e.hasMoreElements()) {
            list.add(e.nextElement());
        }
        return list;
    }
New to GrepCode? Check out our FAQ X