From ba7f975435f870cb0edf2c96f29d7167ab0790ed Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 24 May 2012 21:24:39 +0200 Subject: [PATCH 01/18] added field to user for active state --- .../src/main/java/sonia/scm/user/User.java | 33 +++++++++++++++++-- .../scm/user/orientdb/UserConverter.java | 7 ++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/user/User.java b/scm-core/src/main/java/sonia/scm/user/User.java index 6954b1a4ba..abef0d9829 100644 --- a/scm-core/src/main/java/sonia/scm/user/User.java +++ b/scm-core/src/main/java/sonia/scm/user/User.java @@ -216,6 +216,7 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject && Objects.equal(mail, other.mail) && Objects.equal(type, other.type) && Objects.equal(admin, other.admin) + && Objects.equal(active, other.active) && Objects.equal(password, other.password) && Objects.equal(creationDate, other.creationDate) && Objects.equal(lastModified, other.lastModified) @@ -232,7 +233,7 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject public int hashCode() { return Objects.hashCode(name, displayName, mail, type, admin, password, - creationDate, lastModified, properties); + active, creationDate, lastModified, properties); } /** @@ -256,6 +257,7 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject .add("password", pwd) .add("admin", admin) .add("type", type) + .add("active", active) .add("creationDate", creationDate) .add("lastModified", lastModified) .add("properties", properties) @@ -357,6 +359,18 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject return type; } + /** + * Returns false if the user is deactivated. + * + * + * @return false if the user is deactivated + * @since 1.16 + */ + public boolean isActive() + { + return active; + } + /** * Method description * @@ -384,6 +398,18 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject //~--- set methods ---------------------------------------------------------- + /** + * Activate or deactive this user. + * + * + * @param active false to deactivate the user. + * @since 1.6 + */ + public void setActive(boolean active) + { + this.active = active; + } + /** * Method description * @@ -476,7 +502,10 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject //~--- fields --------------------------------------------------------------- /** Field description */ - private boolean admin; + private boolean active = true; + + /** Field description */ + private boolean admin = false; /** Field description */ private Long creationDate; diff --git a/scm-dao-orientdb/src/main/java/sonia/scm/user/orientdb/UserConverter.java b/scm-dao-orientdb/src/main/java/sonia/scm/user/orientdb/UserConverter.java index 976abccba1..7aabd57101 100644 --- a/scm-dao-orientdb/src/main/java/sonia/scm/user/orientdb/UserConverter.java +++ b/scm-dao-orientdb/src/main/java/sonia/scm/user/orientdb/UserConverter.java @@ -30,6 +30,7 @@ */ + package sonia.scm.user.orientdb; //~--- non-JDK imports -------------------------------------------------------- @@ -59,6 +60,9 @@ public class UserConverter extends AbstractConverter implements Converter /** Field description */ public static final String DOCUMENT_CLASS = "User"; + /** Field description */ + public static final String FIELD_ACTIVE = "active"; + /** Field description */ public static final String FIELD_ADMIN = "admin"; @@ -115,6 +119,7 @@ public class UserConverter extends AbstractConverter implements Converter appendField(doc, FIELD_MAIL, user.getMail()); appendField(doc, FIELD_PASSWORD, user.getPassword()); appendField(doc, FIELD_ADMIN, user.isAdmin()); + appendField(doc, FIELD_ACTIVE, user.isActive()); appendField(doc, FIELD_CREATIONDATE, user.getCreationDate(), OType.LONG); appendPropertiesField(doc, user); @@ -140,6 +145,7 @@ public class UserConverter extends AbstractConverter implements Converter user.setPassword(getStringField(doc, FIELD_PASSWORD)); user.setType(getStringField(doc, FIELD_TYPE)); user.setAdmin(getBooleanField(doc, FIELD_ADMIN)); + user.setAdmin(getBooleanField(doc, FIELD_ACTIVE)); user.setLastModified(getLongField(doc, FIELD_LASTMODIFIED)); user.setCreationDate(getLongField(doc, FIELD_CREATIONDATE)); @@ -176,6 +182,7 @@ public class UserConverter extends AbstractConverter implements Converter oclass.createProperty(FIELD_CREATIONDATE, OType.LONG); oclass.createProperty(FIELD_DISPLAYNAME, OType.STRING); oclass.createProperty(FIELD_MAIL, OType.STRING); + oclass.createProperty(FIELD_ACTIVE, OType.STRING); oclass.createProperty(FIELD_PASSWORD, OType.STRING); oclass.createProperty(FIELD_PROPERTIES, OType.EMBEDDEDMAP); From f63b73c87e816fc7755c954a160176fc21c19964 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 24 May 2012 21:31:06 +0200 Subject: [PATCH 02/18] added activate field to user form --- .../webapp/resources/js/user/sonia.user.formpanel.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js index c696e97e79..1e305926fc 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js @@ -36,6 +36,8 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ mailText: 'Mail', passwordText: 'Password', adminText: 'Administrator', + // TODO i18n + activeText: 'Active', errorTitleText: 'Error', updateErrorMsgText: 'User update failed', createErrorMsgText: 'User creation failed', @@ -48,6 +50,8 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ passwordHelpText: 'Plain text password of the user.', passwordConfirmHelpText: 'Repeat the password for validation.', adminHelpText: 'An administrator is able to create, modify and delete repositories, groups and users.', + // TODO i18n + activeHelpText: 'Activate or deactive the user.', initComponent: function(){ @@ -100,6 +104,11 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ name: 'admin', xtype: 'checkbox', helpText: this.adminHelpText + },{ + fieldLabel: this.activeText, + name: 'active', + xtype: 'checkbox', + helpText: this.activeHelpText }); Ext.apply(this, Ext.apply(this.initialConfig, {items: items})); From 78ddc082dc39bedba36be1b71f27e6f6eafd0689 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 24 May 2012 21:33:04 +0200 Subject: [PATCH 03/18] german localization for active field --- scm-webapp/src/main/webapp/resources/js/i18n/de.js | 4 +++- .../src/main/webapp/resources/js/user/sonia.user.formpanel.js | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scm-webapp/src/main/webapp/resources/js/i18n/de.js b/scm-webapp/src/main/webapp/resources/js/i18n/de.js index c7780c6e8c..63c355abcd 100644 --- a/scm-webapp/src/main/webapp/resources/js/i18n/de.js +++ b/scm-webapp/src/main/webapp/resources/js/i18n/de.js @@ -373,6 +373,7 @@ if (Sonia.user.FormPanel){ mailText: 'E-Mail', passwordText: 'Passwort', adminText: 'Administrator', + activeText: 'Aktiv', errorTitleText: 'Fehler', updateErrorMsgText: 'Benutzer Aktualisierung fehlgeschlagen', createErrorMsgText: 'Benutzer Erstellung fehlgeschlagen', @@ -384,7 +385,8 @@ if (Sonia.user.FormPanel){ mailHelpText: 'E-Mail Adresse des Benutzers.', passwordHelpText: 'Passwort des Benutzers.', passwordConfirmHelpText: 'Passwortwiederholung zur Kontrolle.', - adminHelpText: 'Ein Administrator kann Repositories, Gruppen und Benutzer erstellen, bearbeiten und löschen.' + adminHelpText: 'Ein Administrator kann Repositories, Gruppen und Benutzer erstellen, bearbeiten und löschen.', + activeHelpText: 'User deaktivieren oder aktivieren.' }); } diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js index 1e305926fc..3e8528d5a8 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js @@ -36,7 +36,6 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ mailText: 'Mail', passwordText: 'Password', adminText: 'Administrator', - // TODO i18n activeText: 'Active', errorTitleText: 'Error', updateErrorMsgText: 'User update failed', @@ -50,7 +49,6 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ passwordHelpText: 'Plain text password of the user.', passwordConfirmHelpText: 'Repeat the password for validation.', adminHelpText: 'An administrator is able to create, modify and delete repositories, groups and users.', - // TODO i18n activeHelpText: 'Activate or deactive the user.', initComponent: function(){ From 94c7f96eeb500f73524947f25fe34d48ef84311a Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 24 May 2012 21:48:05 +0200 Subject: [PATCH 04/18] cleanup authenticate method --- .../web/security/BasicSecurityContext.java | 141 ++++++++++++------ 1 file changed, 94 insertions(+), 47 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java b/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java index 97cddfd7d1..7d84af171a 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java +++ b/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java @@ -35,6 +35,7 @@ package sonia.scm.web.security; //~--- non-JDK imports -------------------------------------------------------- +import com.google.common.collect.Sets; import com.google.inject.Inject; import com.google.inject.servlet.SessionScoped; @@ -46,11 +47,14 @@ import sonia.scm.group.Group; import sonia.scm.group.GroupManager; import sonia.scm.security.CipherUtil; import sonia.scm.user.User; +import sonia.scm.user.UserException; import sonia.scm.user.UserManager; import sonia.scm.util.Util; //~--- JDK imports ------------------------------------------------------------ +import java.io.IOException; + import java.util.Collection; import java.util.HashSet; import java.util.Iterator; @@ -129,64 +133,21 @@ public class BasicSecurityContext implements WebSecurityContext try { - Set groupSet = new HashSet(); - - // load external groups - Collection extGroups = ar.getGroups(); - - if (extGroups != null) - { - groupSet.addAll(extGroups); - } - - // load internal groups - loadGroups(groupSet); + Set groupSet = createGroupSet(ar); // check for admin user - if (!user.isAdmin()) - { - user.setAdmin(isAdmin(groupSet)); - - if (logger.isDebugEnabled() && user.isAdmin()) - { - logger.debug("user '{}' is marked as admin by configuration", - user.getName()); - } - } - else if (logger.isDebugEnabled()) - { - logger.debug("authenticator {} marked user '{}' as admin", - user.getType(), user.getName()); - } + checkForAuthenticatedAdmin(user, groupSet); // store user User dbUser = userManager.get(user.getName()); if (dbUser != null) { - - // if database user is an admin, set admin for the current user - if (dbUser.isAdmin()) - { - if (logger.isDebugEnabled()) - { - logger.debug( - "user '{}' of type '{}' is marked as admin by local database", - user.getName(), user.getType()); - } - - user.setAdmin(true); - } - - // modify existing user, copy properties except password and admin - if (user.copyProperties(dbUser, false)) - { - userManager.modify(dbUser); - } + checkForDBAdmin(user, dbUser); } // create new user - else if (dbUser == null) + else { userManager.create(user); } @@ -296,6 +257,92 @@ public class BasicSecurityContext implements WebSecurityContext //~--- methods -------------------------------------------------------------- + /** + * Method description + * + * + * @param user + * @param groupSet + */ + private void checkForAuthenticatedAdmin(User user, Set groupSet) + { + if (!user.isAdmin()) + { + user.setAdmin(isAdmin(groupSet)); + + if (logger.isDebugEnabled() && user.isAdmin()) + { + logger.debug("user '{}' is marked as admin by configuration", + user.getName()); + } + } + else if (logger.isDebugEnabled()) + { + logger.debug("authenticator {} marked user '{}' as admin", + user.getType(), user.getName()); + } + } + + /** + * Method description + * + * + * @param user + * @param dbUser + * + * @throws IOException + * @throws UserException + */ + private void checkForDBAdmin(User user, User dbUser) + throws UserException, IOException + { + + // if database user is an admin, set admin for the current user + if (dbUser.isAdmin()) + { + if (logger.isDebugEnabled()) + { + logger.debug( + "user '{}' of type '{}' is marked as admin by local database", + user.getName(), user.getType()); + } + + user.setAdmin(true); + } + + // modify existing user, copy properties except password and admin + if (user.copyProperties(dbUser, false)) + { + userManager.modify(dbUser); + } + } + + /** + * Method description + * + * + * @param ar + * + * @return + */ + private Set createGroupSet(AuthenticationResult ar) + { + Set groupSet = Sets.newHashSet(); + + // load external groups + Collection extGroups = ar.getGroups(); + + if (extGroups != null) + { + groupSet.addAll(extGroups); + } + + // load internal groups + loadGroups(groupSet); + + return groupSet; + } + /** * Method description * From 1ef15fd281d8a842b17fe3065e7eb915a7eea800 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 24 May 2012 22:02:25 +0200 Subject: [PATCH 05/18] only active users should be able to login --- .../web/security/BasicSecurityContext.java | 180 +++++++++++------- .../DefaultAuthenticationHandler.java | 3 +- 2 files changed, 117 insertions(+), 66 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java b/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java index 7d84af171a..3080da6c65 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java +++ b/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java @@ -129,58 +129,7 @@ public class BasicSecurityContext implements WebSecurityContext if ((ar != null) && (ar.getState() == AuthenticationState.SUCCESS)) { - user = ar.getUser(); - - try - { - Set groupSet = createGroupSet(ar); - - // check for admin user - checkForAuthenticatedAdmin(user, groupSet); - - // store user - User dbUser = userManager.get(user.getName()); - - if (dbUser != null) - { - checkForDBAdmin(user, dbUser); - } - - // create new user - else - { - userManager.create(user); - } - - groups = groupSet; - - if (logger.isDebugEnabled()) - { - logGroups(); - } - - // store encrypted credentials in session - String credentials = user.getName(); - - if (Util.isNotEmpty(password)) - { - credentials = credentials.concat(":").concat(password); - } - - credentials = CipherUtil.getInstance().encode(credentials); - request.getSession(true).setAttribute(SCM_CREDENTIALS, credentials); - } - catch (Exception ex) - { - user = null; - - if (groups != null) - { - groups.clear(); - } - - logger.error("authentication failed", ex); - } + authenticate(request, password, ar); } return user; @@ -261,25 +210,100 @@ public class BasicSecurityContext implements WebSecurityContext * Method description * * - * @param user - * @param groupSet + * @param request + * @param password + * @param ar */ - private void checkForAuthenticatedAdmin(User user, Set groupSet) + private void authenticate(HttpServletRequest request, String password, + AuthenticationResult ar) { - if (!user.isAdmin()) - { - user.setAdmin(isAdmin(groupSet)); + user = ar.getUser(); - if (logger.isDebugEnabled() && user.isAdmin()) + try + { + Set groupSet = createGroupSet(ar); + + // check for admin user + checkForAuthenticatedAdmin(user, groupSet); + + // store user + User dbUser = userManager.get(user.getName()); + + if (dbUser != null) { - logger.debug("user '{}' is marked as admin by configuration", - user.getName()); + checkDBForAdmin(user, dbUser); + checkDBForActive(user, dbUser); + } + + // create new user + else + { + userManager.create(user); + } + + if (user.isActive()) + { + groups = groupSet; + + if (logger.isDebugEnabled()) + { + logGroups(); + } + + // store encrypted credentials in session + String credentials = user.getName(); + + if (Util.isNotEmpty(password)) + { + credentials = credentials.concat(":").concat(password); + } + + credentials = CipherUtil.getInstance().encode(credentials); + request.getSession(true).setAttribute(SCM_CREDENTIALS, credentials); + } + else + { + if (logger.isWarnEnabled()) + { + logger.warn("user '{}' is deactivated", user.getName()); + } + + user = null; + groups = null; } } - else if (logger.isDebugEnabled()) + catch (Exception ex) { - logger.debug("authenticator {} marked user '{}' as admin", - user.getType(), user.getName()); + user = null; + + if (groups != null) + { + groups.clear(); + } + + logger.error("authentication failed", ex); + } + } + + /** + * Method description + * + * + * @param user + * @param dbUser + */ + private void checkDBForActive(User user, User dbUser) + { + + // user is deactivated by database + if (!dbUser.isActive()) + { + if (logger.isDebugEnabled()) + { + logger.debug("user '{}' is marked as deactivated by local database"); + } + + user.setActive(false); } } @@ -293,7 +317,7 @@ public class BasicSecurityContext implements WebSecurityContext * @throws IOException * @throws UserException */ - private void checkForDBAdmin(User user, User dbUser) + private void checkDBForAdmin(User user, User dbUser) throws UserException, IOException { @@ -317,6 +341,32 @@ public class BasicSecurityContext implements WebSecurityContext } } + /** + * Method description + * + * + * @param user + * @param groupSet + */ + private void checkForAuthenticatedAdmin(User user, Set groupSet) + { + if (!user.isAdmin()) + { + user.setAdmin(isAdmin(groupSet)); + + if (logger.isDebugEnabled() && user.isAdmin()) + { + logger.debug("user '{}' is marked as admin by configuration", + user.getName()); + } + } + else if (logger.isDebugEnabled()) + { + logger.debug("authenticator {} marked user '{}' as admin", + user.getType(), user.getName()); + } + } + /** * Method description * diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAuthenticationHandler.java b/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAuthenticationHandler.java index 2892d8d6e4..33dec44642 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAuthenticationHandler.java +++ b/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAuthenticationHandler.java @@ -105,7 +105,8 @@ public class DefaultAuthenticationHandler implements AuthenticationHandler AuthenticationResult result = null; User user = userManager.get(username); - if (user != null) + // return not found, if the user is not active + if (user != null && user.isActive()) { if (userManager.getDefaultType().equals(user.getType())) { From 2331d93eab59efcb93709907c90190df1f6fcb9e Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 24 May 2012 22:03:57 +0200 Subject: [PATCH 06/18] copy active property --- scm-core/src/main/java/sonia/scm/user/User.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scm-core/src/main/java/sonia/scm/user/User.java b/scm-core/src/main/java/sonia/scm/user/User.java index abef0d9829..b273c7ef69 100644 --- a/scm-core/src/main/java/sonia/scm/user/User.java +++ b/scm-core/src/main/java/sonia/scm/user/User.java @@ -155,6 +155,12 @@ public class User extends BasicPropertiesAware implements Principal, ModelObject user.setAdmin(admin); } + if (user.isActive() != active) + { + result = true; + user.setActive(active); + } + if (Util.isNotEquals(user.getDisplayName(), displayName)) { result = true; From da7c279542a6806f71e26bd5896bd7d93f74b243 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 24 May 2012 22:23:09 +0200 Subject: [PATCH 07/18] added active field to user store --- .../src/main/webapp/resources/js/user/sonia.user.formpanel.js | 2 +- scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js index 3e8528d5a8..ff9508e2f5 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js @@ -106,7 +106,7 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ fieldLabel: this.activeText, name: 'active', xtype: 'checkbox', - helpText: this.activeHelpText + helpText: this.activeHelpText }); Ext.apply(this, Ext.apply(this.initialConfig, {items: items})); diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js index 9f4ea8f0be..5524ae0095 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js @@ -52,7 +52,7 @@ Sonia.user.Grid = Ext.extend(Sonia.rest.Grid, { disableCaching: false }), idProperty: 'name', - fields: [ 'name', 'displayName', 'mail', 'admin', 'creationDate', 'lastModified', 'type', 'properties'], + fields: [ 'name', 'displayName', 'mail', 'admin', 'active', 'creationDate', 'lastModified', 'type', 'properties'], sortInfo: { field: 'name' } From f3412f5aee461f090eecf0740cc1dc376428227c Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 24 May 2012 22:28:29 +0200 Subject: [PATCH 08/18] deactivated users should be handled by security context --- .../sonia/scm/web/security/DefaultAuthenticationHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAuthenticationHandler.java b/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAuthenticationHandler.java index 33dec44642..2892d8d6e4 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAuthenticationHandler.java +++ b/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAuthenticationHandler.java @@ -105,8 +105,7 @@ public class DefaultAuthenticationHandler implements AuthenticationHandler AuthenticationResult result = null; User user = userManager.get(username); - // return not found, if the user is not active - if (user != null && user.isActive()) + if (user != null) { if (userManager.getDefaultType().equals(user.getType())) { From 564b603d9a5074daedd65a4383831fd01dcb75f9 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 24 May 2012 22:30:00 +0200 Subject: [PATCH 09/18] improve logging --- .../sonia/scm/web/security/BasicSecurityContext.java | 10 +++++----- .../scm/web/security/DefaultAuthenticationHandler.java | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java b/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java index 3080da6c65..71342661f9 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java +++ b/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java @@ -265,7 +265,7 @@ public class BasicSecurityContext implements WebSecurityContext { if (logger.isWarnEnabled()) { - logger.warn("user '{}' is deactivated", user.getName()); + logger.warn("user {} is deactivated", user.getName()); } user = null; @@ -300,7 +300,7 @@ public class BasicSecurityContext implements WebSecurityContext { if (logger.isDebugEnabled()) { - logger.debug("user '{}' is marked as deactivated by local database"); + logger.debug("user {} is marked as deactivated by local database"); } user.setActive(false); @@ -327,7 +327,7 @@ public class BasicSecurityContext implements WebSecurityContext if (logger.isDebugEnabled()) { logger.debug( - "user '{}' of type '{}' is marked as admin by local database", + "user {} of type {} is marked as admin by local database", user.getName(), user.getType()); } @@ -356,13 +356,13 @@ public class BasicSecurityContext implements WebSecurityContext if (logger.isDebugEnabled() && user.isAdmin()) { - logger.debug("user '{}' is marked as admin by configuration", + logger.debug("user {} is marked as admin by configuration", user.getName()); } } else if (logger.isDebugEnabled()) { - logger.debug("authenticator {} marked user '{}' as admin", + logger.debug("authenticator {} marked user {} as admin", user.getType(), user.getName()); } } diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAuthenticationHandler.java b/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAuthenticationHandler.java index 2892d8d6e4..3e96c4a77e 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAuthenticationHandler.java +++ b/scm-webapp/src/main/java/sonia/scm/web/security/DefaultAuthenticationHandler.java @@ -208,7 +208,7 @@ public class DefaultAuthenticationHandler implements AuthenticationHandler { if (logger.isDebugEnabled()) { - logger.debug("user {} logged in successfully", username); + logger.debug("user {} successfully prepared for login", username); } user.setPassword(null); From 32257dc6d9a1b0709cb9fcc42198d0263245b478 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 24 May 2012 22:33:00 +0200 Subject: [PATCH 10/18] added missing logging parameter --- .../sonia/scm/web/security/BasicSecurityContext.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java b/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java index 71342661f9..f17bb67494 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java +++ b/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java @@ -300,7 +300,8 @@ public class BasicSecurityContext implements WebSecurityContext { if (logger.isDebugEnabled()) { - logger.debug("user {} is marked as deactivated by local database"); + logger.debug("user {} is marked as deactivated by local database", + user.getName()); } user.setActive(false); @@ -326,9 +327,8 @@ public class BasicSecurityContext implements WebSecurityContext { if (logger.isDebugEnabled()) { - logger.debug( - "user {} of type {} is marked as admin by local database", - user.getName(), user.getType()); + logger.debug("user {} of type {} is marked as admin by local database", + user.getName(), user.getType()); } user.setAdmin(true); @@ -362,8 +362,8 @@ public class BasicSecurityContext implements WebSecurityContext } else if (logger.isDebugEnabled()) { - logger.debug("authenticator {} marked user {} as admin", - user.getType(), user.getName()); + logger.debug("authenticator {} marked user {} as admin", user.getType(), + user.getName()); } } From 5259113c4534d1f9e33a3dc73df973625692de7b Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 25 May 2012 12:12:23 +0200 Subject: [PATCH 11/18] added integration test for deactivated users --- .../sonia/scm/it/DeactivatedUserITCase.java | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 scm-webapp/src/test/java/sonia/scm/it/DeactivatedUserITCase.java diff --git a/scm-webapp/src/test/java/sonia/scm/it/DeactivatedUserITCase.java b/scm-webapp/src/test/java/sonia/scm/it/DeactivatedUserITCase.java new file mode 100644 index 0000000000..b29c17b5a4 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/it/DeactivatedUserITCase.java @@ -0,0 +1,137 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of SCM-Manager; + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.it; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import sonia.scm.user.User; +import sonia.scm.user.UserTestData; + +import static org.junit.Assert.*; + +import static sonia.scm.it.IntegrationTestUtil.*; + +//~--- JDK imports ------------------------------------------------------------ + +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.WebResource; + +import javax.ws.rs.core.MediaType; + +/** + * + * @author Sebastian Sdorra + */ +public class DeactivatedUserITCase +{ + + /** + * Method description + * + */ + @Before + public void createDeactivatedUser() + { + Client client = createAdminClient(); + + try + { + WebResource wr = createResource(client, "users"); + + slarti = UserTestData.createSlarti(); + slarti.setPassword("slart123"); + slarti.setActive(false); + + ClientResponse response = + wr.type(MediaType.APPLICATION_XML).post(ClientResponse.class, slarti); + + assertNotNull(response); + assertEquals(201, response.getStatus()); + response.close(); + } + finally + { + client.destroy(); + } + } + + /** + * Method description + * + */ + @After + public void destroyDeactivatedUser() + { + Client client = createAdminClient(); + + try + { + WebResource wr = createResource(client, + "users/".concat(slarti.getName())); + ClientResponse response = + wr.type(MediaType.APPLICATION_XML).delete(ClientResponse.class); + + assertNotNull(response); + assertEquals(204, response.getStatus()); + response.close(); + } + finally + { + client.destroy(); + } + } + + /** + * Method description + * + */ + @Test + public void testFailedAuthentication() + { + Client client = createClient(); + ClientResponse response = authenticate(client, slarti.getName(), + "slart123"); + + assertNotNull(response); + assertEquals(401, response.getStatus()); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private User slarti; +} From 0eea3579e74dec66c2f24cc615578b386688dedd Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 25 May 2012 12:41:46 +0200 Subject: [PATCH 12/18] added active flag to user command output --- .../src/main/resources/sonia/resources/get-user.ftl | 1 + .../src/main/resources/sonia/resources/list-users.ftl | 1 + 2 files changed, 2 insertions(+) diff --git a/scm-clients/scm-cli-client/src/main/resources/sonia/resources/get-user.ftl b/scm-clients/scm-cli-client/src/main/resources/sonia/resources/get-user.ftl index 0b20ab6070..45f08e56d1 100644 --- a/scm-clients/scm-cli-client/src/main/resources/sonia/resources/get-user.ftl +++ b/scm-clients/scm-cli-client/src/main/resources/sonia/resources/get-user.ftl @@ -2,6 +2,7 @@ Name: ${user.name} Display Name: ${user.displayName} Type: ${user.type} E-Mail: ${user.mail!""} +Active: ${user.admin?string} Administrator: ${user.admin?string} Creation-Date: <#if user.creationDate??>${user.creationDate?string("yyyy-MM-dd HH:mm:ss")} Last-Modified: <#if user.lastModified??>${user.lastModified?string("yyyy-MM-dd HH:mm:ss")} diff --git a/scm-clients/scm-cli-client/src/main/resources/sonia/resources/list-users.ftl b/scm-clients/scm-cli-client/src/main/resources/sonia/resources/list-users.ftl index 16e53b7f37..eab8106c3c 100644 --- a/scm-clients/scm-cli-client/src/main/resources/sonia/resources/list-users.ftl +++ b/scm-clients/scm-cli-client/src/main/resources/sonia/resources/list-users.ftl @@ -3,6 +3,7 @@ Name: ${user.name} Display Name: ${user.displayName} Type: ${user.type} E-Mail: ${user.mail!""} +Active: ${user.admin?string} Administrator: ${user.admin?string} Creation-Date: <#if user.creationDate??>${user.creationDate?string("yyyy-MM-dd HH:mm:ss")} Last-Modified: <#if user.lastModified??>${user.lastModified?string("yyyy-MM-dd HH:mm:ss")} From 7e7f6191ed547eedadace05cee0d40580bec0198 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sat, 26 May 2012 10:47:12 +0200 Subject: [PATCH 13/18] added active checkbox to grid --- scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js index 5524ae0095..a4e7b669c2 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.grid.js @@ -37,6 +37,7 @@ Sonia.user.Grid = Ext.extend(Sonia.rest.Grid, { colDisplayNameText: 'Display Name', colMailText: 'Mail', colAdminText: 'Admin', + colActiveText: 'Active', colCreationDateText: 'Creation Date', colLastModifiedText: 'Last modified', colTypeText: 'Type', @@ -69,6 +70,7 @@ Sonia.user.Grid = Ext.extend(Sonia.rest.Grid, { {id: 'displayName', header: this.colDisplayNameText, dataIndex: 'displayName', width: 250}, {id: 'mail', header: this.colMailText, dataIndex: 'mail', renderer: this.renderMailto, width: 200}, {id: 'admin', header: this.colAdminText, dataIndex: 'admin', renderer: this.renderCheckbox, width: 50}, + {id: 'active', header: this.colActiveText, dataIndex: 'active', renderer: this.renderCheckbox, width: 50}, {id: 'creationDate', header: this.colCreationDateText, dataIndex: 'creationDate', renderer: Ext.util.Format.formatTimestamp}, {id: 'lastModified', header: this.colLastModifiedText, dataIndex: 'lastModified', renderer: Ext.util.Format.formatTimestamp}, {id: 'type', header: this.colTypeText, dataIndex: 'type', width: 80} From fd8dd6202a06c8c1d7d79f042f6f7bc2ec761480 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sat, 26 May 2012 10:49:56 +0200 Subject: [PATCH 14/18] default value for active checkbox should be true --- .../src/main/webapp/resources/js/user/sonia.user.formpanel.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js index ff9508e2f5..1982f43be8 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.formpanel.js @@ -106,7 +106,8 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ fieldLabel: this.activeText, name: 'active', xtype: 'checkbox', - helpText: this.activeHelpText + helpText: this.activeHelpText, + checked: true }); Ext.apply(this, Ext.apply(this.initialConfig, {items: items})); From 67bac145a9362c1325ca96a29debd3b31a8004bd Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sat, 26 May 2012 11:03:27 +0200 Subject: [PATCH 15/18] added method to filter deactivated users from user grid --- .../resources/js/user/sonia.user.panel.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js index a3ad2667ed..11d7a1067d 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js @@ -37,6 +37,7 @@ Sonia.user.Panel = Ext.extend(Sonia.rest.Panel, { removeMsgText: 'Remove User "{0}"?', errorTitleText: 'Error', errorMsgText: 'User deletion failed', + showOnlyActiveText: 'Show only active: ', // userGrid for history userGrid: null, @@ -49,7 +50,11 @@ Sonia.user.Panel = Ext.extend(Sonia.rest.Panel, { {xtype: 'tbbutton', text: this.addText, icon: this.addIcon, scope: this, handler: this.showAddPanel}, {xtype: 'tbbutton', text: this.removeText, icon: this.removeIcon, scope: this, handler: this.removeUser}, '-', - {xtype: 'tbbutton', text: this.reloadText, icon: this.reloadIcon, scope: this, handler: this.reload} + {xtype: 'tbbutton', text: this.reloadText, icon: this.reloadIcon, scope: this, handler: this.reload}, + '-', + {xtype: 'label', text: this.showOnlyActiveText, cls: 'ytb-text'}, + ' ', + {xtype: 'checkbox', text: this.reloadText, scope: this, handler: this.toggleActive}, ], items: [{ id: 'userGrid', @@ -77,6 +82,16 @@ Sonia.user.Panel = Ext.extend(Sonia.rest.Panel, { Sonia.user.Panel.superclass.initComponent.apply(this, arguments); }, + toggleActive: function(checkbox, value){ + if (value){ + this.getGrid().getStore().filterBy(function(record){ + return record.get('active'); + }); + } else { + this.getGrid().getStore().clearFilter(); + } + }, + getGrid: function(){ if (!this.userGrid){ if (debug){ From dbb2436c5266ede8ee877790563342295d9c8d45 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sat, 26 May 2012 11:05:03 +0200 Subject: [PATCH 16/18] added missing german localization --- scm-webapp/src/main/webapp/resources/js/i18n/de.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scm-webapp/src/main/webapp/resources/js/i18n/de.js b/scm-webapp/src/main/webapp/resources/js/i18n/de.js index 63c355abcd..e93addef4e 100644 --- a/scm-webapp/src/main/webapp/resources/js/i18n/de.js +++ b/scm-webapp/src/main/webapp/resources/js/i18n/de.js @@ -357,6 +357,7 @@ if (Sonia.user.Grid){ colNameText: 'Name', colDisplayNameText: 'Anzeigename', colMailText: 'E-Mail', + colActiveText: 'Aktiv', colAdminText: 'Admin', colCreationDateText: 'Erstellungsdatum', colLastModifiedText: 'Letzte Änderung', @@ -398,6 +399,7 @@ if (Sonia.user.Panel){ emptyText: 'Es wurde kein Benutzer selektiert', removeTitleText: 'Benutzer entfernen', removeMsgText: 'Benutzer "{0}" entfernen?', + showOnlyActiveText: 'Nur aktive anzeigen: ', errorTitleText: 'Fehler', errorMsgText: 'Entfernen des Benutzers fehlgeschlagen' }); From de30331f204ddb45fac7cdf81609a191b683db4e Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sat, 26 May 2012 11:38:02 +0200 Subject: [PATCH 17/18] fix closure compile error --- .../src/main/webapp/resources/js/user/sonia.user.panel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js index 11d7a1067d..bf4278efd0 100644 --- a/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js +++ b/scm-webapp/src/main/webapp/resources/js/user/sonia.user.panel.js @@ -54,7 +54,7 @@ Sonia.user.Panel = Ext.extend(Sonia.rest.Panel, { '-', {xtype: 'label', text: this.showOnlyActiveText, cls: 'ytb-text'}, ' ', - {xtype: 'checkbox', text: this.reloadText, scope: this, handler: this.toggleActive}, + {xtype: 'checkbox', text: this.reloadText, scope: this, handler: this.toggleActive} ], items: [{ id: 'userGrid', From 82f45ead2c4c61d7ac1d0751298720e065cf1a96 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Tue, 29 May 2012 11:09:37 +0200 Subject: [PATCH 18/18] close branch issue-153