dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #05216
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 1714: STQC security fixes: Adds 10min lockout on 5 incorrect logins. Will add a UI and captcha
------------------------------------------------------------
revno: 1714
committer: Saptarshi <sunbiz@xxxxxxxxx>
branch nick: trunk
timestamp: Wed 2010-03-31 01:08:42 +0200
message:
STQC security fixes: Adds 10min lockout on 5 incorrect logins. Will add a UI and captcha
removed:
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/login.html
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/loginfailed.html
added:
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/login.jsp
dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/loginfailed.jsp
modified:
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/DefaultUserAuditService.java
dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/hibernate/HibernateUserAuditStore.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.
=== modified 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 2010-03-08 07:37:39 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/UserAuditService.java 2010-03-30 23:08:42 +0000
@@ -32,12 +32,20 @@
*/
public interface UserAuditService
{
- final int TIMEFRAME_NUMBER_OF_HOURS = 1;
- final int MAX_NUMBER_OF_ATTEMPTS = 3;
+ final int TIMEFRAME_MINUTES = 10; //TODO: through System Settings
+ final int MAX_NUMBER_OF_ATTEMPTS = 5; //TODO: through System Settings
void registerLoginSuccess( String username );
void registerLogout( String username );
void registerLoginFailure( String username );
+
+ void resetLockoutTimeframe( String username );
+
+ int getLoginFailures( String username );
+
+ int getMaxAttempts();
+
+ int getLockoutTimeframe();
}
=== modified 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 2010-03-08 07:37:39 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/useraudit/UserAuditStore.java 2010-03-30 23:08:42 +0000
@@ -43,5 +43,7 @@
void deleteLoginFailures( String username );
+ void resetLoginFailures( String username, Date date );
+
int getLoginFailures( String username, Date date );
}
=== modified 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 2010-03-08 07:37:39 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/DefaultUserAuditService.java 2010-03-30 23:08:42 +0000
@@ -40,48 +40,76 @@
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;
}
+ @Override
public void registerLoginSuccess( String username )
{
- log.info( "User login success: '" + username + "'" );
+ log.info( "User login success: '" + username + "'" );
+
+ resetLockoutTimeframe( username );
}
+ @Override
public void registerLogout( String username )
{
log.info( "User logout: '" + username + "'" );
}
@Transactional
+ @Override
public void registerLoginFailure( String username )
{
log.info( "User login failure: '" + username + "'" );
-
+
userAuditStore.saveLoginFailure( new LoginFailure( username, new Date() ) );
-
+
int no = userAuditStore.getLoginFailures( username, getDate() );
-
+
if ( no >= MAX_NUMBER_OF_ATTEMPTS )
{
log.info( "Max number of login attempts exceeded: '" + username + "'" );
-
- userAuditStore.deleteLoginFailures( username );
}
}
-
+
private Date getDate()
{
- Calendar cal = Calendar.getInstance();
- cal.clear();
- cal.add( Calendar.HOUR, TIMEFRAME_NUMBER_OF_HOURS * -1 );
-
+ Calendar cal = Calendar.getInstance();
+ cal.add( Calendar.MINUTE, TIMEFRAME_MINUTES * -1 );
return cal.getTime();
}
+
+ @Transactional
+ @Override
+ public int getLoginFailures( String username )
+ {
+ int no = userAuditStore.getLoginFailures( username, getDate() );
+ return no;
+ }
+
+ @Override
+ public int getMaxAttempts()
+ {
+ return MAX_NUMBER_OF_ATTEMPTS;
+ }
+
+ @Override
+ public int getLockoutTimeframe()
+ {
+ return TIMEFRAME_MINUTES;
+ }
+
+ @Override
+ public void resetLockoutTimeframe( String username )
+ {
+ userAuditStore.resetLoginFailures( username, getDate() );
+ }
}
=== modified 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 2010-03-08 07:37:39 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/useraudit/hibernate/HibernateUserAuditStore.java 2010-03-30 23:08:42 +0000
@@ -29,6 +29,7 @@
import java.util.Collection;
import java.util.Date;
+import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
@@ -41,43 +42,67 @@
public class HibernateUserAuditStore
implements UserAuditStore
{
+
private SessionFactory sessionFactory;
-
+
public void setSessionFactory( SessionFactory sessionFactory )
{
this.sessionFactory = sessionFactory;
}
+ @Override
public void saveLoginFailure( LoginFailure login )
{
sessionFactory.getCurrentSession().save( login );
}
-
- @SuppressWarnings( "unchecked" )
+
+ @SuppressWarnings("unchecked")
+ @Override
public Collection<LoginFailure> getAllLoginFailures()
{
return sessionFactory.getCurrentSession().createCriteria( LoginFailure.class ).list();
}
-
+
+ @Override
public void deleteLoginFailures( String username )
{
String hql = "delete from LoginFailure where username = :username";
-
+
sessionFactory.getCurrentSession().createQuery( hql ).setString( "username", username ).executeUpdate();
}
-
+
+ @Override
public int getLoginFailures( String username, Date date )
{
Session session = sessionFactory.getCurrentSession();
-
- String hql = "delete from LoginFailure where date < :date";
-
- session.createQuery( hql ).setDate( "date", date ).executeUpdate();
-
- hql = "select count(*) from LoginFailure where username = :username";
-
- Long no = (Long) session.createQuery( hql ).setString( "username", username ).uniqueResult();
-
+
+ String hql = "select count(*) from LoginFailure where username = :username and date > :date";
+
+ Query q = session.createQuery( hql );
+
+ q.setString( "username", username );
+
+ q.setTimestamp( "date", date );
+
+ Long no = (Long) q.list().get( 0 );
+
return no.intValue();
}
+
+ //TODO: create GUI for reset and accurate logging
+ @Override
+ public void resetLoginFailures( String username, Date date )
+ {
+ Session session = sessionFactory.getCurrentSession();
+
+ String hql = "delete from LoginFailure where username = :username and date > :date";
+
+ Query q = session.createQuery( hql );
+
+ q.setString( "username", username );
+
+ q.setTimestamp( "date", date );
+
+ q.executeUpdate();
+ }
}
=== removed file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/login.html'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/login.html 2010-03-12 16:38:18 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/login.html 1970-01-01 00:00:00 +0000
@@ -1,39 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
- <head>
- <title>DHIS 2</title>
- <script type="text/javascript" src="../util/jquery.js"></script>
- <script type="text/javascript">
- $(document).ready(function() {
- $('#j_username').focus();
- });
- </script>
- <link type="text/css" rel="stylesheet" media="screen" href="../css/login.css">
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- </head>
- <body>
- <div class="loginField" align="center">
- <p><img alt="" src="logo_banner.png"></p>
- <form action="../../dhis-web-commons-security/login.action" method="post">
- <table>
- <tr>
- <td colspan="2" style="height:40px"></td>
- </tr>
- <tr>
- <td><label for="j_username">Username</label></td>
- <td><input type="text" id="j_username" name="j_username" style="width:18em" autocomplete="off"></td>
- </tr>
- <tr>
- <td><label for="j_password">Password</label></td>
- <td><input type="password" id="j_password" name="j_password" style="width:18em" autocomplete="off"></td>
- </tr>
- <tr>
- <td></td>
- <td><input type="submit" value="Login" style="width:9em">
- <input type="reset" value="Clear" style="width:9em"></td>
- </tr>
- </table>
- </form>
- </div>
- </body>
-</html>
=== added file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/login.jsp'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/login.jsp 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/login.jsp 2010-03-30 23:08:42 +0000
@@ -0,0 +1,59 @@
+<jsp:useBean id="userAuditService" type="org.hisp.dhis.useraudit.UserAuditService" scope="application" />
+<jsp:useBean id="userAuditStore" type="org.hisp.dhis.useraudit.UserAuditStore" scope="application" />
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>DHIS 2</title>
+ <script type="text/javascript" src="../util/jquery.js"></script>
+ <script type="text/javascript">
+ $(document).ready(function() {
+ $('#j_username').focus();
+ });
+ </script>
+ <link type="text/css" rel="stylesheet" media="screen" href="../css/login.css">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ </head>
+ <body>
+ <div class="loginField" align="center">
+ <p><img alt="" src="logo_banner.png"></p>
+ <%
+ Object obj = session.getAttribute( "SPRING_SECURITY_LAST_USERNAME" );
+ boolean formVisible = true;
+ if( obj != null )
+ {
+ String username = obj.toString();
+ if( userAuditService.getLoginFailures(username) >= userAuditService.getMaxAttempts() )
+ {
+ formVisible = false;
+ %>
+ <span class="loginMessage">Maximum Tries exceeded... Please try after <%=userAuditService.getLockoutTimeframe() %> mins</span>
+ <%
+ }
+ }
+ %>
+ <% if(formVisible){%>
+ <form action="../../dhis-web-commons-security/login.action" method="post">
+ <table>
+ <tr>
+ <td colspan="2" style="height:40px"></td>
+ </tr>
+ <tr>
+ <td><label for="j_username">Username</label></td>
+ <td><input type="text" id="j_username" name="j_username" style="width:18em" autocomplete="off"></td>
+ </tr>
+ <tr>
+ <td><label for="j_password">Password</label></td>
+ <td><input type="password" id="j_password" name="j_password" style="width:18em" autocomplete="off"></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td><input type="submit" value="Login" style="width:9em">
+ <input type="reset" value="Clear" style="width:9em"></td>
+ </tr>
+ </table>
+ </form>
+ <% } %>
+ </div>
+ </body>
+</html>
=== removed file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/loginfailed.html'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/loginfailed.html 2009-12-10 22:00:36 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/loginfailed.html 1970-01-01 00:00:00 +0000
@@ -1,42 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
- <head>
- <title>DHIS 2</title>
- <script type="text/javascript" src="../util/jquery.js"></script>
- <script type="text/javascript">
- $(document).ready(function() {
- $('#j_username').focus();
- });
- </script>
- <link type="text/css" rel="stylesheet" media="screen" href="../css/login.css">
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- </head>
- <body>
- <div class="loginField" align="center">
- <p><img alt="" src="logo_banner.png"></p>
- <form action="../../dhis-web-commons-security/login.action" method="post">
- <table>
- <tr>
- <td colspan="2" style="height:40px"></td>
- </tr>
- <tr>
- <td><label for="j_username">Username</label></td>
- <td><input type="text" id="j_username" name="j_username" style="width:18em"></td>
- </tr>
- <tr>
- <td><label for="j_password">Password</label></td>
- <td><input type="password" id="j_password" name="j_password" style="width:18em"></td>
- </tr>
- <tr>
- <td></td>
- <td><input type="submit" value="Login" style="width:9em">
- <input type="reset" value="Clear" style="width:9em"></td>
- </tr>
- <tr>
- <td colspan="2" style="height:40px">
- </tr>
- </table>
- </form>
- <span class="loginMessage">Wrong username or password. Please try again.</span> </div>
- </body>
-</html>
=== added file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/loginfailed.jsp'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/loginfailed.jsp 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/loginfailed.jsp 2010-03-30 23:08:42 +0000
@@ -0,0 +1,63 @@
+<jsp:useBean id="userAuditService" type="org.hisp.dhis.useraudit.UserAuditService" scope="application" />
+<jsp:useBean id="userAuditStore" type="org.hisp.dhis.useraudit.UserAuditStore" scope="application" />
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <title>DHIS 2</title>
+ <script type="text/javascript" src="../util/jquery.js"></script>
+ <script type="text/javascript">
+ $(document).ready(function() {
+ $('#j_username').focus();
+ });
+ </script>
+ <link type="text/css" rel="stylesheet" media="screen" href="../css/login.css">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ </head>
+ <body>
+ <div class="loginField" align="center">
+ <p><img alt="" src="logo_banner.png"></p>
+ <%
+ Object obj = session.getAttribute( "SPRING_SECURITY_LAST_USERNAME" );
+ boolean formVisible = true;
+ if( obj != null )
+ {
+ String username = obj.toString();
+ if( userAuditService.getLoginFailures(username) >= userAuditService.getMaxAttempts() )
+ {
+ formVisible = false;
+ %>
+ <span class="loginMessage">Maximum Tries exceeded... Please try after <%=userAuditService.getLockoutTimeframe() %> mins</span>
+ <%
+ }
+ }
+ %>
+ <% if( formVisible ){%>
+ <form action="../../dhis-web-commons-security/login.action" method="post">
+ <table>
+ <tr>
+ <td colspan="2" style="height:40px"></td>
+ </tr>
+ <tr>
+ <td><label for="j_username">Username</label></td>
+ <td><input type="text" id="j_username" name="j_username" style="width:18em" autocomplete="off"></td>
+ </tr>
+ <tr>
+ <td><label for="j_password">Password</label></td>
+ <td><input type="password" id="j_password" name="j_password" style="width:18em" autocomplete="off"></td>
+ </tr>
+ <tr>
+ <td></td>
+ <td><input type="submit" value="Login" style="width:9em">
+ <input type="reset" value="Clear" style="width:9em"></td>
+ </tr>
+ <tr>
+ <td colspan="2" style="height:40px">
+ </tr>
+ </table>
+ </form>
+ <span class="loginMessage">Wrong username or password. Please try again.</span>
+ <% } %>
+ </div>
+ </body>
+</html>
=== 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-25 04:15:30 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/beans.xml 2010-03-30 23:08:42 +0000
@@ -278,7 +278,7 @@
<bean id="authenticationProcessingFilter"
class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
- <property name="authenticationFailureUrl" value="/dhis-web-commons/security/loginfailed.html" />
+ <property name="authenticationFailureUrl" value="/dhis-web-commons/security/loginfailed.jsp" />
<property name="defaultTargetUrl" value="/dhis-web-commons-security/loggedIn.action" />
<property name="filterProcessesUrl" value="/dhis-web-commons-security/login.action" />
<property name="alwaysUseDefaultTargetUrl" value="true" />
@@ -296,7 +296,7 @@
</bean>
<bean id="userAuditLogoutFilter" class="org.hisp.dhis.security.filter.UserAuditLogoutFilter">
- <property name="userAuditService" ref="org.hisp.dhis.useraudit.UserAuditService"/>
+ <property name="userAuditService" ref="org.hisp.dhis.useraudit.UserAuditService"/>
</bean>
<bean id="automaticAccessFilter" class="org.hisp.dhis.security.filter.AutomaticAccessFilter">
@@ -314,7 +314,20 @@
<bean id="requiredLoginFilter" class="org.hisp.dhis.security.filter.RequiredLoginFilter">
<property name="currentUserService" ref="org.hisp.dhis.user.CurrentUserService" />
- <property name="loginPageUrl" value="/dhis-web-commons/security/login.html" />
+ <property name="loginPageUrl" value="/dhis-web-commons/security/login.jsp" />
+ </bean>
+
+ <bean class="org.springframework.web.context.support.ServletContextAttributeExporter">
+ <property name="attributes">
+ <map>
+ <entry key="userAuditService">
+ <ref bean="org.hisp.dhis.useraudit.UserAuditService"/>
+ </entry>
+ <entry key="userAuditStore">
+ <ref bean="org.hisp.dhis.useraudit.UserAuditStore"/>
+ </entry>
+ </map>
+ </property>
</bean>
<!-- Security : Listener -->