← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 1566: Work in progress on user authentication audit. Implemented user login and logout so far. Login ha...

 

------------------------------------------------------------
revno: 1566
committer: Lars Helge Oeverland <larshelge@xxxxxxxxx>
branch nick: trunk
timestamp: Sat 2010-03-06 17:00:25 +0100
message:
  Work in progress on user authentication audit. Implemented user login and logout so far. Login happens in existing LoggedInAction. Added LogoutHandler called UserAuditLogoutFilter to the logout filter chain. Implemented UserAuditService which currently only logs to commons-logging.
added:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/FailedLogin.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/UserAuditService.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/UserAuditStore.java
  dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/
  dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/DefaultUserAuditService.java
  dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/hibernate/
  dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/hibernate/HibernateUserAuditStore.java
  dhis-2/dhis-services/dhis-service-administration/src/main/resources/org/hisp/dhis/useraudit/
  dhis-2/dhis-services/dhis-service-administration/src/main/resources/org/hisp/dhis/useraudit/hibernate/
  dhis-2/dhis-services/dhis-service-administration/src/main/resources/org/hisp/dhis/useraudit/hibernate/FailedLogin.hbm.xml
  dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/useraudit/
  dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/useraudit/UserAuditStoreTest.java
  dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/filter/UserAuditLogoutFilter.java
modified:
  dhis-2/dhis-services/dhis-service-administration/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/action/LoggedInAction.java
  dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/beans.xml


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription.
=== added directory 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit'
=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/FailedLogin.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/FailedLogin.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/FailedLogin.java	2010-03-06 16:00:25 +0000
@@ -0,0 +1,52 @@
+package org.hisp.dhis.useraudit;
+
+import java.util.Date;
+
+public class FailedLogin
+{
+    private int id;
+    
+    private String username;
+    
+    private Date date;
+    
+    public FailedLogin()
+    {
+    }
+    
+    public FailedLogin( String username, Date date )
+    {
+        this.username = username;
+        this.date = date;
+    }
+
+    public int getId()
+    {
+        return id;
+    }
+
+    public void setId( int id )
+    {
+        this.id = id;
+    }
+
+    public String getUsername()
+    {
+        return username;
+    }
+
+    public void setUsername( String username )
+    {
+        this.username = username;
+    }
+
+    public Date getDate()
+    {
+        return date;
+    }
+
+    public void setDate( Date date )
+    {
+        this.date = date;
+    }
+}

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/UserAuditService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/UserAuditService.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/UserAuditService.java	2010-03-06 16:00:25 +0000
@@ -0,0 +1,13 @@
+package org.hisp.dhis.useraudit;
+
+public interface UserAuditService
+{
+    final int TIMEFRAME_NUMBER_OF_HOURS = 1;
+    final int MAX_NUMBER_OF_ATTEMPTS = 3;
+    
+    void registerLogin( String username );
+    
+    void registerLogout( String username );
+    
+    void registerLoginFailed( String username );
+}

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/UserAuditStore.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/UserAuditStore.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/UserAuditStore.java	2010-03-06 16:00:25 +0000
@@ -0,0 +1,15 @@
+package org.hisp.dhis.useraudit;
+
+import java.util.Collection;
+import java.util.Date;
+
+public interface UserAuditStore
+{
+    final String ID = UserAuditStore.class.getName();
+    
+    void saveFailedLogin( FailedLogin login );
+    
+    Collection<FailedLogin> getAllFailedLogins();
+    
+    int getFailedLogins( String username, Date date );
+}

