r276 - in branches/wikitty-eugene-migration/wikitty-api/src: main/java/org/nuiton/wikitty test/java/org/nuiton/wikitty test/java/org/nuiton/wikitty/layers test/resources
Author: bleny Date: 2010-08-27 17:16:41 +0200 (Fri, 27 Aug 2010) New Revision: 276 Url: http://nuiton.org/repositories/revision/wikitty/276 Log: security layer ; bugfixes in WikittyServiceInMemory ; refactoring tests Added: branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/layers/ branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/layers/AbstractWikittyServiceTest.java branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/layers/WikittyServiceSecurityTest.java Removed: branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/cache/ Modified: branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/Wikitty.java branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyCopyOnWrite.java branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyImpl.java branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyServiceInMemory.java branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyServiceSecurity.java branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyUtil.java branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/layers/WikittyServiceCachedTest.java branches/wikitty-eugene-migration/wikitty-api/src/test/resources/log4j.properties Modified: branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/Wikitty.java =================================================================== --- branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/Wikitty.java 2010-08-27 15:13:40 UTC (rev 275) +++ branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/Wikitty.java 2010-08-27 15:16:41 UTC (rev 276) @@ -39,6 +39,8 @@ boolean hasExtension(String extName); boolean hasField(String extName, String fieldName); + + boolean hasField(String fqFieldName); WikittyExtension getExtension(String ext); Modified: branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyCopyOnWrite.java =================================================================== --- branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyCopyOnWrite.java 2010-08-27 15:13:40 UTC (rev 275) +++ branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyCopyOnWrite.java 2010-08-27 15:16:41 UTC (rev 276) @@ -131,6 +131,10 @@ return target.hasField(extName, fieldName); } + public boolean hasField(String fqFieldName) { + return target.hasField(fqFieldName); + } + public WikittyExtension getExtension(String ext) { return target.getExtension(ext); } Modified: branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyImpl.java =================================================================== --- branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyImpl.java 2010-08-27 15:13:40 UTC (rev 275) +++ branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyImpl.java 2010-08-27 15:16:41 UTC (rev 276) @@ -239,6 +239,17 @@ return result; } + @Override + public boolean hasField(String fqFieldName) { + String[] field = fqFieldName.split("\\."); + String fieldName = field[1]; + int crochet = fieldName.indexOf("["); + if (crochet != -1) { + fieldName = fieldName.substring(0, crochet); + } + return hasField(field[0], fieldName); + } + /* (non-Javadoc) * @see org.nuiton.wikitty.IWikitty#getExtension(java.lang.String) */ @@ -640,6 +651,7 @@ } else { if (col.remove(value)) { // field is dirty only if remove is done + setFieldDirty(ext, fieldName, null, col); setField(ext, fieldName, col); // no call dirty, because already done in setField } } Modified: branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyServiceInMemory.java =================================================================== --- branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyServiceInMemory.java 2010-08-27 15:13:40 UTC (rev 275) +++ branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyServiceInMemory.java 2010-08-27 15:16:41 UTC (rev 276) @@ -68,7 +68,16 @@ for (Wikitty wikitty : wikitties) { wikitty.setVersion(WikittyUtil.incrementMajorRevision(wikitty.getVersion())); wikitty.clearDirty(); - this.wikitties.put(wikitty.getId(), wikitty); + try { + this.wikitties.put(wikitty.getId(), wikitty.clone()); + } catch (CloneNotSupportedException e) { + log.error(String.format("unable to clone wikitty %s", wikitty)); + + // modification of the given wikitty out of this method will modify the stored wikitty : side effect !! + log.warn(String.format("%s store a wikitty with a shared reference %s", this, wikitty)); + + this.wikitties.put(wikitty.getId(), wikitty); + } result.addVersionUpdate(wikitty.getId(), wikitty.getVersion()); } return result; @@ -254,6 +263,11 @@ return true; // FIXME: 20091104 jru manage search on extension and id } Object o = w.getFqField( fqfieldName ); + + if (!w.hasField(fqfieldName)) { + return false; + } + FieldType t = w.getFieldType(fqfieldName); Object value = t.getValidValue( binOp.getValue() ); boolean checked = false; Modified: branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyServiceSecurity.java =================================================================== --- branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyServiceSecurity.java 2010-08-27 15:13:40 UTC (rev 275) +++ branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyServiceSecurity.java 2010-08-27 15:16:41 UTC (rev 276) @@ -19,14 +19,16 @@ import static org.nuiton.i18n.I18n._; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import javax.sql.rowset.serial.SerialException; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.wikitty.search.Search; @@ -52,9 +54,45 @@ /** cache de l'id du groupe AppAdmin */ transient protected String appAdminGroupId = null; + public static final String APPADMIN_LOGIN = "root"; + // TODO 20100826 bleny look for password in a config file + public static final String APPADMIN_PASSWORD = "toto"; + public WikittyServiceSecurity(WikittyService ws) { this.ws = ws; + + Wikitty appAdminGroup = getAppAdminGroup(null); + if (WikittyGroupHelper.getMembers(appAdminGroup) == null) { + // first time boot + ws.storeExtension(null, WikittyUserAbstract.extensions); + ws.storeExtension(null, SecurityTokenAbstract.extensions); + ws.storeExtension(null, WikittyGroupAbstract.extensions); + + // create the appAdmin account + Wikitty appAdmin = new WikittyImpl(); + WikittyUserHelper.addExtension(appAdmin); + WikittyUserHelper.setLogin(appAdmin, APPADMIN_LOGIN); + WikittyUserHelper.setPassword(appAdmin, APPADMIN_PASSWORD); + ws.store(null, appAdmin); + + // add APPADMIN_LOGIN to AppAdmin group + WikittyGroupHelper.addMembers(appAdminGroup, appAdmin.getId()); + ws.store(null, appAdminGroup); + + // login as admin to add some security polices + String adminToken = login(APPADMIN_LOGIN, APPADMIN_PASSWORD); + + // making all tokens unwritable, except for app admin + addWikittyAuthorisation(adminToken, SecurityTokenAbstract.extensionSecurityToken); + Wikitty authorizationOnTokens = restoreExtensionAuthorisation(adminToken, SecurityTokenAbstract.extensionSecurityToken); + WikittyAuthorisationHelper.clearWriter(authorizationOnTokens); + WikittyAuthorisationHelper.clearAdmin(authorizationOnTokens); + WikittyAuthorisationHelper.setOwner(authorizationOnTokens, APPADMIN_LOGIN); + store(adminToken, authorizationOnTokens); + + logout(adminToken); + } } @Override @@ -69,21 +107,71 @@ @Override public String login(String login, String password) { - String token = WikittyUtil.genSecurityToken(); - Wikitty wToken = new WikittyImpl(token); - // force add extension to wikitty - SecurityTokenHelper.addExtension(wToken); - // on passe token comme securityToken, mais il ne me semble pas - // que ce soit tres utile, mais comme ca c'est uniform - ws.store(null, wToken); - return token; + Wikitty user = ws.findByCriteria(null, Search.query().eq( + WikittyUser.FQ_FIELD_WIKITTYUSER_LOGIN, login).criteria()); + if (user == null) { + throw new IllegalArgumentException(String.format("no such account '%s'", login)); + } else { + // check password is valid + if (WikittyUserHelper.getPassword(user).equals(password)) { + String tokenId = WikittyUtil.genSecurityTokenId(); + Wikitty wikittyToken = new WikittyImpl(tokenId); + // force add extension to wikitty + SecurityTokenHelper.addExtension(wikittyToken); + SecurityTokenHelper.setUser(wikittyToken, user.getId()); + ws.store(null, wikittyToken); + + log.debug(String.format("token '%s' is for login '%s'", + tokenId, login)); + + return tokenId; + } else { + throw new SecurityException("bad password"); + } + } } + + public void createAccount(String securityToken, String login, String password) { + String userId = getUserId(securityToken); + if (isAppAdmin(securityToken, userId)) { + Wikitty user = ws.findByCriteria(securityToken, Search.query().eq( + WikittyUser.FQ_FIELD_WIKITTYUSER_LOGIN, login).criteria()); + if (user == null) { + user = new WikittyImpl(); + WikittyUserHelper.addExtension(user); + WikittyUserHelper.setLogin(user, login); + WikittyUserHelper.setPassword(user, password); + ws.store(null, user); + log.debug(String.format("login '%s' has userId '%s'", login, user.getId())); + } else { + throw new IllegalArgumentException( + String.format("account already exists '%s'", + login)); + } + } else { + throw new SecurityException("only admin can create accounts"); + } + } + + public String getUserWikittyId(String securityToken, String login) { + String userId = getUserId(securityToken); + String userWikittyId = null; +// if (isAppAdmin(securityToken, userId)) { + Wikitty user = ws.findByCriteria(null, Search.query().eq( + WikittyUser.FQ_FIELD_WIKITTYUSER_LOGIN, login).criteria()); + if (user != null) { + userWikittyId = user.getId(); + } +// } else { +// throw new SecurityException("Only admin can do that"); +// } + return userWikittyId; + } @Override public void logout(String securityToken) { - // on passe securityToken comme token, mais il ne me semble pas - // que ce soit tres utile, mais comme ca c'est uniform - ws.delete(null, securityToken); + getUserId(securityToken); // will throw exception if token is not valid + ws.delete(securityToken, securityToken); } @Override @@ -93,175 +181,300 @@ // seul les AppAdmin on le droit a cette method ws.clear(securityToken); } else { - throw new SecurityException(_("user %s can't clear data", - getUserId(securityToken))); + throw new SecurityException(_("user %s can't clear data", userId)); } } - - /** - * Prepare l'ecriture en ajoutant s'il le faut l'extension - * WikittyAuthorisation et en fixant l'owner a l'utilisateur courant + + protected String extensionToWikittySecurityId(WikittyExtension extension) { + return String.format("WikittySecurity'%s'", extension.getName()); + } + + /** */ + public Wikitty addWikittyAuthorisation(String securityToken, + WikittyExtension extension) { + String userId = getUserId(securityToken); + if (isAppAdmin(securityToken, userId)) { + if (restoreExtensionAuthorisation(securityToken, extension) == null) { + String wikittyAuthorisationId = extensionToWikittySecurityId(extension); + Wikitty wikittyAuthorisation = new WikittyImpl(wikittyAuthorisationId); + WikittyAuthorisationHelper.addExtension(wikittyAuthorisation); + WikittyAuthorisationHelper.setOwner(wikittyAuthorisation, userId); + ws.store(securityToken, wikittyAuthorisation); + return wikittyAuthorisation; + } else { + throw new SecurityException(String.format( + "extension %s already has an security extension attached", + extension.getName())); + } + } else { + throw new SecurityException(String.format( + "Only members of %s group can add authorisation", + WIKITTY_APPADMIN_GROUP_NAME)); + } + } + + /** restore the wikitty authorisation attached to given extension * - * @param securityToken le token de securite qui permet de retrouver - * l'utilisateur - * @param wikitty le wikitty a sauver + * @return a wikitty with WikittyAuthorisation extension, or null if given + * extension has no security policy attached + * @throws SecurityException if user don't have rights required */ - protected void prepareWrite(String securityToken, Wikitty wikitty) { - Wikitty oldVersion = ws.restore(securityToken, wikitty.getId()); - if (oldVersion == null) { - // creation d'une nouvelle entity, on a des choses a faire + public Wikitty restoreExtensionAuthorisation(String securityToken, + WikittyExtension extension) { + String userId = getUserId(securityToken); + String wikittyAuthorisationId = extensionToWikittySecurityId(extension); + Wikitty wikittyAuthorisation = restore(securityToken, wikittyAuthorisationId); + if (wikittyAuthorisation == null) { + log.debug(extension + " has no authorization attached"); + } else { + /* + if ( ! canAdmin(securityToken, userId, wikittyAuthorisation)) { + throw new SecurityException(String.format( + "user %s doesn't have admin rights on extension %s", + userId, extension.getName())); + } + */ + } + return wikittyAuthorisation; + } - // recuperation de l'utilisateur associe au securityToken - String userId = getUserId(securityToken); + /** true if userId has the right to write on extension */ + protected boolean canRead(String securityToken, String userId, Wikitty extensionRights) { + boolean canRead = isReader(securityToken, userId, extensionRights) + || canWrite(securityToken, userId, extensionRights); + return canRead; + } - // on ajoute et on fixe les droits par defaut - WikittyAuthorisationHelper.addExtension(wikitty); - WikittyAuthorisationHelper.setOwner(wikitty, userId); + /** true if userId has the right to write on extension */ + protected boolean canWrite(String securityToken, String userId, Wikitty extensionRights) { + boolean canWrite = isWriter(securityToken, userId, extensionRights) + || isOwner(securityToken, userId, extensionRights) + || isAppAdmin(securityToken, userId); + return canWrite; + } + + /** true if userId has the right to admin on extension */ + protected boolean canAdmin(String securityToken, String userId, Wikitty extensionRights) { + boolean canWrite = isAdmin(securityToken, userId, extensionRights) + || isOwner(securityToken, userId, extensionRights) + || isAppAdmin(securityToken, userId); + return canWrite; + } + + /** true if userId has the right is owner of all the extensions of the given wikitty */ + protected boolean canDelete(String securityToken, String userId, Wikitty wikitty) { + if (isAppAdmin(securityToken, userId)) { + return true; } + + // now read all extensions for this wikitty, and return false + // if user is not owner on one of those extensions + for (WikittyExtension extension : wikitty.getExtensions()) { + Wikitty extensionRights = restoreExtensionAuthorisation(securityToken, extension); + boolean canDelete = extensionRights == null + || isOwner(securityToken, userId, extensionRights); + if (! canDelete) { + return false; + } + } + return true; } @Override - public boolean canWrite(String securityToken, Wikitty wikitty) { - boolean result = false; + public UpdateResponse store(String securityToken, Wikitty wikitty) { + Collection<Wikitty> wikitties = Arrays.asList(wikitty); + return store(securityToken, wikitties); + } + @Override + public UpdateResponse store(String securityToken, Collection<Wikitty> wikitties) { + return store(securityToken, wikitties, false); + } + + @Override + public UpdateResponse store(String securityToken, Collection<Wikitty> wikitties, boolean disableAutoVersionIncrement) { String userId = getUserId(securityToken); - // - // check security - // - // recuperation de l'ancienne version de l'objet pour verifier les droits - Wikitty oldVersion = ws.restore(securityToken, wikitty.getId()); - if (oldVersion == null) { - // creation d'une nouvelle entity + List<Wikitty> wikittiesToStore = new ArrayList<Wikitty>(wikitties); + + for (Wikitty wikitty : wikitties) { + + Wikitty oldVersion = ws.restore(securityToken, wikitty.getId()); + + // check that the wikitty does not have + if (WikittyAuthorisationHelper.isExtension(wikitty)) { + + if (oldVersion == null) { + // if this exception is raised, you should use addWikittyAuthorisation() + throw new IllegalArgumentException("you can't store an authorisation for the fist time"); + } else { + + if ( canAdmin(securityToken, userId, oldVersion)) { + + System.out.println("!!!" + oldVersion); + + // admin can't change owner, admin or parent + // putting back old values + Object oldValue; - // on verifie que l'on a le droit de creer une entity avec cette extension - // TODO poussin 20100607 trouver ou mettre l'autorisation qui retient l'information de qui a le droit de cree une extension - result = true; - } else { - // modification d'une entity existante - - // si c'est le owner il a tous les droits, a defaut les admins - // peuvent aussi le modifier - result = - // owner et admin peuvent tout modifier - isOwner(securityToken, userId, oldVersion) - || isAppAdmin(securityToken, userId) - || isAdmin(securityToken, userId, oldVersion) - // un writer ne peut pas modifier l'extension d'autorisation - || (WikittyAuthorisationHelper.equals(oldVersion, wikitty) - && isWriter(securityToken, userId, oldVersion)); + oldValue = oldVersion.getFieldAsObject( + WikittyAuthorisation.EXT_WIKITTYAUTHORISATION, + WikittyAuthorisation.FIELD_WIKITTYAUTHORISATION_OWNER); + wikitty.setField(WikittyAuthorisation.EXT_WIKITTYAUTHORISATION, + WikittyAuthorisation.FIELD_WIKITTYAUTHORISATION_OWNER, + oldValue); + /* + oldValue = oldVersion.getFieldAsObject( + WikittyAuthorisation.EXT_WIKITTYAUTHORISATION, + WikittyAuthorisation.FIELD_WIKITTYAUTHORISATION_ADMIN); + System.out.println("will preserve" + oldValue); + wikitty.setField(WikittyAuthorisation.EXT_WIKITTYAUTHORISATION, + WikittyAuthorisation.FIELD_WIKITTYAUTHORISATION_ADMIN, + oldValue); + /* + oldValue = oldVersion.getFieldAsObject( + WikittyAuthorisation.EXT_WIKITTYAUTHORISATION, + WikittyAuthorisation.FIELD_WIKITTYAUTHORISATION_PARENT); + wikitty.setField(WikittyAuthorisation.EXT_WIKITTYAUTHORISATION, + WikittyAuthorisation.FIELD_WIKITTYAUTHORISATION_PARENT, + oldValue);*/ + + } else { + // if not admin, ignore this wikitty, this user has no right to modify rights + wikittiesToStore.remove(wikitty); + } + } + } else { + + if (oldVersion == null) { + // it's a creation + + // check that **reader** right on Security for all extension + } else { + // it's an update + for (WikittyExtension extension : wikitty.getExtensions()) { + + Wikitty extensionRights = restoreExtensionAuthorisation(securityToken, extension); + + if (extensionRights != null) { + if ( ! canWrite(securityToken, userId, extensionRights)) { + + for (String fieldName : extension.getFieldNames()) { + if (oldVersion == null) { + wikitty.setField(extension.getName(), fieldName, null); + } else { + Object oldValue = oldVersion.getFieldAsObject(extension.getName(), fieldName); + wikitty.setField(extension.getName(), fieldName, oldValue); + } + } + } + } + } + } + } } + UpdateResponse result = ws.store(securityToken, wikittiesToStore, disableAutoVersionIncrement); return result; } @Override - public boolean canDelete(String securityToken, String wikittyId) { - boolean result = false; + public UpdateResponse store(String securityToken, WikittyTransaction transaction, Collection<Wikitty> wikitties, boolean disableAutoVersionIncrement) { + // FIXME 20100825 bleny implement it without copy/paste code + throw new UnsupportedOperationException(); + } + + @Override + public Wikitty restore(String securityToken, String id) { + List<String> ids = Arrays.asList(id); + List<Wikitty> wikitties = restore(securityToken, ids); + Wikitty wikitty = null; + if (! wikitties.isEmpty()) { + wikitty = wikitties.get(0); + } + return wikitty; + } - // - // check security - // + @Override + public List<Wikitty> restore(String securityToken, List<String> ids) { + List<Wikitty> wikitties = new ArrayList<Wikitty>(); + for (String id : ids) { + // do it first, will throw an exception if security token is invalid - // recuperation de l'ancienne version de l'objet pour verifier les droits - Wikitty oldVersion = ws.restore(securityToken, wikittyId); - if (oldVersion == null) { - // l'objet n'existe pas donc la suppression retourne true - result = true; - } else { - // suppresion d'une entity existante String userId = getUserId(securityToken); - // si c'est le owner il a tous les droits, a defaut les admins - // peuvent aussi le supprimer - result = - // owner et admin peuvent tout modifier - isOwner(securityToken, userId, oldVersion) - || isAppAdmin(securityToken, userId) - || isAdmin(securityToken, userId, oldVersion); + Wikitty wikitty = ws.restore(securityToken, id); + if (wikitty != null) { + // FIXME 20100827 bleny copy on write is done because setting some field to null below modify stored wikitty if WikittyServiceInMemory is used + wikitty = new WikittyCopyOnWrite(wikitty); + + for (WikittyExtension extension : wikitty.getExtensions()) { + Wikitty extensionRights = restoreExtensionAuthorisation(securityToken, extension); + + // field of extension can be read if no policy attached + // if a policy is attached, check that user has right to read + boolean canRead = extensionRights == null || canRead(securityToken, userId, extensionRights); + if ( ! canRead) { + for (String fieldName : extension.getFieldNames()) { + wikitty.setField(extension.getName(), fieldName, null); + } + } + } + wikitties.add(wikitty); + } } - return result; + return wikitties; } + + @Override + public List<Wikitty> restore(String securityToken, WikittyTransaction transaction, List<String> ids) { + throw new UnsupportedOperationException(); + // ws.restore(securityToken, transaction, ids); + } @Override - public boolean canRead(String securityToken, String wikittyId) { - // recuperation de l'utilisateur associe au securityToken - Wikitty securityTokenWikitty = ws.restore(securityToken, securityToken); - String userId = SecurityTokenHelper.getUser(securityTokenWikitty); - - // - // check security - // - - // recuperation de l'objet pour verifier les droits - Wikitty w = ws.restore(securityToken, wikittyId); - boolean result = isReader(securityToken, userId, w) - || isOwner(securityToken, userId, w) - || isAppAdmin(securityToken, userId) - || isAdmin(securityToken, userId, w) - || isWriter(securityToken, userId, w); - return result; + public void delete(String securityToken, String id) { + Collection<String> ids = Arrays.asList(id); + delete(securityToken, ids); } @Override - public UpdateResponse store(String securityToken, Wikitty wikitty) { - if (canWrite(securityToken, wikitty)) { - prepareWrite(securityToken, wikitty); - UpdateResponse result = ws.store(securityToken, wikitty); - return result; - } else { - throw new SecurityException(_("user %s can't modify object %s", - getUserId(securityToken), wikitty.getId())); - } + public void delete(String securityToken, Collection<String> ids) { + List<String> idsAsList = new ArrayList<String>(ids); + secureDelete(securityToken, idsAsList); } - @Override - public UpdateResponse store(String securityToken, Collection<Wikitty> wikitties) { - for (Wikitty w : wikitties) { - if (!canWrite(securityToken, w)) { - throw new SecurityException(_("user %s can't modify object %s", - getUserId(securityToken), w.getId())); + protected void secureDelete(String securityToken, List<String> ids) { + String userId = getUserId(securityToken); + + List<Wikitty> wikitties = ws.restore(securityToken, ids); + List<String> idsToRemove = new ArrayList<String>(); + + for (Wikitty wikitty : wikitties) { + if ( canDelete(securityToken, userId, wikitty)) { + idsToRemove.add(wikitty.getId()); } } - for (Wikitty w : wikitties) { - prepareWrite(securityToken, w); - } - UpdateResponse result = ws.store(securityToken, wikitties); - return result; + + ws.delete(securityToken, idsToRemove); } @Override - public UpdateResponse store(String securityToken, Collection<Wikitty> wikitties, boolean disableAutoVersionIncrement) { - for (Wikitty w : wikitties) { - if (!canWrite(securityToken, w)) { - throw new SecurityException(_("user %s can't modify object %s", - getUserId(securityToken), w.getId())); - } - } - for (Wikitty w : wikitties) { - prepareWrite(securityToken, w); - } - UpdateResponse result = ws.store(securityToken, wikitties, disableAutoVersionIncrement); - return result; + @Deprecated + public boolean canWrite(String securityToken, Wikitty wikitty) { + throw new UnsupportedOperationException(); } @Override - public UpdateResponse store(String securityToken, WikittyTransaction transaction, - Collection<Wikitty> wikitties, boolean disableAutoVersionIncrement) { - for (Wikitty w : wikitties) { - if (!canWrite(securityToken, w)) { - throw new SecurityException(_("user %s can't modify object %s", - getUserId(securityToken), w.getId())); - } - } - for (Wikitty w : wikitties) { - // preparation des wikitty pour la sauvegarde - // - ajout extension d'autorisation si necessaire - prepareWrite(securityToken, w); - } - UpdateResponse result = ws.store(securityToken, transaction, wikitties, - disableAutoVersionIncrement); - return result; - } + @Deprecated + public boolean canDelete(String securityToken, String wikittyId) { + throw new UnsupportedOperationException(); + } + + @Override + @Deprecated + public boolean canRead(String securityToken, String wikittyId) { + throw new UnsupportedOperationException(); + } @Override public List<String> getAllExtensionIds(String securityToken) { @@ -279,8 +492,8 @@ @Override public UpdateResponse storeExtension( String securityToken, WikittyExtension ext) { - // TODO poussin 20100607 check security, mais qui a le droit ? - return ws.storeExtension(securityToken, ext); + Collection<WikittyExtension> exts = Arrays.asList(ext); + return storeExtension(securityToken, exts); } @Override @@ -293,8 +506,12 @@ @Override public UpdateResponse storeExtension(String securityToken, WikittyTransaction transaction, Collection<WikittyExtension> exts) { - // TODO poussin 20100607 check security, mais qui a le droit ? - return ws.storeExtension(securityToken, transaction, exts); + String userId = getUserId(securityToken); + UpdateResponse response = null; + if (isAppAdmin(securityToken, userId)) { + response = ws.storeExtension(securityToken, transaction, exts); + } + return response; } @Override @@ -325,75 +542,6 @@ } @Override - public Wikitty restore(String securityToken, String id) { - Wikitty result = null; - if (canRead(securityToken, id)) { - result = ws.restore(securityToken, id); - } else { - if (log.isDebugEnabled()) { - log.debug(_("user %s can't read object %s", - getUserId(securityToken), id)); - } - } - return result; - } - - @Override - public List<Wikitty> restore(String securityToken, List<String> ids) { - List<String> authorizedIds = new LinkedList<String>(ids); - for (Iterator<String> i=authorizedIds.iterator(); i.hasNext();) { - String id = i.next(); - if (!canRead(securityToken, id)) { - if (log.isDebugEnabled()) { - log.debug(_( - "user %s can't read object %s, remove it in restore list", - getUserId(securityToken), id)); - } - i.remove(); - } - } - - return ws.restore(securityToken, authorizedIds); - } - - @Override - public List<Wikitty> restore(String securityToken, WikittyTransaction transaction, List<String> ids) { - List<String> authorizedIds = new LinkedList<String>(ids); - for (Iterator<String> i=authorizedIds.iterator(); i.hasNext();) { - String id = i.next(); - if (!canRead(securityToken, id)) { - if (log.isDebugEnabled()) { - log.debug(_( - "user %s can't read object %s, remove it in restore list", - getUserId(securityToken), id)); - } - i.remove(); - } - } - - return ws.restore(securityToken, transaction, authorizedIds); - } - - @Override - public void delete(String securityToken, String id) { - if (canDelete(securityToken, id)) { - ws.delete(securityToken, id); - } - } - - @Override - public void delete(String securityToken, Collection<String> ids) { - for (String id : ids) { - if (!canDelete(securityToken, id)) { - throw new SecurityException(_("user %s can't delete object %s", - getUserId(securityToken), id)); - } - } - - ws.delete(securityToken, ids); - } - - @Override public PagedResult<String> findAllByCriteria(String securityToken, Criteria criteria) { // All people can read PagedResult that contains only id PagedResult<String> result = ws.findAllByCriteria(securityToken, criteria); @@ -488,7 +636,7 @@ // seul les AppAdmin on le droit a cette method return ws.syncEngin(securityToken); } else { - throw new SecurityException(_("user %s can't sync sear engine", + throw new SecurityException(_("user %s can't sync search engine", getUserId(securityToken))); } } @@ -522,56 +670,71 @@ // recuperation de l'utilisateur associe au securityToken // le securityToken est aussi l'id de l'objet Wikitty securityTokenWikitty = ws.restore(securityToken, securityToken); - if (securityTokenWikitty != null) { + if (securityTokenWikitty == null) { + throw new SecurityException(_("trying to use an invalidate security token %s", securityToken)); + } else { result = SecurityTokenHelper.getUser(securityTokenWikitty); } return result; } - /** - * Verifie que l'utilisateur est bien le proprietaire de l'objet + * verifie que l'utilisateur est dans la liste des admin * * @param userId * @param w - * @return + * @return vrai si et seulement si l'utilisateur est dans la liste des + * admin */ - protected boolean isOwner(String securityToken, String userId, Wikitty w) { - boolean result = false; - if (WikittyAuthorisationHelper.isExtension(w)) { - String owner = WikittyAuthorisationHelper.getOwner(w); - result = userId.equals(owner); - } + protected boolean isAdmin(String securityToken, String userId, Wikitty extensionRights) { + boolean result = isMember( + securityToken, userId, extensionRights, WikittyAuthorisation.FIELD_WIKITTYAUTHORISATION_ADMIN); return result; } /** - * verifie que l'utilisateur est dans la liste des admin + * verifie que l'utilisateur est dans la liste des writer * * @param userId * @param w * @return vrai si et seulement si l'utilisateur est dans la liste des - * admin + * writers */ - protected boolean isAdmin(String securityToken, String userId, Wikitty w) { + protected boolean isWriter(String securityToken, String userId, Wikitty extensionRights) { boolean result = isMember( - securityToken, userId, w, WikittyAuthorisation.FIELD_WIKITTYAUTHORISATION_ADMIN); + securityToken, userId, extensionRights, WikittyAuthorisation.FIELD_WIKITTYAUTHORISATION_WRITER); return result; } /** - * verifie que l'utilisateur est dans la liste des writer + * Verifie que l'utilisateur est bien le proprietaire de l'objet * * @param userId * @param w - * @return vrai si et seulement si l'utilisateur est dans la liste des - * writers + * @return */ - protected boolean isWriter(String securityToken, String userId, Wikitty w) { - boolean result = isMember( - securityToken, userId, w, WikittyAuthorisation.FIELD_WIKITTYAUTHORISATION_WRITER); + protected boolean isOwner(String securityToken, String userId, Wikitty extensionRights) { + String owner = WikittyAuthorisationHelper.getOwner(extensionRights); + boolean result = userId.equals(owner); return result; } + + protected boolean isMember(String securityToken, String userId, Wikitty extensionRights, String fieldName) { + Set<String> groupOrUser = extensionRights.getFieldAsSet( + WikittyAuthorisation.EXT_WIKITTYAUTHORISATION, + fieldName, + String.class); + boolean result = isMember(securityToken, userId, groupOrUser); + if (!result) { + // user don't have right on current object, check parent right + String parentId = WikittyAuthorisationHelper.getParent(extensionRights); + if (parentId != null) { + Wikitty parent = ws.restore(securityToken, parentId); + result = isMember(securityToken, userId, parent, fieldName); + } + } + return result; + } /** * Par defaut un objet est lisible par tous, sauf s'il a l'extension @@ -611,6 +774,13 @@ * @return */ protected boolean isAppAdmin(String securityToken, String userId) { + Wikitty group = getAppAdminGroup(securityToken); + Set<String> ids = WikittyGroupHelper.getMembers(group); + boolean result = isMember(securityToken, userId, ids); + return result; + } + + protected Wikitty getAppAdminGroup(String securityToken) { Wikitty group; if (appAdminGroupId == null) { // 1er fois, on le recherche @@ -623,48 +793,19 @@ group = ws.restore(securityToken, appAdminGroupId); // group peut-etre null, si entre temps un admin a supprime le group } + if (group == null) { // il n'existe pas on le cree. - WikittyGroup appAdminGroup = new WikittyGroupImpl(); + WikittyGroupAbstract appAdminGroup = new WikittyGroupImpl(); appAdminGroup.setName(WIKITTY_APPADMIN_GROUP_NAME); - } - // on garde l'id pour ne plus faire la recherche, - // vu que le groupe doit etre unique cela ne pose pas de probleme - appAdminGroupId = group.getId(); + ws.store(securityToken, appAdminGroup.getWikitty()); + group = appAdminGroup.getWikitty(); - Set<String> ids = WikittyGroupHelper.getMembers(group); - boolean result = isMember(securityToken, userId, ids); - return result; - } - - /** - * verifie qu'un utilisateur est membre d'un groupe passe en parametre via - * l'arguement field - * - * @param userId - * @param w - * @param field must be WikittyAuthorisation field name: admin, writer, reader - * @return - */ - protected boolean isMember( - String securityToken, String userId, Wikitty w, String field) { - boolean result = false; - if (WikittyAuthorisationHelper.isExtension(w)) { - Set<String> groupOrUser = w.getFieldAsSet( - WikittyAuthorisation.EXT_WIKITTYAUTHORISATION, - field, - String.class); - result = isMember(securityToken, userId, groupOrUser); - if (!result) { - // user don't have right on current object, check parent right - String parentId = WikittyAuthorisationHelper.getParent(w); - if (parentId != null) { - Wikitty parent = ws.restore(securityToken, parentId); - result = isMember(securityToken, userId, parent, field); - } - } + // on garde l'id pour ne plus faire la recherche, + // vu que le groupe doit etre unique cela ne pose pas de probleme + appAdminGroupId = group.getId(); } - return result; + return group; } /** @@ -677,26 +818,20 @@ */ protected boolean isMember( String securityToken, String userId, Set<String> groupOrUser) { - boolean result = false; if (groupOrUser != null) { for (String id : groupOrUser) { if (userId.equals(id)) { - result = true; - break; + return true; } else { - Wikitty w = ws.restore(securityToken, id); - if (WikittyGroupHelper.isExtension(w)) { - Set<String> members = WikittyGroupHelper.getMembers(w); - if (isMember(securityToken, userId, members)) { - result = true; - break; - } + Wikitty groupWikitty = ws.restore(securityToken, id); + if (WikittyGroupHelper.isExtension(groupWikitty)) { + Set<String> members = WikittyGroupHelper.getMembers(groupWikitty); + return isMember(securityToken, userId, members); } } } } - // not found in groupOrUser - return result; + return false; // not found in groupOrUser } } Modified: branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyUtil.java =================================================================== --- branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyUtil.java 2010-08-27 15:13:40 UTC (rev 275) +++ branches/wikitty-eugene-migration/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyUtil.java 2010-08-27 15:16:41 UTC (rev 276) @@ -774,7 +774,7 @@ * * @return SecurityToken that can be used like wikitty id */ - static public String genSecurityToken() { + static public String genSecurityTokenId() { String result = "_" + Math.abs(Math.random()); result.replace(".", ""); // on supprime le '.' dans le nombre aleatoire result = genUID() + result; Added: branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/layers/AbstractWikittyServiceTest.java =================================================================== --- branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/layers/AbstractWikittyServiceTest.java (rev 0) +++ branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/layers/AbstractWikittyServiceTest.java 2010-08-27 15:16:41 UTC (rev 276) @@ -0,0 +1,40 @@ +package org.nuiton.wikitty.layers; + +import org.junit.Before; +import org.nuiton.wikitty.ExtensionFactory; +import org.nuiton.wikitty.FieldType.TYPE; +import org.nuiton.wikitty.Wikitty; +import org.nuiton.wikitty.WikittyExtension; +import org.nuiton.wikitty.WikittyImpl; +import org.nuiton.wikitty.WikittyService; + +public class AbstractWikittyServiceTest { + + /** a wikitty service (in memory) with a cache */ + protected WikittyService service; + + protected static final String EXT_NAME = "myextension"; + protected static final String FIELD_NAME = "myfield"; + protected static final String VALUE = "myvalue"; + + /** an extension */ + protected WikittyExtension extension; + + /** a wikitty with extension */ + protected Wikitty aWikitty; + + protected String token; + + /** create a service, an extension, a wikitty, login, and store wikitty */ + @Before + public void setUp() throws Exception { + + extension = ExtensionFactory.create(EXT_NAME, "1") + .addField(FIELD_NAME, TYPE.STRING) + .extension(); + aWikitty = new WikittyImpl(); + aWikitty.addExtension(extension); + aWikitty.setField(EXT_NAME, FIELD_NAME, VALUE); + } + +} Modified: branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/layers/WikittyServiceCachedTest.java =================================================================== --- branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/cache/WikittyServiceCachedTest.java 2010-08-18 15:40:40 UTC (rev 269) +++ branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/layers/WikittyServiceCachedTest.java 2010-08-27 15:16:41 UTC (rev 276) @@ -1,9 +1,7 @@ -package org.nuiton.wikitty.cache; +package org.nuiton.wikitty.layers; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; @@ -11,43 +9,15 @@ import org.junit.Before; import org.junit.Test; -import org.nuiton.wikitty.ExtensionFactory; -import org.nuiton.wikitty.FieldType.TYPE; import org.nuiton.wikitty.Wikitty; -import org.nuiton.wikitty.WikittyExtension; -import org.nuiton.wikitty.WikittyImpl; -import org.nuiton.wikitty.WikittyService; import org.nuiton.wikitty.WikittyServiceCached; import org.nuiton.wikitty.WikittyServiceInMemory; -/** check that the cache */ -public class WikittyServiceCachedTest { - - /** a wikitty service (in memory) with a cache */ - protected WikittyService service; - - protected static final String EXT_NAME = "myextension"; - protected static final String FIELD_NAME = "myfield"; - - /** an extension */ - protected WikittyExtension extension; - - /** a wikitty with extension */ - protected Wikitty aWikitty; - - protected String token; +/** test {@link WikittyServiceCached} */ +public class WikittyServiceCachedTest extends AbstractWikittyServiceTest { - /** create a service, an extension, a wikitty, login, and store wikitty */ @Before - public void setUp() throws Exception { - - extension = ExtensionFactory.create(EXT_NAME, "1") - .addField(FIELD_NAME, TYPE.STRING) - .extension(); - aWikitty = new WikittyImpl(); - aWikitty.addExtension(extension); - aWikitty.setField(EXT_NAME, FIELD_NAME, "myvalue"); - + public void setUpWikittyServiceCachedTest() { service = new WikittyServiceCached(new WikittyServiceInMemory()); token = service.login(null, null); service.store(token, aWikitty); Added: branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/layers/WikittyServiceSecurityTest.java =================================================================== --- branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/layers/WikittyServiceSecurityTest.java (rev 0) +++ branches/wikitty-eugene-migration/wikitty-api/src/test/java/org/nuiton/wikitty/layers/WikittyServiceSecurityTest.java 2010-08-27 15:16:41 UTC (rev 276) @@ -0,0 +1,173 @@ +package org.nuiton.wikitty.layers; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Before; +import org.junit.Test; +import org.nuiton.wikitty.TreeNodeAbstract; +import org.nuiton.wikitty.Wikitty; +import org.nuiton.wikitty.WikittyAuthorisation; +import org.nuiton.wikitty.WikittyAuthorisationHelper; +import org.nuiton.wikitty.WikittyService; +import org.nuiton.wikitty.WikittyServiceInMemory; +import org.nuiton.wikitty.WikittyServiceSecurity; + +/** test {@link org.nuiton.wikitty.WikittyServiceSecurity} */ +public class WikittyServiceSecurityTest extends AbstractWikittyServiceTest { + + protected static final String APPADMIN_LOGIN = WikittyServiceSecurity.APPADMIN_LOGIN; + protected static final String APPADMIN_PASSWORD = WikittyServiceSecurity.APPADMIN_PASSWORD; + + protected WikittyServiceSecurity securityService; + + protected String noRightsToken; + protected String readerToken; + protected String writerToken; + protected String adminToken; + protected String ownerToken; + + @Before + public void setUpWikittyServiceSecurityTest() { + WikittyService inMemoryService = new WikittyServiceInMemory(); + + securityService = new WikittyServiceSecurity(inMemoryService); + + service = securityService; + + token = service.login(APPADMIN_LOGIN, APPADMIN_PASSWORD); + + securityService.createAccount(token, "i have no rights", ""); + securityService.createAccount(token, "reader", ""); + securityService.createAccount(token, "writer", ""); + securityService.createAccount(token, "admin", ""); + securityService.createAccount(token, "owner", ""); + + + Wikitty authorizations = securityService.addWikittyAuthorisation(token, extension); + WikittyAuthorisationHelper.addReader(authorizations, securityService.getUserWikittyId(token, "reader")); + WikittyAuthorisationHelper.addWriter(authorizations, securityService.getUserWikittyId(token, "writer")); + WikittyAuthorisationHelper.addAdmin(authorizations, securityService.getUserWikittyId(token, "admin")); + WikittyAuthorisationHelper.setOwner(authorizations, securityService.getUserWikittyId(token, "owner")); + service.store(token, authorizations); + + service.logout(token); + token = null; + + noRightsToken = service.login("i have no rights", ""); + readerToken = service.login("reader", ""); + writerToken = service.login("writer", ""); + adminToken = service.login("admin", ""); + ownerToken = service.login("owner", ""); + } + + @Test + public void testInvalidToken() { + // try to store with invalid token + String invalidToken = "INVALID TOKEN"; + try { + service.store(invalidToken, aWikitty); + fail(); + } catch (SecurityException e) {} + + // now storing the wikitty for next tests + token = service.login(APPADMIN_LOGIN, APPADMIN_PASSWORD); + service.store(token, aWikitty); + + // try to make operations on the stored wikitty with a bad token + try { + service.restore(invalidToken, aWikitty.getId()); + fail(); + } catch (SecurityException e) {} + +// try { +// service.canRead(invalidToken, aWikitty.getId()); +// fail(); +// } catch (SecurityException e) {} +// +// try { +// service.canWrite(invalidToken, aWikitty); +// fail(); +// } catch (SecurityException e) {} +// +// try { +// service.canDelete(invalidToken, aWikitty.getId()); +// fail(); +// } catch (SecurityException e) {} + + try { + service.logout(invalidToken); + fail(); + } catch (SecurityException e) {} + + // now try to make a valid token invalid + service.logout(token); + try { + service.store(token, aWikitty); + fail(); + } catch (SecurityException e) {} + } + + /*@Test*/ + public void testAppAdmin() { + token = service.login(APPADMIN_LOGIN, APPADMIN_PASSWORD); + assertTrue(service.canWrite(token, aWikitty)); + service.store(token, aWikitty); + assertTrue(service.canRead(token, aWikitty.getId())); + assertTrue(service.canDelete(token, aWikitty.getId())); + } + + @Test + public void addPolicyOnExtension() { + + service.store(ownerToken, aWikitty); + String aWikittyId = aWikitty.getId(); + aWikitty = null; + + // check that people who have the right can read + assertNull(service.restore(noRightsToken, aWikittyId) + .getFieldAsString(EXT_NAME, FIELD_NAME)); + assertEquals(VALUE, service.restore(readerToken, aWikittyId) + .getFieldAsString(EXT_NAME, FIELD_NAME)); + assertEquals(VALUE, service.restore(writerToken, aWikittyId) + .getFieldAsString(EXT_NAME, FIELD_NAME)); + + // check that people who have the right can write + aWikitty = service.restore(readerToken, aWikittyId); + aWikitty.setField(EXT_NAME, FIELD_NAME, VALUE + VALUE); + service.store(writerToken, aWikitty); + assertEquals(VALUE + VALUE, service.restore(readerToken, aWikittyId) + .getFieldAsString(EXT_NAME, FIELD_NAME)); + + // now check that reader can't write + aWikitty = service.restore(readerToken, aWikittyId); + aWikitty.setField(EXT_NAME, FIELD_NAME, VALUE); + // this store should not update field value (only reader access) + service.store(readerToken, aWikitty); + // check that field value remains the same after as before the store call + assertEquals(VALUE + VALUE, service.restore(readerToken, aWikittyId) + .getFieldAsString(EXT_NAME, FIELD_NAME)); + } + + @Test + public void testAdmin() { + + // FIXME 20108027 assertions missing, test fail + + Wikitty extensionAuthorisation = securityService.restoreExtensionAuthorisation(adminToken, extension); + + System.out.println("before " + extensionAuthorisation); + + WikittyAuthorisationHelper.clearReader(extensionAuthorisation); + WikittyAuthorisationHelper.clearWriter(extensionAuthorisation); + WikittyAuthorisationHelper.addWriter(extensionAuthorisation, "ID1"); // securityService.getUserWikittyId(adminToken, "admin")); + WikittyAuthorisationHelper.setOwner(extensionAuthorisation, "ID2"); // securityService.getUserWikittyId(adminToken, "admin")); + + service.store(adminToken, extensionAuthorisation); + + System.out.println("after " + service.restore(adminToken, extensionAuthorisation.getId())); + } + +} Modified: branches/wikitty-eugene-migration/wikitty-api/src/test/resources/log4j.properties =================================================================== --- branches/wikitty-eugene-migration/wikitty-api/src/test/resources/log4j.properties 2010-08-27 15:13:40 UTC (rev 275) +++ branches/wikitty-eugene-migration/wikitty-api/src/test/resources/log4j.properties 2010-08-27 15:16:41 UTC (rev 276) @@ -1,8 +1,11 @@ # Appender and Layout log4j.appender.logConsole=org.apache.log4j.ConsoleAppender log4j.appender.logConsole.layout=org.apache.log4j.PatternLayout -log4j.appender.logConsole.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n +# log4j.appender.logConsole.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n +log4j.appender.logConsole.layout.ConversionPattern=%d %5p [%t] (%F:%L) %M - %m%n # Configuration by components log4j.rootLogger=ERROR, logConsole -log4j.category.org.nuiton.wikitty=DEBUG + +log4j.logger.org.nuiton.wikitty=WARN +log4j.logger.org.nuiton.wikitty.WikittyServiceSecurity=TRACE
participants (1)
-
bleny@users.nuiton.org