From d2e13a634df6f61d1d1280e4a6d2523bc2069203 Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Tue, 9 Sep 2008 07:27:56 +0000
Subject: [PATCH] LMS-445 GenericServer with authentication and session
 management implemented

SVN: 8241
---
 .../web/client/IGenericClientService.java     |   5 +
 .../client/IGenericClientServiceAsync.java    |   4 +
 .../client/web/client/dto/SessionContext.java |  11 ++
 .../web/server/GenericClientService.java      | 105 +++++++++++++++++-
 .../server/GenericClientServiceServlet.java   |   6 +-
 .../generic/genericApplicationContext.xml     |  12 +-
 .../cisd/openbis/generic/server/.gitignore    |   0
 .../openbis/generic/server/GenericServer.java |  70 ++++++++++++
 .../server/LogMessagePrefixGenerator.java     |  64 +++++++++++
 .../generic/server/SessionFactory.java        |  38 +++++++
 .../generic/shared/IGenericServer.java        |  33 ++++++
 .../openbis/generic/shared/dto/Session.java   |  64 +++++++++++
 openbis/source/java/service.properties        |   4 +
 13 files changed, 406 insertions(+), 10 deletions(-)
 delete mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/.gitignore
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/GenericServer.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/LogMessagePrefixGenerator.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SessionFactory.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IGenericServer.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/Session.java

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IGenericClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IGenericClientService.java
index 443894824b0..71d218bc323 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IGenericClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IGenericClientService.java
@@ -42,4 +42,9 @@ public interface IGenericClientService extends RemoteService
      * Tries to login with specified user ID and password. If failed <code>null</code> is returned.
      */
     public SessionContext tryToLogin(String userID, String password);
+    
+    /**
+     * Logs out. 
+     */
+    public void logout();
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IGenericClientServiceAsync.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IGenericClientServiceAsync.java
index 710474a2570..c715a9a43e9 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IGenericClientServiceAsync.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/IGenericClientServiceAsync.java
@@ -36,4 +36,8 @@ public interface IGenericClientServiceAsync
     
     /** @see IGenericClientService#tryToLogin(String, String) */
     public void tryToLogin(String userID, String password, AsyncCallback<SessionContext> callback);
+    
+    /** @see IGenericClientService#logout() */
+    public void logout(AsyncCallback<Void> callback);
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/SessionContext.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/SessionContext.java
index bf4570e1252..97eb387a273 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/SessionContext.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/SessionContext.java
@@ -26,6 +26,7 @@ import com.google.gwt.user.client.rpc.IsSerializable;
 public class SessionContext implements IsSerializable
 {
     private User user;
+    private String sessionID;
 
     public final User getUser()
     {
@@ -36,4 +37,14 @@ public class SessionContext implements IsSerializable
     {
         this.user = user;
     }
+
+    public final String getSessionID()
+    {
+        return sessionID;
+    }
+
+    public final void setSessionID(String sessionID)
+    {
+        this.sessionID = sessionID;
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/GenericClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/GenericClientService.java
index 59f4530d253..91c2c8c95ae 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/GenericClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/GenericClientService.java
@@ -16,10 +16,23 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.server;
 
+import javax.servlet.http.HttpSession;
+
+import org.apache.log4j.Logger;
+
+import ch.systemsx.cisd.common.exceptions.InvalidSessionException;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.servlet.IRequestContextProvider;
 import ch.systemsx.cisd.common.utilities.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.lims.base.dto.GroupPE;
+import ch.systemsx.cisd.lims.base.dto.PersonPE;
 import ch.systemsx.cisd.openbis.generic.client.web.client.IGenericClientService;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ApplicationInfo;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.SessionContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.User;
+import ch.systemsx.cisd.openbis.generic.shared.IGenericServer;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 
 /**
  * 
@@ -28,10 +41,69 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.dto.SessionContext;
  */
 public class GenericClientService implements IGenericClientService
 {
+    private static final String SESSION_KEY = "openbis-session";
+
+    private static final Logger operationLog =
+        LogFactory.getLogger(LogCategory.OPERATION, GenericClientService.class);
+
+    private final IGenericServer server;
+    private final IRequestContextProvider requestContextProvider;
+
+    public GenericClientService(final IGenericServer server,
+            final IRequestContextProvider requestContextProvider)
+    {
+        this.server = server;
+        this.requestContextProvider = requestContextProvider;
+    }
+    
     void setConfigParameters(GenericConfigParameters configParameters)
     {
     }
     
+    private SessionContext createSessionContext(final Session session)
+    {
+        SessionContext sessionContext = new SessionContext();
+        sessionContext.setSessionID(session.getSessionToken());
+        User user = new User();
+        user.setUserName(session.getUserName());
+        PersonPE person = session.tryToGetPerson();
+        if (person != null)
+        {
+            GroupPE homeGroup = person.getHomeGroup();
+            if (homeGroup != null)
+            {
+                user.setHomeGroupCode(homeGroup.getCode());
+            }
+        }
+        sessionContext.setUser(user);
+        return sessionContext;
+    }
+    
+    private Session getSession(final HttpSession httpSession)
+    {
+        Session session = (Session) httpSession.getAttribute(SESSION_KEY);
+        if (session == null)
+        {
+            final String remoteHost =
+                    requestContextProvider.getHttpServletRequest().getRemoteHost();
+            final String msg =
+                    "Attempt to get non-existent session from host '" + remoteHost
+                            + "': user is not logged in.";
+            if (operationLog.isInfoEnabled())
+            {
+                operationLog.info(msg);
+            }
+            throw new InvalidSessionException(msg);
+
+        }
+        return session;
+    }
+    
+    private HttpSession getOrCreateHttpSession(boolean create)
+    {
+        return requestContextProvider.getHttpServletRequest().getSession(create);
+    }
+    
     public ApplicationInfo getApplicationInfo()
     {
         ApplicationInfo applicationInfo = new ApplicationInfo();
@@ -41,14 +113,39 @@ public class GenericClientService implements IGenericClientService
 
     public SessionContext tryToGetCurrentSessionContext()
     {
-        // TODO Auto-generated method stub
-        return null;
+        final HttpSession httpSession = getOrCreateHttpSession(false);
+        if (httpSession == null)
+        {
+            return null;
+        }
+        final Session session = getSession(httpSession);
+        return createSessionContext(session);
     }
 
     public SessionContext tryToLogin(String userID, String password)
     {
-        // TODO Auto-generated method stub
-        return null;
+        Session session = server.tryToAuthenticate(userID, password);
+        if (session == null)
+        {
+            return null;
+        }
+        HttpSession httpSession = getOrCreateHttpSession(true);
+        // Expiration time of httpSession is 10 seconds less than of session
+        httpSession.setMaxInactiveInterval(session.getSessionExpirationTime() / 1000 - 10);
+        httpSession.setAttribute(SESSION_KEY, session);
+        return createSessionContext(session);
+    }
+
+    public void logout()
+    {
+        HttpSession httpSession = getOrCreateHttpSession(false);
+        if (httpSession != null)
+        {
+            Session session = getSession(httpSession);
+            httpSession.removeAttribute(SESSION_KEY);
+            httpSession.invalidate();
+            server.logout(session.getSessionToken());
+        }
     }
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/GenericClientServiceServlet.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/GenericClientServiceServlet.java
index 2d2cf6df20b..bb026a18cfc 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/GenericClientServiceServlet.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/GenericClientServiceServlet.java
@@ -95,7 +95,6 @@ public class GenericClientServiceServlet extends GWTSpringController implements
 
     public ApplicationInfo getApplicationInfo()
     {
-        operationLog.info("getApplicationInfo()");
         return service.getApplicationInfo();
     }
 
@@ -109,4 +108,9 @@ public class GenericClientServiceServlet extends GWTSpringController implements
         return service.tryToLogin(userID, password);
     }
 
+    public void logout()
+    {
+        service.logout();
+    }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/genericApplicationContext.xml b/openbis/source/java/ch/systemsx/cisd/openbis/generic/genericApplicationContext.xml
index 184b4199b97..f3f4a5c4927 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/genericApplicationContext.xml
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/genericApplicationContext.xml
@@ -12,14 +12,16 @@
     -->
 
     <bean id="generic-service" class="ch.systemsx.cisd.openbis.generic.client.web.server.GenericClientService">
-        <!-- constructor-arg ref="${authentication-service}" />
+        <constructor-arg ref="generic-server" />
         <constructor-arg ref="request-context-provider" />
-        <constructor-arg ref="console-factory" />
-        <constructor-arg ref="action-log" />
-        <property name="sessionExpirationPeriodInMinutes" value="${session-timeout}" /-->
     </bean>
     
-    <bean id="action-log" class="ch.systemsx.cisd.openbis.generic.client.web.server.GenericActionLog">
+    <bean id="generic-server" class="ch.systemsx.cisd.openbis.generic.server.GenericServer">
+        <constructor-arg ref="${authentication-service}" />
+        <constructor-arg ref="request-context-provider" />
+        <!-- The time after which an inactive session is expired by the service (in minutes). -->
+        <constructor-arg value="${session-timeout}" />
     </bean>
+    
 
 </beans>
\ No newline at end of file
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/.gitignore b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/.gitignore
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/GenericServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/GenericServer.java
new file mode 100644
index 00000000000..78a9be3ecf5
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/GenericServer.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.server;
+
+import ch.systemsx.cisd.authentication.DefaultSessionManager;
+import ch.systemsx.cisd.authentication.IAuthenticationService;
+import ch.systemsx.cisd.authentication.ISessionManager;
+import ch.systemsx.cisd.common.servlet.IRequestContextProvider;
+import ch.systemsx.cisd.common.servlet.RequestContextProviderAdapter;
+import ch.systemsx.cisd.openbis.generic.shared.IGenericServer;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class GenericServer implements IGenericServer
+{
+    private final ISessionManager<Session> sessionManager;
+
+    public GenericServer(IAuthenticationService authenticationService,
+            IRequestContextProvider requestContextProvider, int sessionExpirationPeriodInMinutes)
+    {
+        this(new DefaultSessionManager<Session>(new SessionFactory(),
+                new LogMessagePrefixGenerator(), authenticationService,
+                new RequestContextProviderAdapter(requestContextProvider),
+                sessionExpirationPeriodInMinutes));
+    }
+    
+    GenericServer(ISessionManager<Session> sessionManager)
+    {
+        this.sessionManager = sessionManager;
+    }
+    
+    public int getVersion()
+    {
+        return 1;
+    }
+
+    public void logout(String sessionToken)
+    {
+        sessionManager.closeSession(sessionToken);
+    }
+
+    public Session tryToAuthenticate(String user, String password)
+    {
+        String sessionToken = sessionManager.tryToOpenSession(user, password);
+        if (sessionToken == null)
+        {
+            return null;
+        }
+        return sessionManager.getSession(sessionToken);
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/LogMessagePrefixGenerator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/LogMessagePrefixGenerator.java
new file mode 100644
index 00000000000..9e247f09247
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/LogMessagePrefixGenerator.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.server;
+
+import ch.systemsx.cisd.authentication.ILogMessagePrefixGenerator;
+import ch.systemsx.cisd.lims.base.dto.GroupPE;
+import ch.systemsx.cisd.lims.base.dto.PersonPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+class LogMessagePrefixGenerator implements ILogMessagePrefixGenerator<Session>
+{
+
+    public String createPrefix(Session session)
+    {
+        String userName = session.getUserName();
+        String groupCode = null;
+        PersonPE person = session.tryToGetPerson();
+        if (person != null)
+        {
+            GroupPE homeGroup = person.getHomeGroup();
+            if (homeGroup != null)
+            {
+                groupCode = homeGroup.getCode();
+            }
+        }
+        String remoteHost = session.getRemoteHost();
+        return createPrefix(userName, groupCode, remoteHost);
+    }
+
+    public String createPrefix(String user, String remoteHost)
+    {
+        return createPrefix(user, null, remoteHost);
+    }
+    
+    private String createPrefix(String user, String groupCodeOrNull, String remoteHost)
+    {
+        return String.format("[USER:%s GROUP:%s HOST:%s]", cite(user),
+        cite(groupCodeOrNull), cite(remoteHost));
+    }
+    
+    private String cite(final String text)
+    {
+        return text == null ? "<UNDEFINED>" : "'" + text + "'";
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SessionFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SessionFactory.java
new file mode 100644
index 00000000000..3d40db13169
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SessionFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.server;
+
+import ch.systemsx.cisd.authentication.ISessionFactory;
+import ch.systemsx.cisd.authentication.Principal;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+class SessionFactory implements ISessionFactory<Session>
+{
+
+    public Session create(String sessionToken, String userName, Principal principal,
+            String remoteHost, long sessionStart, int expirationTime)
+    {
+        return new Session(sessionToken, userName, principal, remoteHost, sessionStart,
+                expirationTime);
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IGenericServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IGenericServer.java
new file mode 100644
index 00000000000..88e89d4c766
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IGenericServer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.shared;
+
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface IGenericServer
+{
+    public int getVersion();
+    
+    public Session tryToAuthenticate(String user, String password);
+    
+    public void logout(String sessionToken);
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/Session.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/Session.java
new file mode 100644
index 00000000000..93e2ce09e08
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/Session.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.shared.dto;
+
+import org.apache.commons.lang.time.DateFormatUtils;
+
+import ch.systemsx.cisd.authentication.BasicSession;
+import ch.systemsx.cisd.authentication.Principal;
+import ch.systemsx.cisd.lims.base.dto.PersonPE;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class Session extends BasicSession
+{
+    private static final long serialVersionUID = 1L;
+    
+    private PersonPE person;
+    
+    /**
+     * Creates a new instance.
+     */
+    public Session(String sessionToken, String userName, Principal principal, String remoteHost,
+            long sessionStart, int expirationTime)
+    {
+        super(sessionToken, userName, principal, remoteHost, sessionStart, expirationTime);
+    }
+
+    public final PersonPE tryToGetPerson()
+    {
+        return person;
+    }
+
+    public final void setPerson(PersonPE person)
+    {
+        this.person = person;
+    }
+    
+    @Override
+    public final String toString()
+    {
+        return "Session{user=" + getUserName() + ",group=" + person.getHomeGroup() + ",remoteHost="
+                + getRemoteHost() + ",sessionstart="
+                + DateFormatUtils.format(getSessionStart(), DATE_FORMAT_PATTERN) + "}";
+    }
+
+
+}
diff --git a/openbis/source/java/service.properties b/openbis/source/java/service.properties
index e69de29bb2d..d51b73ae2dc 100644
--- a/openbis/source/java/service.properties
+++ b/openbis/source/java/service.properties
@@ -0,0 +1,4 @@
+authentication-service = dummy-authentication-service
+
+# The time after which an inactive session is expired by the service (in minutes).
+session-timeout = 30
-- 
GitLab