=== added directory 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit'
=== added file 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/DefaultUserAuditService.java'
--- dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/DefaultUserAuditService.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/DefaultUserAuditService.java	2010-03-06 16:00:25 +0000
@@ -0,0 +1,53 @@
+package org.hisp.dhis.useraudit;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class DefaultUserAuditService
+    implements UserAuditService
+{
+    private static final Log log = LogFactory.getLog( DefaultUserAuditService.class );
+    
+    private UserAuditStore userAuditStore;
+    
+    public void setUserAuditStore( UserAuditStore userAuditStore )
+    {
+        this.userAuditStore = userAuditStore;
+    }
+
+    public void registerLogin( String username )
+    {
+        log.info( "User login: '" + username + "'" );        
+    }
+
+    public void registerLogout( String username )
+    {
+        log.info( "User logout: '" + username + "'" );
+    }
+
+    public void registerLoginFailed( String username )
+    {
+        log.info( "User login failed: '" + username + "'" );
+        
+        userAuditStore.saveFailedLogin( new FailedLogin( username, new Date() ) );
+        
+        int no = userAuditStore.getFailedLogins( username, getDate() );
+        
+        if ( no > MAX_NUMBER_OF_ATTEMPTS )
+        {
+            log.info( "Max number of login attempts exceeded: '" + username + "'" );
+        }
+    }
+    
+    private Date getDate()
+    {
+        Calendar cal = Calendar.getInstance();        
+        cal.clear();
+        cal.add( Calendar.HOUR, TIMEFRAME_NUMBER_OF_HOURS * -1 );
+        
+        return cal.getTime();
+    }
+}

=== added directory 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/hibernate'
=== added file 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/hibernate/HibernateUserAuditStore.java'
--- dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/hibernate/HibernateUserAuditStore.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/hibernate/HibernateUserAuditStore.java	2010-03-06 16:00:25 +0000
@@ -0,0 +1,46 @@
+package org.hisp.dhis.useraudit.hibernate;
+
+import java.util.Collection;
+import java.util.Date;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hisp.dhis.useraudit.FailedLogin;
+import org.hisp.dhis.useraudit.UserAuditStore;
+
+public class HibernateUserAuditStore
+    implements UserAuditStore
+{
+    private SessionFactory sessionFactory;
+    
+    public void setSessionFactory( SessionFactory sessionFactory )
+    {
+        this.sessionFactory = sessionFactory;
+    }
+
+    public void saveFailedLogin( FailedLogin login )
+    {
+        sessionFactory.getCurrentSession().save( login );
+    }
+    
+    @SuppressWarnings( "unchecked" )
+    public Collection<FailedLogin> getAllFailedLogins()
+    {
+        return sessionFactory.getCurrentSession().createCriteria( FailedLogin.class ).list();
+    }
+    
+    public int getFailedLogins( String username, Date date )
+    {
+        Session session = sessionFactory.getCurrentSession();
+        
+        String hql = "delete from FailedLogin where date < :date";
+        
+        session.createQuery( hql ).setDate( "date", date ).executeUpdate();
+        
+        hql = "select count(*) from FailedLogin where username = :username";
+        
+        Long no = (Long) session.createQuery( hql ).setString( "username", username ).uniqueResult();
+        
+        return no.intValue();
+    }
+}

=== modified file 'dhis-2/dhis-services/dhis-service-administration/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-administration/src/main/resources/META-INF/dhis/beans.xml	2010-02-10 18:04:44 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/main/resources/META-INF/dhis/beans.xml	2010-03-06 16:00:25 +0000
@@ -133,6 +133,19 @@
 		ref="org.hisp.dhis.dataarchive.DataArchiveStore"/>
   </bean>
   
+  <!-- User audit -->
+  
+  <bean id="org.hisp.dhis.useraudit.UserAuditService"
+	class="org.hisp.dhis.useraudit.DefaultUserAuditService">
+	<property name="userAuditStore"
+	  ref="org.hisp.dhis.useraudit.UserAuditStore"/>
+  </bean>
+	
+  <bean id="org.hisp.dhis.useraudit.UserAuditStore"
+    class="org.hisp.dhis.useraudit.hibernate.HibernateUserAuditStore">
+	<property name="sessionFactory" ref="sessionFactory"/>
+  </bean>
+  
   <!--DeletionHandler -->
   
   <bean id="org.hisp.dhis.dataarchive.ArchivedDataValueDeletionHandler"

