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

Reply via email to