Juan Hernandez has uploaded a new change for review. Change subject: core: Automatic login filter ......................................................................
core: Automatic login filter Currently login is performed by the GUI using a form where the user provides the user name, the password and the authentication profile. This works well for authentication mechanisms based on passwords, but it doesnt work for other authentication mechanisms or when the authentication is performed by the web server. This patches changes the engine so that it will be able to automatically perform the login even before the GUI is displayed. This is based on a filter that trusts the principal provided in the HTTP request, assuming that it has been populated by the external authentication mechanism (the web server, for example). This principal isn't currently populated, but it in the future it will be populated by the authentication filter. To actually have this working both the authentication filter (part of the new authentication mechanism introduced in previous patches) and this filter have to be enabled in the web application, adding something like this to the web.xml files: <!-- Perform authentication: --> <filter> <filter-name>AuthenticationFilter</filter-name> <filter-class>o.o.e.c.a.AuthenticationFilter</filter-class> </filter> <filter-mapping> <filter-name>AuthenticationFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Perform automatic login: --> <filter> <filter-name>AutomaticLoginFilter</filter-name> <filter-class>o.o.e.c.b.AutomaticLoginFilter</filter-class> </filter> <filter-mapping> <filter-name>AutomaticLoginFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> This patch doesn't include these changes to web.xml files, they will be included in later patches, so there isn't actually any change in behaviour yet. Change-Id: I0b8cbee89b5bb96271c3706e9e75acbf2890a0b8 Signed-off-by: Juan Hernandez <juan.hernan...@redhat.com> --- A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AutomaticLoginFilter.java 1 file changed, 154 insertions(+), 0 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/23/21023/1 diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AutomaticLoginFilter.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AutomaticLoginFilter.java new file mode 100644 index 0000000..30c3c6d --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AutomaticLoginFilter.java @@ -0,0 +1,154 @@ +package org.ovirt.engine.core.bll; + +import java.io.IOException; +import java.security.Principal; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.ovirt.engine.core.authentication.AuthenticationProfile; +import org.ovirt.engine.core.authentication.AuthenticationProfileManager; +import org.ovirt.engine.core.authentication.Directory; +import org.ovirt.engine.core.authentication.DirectoryUser; +import org.ovirt.engine.core.bll.session.SessionDataContainer; +import org.ovirt.engine.core.common.VdcObjectType; +import org.ovirt.engine.core.common.action.VdcActionType; +import org.ovirt.engine.core.common.businessentities.DbUser; +import org.ovirt.engine.core.compat.Guid; +import org.ovirt.engine.core.dal.dbbroker.DbFacade; +import org.ovirt.engine.core.dao.DbUserDAO; +import org.ovirt.engine.core.dao.PermissionDAO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This filter takes the login name and the authentication profile name from the authenticated principal and performs + * an automatic loggin of that user, without checking any password. This assumes that the user has already been + * authenticated by an external mechanism and that the login name and the authentication profile name are contained + * in the name of the principal object separated by an at sign. + */ +public class AutomaticLoginFilter implements Filter { + // The log: + private static final Logger log = LoggerFactory.getLogger(AutomaticLoginFilter.class); + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // Nothing. + } + + @Override + public void destroy() { + // Nothing. + } + + @Override + public void doFilter(ServletRequest req, ServletResponse rsp, FilterChain chain) + throws IOException, ServletException { + doFilter((HttpServletRequest) req, (HttpServletResponse) rsp, chain); + } + + private void doFilter(HttpServletRequest req, HttpServletResponse rsp, FilterChain chain) + throws IOException, ServletException { + // In order to perform the automatic login the principal needs to be populated, if it isn't then we just forward + // the request to the next filter: + Principal principal = req.getUserPrincipal(); + if (principal == null) { + chain.doFilter(req, rsp); + return; + } + + // If the user is already logged in then this filter doesn't need to do anything else: + DbUser dbUser = SessionDataContainer.getInstance().getUser(req.getSession().getId(), false); + if (dbUser != null) { + chain.doFilter(req, rsp); + return; + } + + // Extract the login name and the authentication profile name from the principal: + String principalName = principal.getName(); + int index = principalName.lastIndexOf('@'); + if (index == -1) { + log.error( + "Can't login user because the principal name \"{}\" doesn't contain the name of the authentication " + + "profile.", + principalName + ); + rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + String loginName = principalName.substring(0, index); + String profileName = principalName.substring(index + 1); + + // Check that the authentication profile exists: + AuthenticationProfile profile = AuthenticationProfileManager.getInstance().getProfile(profileName); + if (profile == null) { + log.error( + "Can't login user \"{}\" because authentication profile \"{}\" doesn't exist.", + loginName, + profileName + ); + rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + // Check that the user exists in the directory associated to the authentication profile: + Directory directory = profile.getDirectory(); + DirectoryUser directoryUser = directory.findUser(loginName); + if (directoryUser == null) { + log.info( + "Can't login user \"{}\" with authentication profile \"{}\" because the user doesn't exist in the " + + "directory.", + loginName, + profileName + ); + rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + // Check that the user exists in the database, if it doesn't exist then we need to add it now: + DbUserDAO dbUserDao = DbFacade.getInstance().getDbUserDao(); + dbUser = dbUserDao.getByExternalId(directory.getName(), directoryUser.getId()); + if (dbUser == null) { + dbUser = new DbUser(directoryUser); + dbUser.setId(Guid.newGuid()); + dbUserDao.save(dbUser); + } + + // Check if the user has permission to log in: + PermissionDAO permissionDao = DbFacade.getInstance().getPermissionDao(); + Guid permissionId = permissionDao.getEntityPermissionsForUserAndGroups( + dbUser.getId(), + dbUser.getGroupIds(), + VdcActionType.LoginUser.getActionGroup(), + MultiLevelAdministrationHandler.BOTTOM_OBJECT_ID, + VdcObjectType.Bottom, + true + ); + if (permissionId == null) { + log.info( + "Can't login user \"{}\" with authentication profile \"{}\" because the user doesn't have the " + + "required permission.", + loginName, + profileName + ); + rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + // Retrieve the MLA admin status of the user, this may be redundant in some use-cases, but looking forward to + // single sign on we will want this informatin: + boolean isAdmin = MultiLevelAdministrationHandler.isAdminUser(dbUser); + dbUser.setAdmin(isAdmin); + + // Attach the user to the session: + SessionDataContainer.getInstance().setUser(req.getSession().getId(), dbUser); + + // Forward the request to the next filter in the chain: + chain.doFilter(req, rsp); + } +} -- To view, visit http://gerrit.ovirt.org/21023 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I0b8cbee89b5bb96271c3706e9e75acbf2890a0b8 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Juan Hernandez <juan.hernan...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches