Index: magnolia-module-admininterface/src/main/resources/info/magnolia/module/admininterface/messages_en.properties =================================================================== --- magnolia-module-admininterface/src/main/resources/info/magnolia/module/admininterface/messages_en.properties (revision 46635) +++ magnolia-module-admininterface/src/main/resources/info/magnolia/module/admininterface/messages_en.properties (working copy) @@ -339,7 +339,7 @@ webdav.error = An error occurred. Unable to connect to WebDAV Server -login.defaultError = Error during login. Please try again. +login.defaultError = Error during login. Please try again. Your account might be locked, please contact an administrator if you feel this is wrong. #login.FailedLoginException = Username and password do not match. Please try again. #login.AccountNotFoundException = This account does not exist. Please try again or contact an administrator if you feel this is wrong. #login.AccountLockedException = This account is locked. Please contact an administrator if you feel this is wrong. Index: magnolia-ui-admincentral/src/main/resources/info/magnolia/ui/admincentral/messages.properties =================================================================== --- magnolia-ui-admincentral/src/main/resources/info/magnolia/ui/admincentral/messages.properties (revision 46635) +++ magnolia-ui-admincentral/src/main/resources/info/magnolia/ui/admincentral/messages.properties (working copy) @@ -347,7 +347,7 @@ webdav.error = An error occurred. Unable to connect to WebDAV Server -login.defaultError = Error during login. Please try again. +login.defaultError = Error during login. Please try again. Your account might be locked, please contact an administrator if you feel this is wrong. #login.FailedLoginException = Username and password do not match. Please try again. #login.AccountNotFoundException = This account does not exist. Please try again or contact an administrator if you feel this is wrong. #login.AccountLockedException = This account is locked. Please contact an administrator if you feel this is wrong. Index: magnolia-jaas/src/main/java/info/magnolia/jaas/sp/jcr/JCRAuthenticationModule.java =================================================================== --- magnolia-jaas/src/main/java/info/magnolia/jaas/sp/jcr/JCRAuthenticationModule.java (revision 46635) +++ magnolia-jaas/src/main/java/info/magnolia/jaas/sp/jcr/JCRAuthenticationModule.java (working copy) @@ -45,7 +45,10 @@ import org.apache.commons.lang.StringUtils; import org.apache.jackrabbit.core.security.UserPrincipal; import org.apache.jackrabbit.core.security.principal.AdminPrincipal; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import javax.security.auth.login.FailedLoginException; import javax.security.auth.login.LoginException; import javax.security.auth.login.AccountNotFoundException; @@ -64,6 +67,7 @@ // JR requires login module to be serializable! public class JCRAuthenticationModule extends AbstractLoginModule implements UserAwareLoginModule, Serializable { + private static final Logger log = LoggerFactory.getLogger(JCRAuthenticationModule.class); private static final boolean logAdmin = false; protected User user; @@ -78,6 +82,21 @@ } } + + /** + * Get number of failed login attempts before locking account. + */ + public int getMaxAttempts() { + String realm; + if (this.user instanceof MgnlUser) { + realm = ((MgnlUser) user).getRealm(); + //If not supported by user manager then lockout is disabled. + } else { + return 0; + } + MgnlUserManager manager = (MgnlUserManager) SecuritySupport.Factory.getInstance().getUserManager(realm); + return (int)manager.getMaxFailedLoginAttempts(); + } /** * Releases all associated memory. @@ -99,11 +118,11 @@ throw new AccountNotFoundException("User account " + this.name + " not found."); } - matchPassword(); - if (!this.user.isEnabled()) { throw new AccountLockedException("User account " + this.name + " is locked."); } + + matchPassword(); if (!UserManager.ANONYMOUS_USER.equals(user.getName()) && !isAdmin()) { // update last access date for all non anonymous users @@ -152,8 +171,26 @@ } if (!StringUtils.equals(serverPassword, new String(this.pswd))) { + if (getMaxAttempts() > 0 && !UserManager.ANONYMOUS_USER.equals(user.getName())){ + //Only MgnlUser is able to use lockout i.e. has maxAttempts higher than 0. + MgnlUser mgnlUser = (MgnlUser) user; + System.out.println("ATTEMPTS: " + mgnlUser.getFailedLoginAttempts()); + mgnlUser.setFailedLoginAttempts(mgnlUser.getFailedLoginAttempts() + 1); + + if (mgnlUser.getFailedLoginAttempts() >= getMaxAttempts()){ + mgnlUser.setEnabled(false); + mgnlUser.setFailedLoginAttempts(0); + log.warn("Account " + this.name + " was locked due to high number of failed login attempts."); + } + } throw new FailedLoginException("passwords do not match"); } + if(user instanceof MgnlUser){ + MgnlUser mgnlUser = (MgnlUser) user; + if (getMaxAttempts() > 0 && !UserManager.ANONYMOUS_USER.equals(mgnlUser.getName()) && mgnlUser.getFailedLoginAttempts() > 0){ + mgnlUser.setFailedLoginAttempts(0); + } + } } /** Property changes on: magnolia-core ___________________________________________________________________ Modified: svn:mergeinfo Merged /community/magnolia/branches/magnolia-4.4/magnolia-core:r45105,45194 Property changes on: magnolia-core/src/test/java/info/magnolia/objectfactory ___________________________________________________________________ Modified: svn:mergeinfo Merged /community/magnolia/branches/magnolia-4.4/magnolia-core/src/test/java/info/magnolia/objectfactory:r45105,45194 Property changes on: magnolia-core/src/test/java/info/magnolia/objectfactory/DefaultClassFactoryTest.java ___________________________________________________________________ Modified: svn:mergeinfo Merged /community/magnolia/branches/magnolia-4.4/magnolia-core/src/test/java/info/magnolia/objectfactory/DefaultClassFactoryTest.java:r45105,45194 Property changes on: magnolia-core/src/test/java/info/magnolia/objectfactory/DefaultComponentProviderTest.java ___________________________________________________________________ Modified: svn:mergeinfo Merged /community/magnolia/branches/magnolia-4.4/magnolia-core/src/test/java/info/magnolia/objectfactory/DefaultComponentProviderTest.java:r45105,45194 Property changes on: magnolia-core/src/test/java/info/magnolia/objectfactory/ObservedComponentFactoryTest.java ___________________________________________________________________ Modified: svn:mergeinfo Merged /community/magnolia/branches/magnolia-4.4/magnolia-core/src/test/java/info/magnolia/objectfactory/ObservedComponentFactoryTest.java:r45105,45194 Property changes on: magnolia-core/src/test/java/info/magnolia/objectfactory/ClassesTest.java ___________________________________________________________________ Modified: svn:mergeinfo Merged /community/magnolia/branches/magnolia-4.4/magnolia-core/src/test/java/info/magnolia/objectfactory/ClassesTest.java:r45105,45194 Property changes on: magnolia-core/src/test/java/info/magnolia/objectfactory/ObjectFactoryTest.java ___________________________________________________________________ Modified: svn:mergeinfo Merged /community/magnolia/branches/magnolia-4.4/magnolia-core/src/test/java/info/magnolia/objectfactory/ObjectFactoryTest.java:r45105,45194 Index: magnolia-core/src/main/java/info/magnolia/cms/security/MgnlUserManager.java =================================================================== --- magnolia-core/src/main/java/info/magnolia/cms/security/MgnlUserManager.java (revision 46635) +++ magnolia-core/src/main/java/info/magnolia/cms/security/MgnlUserManager.java (working copy) @@ -94,12 +94,22 @@ private String realmName; + private int maxFailedLoginAttempts; + /** * There should be no need to instantiate this class except maybe for testing. Manual instantiation might cause manager not to be initialized properly. */ public MgnlUserManager() { } + public void setMaxFailedLoginAttempts(int maxFailedLoginAttempts){ + this.maxFailedLoginAttempts = maxFailedLoginAttempts; + } + + public int getMaxFailedLoginAttempts(){ + return maxFailedLoginAttempts; + } + /** * TODO : rename to getRealmName and setRealmName (and make sure Content2Bean still sets realmName using the parent's node name). * @deprecated since 5.0 use realmName instead Index: magnolia-core/src/main/java/info/magnolia/cms/security/MgnlUser.java =================================================================== --- magnolia-core/src/main/java/info/magnolia/cms/security/MgnlUser.java (revision 46635) +++ magnolia-core/src/main/java/info/magnolia/cms/security/MgnlUser.java (working copy) @@ -104,6 +104,40 @@ encodedPassword = properties.get(MgnlUserManager.PROPERTY_PASSWORD); } + public int getFailedLoginAttempts(){ + + return MgnlContext.doInSystemContext(new SilentSessionOp(ContentRepository.USERS) { + + @Override + public Integer doExec(Session session) throws RepositoryException { + Node userNode = session.getNode("/" + getRealm() + "/" + getName()); + //if(session.isLive()){ + // session.logout(); + //} + return (int)userNode.getProperty("failedAttempts").getLong(); + + }}); + } + + public User setFailedLoginAttempts(final int failed){ + return MgnlContext.doInSystemContext(new SilentSessionOp(ContentRepository.USERS) { + + @Override + public User doExec(Session session) throws RepositoryException { + Node userNode = session.getNode("/" + getRealm() + "/" + getName()); + userNode.setProperty("failedAttempts", (long)failed); + + session.save(); + + //if(session.isLive()){ + // session.logout(); + //} + MgnlUserManager manager = new MgnlUserManager(); + return manager.newUserInstance(userNode); + } + }); + } + /** * Is this user in a specified group? * @param groupName the name of the group Index: magnolia-core/src/main/java/info/magnolia/setup/CoreModuleVersionHandler.java =================================================================== --- magnolia-core/src/main/java/info/magnolia/setup/CoreModuleVersionHandler.java (revision 46635) +++ magnolia-core/src/main/java/info/magnolia/setup/CoreModuleVersionHandler.java (working copy) @@ -69,6 +69,7 @@ import info.magnolia.setup.for3_6_2.UpdateRoles; import info.magnolia.setup.for3_6_2.UpdateUsers; import info.magnolia.setup.for4_3.UpdateUserPermissions; +import info.magnolia.setup.for4_4_3.UpdateUserManagers; import java.util.ArrayList; import java.util.List; @@ -208,6 +209,10 @@ addProperty("toWebContainerResources", Boolean.FALSE)) ))))); + register(DeltaBuilder.update("5.0", "") + .addTask(new NodeExistsDelegateTask("", "", ContentRepository.CONFIG, "/server/security/userManagers", new UpdateUserManagers())) + ); + } private PropertyValueDelegateTask fixMimetype(String mimeType, final String previouslyWrongValue, final String fixedValue) { Index: magnolia-core/src/main/resources/mgnl-bootstrap/core/config.server.security.xml =================================================================== --- magnolia-core/src/main/resources/mgnl-bootstrap/core/config.server.security.xml (revision 46635) +++ magnolia-core/src/main/resources/mgnl-bootstrap/core/config.server.security.xml (working copy) @@ -79,6 +79,9 @@ system + + 5 + mgnl:metaData @@ -113,6 +116,9 @@ admin + + 5 + mgnl:metaData