Commit 6278e836 authored by Alinga Yeung's avatar Alinga Yeung
Browse files

Merge branch 'ac2' of /srv/cadc/git/wopencadc into ac2

parents 74843763 5166d677
Loading
Loading
Loading
Loading
+0 −16
Original line number Diff line number Diff line
@@ -174,20 +174,4 @@ public interface GroupPersistence<T extends Principal>
        throws UserNotFoundException, GroupNotFoundException,
               TransientException, AccessControlException;
  
    /**
     * Check whether the user is a member of the group.
     *
     * @param userID The userID.
     * @param groupID The groupID.
     *
     * @return true or false
     *
     * @throws UserNotFoundException If the user is not found.
     * @throws TransientException If an temporary, unexpected problem occurred.
     * @throws AccessControlException If the operation is not permitted.
     */
    boolean isMember(T userID, String groupID)
        throws UserNotFoundException, TransientException,
               AccessControlException;
  
}
+4 −2
Original line number Diff line number Diff line
@@ -127,6 +127,9 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO

    private LdapUserDAO<T> userPersist;
    
    // this gets filled by the LdapgroupPersistence
    GroupDetailSelector searchDetailSelector;

    public LdapGroupDAO(LdapConfig config, LdapUserDAO<T> userPersist)
    {
        super(config);
@@ -811,8 +814,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO
        }
        throw new RuntimeException("BUG: failed to extract group name from " + groupDN.toString());
    }
    // this gets filled by the LdapgroupPersistence
    GroupDetailSelector searchDetailSelector;


    private boolean isDetailedSearch(Group g, Role r)
    {
+2 −11
Original line number Diff line number Diff line
@@ -97,7 +97,7 @@ public class LdapGroupPersistence<T extends Principal>
        config = LdapConfig.getLdapConfig();
    }
    
    protected void setDetailSelector(GroupDetailSelector gds)
    public void setDetailSelector(GroupDetailSelector gds)
    {
        this.detailSelector = gds;
    }
@@ -257,13 +257,4 @@ public class LdapGroupPersistence<T extends Principal>
            }
        }
    }  
    
    public boolean isMember(T userID, String groupID)
            throws UserNotFoundException, TransientException,
            AccessControlException
    {
        return (new LdapUserPersistence<T>()).isMember(userID, groupID);
    }

  
}
+159 −8
Original line number Diff line number Diff line
@@ -70,17 +70,30 @@ package ca.nrc.cadc.ac.server.web;

import java.io.IOException;
import java.security.AccessControlException;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;

import javax.security.auth.Subject;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import ca.nrc.cadc.ac.Group;
import ca.nrc.cadc.ac.Role;
import ca.nrc.cadc.ac.UserNotFoundException;
import ca.nrc.cadc.ac.server.GroupDetailSelector;
import ca.nrc.cadc.ac.server.UserPersistence;
import ca.nrc.cadc.ac.server.ldap.LdapGroupPersistence;
import ca.nrc.cadc.ac.server.ldap.LdapUserPersistence;
import ca.nrc.cadc.auth.AuthenticatorImpl;
import ca.nrc.cadc.auth.HttpPrincipal;
import ca.nrc.cadc.auth.SSOCookieManager;
import ca.nrc.cadc.log.ServletLogInfo;
import ca.nrc.cadc.net.TransientException;
import ca.nrc.cadc.util.StringUtil;