=== added directory 'dhis-2/dhis-services/dhis-service-administration/src/main/resources/org/hisp/dhis/useraudit'
=== added directory 'dhis-2/dhis-services/dhis-service-administration/src/main/resources/org/hisp/dhis/useraudit/hibernate'
=== added file 'dhis-2/dhis-services/dhis-service-administration/src/main/resources/org/hisp/dhis/useraudit/hibernate/FailedLogin.hbm.xml'
--- dhis-2/dhis-services/dhis-service-administration/src/main/resources/org/hisp/dhis/useraudit/hibernate/FailedLogin.hbm.xml	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/main/resources/org/hisp/dhis/useraudit/hibernate/FailedLogin.hbm.xml	2010-03-06 16:00:25 +0000
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd";>
+
+<hibernate-mapping>
+  <class name="org.hisp.dhis.useraudit.FailedLogin" table="failedlogin">
+    <id name="id" column="failedloginid">
+      <generator class="native"/>
+    </id>        
+    <property name="username"/>
+    <property name="date"/>
+  </class>
+</hibernate-mapping>

=== added directory 'dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/useraudit'
=== added file 'dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/useraudit/UserAuditStoreTest.java'
--- dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/useraudit/UserAuditStoreTest.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/useraudit/UserAuditStoreTest.java	2010-03-06 16:00:25 +0000
@@ -0,0 +1,41 @@
+package org.hisp.dhis.useraudit;
+
+import org.hisp.dhis.DhisSpringTest;
+import org.junit.Test;
+
+import static junit.framework.Assert.*;
+
+public class UserAuditStoreTest
+    extends DhisSpringTest
+{
+    private UserAuditStore userAuditStore;
+    
+    @Override
+    public void setUpTest()
+    {
+        userAuditStore = (UserAuditStore) getBean( UserAuditStore.ID );
+    }
+    
+    @Test
+    public void save()
+    {
+        userAuditStore.saveFailedLogin( new FailedLogin( "userA", getDate( 2000, 1, 3 ) ) );
+        userAuditStore.saveFailedLogin( new FailedLogin( "userA", getDate( 2000, 1, 4 ) ) );
+        userAuditStore.saveFailedLogin( new FailedLogin( "userB", getDate( 2000, 1, 5 ) ) );
+        
+        assertNotNull( userAuditStore.getAllFailedLogins() );
+        assertEquals( 3, userAuditStore.getAllFailedLogins().size() );
+    }
+    
+    @Test
+    public void get()
+    {
+        userAuditStore.saveFailedLogin( new FailedLogin( "userA", getDate( 2000, 1, 3 ) ) );
+        userAuditStore.saveFailedLogin( new FailedLogin( "userA", getDate( 2000, 1, 4 ) ) );
+        userAuditStore.saveFailedLogin( new FailedLogin( "userA", getDate( 2000, 1, 5 ) ) );
+        userAuditStore.saveFailedLogin( new FailedLogin( "userA", getDate( 2000, 1, 6 ) ) );
+        userAuditStore.saveFailedLogin( new FailedLogin( "userB", getDate( 2000, 1, 7 ) ) );
+        
+        assertEquals( 3, userAuditStore.getFailedLogins( "userA", getDate( 2000, 1, 4 ) ) );
+    }
+}

=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/action/LoggedInAction.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/action/LoggedInAction.java	2009-08-20 08:17:49 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/action/LoggedInAction.java	2010-03-06 16:00:25 +0000
@@ -33,6 +33,8 @@
 import org.hisp.dhis.oust.manager.SelectionTreeManager;
 import org.hisp.dhis.ouwt.manager.OrganisationUnitSelectionManager;
 import org.hisp.dhis.user.CurrentUserService;
+import org.hisp.dhis.useraudit.UserAuditService;
+import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
 
 import com.opensymphony.xwork2.Action;
 
@@ -67,6 +69,13 @@
     {
         this.currentUserService = currentUserService;
     }
+    
+    private UserAuditService userAuditService;
+
+    public void setUserAuditService( UserAuditService userAuditService )
+    {
+        this.userAuditService = userAuditService;
+    }
 
     // -------------------------------------------------------------------------
     // Action implementation
