Fix various issues:
authorMathieu Baudier <mbaudier@argeo.org>
Sun, 20 Sep 2009 14:26:56 +0000 (14:26 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sun, 20 Sep 2009 14:26:56 +0000 (14:26 +0000)
- roles not saved
- password transmitted
- natures added

git-svn-id: https://svn.argeo.org/commons/trunk@2989 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

13 files changed:
security/demo/org.argeo.security.demo.log4j/log4j.properties
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ArgeoSecurityDao.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/UserNature.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/ArgeoUserDetails.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/DefaultSecurityService.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoSecurityDaoLdap.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/ArgeoUserDetailsContextMapper.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/nature/CoworkerUserNatureMapper.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/ldap/nature/SimpleUserNatureMapper.java
security/runtime/org.argeo.security.core/src/test/resources/org/argeo/security/json/gandalf2.json
security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/UsersRolesController.java
server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/JsonServerMapper.java
server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/JsonServerSerializer.java

index 274c8060826a74cf07513faa6189adb5a15c1f58..87bf4b76868d6af1378684b381cfa465ba7ed9da 100644 (file)
@@ -2,12 +2,10 @@ log4j.rootLogger=WARN, console
 
 ## Levels
 log4j.logger.org.argeo=DEBUG
-
-log4j.logger.org.hibernate=WARN
+log4j.logger.org.argeo.server.json=TRACE
+log4j.logger.org.argeo.security.core=TRACE
 
 log4j.logger.org.springframework=WARN
-#log4j.logger.org.springframework.web=DEBUG
-#log4j.logger.org.springframework.jms=WARN
 log4j.logger.org.springframework.security=WARN
 
 log4j.logger.org.apache.directory.server=INFO
@@ -18,9 +16,6 @@ log4j.logger.org.apache.catalina.core.ContainerBase=INFO
 log4j.logger.org.apache.coyote=INFO
 
 ## Appenders
-# console is set to be a ConsoleAppender.
 log4j.appender.console=org.apache.log4j.ConsoleAppender
-
-# console uses PatternLayout.
 log4j.appender.console.layout=org.apache.log4j.PatternLayout
 log4j.appender.console.layout.ConversionPattern= %-5p %d{ISO8601} %m - %c%n
index dacf667f2c620a4598841e72241dbeb197d8ce14..470c204786afb67b8c144a9932538bccc720d4d6 100644 (file)
@@ -4,7 +4,7 @@ import java.util.List;
 
 public interface ArgeoSecurityDao {
        public ArgeoUser getCurrentUser();
-       
+
        public List<ArgeoUser> listUsers();
 
        public List<String> listEditableRoles();
@@ -24,4 +24,6 @@ public interface ArgeoSecurityDao {
        public Boolean userExists(String username);
 
        public ArgeoUser getUser(String username);
+
+       public ArgeoUser getUserWithPassword(String username);
 }
index a0cda3c83a84f8d25b9942c37e2f07149e2adb6e..f41643b9ad88be6c07539170e4882bd4f8a8e6d8 100644 (file)
@@ -1,25 +1,12 @@
 package org.argeo.security;
 
 import java.io.Serializable;
-import java.util.UUID;
 
-//@JsonAutoDetect(value = { JsonMethod.GETTER, JsonMethod.SETTER })
 public class UserNature implements Serializable {
        private static final long serialVersionUID = 1L;
 
-       // private final static Log log = LogFactory.getLog(UserNature.class);
-
-       private String uuid = UUID.randomUUID().toString();
        private String type;
 
-       public String getUuid() {
-               return uuid;
-       }
-
-       public void setUuid(String uuid) {
-               this.uuid = uuid;
-       }
-
        public String getType() {
                if (type != null)
                        return type;
@@ -30,11 +17,4 @@ public class UserNature implements Serializable {
        public void setType(String type) {
                this.type = type;
        }
-
-       // @JsonAnySetter
-       // public void anySetter(String key, Object obj) {
-       // if (obj != null)
-       // log.info("anySetter: " + key + "=" + obj + " (" + obj.getClass()
-       // + "), natureType=" + type);
-       // }
 }
index 7ec9ce74ee768bd780f8b9e58505e10bbf23d55f..a05dd1245399e931567cc56a9c0dc19a54c6c762 100644 (file)
@@ -4,6 +4,8 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.argeo.security.ArgeoUser;
 import org.argeo.security.SimpleArgeoUser;
 import org.argeo.security.UserNature;
@@ -15,6 +17,7 @@ import org.springframework.security.userdetails.UserDetails;
 
 public class ArgeoUserDetails extends User implements ArgeoUser {
        private static final long serialVersionUID = 1L;
+       private final static Log log = LogFactory.getLog(ArgeoUserDetails.class);
 
        private final List<UserNature> userNatures;
        private final List<String> roles;
@@ -55,12 +58,16 @@ public class ArgeoUserDetails extends User implements ArgeoUser {
        protected static GrantedAuthority[] rolesToAuthorities(List<String> roles) {
                GrantedAuthority[] arr = new GrantedAuthority[roles.size()];
                for (int i = 0; i < roles.size(); i++) {
-                       arr[i] = new GrantedAuthorityImpl(roles.get(i));
+                       String role = roles.get(i);
+                       if (log.isTraceEnabled())
+                               log.debug("Convert role " + role + " to authority (i=" + i
+                                               + ")");
+                       arr[i] = new GrantedAuthorityImpl(role);
                }
                return arr;
        }
 
-       public static SimpleArgeoUser createBasicArgeoUser(UserDetails userDetails) {
+       public static SimpleArgeoUser createSimpleArgeoUser(UserDetails userDetails) {
                if (userDetails instanceof ArgeoUser) {
                        return new SimpleArgeoUser((ArgeoUser) userDetails);
                } else {
@@ -74,7 +81,8 @@ public class ArgeoUserDetails extends User implements ArgeoUser {
 
        public static ArgeoUser asArgeoUser(Authentication authentication) {
                if (authentication.getPrincipal() instanceof ArgeoUser) {
-                       return new SimpleArgeoUser((ArgeoUser) authentication.getPrincipal());
+                       return new SimpleArgeoUser((ArgeoUser) authentication
+                                       .getPrincipal());
                } else {
                        SimpleArgeoUser argeoUser = new SimpleArgeoUser();
                        argeoUser.setUsername(authentication.getName());
index 5959704108c27627a8725a1c7d550a327d6092d2..74aa57cd50b8759f047890b51f324be21c13e93f 100644 (file)
@@ -19,16 +19,26 @@ public class DefaultSecurityService implements ArgeoSecurityService {
        }
 
        public void updateUserPassword(String username, String password) {
-               SimpleArgeoUser user = new SimpleArgeoUser(securityDao.getUser(username));
+               SimpleArgeoUser user = new SimpleArgeoUser(securityDao
+                               .getUser(username));
                user.setPassword(password);
                securityDao.update(user);
        }
 
        public void newUser(ArgeoUser user) {
+               user.getUserNatures().clear();
                argeoSecurity.beforeCreate(user);
                securityDao.create(user);
        }
 
+       public void updateUser(ArgeoUser user) {
+               String password = securityDao.getUserWithPassword(user.getUsername())
+                               .getPassword();
+               SimpleArgeoUser simpleArgeoUser = new SimpleArgeoUser(user);
+               simpleArgeoUser.setPassword(password);
+               securityDao.update(user);
+       }
+
        public void setArgeoSecurity(ArgeoSecurity argeoSecurity) {
                this.argeoSecurity = argeoSecurity;
        }
index 763539ce25afb8d0b39d98bb94fb40a59756ec03..c5cda2ed4a15b81c38f52575fd277b232565e4ca 100644 (file)
@@ -1,6 +1,6 @@
 package org.argeo.security.ldap;
 
-import static org.argeo.security.core.ArgeoUserDetails.createBasicArgeoUser;
+import static org.argeo.security.core.ArgeoUserDetails.createSimpleArgeoUser;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -11,6 +11,7 @@ import javax.naming.directory.DirContext;
 
 import org.argeo.security.ArgeoSecurityDao;
 import org.argeo.security.ArgeoUser;
+import org.argeo.security.SimpleArgeoUser;
 import org.argeo.security.core.ArgeoUserDetails;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.ldap.core.ContextExecutor;
@@ -91,7 +92,13 @@ public class ArgeoSecurityDaoLdap implements ArgeoSecurityDao, InitializingBean
        }
 
        public ArgeoUser getUser(String uname) {
-               return createBasicArgeoUser(getDetails(uname));
+               SimpleArgeoUser user = createSimpleArgeoUser(getDetails(uname));
+               user.setPassword(null);
+               return user;
+       }
+
+       public ArgeoUser getUserWithPassword(String uname) {
+               return createSimpleArgeoUser(getDetails(uname));
        }
 
        public ArgeoUser getCurrentUser() {
@@ -115,7 +122,7 @@ public class ArgeoSecurityDaoLdap implements ArgeoSecurityDao, InitializingBean
 
                List<ArgeoUser> lst = new ArrayList<ArgeoUser>();
                for (String username : usernames) {
-                       lst.add(createBasicArgeoUser(getDetails(username)));
+                       lst.add(createSimpleArgeoUser(getDetails(username)));
                }
                return lst;
        }
index 3bb8fb7e43410089a139a8f56821574b8d8cd1a5..55232648066d2368e67d39d9e799d72140367edb 100644 (file)
@@ -4,8 +4,6 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.argeo.security.ArgeoUser;
 import org.argeo.security.UserNature;
 import org.argeo.security.core.ArgeoUserDetails;
@@ -16,8 +14,8 @@ import org.springframework.security.userdetails.UserDetails;
 import org.springframework.security.userdetails.ldap.UserDetailsContextMapper;
 
 public class ArgeoUserDetailsContextMapper implements UserDetailsContextMapper {
-       private final static Log log = LogFactory
-                       .getLog(ArgeoUserDetailsContextMapper.class);
+//     private final static Log log = LogFactory
+//                     .getLog(ArgeoUserDetailsContextMapper.class);
 
        private List<UserNatureMapper> userNatureMappers = new ArrayList<UserNatureMapper>();
 
@@ -27,16 +25,15 @@ public class ArgeoUserDetailsContextMapper implements UserDetailsContextMapper {
                                .first();
                String password = new String(arr);
 
-               List<UserNature> userInfos = new ArrayList<UserNature>();
+               List<UserNature> userNatures = new ArrayList<UserNature>();
                for (UserNatureMapper userInfoMapper : userNatureMappers) {
                        UserNature userNature = userInfoMapper.mapUserInfoFromContext(ctx);
-                       if (log.isTraceEnabled())
-                               log.debug("Add user nature " + userNature);
-                       userInfos.add(userNature);
+                       if (userNature != null)
+                               userNatures.add(userNature);
                }
 
                return new ArgeoUserDetails(username, Collections
-                               .unmodifiableList(userInfos), password, authorities);
+                               .unmodifiableList(userNatures), password, authorities);
        }
 
        public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
@@ -45,10 +42,10 @@ public class ArgeoUserDetailsContextMapper implements UserDetailsContextMapper {
                ctx.setAttributeValue("userPassword", user.getPassword());
                if (user instanceof ArgeoUser) {
                        ArgeoUser argeoUser = (ArgeoUser) user;
-                       for (UserNature userInfo : argeoUser.getUserNatures()) {
+                       for (UserNature userNature : argeoUser.getUserNatures()) {
                                for (UserNatureMapper userInfoMapper : userNatureMappers) {
-                                       if (userInfoMapper.supports(userInfo)) {
-                                               userInfoMapper.mapUserInfoToContext(userInfo, ctx);
+                                       if (userInfoMapper.supports(userNature)) {
+                                               userInfoMapper.mapUserInfoToContext(userNature, ctx);
                                                break;// use the first mapper found and no others
                                        }
                                }
index 2ed072526d97ea65b9abebeafa1945760eec445b..0ea573ccbbac5549fa10924096687d1d3ced111f 100644 (file)
@@ -9,34 +9,36 @@ import org.springframework.ldap.core.DirContextOperations;
 public class CoworkerUserNatureMapper implements UserNatureMapper {
 
        public UserNature mapUserInfoFromContext(DirContextOperations ctx) {
-               CoworkerNature basicUserInfo = new CoworkerNature();
-               basicUserInfo.setDescription(ctx.getStringAttribute("description"));
-               basicUserInfo.setMobile(ctx.getStringAttribute("mobile"));
-               basicUserInfo.setTelephoneNumber(ctx
-                               .getStringAttribute("telephoneNumber"));
-               basicUserInfo.setUuid(ctx.getStringAttribute("employeeNumber"));
-               return basicUserInfo;
+               CoworkerNature nature = new CoworkerNature();
+               nature.setDescription(ctx.getStringAttribute("description"));
+               nature.setMobile(ctx.getStringAttribute("mobile"));
+               nature.setTelephoneNumber(ctx.getStringAttribute("telephoneNumber"));
+
+               if (nature.getDescription() == null && nature.getMobile() == null
+                               && nature.getTelephoneNumber() == null)
+                       return null;
+               else
+                       return nature;
        }
 
        public void mapUserInfoToContext(UserNature userInfoArg,
                        DirContextAdapter ctx) {
-               CoworkerNature userInfo = (CoworkerNature) userInfoArg;
-               ctx.setAttributeValue("employeeNumber", userInfo.getUuid());
-               if (userInfo.getDescription() != null) {
-                       ctx.setAttributeValue("description", userInfo.getDescription());
+               CoworkerNature nature = (CoworkerNature) userInfoArg;
+               if (nature.getDescription() != null) {
+                       ctx.setAttributeValue("description", nature.getDescription());
                }
-               if (userInfo.getMobile() == null || !userInfo.getMobile().equals("")) {
-                       ctx.setAttributeValue("mobile", userInfo.getMobile());
+               if (nature.getMobile() == null || !nature.getMobile().equals("")) {
+                       ctx.setAttributeValue("mobile", nature.getMobile());
                }
-               if (userInfo.getTelephoneNumber() == null
-                               || !userInfo.getTelephoneNumber().equals("")) {
-                       ctx.setAttributeValue("telephoneNumber", userInfo
+               if (nature.getTelephoneNumber() == null
+                               || !nature.getTelephoneNumber().equals("")) {
+                       ctx.setAttributeValue("telephoneNumber", nature
                                        .getTelephoneNumber());
                }
        }
 
-       public Boolean supports(UserNature userInfo) {
-               return userInfo instanceof CoworkerNature;
+       public Boolean supports(UserNature userNature) {
+               return userNature instanceof CoworkerNature;
        }
 
 }
index 3bc4b51e11af15dd016e5a9635926a684b14f91c..9cad98d68b13b9e3baf1da4a99f7be68f2fa0372 100644 (file)
@@ -9,28 +9,25 @@ import org.springframework.ldap.core.DirContextOperations;
 public class SimpleUserNatureMapper implements UserNatureMapper {
 
        public UserNature mapUserInfoFromContext(DirContextOperations ctx) {
-               SimpleUserNature basicUserInfo = new SimpleUserNature();
-               basicUserInfo.setLastName(ctx.getStringAttribute("sn"));
-               basicUserInfo.setFirstName(ctx.getStringAttribute("givenName"));
-               basicUserInfo.setEmail(ctx.getStringAttribute("mail"));
-               basicUserInfo.setUuid(ctx.getStringAttribute("seeAlso"));
-               return basicUserInfo;
+               SimpleUserNature nature = new SimpleUserNature();
+               nature.setLastName(ctx.getStringAttribute("sn"));
+               nature.setFirstName(ctx.getStringAttribute("givenName"));
+               nature.setEmail(ctx.getStringAttribute("mail"));
+               return nature;
        }
 
        public void mapUserInfoToContext(UserNature userInfoArg,
                        DirContextAdapter ctx) {
-               SimpleUserNature userInfo = (SimpleUserNature) userInfoArg;
-               ctx.setAttributeValue("cn", userInfo.getFirstName() + " "
-                               + userInfo.getLastName());
-               ctx.setAttributeValue("sn", userInfo.getLastName());
-               ctx.setAttributeValue("givenName", userInfo.getFirstName());
-               ctx.setAttributeValue("mail", userInfo.getEmail());
-               // TODO: find a cleaner way?
-               ctx.setAttributeValue("seeAlso", userInfo.getUuid());
+               SimpleUserNature nature = (SimpleUserNature) userInfoArg;
+               ctx.setAttributeValue("cn", nature.getFirstName() + " "
+                               + nature.getLastName());
+               ctx.setAttributeValue("sn", nature.getLastName());
+               ctx.setAttributeValue("givenName", nature.getFirstName());
+               ctx.setAttributeValue("mail", nature.getEmail());
        }
 
-       public Boolean supports(UserNature userInfo) {
-               return userInfo instanceof SimpleUserNature;
+       public Boolean supports(UserNature userNature) {
+               return userNature instanceof SimpleUserNature;
        }
 
 }
index a7edbf07247ae7fe1f32359d77d9e44c76b665c7..22f96f960f786fd22003108a57d68d81610fee51 100644 (file)
@@ -1 +1 @@
-{"roles":["ROLE_ADMIN","ROLE_USER"],"userNatures":[{"email":"admin@localhost","firstName":"Gandalf","lastName":"User","type":"org.argeo.security.nature.SimpleUserNature","uuid":null},{"description":"Superuser","mobile":null,"telephoneNumber":null,"type":"org.argeo.security.nature.CoworkerNature","uuid":null}],"username":"gandalf2","enabled":true,"password":"{SHA}ieSV55Qc+eQOaYDRSha/AjzNTJE=","authorities":[{"authority":"ROLE_ADMIN"},{"authority":"ROLE_USER"}],"accountNonExpired":true,"accountNonLocked":true,"credentialsNonExpired":true}
\ No newline at end of file
+{"roles":["ROLE_ADMIN","ROLE_USER"],"userNatures":[{"email":"admin@localhost","firstName":"Gandalf","lastName":"User","type":"org.argeo.security.nature.SimpleUserNature"},{"description":"Superuser","mobile":null,"telephoneNumber":null,"type":"org.argeo.security.nature.CoworkerNature"}],"username":"gandalf2","enabled":true,"password":"{SHA}ieSV55Qc+eQOaYDRSha/AjzNTJE=","authorities":[{"authority":"ROLE_ADMIN"},{"authority":"ROLE_USER"}],"accountNonExpired":true,"accountNonLocked":true,"credentialsNonExpired":true}
\ No newline at end of file
index 88dc15589b33732e071d515a2e2385a94e99e7c6..3413b33ed33d00bb9a4cd83e662093067baf8926 100644 (file)
@@ -1,12 +1,8 @@
 package org.argeo.security.mvc;
 
 import java.io.Reader;
-import java.io.StringReader;
 import java.util.List;
 
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.argeo.security.ArgeoSecurityService;
 import org.argeo.security.ArgeoUser;
 import org.argeo.server.BooleanAnswer;
@@ -20,19 +16,13 @@ import org.springframework.web.bind.annotation.RequestParam;
 
 @Controller
 public class UsersRolesController implements MvcConstants {
-       private final static Log log = LogFactory
-                       .getLog(UsersRolesController.class);
+//     private final static Log log = LogFactory
+//                     .getLog(UsersRolesController.class);
 
        private ArgeoSecurityService securityService;
 
        private ServerDeserializer userDeserializer = null;
 
-       // @InitBinder
-       // public void initBinder(WebDataBinder binder) {
-       // binder.registerCustomEditor(SimpleArgeoUser.class,
-       // new DeserializingEditor(userDeserializer));
-       // }
-
        /* USER */
 
        @RequestMapping("/getCredentials.security")
@@ -58,7 +48,7 @@ public class UsersRolesController implements MvcConstants {
        @ModelAttribute(ANSWER_MODEL_KEY)
        public ArgeoUser createUser(Reader reader) {
                ArgeoUser user = (ArgeoUser) userDeserializer.deserialize(reader);
-               cleanUserBeforeCreate(user);
+               //cleanUserBeforeCreate(user);
                securityService.newUser(user);
                return securityService.getSecurityDao().getUser(user.getUsername());
        }
@@ -70,7 +60,7 @@ public class UsersRolesController implements MvcConstants {
                securityService.getSecurityDao().update(user);
                return securityService.getSecurityDao().getUser(user.getUsername());
        }
-
+/*
        @RequestMapping("/createUser2.security")
        @ModelAttribute(ANSWER_MODEL_KEY)
        public ArgeoUser createUser(@RequestParam("body") String body) {
@@ -86,7 +76,7 @@ public class UsersRolesController implements MvcConstants {
                cleanUserBeforeCreate(user);
                securityService.newUser(user);
                return securityService.getSecurityDao().getUser(user.getUsername());
-       }
+       }*/
 
        @RequestMapping("/deleteUser.security")
        @ModelAttribute(ANSWER_MODEL_KEY)
@@ -140,10 +130,9 @@ public class UsersRolesController implements MvcConstants {
                return ServerAnswer.ok("Password updated");
        }
 
-       protected void cleanUserBeforeCreate(ArgeoUser user) {
-               user.getUserNatures().clear();
-               user.getRoles().clear();
-       }
+//     protected void cleanUserBeforeCreate(ArgeoUser user) {
+//             user.getUserNatures().clear();
+//     }
 
        public void setUserDeserializer(ServerDeserializer userDeserializer) {
                this.userDeserializer = userDeserializer;
index 266ff2eec3f041ec37f1908b4c18c86456aa7660..601b55dc17dcf46e0b6a24153c5e73f1336f608a 100644 (file)
@@ -53,17 +53,12 @@ public class JsonServerMapper extends JsonServerSerializer implements
 
        public Object deserialize(Reader reader) {
                try {
-                       // String body = request.getParameter("body");
-                       // if (body == null) {
-                       // // lets read the message body instead
-                       // BufferedReader reader = request.getReader();
-                       // StringBuffer buffer = new StringBuffer();
-                       // String line = null;
-                       // while (((line = reader.readLine()) != null)) {
-                       // buffer.append(line);
-                       // }
-                       // body = buffer.toString();
-                       // }
+                       if (log.isTraceEnabled()) {
+                               String str = IOUtils.toString(reader);
+                               log.debug(str);
+                               reader = new StringReader(str);
+                       }
+
                        return getObjectMapper().readValue(reader, targetClass);
                } catch (Exception e) {
                        throw new ArgeoServerException("Cannot deserialize " + reader, e);
@@ -84,7 +79,8 @@ public class JsonServerMapper extends JsonServerSerializer implements
                this.targetClass = targetClass;
        }
 
-       public void setDeserializers(Map<Class<?>, JsonDeserializer<?>> deserializers) {
+       public void setDeserializers(
+                       Map<Class<?>, JsonDeserializer<?>> deserializers) {
                this.deserializers = deserializers;
        }
 
index 1c38bbe15f0775e1fce5fc55ecbaa993d50aa5c5..90a9c135c2815a37637f4d2f85b685a32c7ab38c 100644 (file)
@@ -1,6 +1,7 @@
 package org.argeo.server.json;
 
 import java.io.IOException;
+import java.io.StringWriter;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -28,14 +29,28 @@ public class JsonServerSerializer implements ServerSerializer {
                try {
                        response.setContentType("application/json");
 
-                       jsonGenerator = jsonFactory.createJsonGenerator(response
-                                       .getWriter());
+                       StringWriter stringWriter = null;
+                       if (log.isTraceEnabled()) {
+                               stringWriter = new StringWriter();
+                               jsonGenerator = jsonFactory.createJsonGenerator(stringWriter);
+                       } else {
+                               jsonGenerator = jsonFactory.createJsonGenerator(response
+                                               .getWriter());
+                       }
+
                        if (prettyPrint)
                                jsonGenerator.useDefaultPrettyPrinter();
 
                        objectMapper.writeValue(jsonGenerator, obj);
 
                        jsonGenerator.close();
+
+                       if (stringWriter != null) {
+                               if (log.isTraceEnabled())
+                                       log.debug(stringWriter.toString());
+                               response.getWriter().append(stringWriter.toString());
+                       }
+
                } catch (Exception e) {
                        throw new ArgeoServerException("Cannot serialize " + obj, e);
                } finally {