@SuppressWarnings("serial")
@@ -88,6 +101,33 @@ public class LoginServlet extends HttpServlet
{
    private static final Logger log = Logger.getLogger(LoginServlet.class);
    private static final String CONTENT_TYPE = "text/plain";
    // " as " - delimiter use for proxy user authentication
    public static final String PROXY_USER_DELIM = "\\s[aA][sS]\\s";
    String proxyGroup; // only users in this group can impersonate other users
    String nonImpersonGroup; // users in this group cannot be impersonated
    
    private static final String PROXY_ACCESS = "Proxy user access: ";
    
    
    @Override
    public void init(final ServletConfig config) throws ServletException
    {
        super.init(config);

        try
        {
            this.proxyGroup = config.getInitParameter(
                    LoginServlet.class.getName() + ".proxyGroup");
            log.info("proxyGroup: " + proxyGroup);
            this.nonImpersonGroup = config.getInitParameter(
                    LoginServlet.class.getName() + ".nonImpersonGroup");
            log.info("nonImpersonGroup: " + nonImpersonGroup);
        }
        catch(Exception ex)
        {
            log.error("failed to init: " + ex);
        }
    }
    /**
     * Attempt to login for userid/password.
     */
@@ -100,15 +140,29 @@ public class LoginServlet extends HttpServlet
        try
        {
            log.info(logInfo.start());
            String userID = request.getParameter("username");
            String userID = request.getParameter("username").trim();
            String proxyUser = null;
            String[] fields = userID.split(PROXY_USER_DELIM);
            if (fields.length == 2 )
            {
                proxyUser = fields[0].trim();
                userID = fields[1].trim();
                checkCanImpersonate(userID, proxyUser);
            }
            String password = request.getParameter("password");
            UserPersistence up = new LdapUserPersistence();
            if (StringUtil.hasText(userID))
            {
                if (StringUtil.hasText(password))
                {
                	if (new LdapUserPersistence().doLogin(userID, password))
                    if ((StringUtil.hasText(proxyUser) && 
                            up.doLogin(proxyUser, password)) ||
                        (!StringUtil.hasText(proxyUser) &&
                                up.doLogin(userID, password)))   
                    {
	            	    String token = new SSOCookieManager().generate(new HttpPrincipal(userID));
	            	    String token = 
	            	            new SSOCookieManager().generate(
	            	                    new HttpPrincipal(userID, proxyUser));
	            	    response.setContentType(CONTENT_TYPE);
	            	    response.setContentLength(token.length());
	            	    response.getWriter().write(token);
@@ -126,16 +180,24 @@ public class LoginServlet extends HttpServlet
        }
        catch (IllegalArgumentException e)
        {
            log.debug(e.getMessage(), e);
            logInfo.setMessage(e.getMessage());
            String msg = e.getMessage();
            if (msg.startsWith(PROXY_ACCESS))
            {
                log.warn(msg, e);
            }
            else
            {
                log.debug(msg, e);
            }
            logInfo.setMessage(msg);
    	    response.setContentType(CONTENT_TYPE);
            response.getWriter().write(e.getMessage());
            response.getWriter().write(msg);
            response.setStatus(400);
        }
        catch (AccessControlException e)
        {
            log.debug(e.getMessage(), e);
            String message = "Invalid credentials";
            String message = e.getMessage();
            logInfo.setMessage(message);
    	    response.setContentType(CONTENT_TYPE);
            response.getWriter().write(message);
@@ -157,4 +219,93 @@ public class LoginServlet extends HttpServlet
            log.info(logInfo.end());
        }
    }
	
	/**
	 * Checks if user can impersonate another user
	 */
    protected void checkCanImpersonate(final String userID, final String proxyUser)
            throws AccessControlException, UserNotFoundException,
            TransientException, Throwable
    {
        final LdapGroupPersistence<HttpPrincipal> gp = 
                getLdapGroupPersistence();
        
        // Users (proxy and the user to be impersonated) are not authenticated
        // at this point so in order to make the calls to check their group
        // membership we need to create corresponding subjects and run the
        // get groups command in the corresponding subject context.
        AuthenticatorImpl ai = new AuthenticatorImpl();
        Subject proxySubject = new Subject();
        proxySubject.getPrincipals().add(new HttpPrincipal(proxyUser));
        ai.augmentSubject(proxySubject);
        try
        {
            Subject.doAs(proxySubject, new PrivilegedExceptionAction<Object>()
            {
                @Override
                public Object run() throws Exception
                {
                    
                    if (gp.getGroups(new HttpPrincipal(proxyUser), Role.MEMBER,
                            proxyGroup).size() == 0)
                    {
                        throw new AccessControlException(PROXY_ACCESS
                                + proxyUser + " as " + userID
                                + " failed - not allowed to impersonate ("
                                + proxyUser + " not in " + proxyGroup
                                + " group)");
                    }
                    return null;
                }
            });

            Subject userSubject = new Subject();
            userSubject.getPrincipals().add(new HttpPrincipal(userID));
            ai.augmentSubject(userSubject);
            Subject.doAs(userSubject, new PrivilegedExceptionAction<Object>()
            {
                @Override
                public Object run() throws Exception
                {
                    if (gp.getGroups(new HttpPrincipal(userID), Role.MEMBER,
                            nonImpersonGroup).size() != 0)
                    {
                        throw new AccessControlException(PROXY_ACCESS
                                + proxyUser + " as " + userID
                                + " failed - non impersonable (" + userID
                                + " in " + nonImpersonGroup + " group)");
                    }
                    return null;
                }
            });
        }
        catch (PrivilegedActionException e)
        {
            Throwable cause = e.getCause();
            if (cause != null)
            {
                throw cause;
            }
            Exception exception = e.getException();
            if (exception != null)
            {
                throw exception;
            }
            throw e;
        }
    }
    
    protected LdapGroupPersistence<HttpPrincipal> getLdapGroupPersistence()
    {
        LdapGroupPersistence<HttpPrincipal> gp = new LdapGroupPersistence<HttpPrincipal>();
        gp.setDetailSelector(new GroupDetailSelector()
        {
            @Override
            public boolean isDetailedSearch(Group g, Role r)
            {
                return false;
            }
        });
        return gp;
    }
}
+5 −3
Original line number Diff line number Diff line
@@ -126,7 +126,7 @@ public class WhoAmIServlet extends HttpServlet
            else
            {
                redirect(response, currentWebPrincipals.toArray(
                        new HttpPrincipal[1])[0]);
                        new HttpPrincipal[1])[0], request.getScheme());
            }
        }
        catch (IllegalArgumentException e)
@@ -155,14 +155,16 @@ public class WhoAmIServlet extends HttpServlet
     *
     * @param response     The HTTP response.
     * @param webPrincipal The HttpPrincipal instance.
     * @param scheme       The scheme
     */
    void redirect(final HttpServletResponse response,
                  final HttpPrincipal webPrincipal) throws IOException
                  final HttpPrincipal webPrincipal, 
                  final String scheme) throws IOException
    {
        final RegistryClient registryClient = getRegistryClient();
        final URL redirectURL =
                registryClient.getServiceURL(
                        URI.create(AC.GMS_SERVICE_URI), "https", USER_GET_PATH);
                        URI.create(AC.GMS_SERVICE_URI), scheme, USER_GET_PATH);

        // Take the first one.
        final String redirectUrl =
Loading