@@ -75,8 +84,20 @@
     public String execute()
         throws Exception
     {
-        if ( currentUserService.getCurrentUser() != null )
+        String username = currentUserService.getCurrentUsername();
+        
+        if ( username != null )
         {
+            // -----------------------------------------------------------------
+            // Register login
+            // -----------------------------------------------------------------
+
+            userAuditService.registerLogin( username );
+
+            // -----------------------------------------------------------------
+            // Initialize ouwt and selection tree
+            // -----------------------------------------------------------------
+
             Collection<OrganisationUnit> orgUnits = currentUserService.getCurrentUser().getOrganisationUnits();
 
             if ( orgUnits.size() > 0 )

=== added file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/filter/UserAuditLogoutFilter.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/filter/UserAuditLogoutFilter.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/filter/UserAuditLogoutFilter.java	2010-03-06 16:00:25 +0000
@@ -0,0 +1,27 @@
+package org.hisp.dhis.security.filter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.hisp.dhis.useraudit.UserAuditService;
+import org.springframework.security.Authentication;
+import org.springframework.security.ui.logout.LogoutHandler;
+import org.springframework.security.userdetails.UserDetails;
+
+public class UserAuditLogoutFilter
+    implements LogoutHandler
+{
+    private UserAuditService userAuditService;
+
+    public void setUserAuditService( UserAuditService userAuditService )
+    {
+        this.userAuditService = userAuditService;
+    }
+
+    public void logout( HttpServletRequest request, HttpServletResponse response, Authentication authentication )
+    {
+        String username = (( UserDetails ) authentication.getPrincipal()).getUsername();
+        
+        userAuditService.registerLogout( username );
+    }
+}

=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/beans.xml	2010-03-04 22:55:47 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/beans.xml	2010-03-06 16:00:25 +0000
@@ -23,9 +23,9 @@
 		
     <bean id="filterChainProxy" class="org.springframework.security.util.FilterChainProxy">
         <sec:filter-chain-map path-type="ant">
-        <sec:filter-chain pattern="/dhis-web-commons/security/**"  filters="none"/>
-        <sec:filter-chain pattern="/dhis-web-commons/util/**"  filters="none"/>
-        <sec:filter-chain pattern="/dhis-web-commons/css/**"  filters="none"/>
+        <sec:filter-chain pattern="/dhis-web-commons/security/**" filters="none"/>
+        <sec:filter-chain pattern="/dhis-web-commons/util/**" filters="none"/>
+        <sec:filter-chain pattern="/dhis-web-commons/css/**" filters="none"/>
         <sec:filter-chain pattern="/**"
             filters="httpSessionContextIntegrationFilter,authenticationProcessingFilter,logoutFilter,automaticAccessFilter,requiredLoginFilter"/>
         </sec:filter-chain-map>
@@ -268,8 +268,10 @@
 			ref="org.hisp.dhis.ouwt.manager.OrganisationUnitSelectionManager" />
 		<property name="selectionTreeManager"
 			ref="org.hisp.dhis.oust.manager.SelectionTreeManager" />
+		<property name="userAuditService"
+			ref="org.hisp.dhis.useraudit.UserAuditService" />
 	</bean>
-	
+		
     <!-- Security : Filter -->
 	
 	<bean id="httpSessionContextIntegrationFilter"
@@ -288,12 +290,17 @@
 		<constructor-arg value="/" />
 		<constructor-arg>
 			<list>
+				<ref bean="userAuditLogoutFilter" />
 				<bean class="org.springframework.security.ui.logout.SecurityContextLogoutHandler" />
 			</list>
 		</constructor-arg>
 		<property name="filterProcessesUrl" value="/dhis-web-commons-security/logout.action" />
 	</bean>
 
+	<bean id="userAuditLogoutFilter" class="org.hisp.dhis.security.filter.UserAuditLogoutFilter">
+		<property name="userAuditService" ref="org.hisp.dhis.useraudit.UserAuditService"/>
+	</bean>
+
 	<bean id="automaticAccessFilter" class="org.hisp.dhis.security.filter.AutomaticAccessFilter">
 		<property name="accessProviders">
 			<map>