cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/TableGenerator.java -text
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/TableGeneratorGlobalOverride.java -text
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/UpdateEntityListener.java -text
-cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/AuthorityPermission.java -text
-cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/CdmPermission.java -text
+cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/CRUD.java -text
+cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/CdmAuthority.java -text
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/CdmPermissionClass.java -text
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/CdmPermissionEvaluator.java -text
-cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/CdmPermissionEvaluatorPermitAll.java -text
-cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/DescriptionPermissionEvaluator.java -text
+cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/Operation.java -text
+cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/voter/CdmPermissionVoter.java -text
+cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/voter/DescriptionBaseVoter.java -text
+cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/voter/DescriptionElementVoter.java -text
+cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/voter/GrantAlwaysVoter.java -text
+cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/voter/TaxonBaseVoter.java -text
+cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/permission/voter/TaxonNodeVoter.java -text
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/replace/ReferringObjectMetadata.java -text
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/replace/ReferringObjectMetadataFactory.java -text
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/replace/impl/ListReferringObjectMetadata.java -text
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/NaturalLanguageGeneratorTest.java -text
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/PolytomousKeyServiceImplTest.java -text
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/SecurityTest.java -text
+cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/SecurityTest.java.orig -text
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/SecurityWithTransaction.java -text
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/TaxonNodeServiceImplTest.java -text
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/TaxonServiceImplBusinessTest.java -text
/**\r
* Copyright (C) 2007 EDIT\r
- * European Distributed Institute of Taxonomy \r
+ * European Distributed Institute of Taxonomy\r
* http://www.e-taxonomy.eu\r
- * \r
+ *\r
* The contents of this file are subject to the Mozilla Public License Version 1.1\r
* See LICENSE.TXT at the top of this package for the full license terms.\r
*/\r
@XmlRootElement(name = "Group")\r
@Entity\r
public class GrantedAuthorityImpl extends CdmBase implements GrantedAuthority {\r
- private static final long serialVersionUID = 2651969425860655040L;\r
- private static final Logger logger = Logger\r
- .getLogger(GrantedAuthority.class);\r
+ private static final long serialVersionUID = 2651969425860655040L;\r
+ private static final Logger logger = Logger\r
+ .getLogger(GrantedAuthority.class);\r
\r
- @XmlElement(name = "Authority")\r
- @NaturalId\r
- private String authority;\r
+ @XmlElement(name = "Authority")\r
+ @NaturalId\r
+ private String authority;\r
\r
- protected GrantedAuthorityImpl() {\r
- super();\r
- }\r
+ protected GrantedAuthorityImpl() {\r
+ super();\r
+ }\r
\r
- public static GrantedAuthorityImpl NewInstance() {\r
- return new GrantedAuthorityImpl();\r
- }\r
+ public static GrantedAuthorityImpl NewInstance() {\r
+ return new GrantedAuthorityImpl();\r
+ }\r
\r
- public String getAuthority() {\r
- return authority;\r
- }\r
+ public String getAuthority() {\r
+ return authority;\r
+ }\r
\r
- public void setAuthority(String authority) {\r
- this.authority = authority;\r
- }\r
+ public void setAuthority(String authority) {\r
+ this.authority = authority;\r
+ }\r
\r
- public int compareTo(Object o) {\r
- if (o instanceof GrantedAuthority) {\r
- return this.authority.compareTo(((GrantedAuthority) o)\r
- .getAuthority());\r
- }\r
- return 0;\r
- }\r
+ public int compareTo(Object o) {\r
+ if (o instanceof GrantedAuthority) {\r
+ return this.authority.compareTo(((GrantedAuthority) o)\r
+ .getAuthority());\r
+ }\r
+ return 0;\r
+ }\r
\r
- // *********** CLONE **********************************/\r
+ /* (non-Javadoc)\r
+ * @see eu.etaxonomy.cdm.model.common.CdmBase#toString()\r
+ */\r
+ @Override\r
+ public String toString() {\r
+ return getAuthority();\r
+ }\r
\r
- /**\r
- * Clones <i>this</i> Granted Authority. This is a shortcut that enables to\r
- * create a new instance that differs only slightly from <i>this</i> Granted\r
- * Authority by modifying only some of the attributes.<BR>\r
- * \r
- * \r
- * \r
- * @see eu.etaxonomy.cdm.model.common.CdmBase#clone()\r
- * @see java.lang.Object#clone()\r
- */\r
- @Override\r
- public Object clone() {\r
- GrantedAuthority result;\r
- try {\r
- result = (GrantedAuthority) super.clone();\r
- // no changes to authority\r
- return result;\r
- } catch (CloneNotSupportedException e) {\r
- logger.warn("Object does not implement cloneable");\r
- e.printStackTrace();\r
- return null;\r
- }\r
- }\r
+ // *********** CLONE **********************************/\r
+\r
+ /**\r
+ * Clones <i>this</i> Granted Authority. This is a shortcut that enables to\r
+ * create a new instance that differs only slightly from <i>this</i> Granted\r
+ * Authority by modifying only some of the attributes.<BR>\r
+ *\r
+ *\r
+ *\r
+ * @see eu.etaxonomy.cdm.model.common.CdmBase#clone()\r
+ * @see java.lang.Object#clone()\r
+ */\r
+ @Override\r
+ public Object clone() {\r
+ GrantedAuthority result;\r
+ try {\r
+ result = (GrantedAuthority) super.clone();\r
+ // no changes to authority\r
+ return result;\r
+ } catch (CloneNotSupportedException e) {\r
+ logger.warn("Object does not implement cloneable");\r
+ e.printStackTrace();\r
+ return null;\r
+ }\r
+ }\r
}\r
\r
package eu.etaxonomy.cdm.database;\r
\r
+import java.util.EnumSet;\r
+\r
import org.apache.log4j.Logger;\r
import org.hibernate.HibernateException;\r
import org.springframework.security.core.Authentication;\r
\r
import eu.etaxonomy.cdm.model.common.CdmBase;\r
-import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermission;\r
+import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;\r
+import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;\r
+\r
\r
+/**\r
+ * FIXME Rename to PermissionDeniedException ???\r
+ *\r
+ * @author andreas\r
+ * @date Sep 4, 2012\r
+ *\r
+ */\r
public class EvaluationFailedException extends HibernateException {\r
private static final Logger logger = Logger\r
.getLogger(EvaluationFailedException.class);\r
super(message);\r
}\r
\r
- public EvaluationFailedException(Authentication autherntication, CdmBase entity, CdmPermission permission) {\r
- super(permission.name() + " not permitted for '" + autherntication.getName()\r
+ public EvaluationFailedException(Authentication authentication, CdmBase entity, Operation requiredOperation) {\r
+ super(requiredOperation + " not permitted for '" + authentication.getName()\r
+ + "' on " + entity.getClass().getSimpleName() + "[uuid:" + entity.getUuid() + "', toString:'" + entity.toString() + "']");\r
+ }\r
+\r
+ public EvaluationFailedException(Authentication authentication, CdmBase entity, EnumSet<CRUD> requiredOperation) {\r
+ super(requiredOperation + " not permitted for '" + authentication.getName()\r
+ "' on " + entity.getClass().getSimpleName() + "[uuid:" + entity.getUuid() + "', toString:'" + entity.toString() + "']");\r
}\r
\r
- public EvaluationFailedException(Authentication autherntication, CdmBase entity, String permission) {\r
- super(permission + " not permitted for '" + autherntication.getName()\r
+ public EvaluationFailedException(Authentication authentication, CdmBase entity, String requiredOperation) {\r
+ super(requiredOperation + " not permitted for '" + authentication.getName()\r
+ "' on " + entity.getClass().getSimpleName() + "[uuid:" + entity.getUuid() + "', toString:'" + entity.toString() + "']");\r
}\r
\r
\r
\r
import java.io.Serializable;\r
+import java.util.EnumSet;\r
\r
import org.apache.log4j.Logger;\r
import org.hibernate.EmptyInterceptor;\r
\r
import eu.etaxonomy.cdm.database.EvaluationFailedException;\r
import eu.etaxonomy.cdm.model.common.CdmBase;\r
-import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermission;\r
+import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;\r
+import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;\r
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator;\r
/**\r
* @author k.luther\r
@Component\r
public class CdmSecurityHibernateInterceptor extends EmptyInterceptor {\r
\r
- private static final Logger logger = Logger.getLogger(CdmSecurityHibernateInterceptor.class);\r
+ private static final long serialVersionUID = 8477758472369568074L;\r
+\r
+ public static final Logger logger = Logger.getLogger(CdmSecurityHibernateInterceptor.class);\r
+\r
+ private CdmPermissionEvaluator permissionEvaluator;\r
+\r
+ public CdmPermissionEvaluator getPermissionEvaluator() {\r
+ return permissionEvaluator;\r
+ }\r
+\r
+ public void setPermissionEvaluator(CdmPermissionEvaluator permissionEvaluator) {\r
+ this.permissionEvaluator = permissionEvaluator;\r
+ }\r
\r
\r
/* (non-Javadoc)\r
String[] propertyNames,\r
Type[] type) {\r
\r
- CdmPermissionEvaluator permissionEvaluator = new eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator();\r
- if (SecurityContextHolder.getContext().getAuthentication() != null && entity instanceof CdmBase){\r
- if (!permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(), entity, CdmPermission.CREATE)){\r
- throw new EvaluationFailedException(SecurityContextHolder.getContext().getAuthentication(), (CdmBase)entity, CdmPermission.CREATE);\r
- }else return true;\r
+ if (SecurityContextHolder.getContext().getAuthentication() == null || !(entity instanceof CdmBase) ) {\r
+ return true;\r
}\r
- else return true;\r
-\r
+ // evaluate throws EvaluationFailedException\r
+ checkPermissions((CdmBase)entity, Operation.CREATE);\r
+ logger.debug("permission check suceeded - object creation granted");\r
+ return true;\r
}\r
+\r
+\r
/* (non-Javadoc)\r
* @see org.hibernate.EmptyInterceptor#onFlushDirty(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.Object[], java.lang.String[], org.hibernate.type.Type[])\r
*/\r
String[] propertyNames,\r
Type[] types) {\r
\r
- if( !(entity instanceof CdmBase) ){\r
+ if (SecurityContextHolder.getContext().getAuthentication() == null || !(entity instanceof CdmBase) ) {\r
return true;\r
}\r
CdmBase cdmEntity = (CdmBase)entity;\r
\r
- CdmPermissionEvaluator permissionEvaluator = new CdmPermissionEvaluator();\r
- String permission = null;;\r
- if (SecurityContextHolder.getContext().getAuthentication() != null){\r
- boolean equals = true;\r
- for (int i = 0; i<currentState.length; i++){\r
- if (currentState[i]== null ) {\r
- if ( previousState[i]!= null) {\r
- equals = false;\r
- break;\r
- }\r
- }\r
- if (currentState[i]!= null ){\r
- if (previousState == null){\r
- equals = false;\r
- break;\r
- }\r
- }\r
- if (currentState[i]!= null && previousState[i] != null){\r
- Object a = currentState[i];\r
- Object b = previousState[i];\r
- if (!currentState[i].equals(previousState[i])) {\r
- if (propertyNames[i].equals("password")){\r
- permission = "changePassword";\r
- }\r
- equals = false;\r
- break;\r
- }\r
- }\r
- }\r
+ if (isModified(currentState, previousState)){\r
+ // evaluate throws EvaluationFailedException\r
+ checkPermissions(cdmEntity, Operation.UPDATE);\r
+ logger.debug("permission check suceeded - object update granted");\r
+ }\r
+ return true;\r
+ }\r
\r
+ /**\r
+ * checks if the current authentication has the <code>expectedPermission</code> on the supplied <code>entity</code>.\r
+ * Throws an {@link EvaluationFailedException} if the evaluation fails.\r
+ *\r
+ * @param entity\r
+ * @param expectedOperation\r
+ */\r
+ private void checkPermissions(CdmBase entity, EnumSet<CRUD> expectedOperation) {\r
\r
- if (!equals){\r
- if (permission != null){\r
- if (!permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(), cdmEntity, permission)){\r
- throw new EvaluationFailedException(SecurityContextHolder.getContext().getAuthentication(), cdmEntity, permission);\r
- }else {\r
- return true;\r
- }\r
+ if (!permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(), entity, expectedOperation)){\r
+ throw new EvaluationFailedException(SecurityContextHolder.getContext().getAuthentication(), entity, expectedOperation);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Checks if the CDM entity as been modified by comparing the current with the previous state.\r
+ *\r
+ * @param currentState\r
+ * @param previousState\r
+ * @return true if the currentState and previousState differ.\r
+ */\r
+ private boolean isModified(Object[] currentState, Object[] previousState) {\r
+ boolean equals = true;\r
+ for (int i = 0; i<currentState.length; i++){\r
+ if (currentState[i]== null ) {\r
+ if ( previousState[i]!= null) {\r
+ equals = false;\r
+ break;\r
}\r
- if (!permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(), cdmEntity, CdmPermission.UPDATE)){\r
- throw new EvaluationFailedException(SecurityContextHolder.getContext().getAuthentication(), cdmEntity, CdmPermission.UPDATE);\r
- }else {\r
- return true;\r
+ }\r
+ if (currentState[i]!= null ){\r
+ if (previousState == null){\r
+ equals = false;\r
+ break;\r
+ }\r
+ }\r
+ if (currentState[i]!= null && previousState[i] != null){\r
+ Object a = currentState[i];\r
+ Object b = previousState[i];\r
+ if (!currentState[i].equals(previousState[i])) {\r
+ equals = false;\r
+ break;\r
}\r
- }else {\r
- return true;\r
}\r
}\r
- else{\r
- return true;\r
- }\r
-\r
+ return equals;\r
}\r
\r
\r
-\r
}\r
+++ /dev/null
-\r
-package eu.etaxonomy.cdm.persistence.hibernate.permission;\r
-\r
-import java.util.UUID;\r
-\r
-import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;\r
-\r
-/**\r
- * A <code>AuthorityPermission</code> consists of two parts which are separated\r
- * by a dot character '.' in the permissionString which can retrieved by\r
- * {@link #getPermissionString(String)}:\r
- *\r
- * <ul>\r
- * <li><code>className</code>: an {@link CdmPermissionClass} instance with represents a cdm\r
- * type or a part of the cdm type hierarchy. The className is always represented\r
- * as an upper case string.</li>\r
- * <li><code>permission</code>: a string which specifies a {@link CdmPermission} on that set of cdm\r
- * types</li>\r
- * <li><code>targetUuid</code>: The permission may be restricted to a specific cdm entity by adding\r
- * the entity uuid to the permission. The uuid string is enclosed in curly brackets '<code>{</code>'\r
- * , '<code>}</code>' and appended to the end of the permission.</li>\r
- * </ul>\r
- * The authority string syntax looks like:<br>\r
- * <pre>CLASSNAME.PERMISSION[{UUID}]</pre>\r
- * Whereas the square brackets are indicating an optional element.\r
- *\r
- * <h3>Examples for permissionStrings</h3>\r
- *\r
- * <pre>\r
- * TAXONBASE.CREATE\r
- * TAXONBASE.READ\r
- * TAXONBASE.UPDATE\r
- * TAXONBASE.DELETE\r
- * DESCRIPTIONBASE.UPDATE\r
- * TAXONNODE.UPDATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}\r
- * </pre>\r
- *\r
- * The method {@link #getPermissionString(String)} parses a full authority and returns permissionString and\r
- * the {@link AuthorityPermission} from the <code>authority</code>.\r
- *\r
- *\r
- *\r
- * @author k.luther\r
- */\r
-public class AuthorityPermission{\r
- CdmPermissionClass className;\r
- CdmPermission permission;\r
- UUID targetUuid;\r
-\r
- public AuthorityPermission(Object targetDomainObject, CdmPermission permission, UUID uuid){\r
- this.className = CdmPermissionClass.getValueOf(targetDomainObject);\r
- this.permission = permission;\r
- targetUuid = uuid;\r
- }\r
-\r
- public CdmPermissionClass getClassName(){\r
- return className;\r
- }\r
-\r
- public CdmPermission getPermission(){\r
- return permission;\r
- }\r
-\r
- public UUID getTargetUUID(){\r
- return targetUuid;\r
- }\r
-\r
- /**\r
- * Constructs a new AuthorityPermission by parsing the contents of an\r
- * authority string. For details on the syntax please refer to the class\r
- * documentation above.\r
- *\r
- * @param authority\r
- */\r
- public AuthorityPermission (String authority){\r
- String permissionString;\r
- int firstPoint = authority.indexOf(".");\r
- if (firstPoint == -1){\r
- // no dot: the authorityString only holds a CdmPermissionClass\r
- className = CdmPermissionClass.valueOf(authority);\r
- }else{\r
- // has a dot: the authorityString only holds a CdmPermissionClass and a permissionString\r
- className = CdmPermissionClass.valueOf((authority.substring(0, firstPoint)));\r
- int bracket = authority.indexOf("{");\r
- permissionString = getPermissionString(authority);\r
- if (bracket != -1){\r
- // having a bracket means the permissionString contains a uuid !!!\r
- int secondBracket = authority.indexOf("}");\r
- String uuid = authority.substring(bracket+1, secondBracket);\r
- targetUuid = UUID.fromString(uuid);\r
- }\r
- permission = CdmPermission.valueOf(permissionString.toUpperCase());\r
- }\r
- }\r
-\r
- /**\r
- * The method {@link #getPermissionString(String)} parses a full authority\r
- * string like\r
- * "<code>TAXONNODE.READ{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}</code>"and\r
- * returns the string representation of the CdmPermission "<code>READ</code>"\r
- * contained in the authority string\r
- *\r
- * @param authority\r
- * @return\r
- */\r
- private static String getPermissionString(String authority){\r
- int lastPoint = authority.lastIndexOf(".");\r
- int bracket = authority.indexOf("{");\r
- if (bracket == -1){\r
- return authority.substring(lastPoint+1);\r
- }else{\r
- return authority.substring(lastPoint+1, bracket);\r
- }\r
- }\r
-\r
-}
\ No newline at end of file
--- /dev/null
+package eu.etaxonomy.cdm.persistence.hibernate.permission;
+
+public enum CRUD {
+ CREATE, READ, UPDATE, DELETE;
+}
\ No newline at end of file
--- /dev/null
+\r
+package eu.etaxonomy.cdm.persistence.hibernate.permission;\r
+\r
+import java.util.EnumSet;\r
+import java.util.UUID;\r
+import java.util.regex.Matcher;\r
+import java.util.regex.Pattern;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.springframework.security.access.ConfigAttribute;\r
+\r
+import eu.etaxonomy.cdm.model.common.CdmBase;\r
+\r
+import sun.security.provider.PolicyParser.ParsingException;\r
+\r
+/**\r
+ * A <code>CdmAuthority</code> consists basically of two parts which are separated\r
+ * by a dot character '.'.\r
+ *\r
+ * <ul>\r
+ * <li><code>permissionClass</code>: an {@link CdmPermissionClass} instance with represents a cdm\r
+ * type or a part of the cdm type hierarchy. The className is always represented\r
+ * as an upper case string.</li>\r
+ * <li><code>property</code>: The <code>CdmAuthority</code> only applies to instances\r
+ * which satisfy the specified property. Interpretation is up to type specific voters.</li>\r
+ * <li><code>operation</code>: a string which specifies a {@link Operation} on that set of cdm\r
+ * types</li>\r
+ * <li><code>targetUuid</code>: The <code>operation</code> may be restricted to a specific cdm entity by adding\r
+ * the entity uuid to the <code>operation</code>. The uuid string is enclosed in curly brackets '<code>{</code>'\r
+ * , '<code>}</code>' and appended to the end of the <code>operation</code>.</li>\r
+ * </ul>\r
+ *\r
+ * <h3>Examples for permissionStrings</h3>\r
+ *\r
+ * <pre>\r
+ * TAXONBASE.CREATE\r
+ * TAXONBASE.READ\r
+ * TAXONBASE.UPDATE\r
+ * TAXONBASE.DELETE\r
+ * DESCRIPTIONBASE.UPDATE\r
+ * TAXONNODE.UPDATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}\r
+ * </pre>\r
+ *\r
+ * The method {@link #getPermissionString(String)} parses a full authority and returns permissionString and\r
+ * the {@link CdmAuthority} from the <code>authority</code>.\r
+ *\r
+ *\r
+ * @author k.luther\r
+ */\r
+public class CdmAuthority implements ConfigAttribute {\r
+\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ public static final Logger logger = Logger.getLogger(CdmAuthority.class);\r
+\r
+ CdmPermissionClass permissionClass;\r
+ String property;\r
+ EnumSet<CRUD> operation;\r
+ UUID targetUuid;\r
+\r
+ public CdmAuthority(CdmBase targetDomainObject, EnumSet<CRUD> operation, UUID uuid){\r
+ this.permissionClass = CdmPermissionClass.getValueOf(targetDomainObject);\r
+ this.property = null;\r
+ this.operation = operation;\r
+ this.targetUuid = uuid;\r
+ }\r
+\r
+ public CdmAuthority(CdmBase targetDomainObject, String property, EnumSet<CRUD> operation, UUID uuid){\r
+ this.permissionClass = CdmPermissionClass.getValueOf(targetDomainObject);\r
+ this.property = property;\r
+ this.operation = operation;\r
+ this.targetUuid = uuid;\r
+ }\r
+\r
+\r
+ public CdmAuthority(CdmPermissionClass permissionClass, String property, EnumSet<CRUD> operation, UUID uuid){\r
+ this.permissionClass = permissionClass;\r
+ this.property = property;\r
+ this.operation = operation;\r
+ this.targetUuid = uuid;\r
+ }\r
+\r
+ /**\r
+ * Constructs a new CdmAuthority by parsing the contents of an\r
+ * authority string. For details on the syntax please refer to the class\r
+ * documentation above.\r
+ *\r
+ * TODO usually one would not use a constructor but a valueOf(String) or fromSting() method for this\r
+ *\r
+ * @param authority\r
+ * @throws ParsingException\r
+ */\r
+ public CdmAuthority (String authority) throws ParsingException{\r
+\r
+ String[] tokens = parse(authority);\r
+ // className must never be null\r
+ permissionClass = CdmPermissionClass.valueOf(tokens[0]);\r
+ property = tokens[1];\r
+ if(tokens[2] != null){\r
+ try {\r
+ operation = Operation.fromString(tokens[2]);\r
+ } catch (IllegalArgumentException e) {\r
+ logger.warn("cannot parse Operation " + tokens[2]);\r
+ throw e;\r
+ }\r
+ }\r
+ if(tokens[3] != null){\r
+ targetUuid = UUID.fromString(tokens[3]);\r
+ }\r
+ }\r
+\r
+ public CdmPermissionClass getPermissionClass(){\r
+ return permissionClass;\r
+ }\r
+\r
+ public String getProperty(){\r
+ return property;\r
+ }\r
+\r
+ public EnumSet<CRUD> getOperation(){\r
+ return operation;\r
+ }\r
+\r
+ public UUID getTargetUUID(){\r
+ return targetUuid;\r
+ }\r
+\r
+ public boolean hasTargetUuid() {\r
+ return targetUuid != null;\r
+ }\r
+\r
+ public boolean hasProperty() {\r
+ return property != null;\r
+ }\r
+\r
+ /**\r
+ * Parses the given <code>authority</code> and returns an array of tokens.\r
+ * The array has a length of four elements whereas the elements can be null.\r
+ * The elements in the array correspond to the fields of {@link CdmAuthority}:\r
+ * <ol>\r
+ * <li>{@link CdmAuthority#permissionClass}</li>\r
+ * <li>{@link CdmAuthority#property}</li>\r
+ * <li>{@link CdmAuthority#operation}</li>\r
+ * <li>{@link CdmAuthority#targetUuid}</li>\r
+ * </ol>\r
+ * @param authority\r
+ * @return an array of tokens\r
+ * @throws ParsingException\r
+ */\r
+ protected String[] parse(String authority) throws ParsingException {\r
+ //\r
+ // regex pattern explained:\r
+ // (\\w*) -> classname\r
+ // (?:\\((\\w*)\\))? -> (property)\r
+ // \\.? -> .\r
+ // (?:(\\w*))(?:\\{([\\da-z\\-]+)\\})? -> Permmission and targetUuid\r
+ //\r
+ String regex = "(\\w*)(?:\\((\\w*)\\))?\\.?(?:(\\w*))(?:\\{([\\da-z\\-]+)\\})?";\r
+ Pattern pattern = Pattern.compile(regex);\r
+ String[] tokens = new String[4];\r
+ logger.debug("parsing '" + authority + "'");\r
+ Matcher m = pattern.matcher(authority);\r
+\r
+ if (m.find() && m.groupCount() == 4 ) {\r
+ for (int i = 0; i < m.groupCount(); i++) {\r
+ tokens[i] = m.group(i+1);\r
+ // normalize empty strings to null\r
+ if(tokens[i] != null && tokens[i].length() == 0){\r
+ tokens[i] = null;\r
+ }\r
+ logger.debug("[" + i + "]: " + tokens[i]+ "\n");\r
+ }\r
+ } else {\r
+ logger.debug("no match");\r
+ throw new ParsingException("Unsupported authority string: '" + authority + "'");\r
+ }\r
+\r
+ return tokens;\r
+ }\r
+\r
+\r
+ @Override\r
+ public String toString() {\r
+ StringBuilder sb = new StringBuilder();\r
+ sb.append(permissionClass.toString());\r
+ if(property != null){\r
+ sb.append('(').append(property).append(')');\r
+ }\r
+ sb.append('.').append(operation.toString());\r
+ if(targetUuid != null){\r
+ sb.append('{').append(targetUuid.toString()).append('}');\r
+ }\r
+ return sb.toString() ;\r
+ }\r
+\r
+ @Override\r
+ public String getAttribute() {\r
+ return toString();\r
+ }\r
+\r
+}
\ No newline at end of file
+++ /dev/null
-/**\r
-* Copyright (C) 2009 EDIT\r
-* European Distributed Institute of Taxonomy\r
-* http://www.e-taxonomy.eu\r
-*\r
-* The contents of this file are subject to the Mozilla Public License Version 1.1\r
-* See LICENSE.TXT at the top of this package for the full license terms.\r
-*/ \r
-package eu.etaxonomy.cdm.persistence.hibernate.permission;\r
-\r
-\r
-/**\r
- * @author k.luther\r
- * @date 06.07.2011\r
- *\r
- */\r
-public enum CdmPermission {\r
- CREATE, READ, UPDATE, DELETE, DENYALL, ADMIN;\r
-}\r
-\r
-\r
*\r
* The contents of this file are subject to the Mozilla Public License Version 1.1\r
* See LICENSE.TXT at the top of this package for the full license terms.\r
-*/ \r
+*/\r
package eu.etaxonomy.cdm.persistence.hibernate.permission;\r
\r
import eu.etaxonomy.cdm.model.common.CdmBase;\r
* @date 06.07.2011\r
*/\r
public enum CdmPermissionClass {\r
- USER, DESCRIPTIONBASE, DESCRIPTIONELEMENTBASE, TAXONBASE, ALL, TAXONNODE, CLASSIFICATION;\r
- \r
- \r
- public static CdmPermissionClass getValueOf(Object s){\r
- String permissionClassString ;\r
- if (s instanceof String){\r
- permissionClassString = (String)s;\r
- }else if (s instanceof CdmBase){\r
- permissionClassString = s.getClass().getSimpleName().toUpperCase(); \r
- } else if(s instanceof Class){\r
- permissionClassString = ((Class) s).getSimpleName().toUpperCase();\r
- }else{\r
- \r
- return null;\r
- }\r
- try{\r
- return CdmPermissionClass.valueOf(permissionClassString);\r
- }catch(IllegalArgumentException e){\r
- if (s instanceof CdmBase){\r
- s = s.getClass().getSuperclass();\r
- \r
- return getValueOf(s);\r
- }\r
- \r
- }\r
- return null;\r
- }\r
+ USER,\r
+ DESCRIPTIONBASE,\r
+ DESCRIPTIONELEMENTBASE,\r
+ TAXONBASE,\r
+ ALL,\r
+ TAXONNODE,\r
+ CLASSIFICATION;\r
+\r
+\r
+ /**\r
+ * return the appropriate CdmPermissionClass for the given Object. May return null if no matching CdmPermissionClass was found.\r
+ * @param s\r
+ * @return the CdmPermissionClass or null\r
+ */\r
+ public static CdmPermissionClass getValueOf(Object s){\r
+\r
+ String permissionClassString ;\r
+ if (s instanceof String){\r
+ permissionClassString = (String)s;\r
+ }else if (s instanceof CdmBase){\r
+ permissionClassString = s.getClass().getSimpleName().toUpperCase();\r
+ } else if(s instanceof Class){\r
+ permissionClassString = ((Class) s).getSimpleName().toUpperCase();\r
+ }else{\r
+\r
+ return null;\r
+ }\r
+\r
+ try{\r
+ return CdmPermissionClass.valueOf(permissionClassString);\r
+ }catch(IllegalArgumentException e){\r
+ if (s instanceof CdmBase){\r
+ s = s.getClass().getSuperclass();\r
+\r
+ return getValueOf(s);\r
+ }\r
+\r
+ }\r
+\r
+ return null;\r
+ }\r
}\r
\r
import java.io.Serializable;\r
import java.util.Collection;\r
+import java.util.EnumSet;\r
+import java.util.HashSet;\r
import java.util.UUID;\r
\r
import org.apache.log4j.Logger;\r
+import org.springframework.security.access.AccessDecisionManager;\r
+import org.springframework.security.access.ConfigAttribute;\r
import org.springframework.security.access.PermissionEvaluator;\r
import org.springframework.security.core.Authentication;\r
import org.springframework.security.core.GrantedAuthority;\r
+import org.springframework.stereotype.Component;\r
\r
import eu.etaxonomy.cdm.model.common.CdmBase;\r
-import eu.etaxonomy.cdm.model.common.User;\r
import eu.etaxonomy.cdm.model.description.DescriptionBase;\r
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;\r
import eu.etaxonomy.cdm.model.taxon.TaxonNode;\r
* @author k.luther\r
* @date 06.07.2011\r
*/\r
+@Component\r
public class CdmPermissionEvaluator implements PermissionEvaluator {\r
\r
protected static final Logger logger = Logger.getLogger(CdmPermissionEvaluator.class);\r
\r
+ private AccessDecisionManager accessDecisionManager;\r
+\r
+ public AccessDecisionManager getAccessDecisionManager() {\r
+ return accessDecisionManager;\r
+ }\r
+\r
+ public void setAccessDecisionManager(AccessDecisionManager accessDecisionManager) {\r
+ this.accessDecisionManager = accessDecisionManager;\r
+ }\r
+\r
/* (non-Javadoc)\r
* @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication, java.io.Serializable, java.lang.String, java.lang.Object)\r
*/\r
/* (non-Javadoc)\r
* @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication, java.lang.Object, java.lang.Object)\r
*/\r
- public boolean hasPermission(Authentication authentication,\r
- Object targetDomainObject, Object permission) {\r
+ public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {\r
\r
\r
- AuthorityPermission evalPermission;\r
- CdmPermission cdmPermission;\r
+ CdmAuthority evalPermission;\r
+ EnumSet<CRUD> requiredOperation;\r
+\r
if(logger.isDebugEnabled()){\r
StringBuilder grantedAuthoritiesTxt = new StringBuilder();\r
for(GrantedAuthority ga : authentication.getAuthorities()){\r
grantedAuthoritiesTxt.append(" - ").append(ga.getAuthority()).append("\n");\r
- logger.debug("evaluating:\n"\r
- + " User '" + authentication.getName() + "':\n"\r
- + grantedAuthoritiesTxt\r
- + " Object: " + ((CdmBase)targetDomainObject).instanceToString() + "\n"\r
- + " Permission: " + permission);\r
}\r
- }\r
- if (!(permission instanceof CdmPermission)){\r
- String permissionString = (String)permission;\r
- if (permissionString.equals("changePassword")){\r
- if (targetDomainObject.equals(((User)authentication.getPrincipal()))){\r
- return true;\r
- }else{\r
- cdmPermission = CdmPermission.ADMIN;\r
- }\r
- }else{\r
- cdmPermission = CdmPermission.valueOf(permissionString);\r
+ if(grantedAuthoritiesTxt.length() == 0){\r
+ grantedAuthoritiesTxt.append(" - ").append("<No GrantedAuthority given>").append("\n");\r
}\r
- }else {\r
- cdmPermission = (CdmPermission)permission;\r
+ logger.debug("hasPermission()\n"\r
+ + " User '" + authentication.getName() + "':\n"\r
+ + grantedAuthoritiesTxt\r
+ + " Object: " + ((CdmBase)targetDomainObject).instanceToString() + "\n"\r
+ + " Permission: " + permission);\r
}\r
+ try {\r
+ // FIXME refactor into Operation ======\r
+ if (Operation.isOperation(permission)){\r
+ requiredOperation = (EnumSet<CRUD>)permission;\r
+ } else {\r
+ // try to treat as string\r
+ requiredOperation = Operation.fromString(permission.toString());\r
+ }\r
+ // =======================================\r
\r
- Collection<GrantedAuthority> authorities = ((User)authentication.getPrincipal()).getAuthorities();\r
+ } catch (IllegalArgumentException e) {\r
+ logger.debug("permission string '"+ permission.toString() + "' not parsable => true");\r
+ return true; // it might be wrong to return true\r
+ }\r
\r
try{\r
- //evalPermission = new AuthorityPermission(targetDomainObject.getClass().getSimpleName().toUpperCase(), cdmPermission, ((CdmBase)targetDomainObject).getUuid());\r
- evalPermission = new AuthorityPermission(targetDomainObject, cdmPermission, ((CdmBase)targetDomainObject).getUuid());\r
+ //evalPermission = new CdmAuthority(targetDomainObject.getClass().getSimpleName().toUpperCase(), cdmPermission, ((CdmBase)targetDomainObject).getUuid());\r
+ evalPermission = new CdmAuthority((CdmBase)targetDomainObject, requiredOperation, ((CdmBase)targetDomainObject).getUuid());\r
}catch(NullPointerException e){\r
- //evalPermission = new AuthorityPermission(targetDomainObject.getClass().getSimpleName().toUpperCase(), cdmPermission, null);\r
- evalPermission = new AuthorityPermission(targetDomainObject, cdmPermission, null);\r
+ //evalPermission = new CdmAuthority(targetDomainObject.getClass().getSimpleName().toUpperCase(), cdmPermission, null);\r
+ evalPermission = new CdmAuthority((CdmBase)targetDomainObject, requiredOperation, null);\r
}\r
\r
\r
- if (evalPermission.className != null) {\r
- return evalPermission(authorities, evalPermission, (CdmBase) targetDomainObject);\r
-\r
+ if (evalPermission.permissionClass != null) {\r
+ logger.debug("starting evaluation => ...");\r
+ return evalPermission(authentication, evalPermission, (CdmBase) targetDomainObject);\r
}else{\r
+ logger.debug("skipping evaluation => true");\r
return true;\r
}\r
\r
}\r
\r
+ /**\r
+ * @param targetUuid\r
+ * @param node\r
+ * @return\r
+ */\r
private TaxonNode findTargetUuidInTree(UUID targetUuid, TaxonNode node){\r
if (targetUuid.equals(node.getUuid()))\r
return node;\r
}\r
\r
\r
- public boolean evalPermission(Collection<GrantedAuthority> authorities, AuthorityPermission evalPermission, CdmBase targetDomainObject){\r
+ /**\r
+ * @param authorities\r
+ * @param evalPermission\r
+ * @param targetDomainObject\r
+ * @return\r
+ */\r
+ private boolean evalPermission(Authentication authentication, CdmAuthority evalPermission, CdmBase targetDomainObject){\r
\r
//if user has administrator rights return true;\r
- for (GrantedAuthority authority: authorities){\r
- if (authority.getAuthority().equals("ALL.ADMIN"))return true;\r
+ for (GrantedAuthority authority: authentication.getAuthorities()){\r
+ if (authority.getAuthority().equals("ROLE_ADMIN")){\r
+ logger.debug("ROLE_ADMIN found => true");\r
+ return true;\r
+ }\r
}\r
\r
- //if targetDomainObject is instance of DescriptionBase or DescriptionElementBase use the DescriptionPermissionEvaluator\r
- if (targetDomainObject instanceof DescriptionElementBase || targetDomainObject instanceof DescriptionBase){\r
- return DescriptionPermissionEvaluator.hasPermission(authorities, targetDomainObject, evalPermission);\r
- }\r
-\r
- for (GrantedAuthority authority: authorities){\r
- AuthorityPermission authorityPermission= new AuthorityPermission(authority.getAuthority());\r
- //evaluate authorities\r
- //if classnames match or the authorityClassName is ALL, AND the permission matches or is ADMIN the evaluation is successful\r
- if ((authorityPermission.className.equals(evalPermission.className) || authorityPermission.className.equals(CdmPermissionClass.ALL))\r
- && (authorityPermission.permission.equals(evalPermission.permission)|| authorityPermission.permission.equals(CdmPermission.ADMIN))){\r
- /* if (authorityPermission.targetUuid != null){\r
- //TODO\r
+ // === run voters\r
+ Collection<ConfigAttribute> attributes = new HashSet<ConfigAttribute>();\r
+ attributes.add(evalPermission);\r
\r
- }else{*/\r
- return true;\r
- //}\r
+ // decide() throws AccessDeniedException, InsufficientAuthenticationException\r
+ logger.debug("AccessDecisionManager will decide ...");\r
+ accessDecisionManager.decide(authentication, targetDomainObject, attributes);\r
\r
- }\r
- //if authority is restricted to only one object (and the cascaded objects???)\r
- if (authorityPermission.targetUuid != null){\r
- if (authorityPermission.targetUuid.equals(((CdmBase)targetDomainObject).getUuid())){\r
- if (authorityPermission.permission.equals(evalPermission.permission)){\r
- return true;\r
- }\r
- }\r
- }\r
- //if the user has the rights for a subtree\r
- if (authorityPermission.className.equals(CdmPermissionClass.TAXONBASE) && targetDomainObject.getClass().getSimpleName().toUpperCase().equals("TaxonNode")){\r
-\r
- TaxonNode node = (TaxonNode)targetDomainObject;\r
- TaxonNode targetNode = findTargetUuidInTree(authorityPermission.targetUuid, node);\r
- if (targetNode != null){\r
- if (evalPermission.permission.equals(authorityPermission.permission) ){\r
- return true;\r
- }\r
- }\r
- }\r
-\r
-\r
- }\r
- return false;\r
+ return true;\r
}\r
\r
}\r
+++ /dev/null
-// $Id$\r
-/**\r
-* Copyright (C) 2007 EDIT\r
-* European Distributed Institute of Taxonomy \r
-* http://www.e-taxonomy.eu\r
-* \r
-* The contents of this file are subject to the Mozilla Public License Version 1.1\r
-* See LICENSE.TXT at the top of this package for the full license terms.\r
-*/\r
-\r
-package eu.etaxonomy.cdm.persistence.hibernate.permission;\r
-\r
-import java.io.Serializable;\r
-\r
-import org.apache.log4j.Logger;\r
-import org.springframework.security.access.PermissionEvaluator;\r
-import org.springframework.security.core.Authentication;\r
-\r
-/**\r
- * @author k.luther\r
- * @created 13.07.2011\r
- * @version 1.0\r
- */\r
-public class CdmPermissionEvaluatorPermitAll implements PermissionEvaluator {\r
- private static final Logger logger = Logger.getLogger(CdmPermissionEvaluatorPermitAll.class);\r
-\r
- /* (non-Javadoc)\r
- * @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication, java.lang.Object, java.lang.Object)\r
- */\r
- \r
- public boolean hasPermission(Authentication authentication,\r
- Object targetDomainObject, Object permission) {\r
- //everybody has the permission\r
- return true;\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication, java.io.Serializable, java.lang.String, java.lang.Object)\r
- */\r
- \r
- public boolean hasPermission(Authentication authentication,\r
- Serializable targetId, String targetType, Object permission) {\r
- // TODO Auto-generated method stub\r
- return false;\r
- }\r
-}\r
+++ /dev/null
-/**\r
-* Copyright (C) 2009 EDIT\r
-* European Distributed Institute of Taxonomy\r
-* http://www.e-taxonomy.eu\r
-*\r
-* The contents of this file are subject to the Mozilla Public License Version 1.1\r
-* See LICENSE.TXT at the top of this package for the full license terms.\r
-*/\r
-package eu.etaxonomy.cdm.persistence.hibernate.permission;\r
-\r
-import java.util.Collection;\r
-import java.util.Set;\r
-\r
-import org.springframework.security.core.Authentication;\r
-import org.springframework.security.core.GrantedAuthority;\r
-\r
-import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;\r
-import eu.etaxonomy.cdm.model.common.User;\r
-import eu.etaxonomy.cdm.model.description.DescriptionBase;\r
-import eu.etaxonomy.cdm.model.description.DescriptionElementBase;\r
-import eu.etaxonomy.cdm.model.description.Feature;\r
-\r
-/**\r
- * Evaluates permissions ...\r
- *\r
- * @author k.luther\r
- * @date 06.07.2011\r
- *\r
- */\r
-public class DescriptionPermissionEvaluator {\r
-\r
- public static boolean hasPermission(Collection<GrantedAuthority> authorities,\r
- Object targetDomainObject, AuthorityPermission evalPermission) {\r
- Feature feature = null;\r
- String authorityString;\r
- AuthorityPermission authorityPermission;\r
-\r
-\r
- if (targetDomainObject instanceof DescriptionElementBase){\r
- feature = ((DescriptionElementBase)targetDomainObject).getFeature();\r
- }\r
-\r
- for (GrantedAuthority authority: authorities){\r
-\r
- authorityString = authority.getAuthority();\r
- authorityPermission = new AuthorityPermission(authorityString);\r
-\r
- if (targetDomainObject instanceof DescriptionElementBase){\r
- try{\r
- //check for a special feature\r
- if (feature != null){\r
- if (authorityString.contains(feature.getLabel()) && (evalPermission.permission.equals(authorityPermission.permission) || authorityPermission.equals(CdmPermission.ADMIN))){\r
- return true;\r
- } else if (authorityPermission.className.equals(CdmPermissionClass.DESCRIPTIONBASE)) {\r
- if (evalPermission.permission.equals(authorityPermission.permission) ){\r
- return true;\r
- } else if (authorityPermission.permission.equals(CdmPermission.ADMIN)){\r
- return true;\r
- }\r
- }\r
- }\r
- }catch(Exception e){\r
- //in tests the initialisation of terms like features fails...\r
- if (org.hibernate.ObjectNotFoundException.class.isInstance(e)){\r
- if (evalPermission.permission.equals(authorityPermission.permission)|| authorityPermission.permission.equals(CdmPermission.ADMIN)){\r
- return true;\r
- }\r
- }else {\r
- return false;\r
- }\r
-\r
- }\r
- //the user has the general right for descriptions\r
- if (authorityPermission.className.equals(CdmPermissionClass.DESCRIPTIONBASE)){\r
- //no special feature\r
- if (authority.getAuthority().lastIndexOf(".") == authority.getAuthority().indexOf(".") && (authorityPermission.className.equals(evalPermission.permission) || authorityPermission.equals(CdmPermission.ADMIN))){\r
- return true;\r
- }\r
- }\r
- } else{\r
- if (authorityPermission.getClassName().equals(CdmPermissionClass.DESCRIPTIONBASE) && authorityPermission.permission.equals(evalPermission.permission)){\r
- return true;\r
- }\r
- }\r
- }\r
-\r
- return false;\r
- }\r
-\r
-\r
- /*public static boolean hasPermission (Collection<GrantedAuthority> authorities,\r
- DescriptionBase targetDomainObject, AuthorityPermission evalPermission){\r
- Set<DescriptionElementBase> elements = targetDomainObject.getElements();\r
-\r
- for (GrantedAuthority authority :authorities){\r
- if (authority.getAuthority().contains(CdmPermissionClass.DESCRIPTIONBASE.toString())){\r
- if (authority.getAuthority().lastIndexOf(".") == authority.getAuthority().indexOf(".") && authority.getAuthority().contains(evalPermission.permission.toString())){\r
- return true;\r
- }else{\r
- //TODO: das stimmt noch nicht so ganz!!!\r
- for (DescriptionElementBase element: elements){\r
- if (authority.getAuthority().contains(element.getFeature().getLabel()) && authority.getAuthority().contains(evalPermission.permission.toString())){\r
- return true;\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
-\r
- return false;\r
-\r
- }*/\r
-}\r
--- /dev/null
+/**\r
+* Copyright (C) 2009 EDIT\r
+* European Distributed Institute of Taxonomy\r
+* http://www.e-taxonomy.eu\r
+*\r
+* The contents of this file are subject to the Mozilla Public License Version 1.1\r
+* See LICENSE.TXT at the top of this package for the full license terms.\r
+*/\r
+package eu.etaxonomy.cdm.persistence.hibernate.permission;\r
+\r
+import java.util.EnumSet;\r
+\r
+\r
+/**\r
+ * @author k.luther\r
+ * @date 06.07.2011\r
+ *\r
+ */\r
+public class Operation {\r
+\r
+ private Operation(){\r
+\r
+ }\r
+\r
+ final static public EnumSet<CRUD> CREATE = EnumSet.of(CRUD.CREATE);\r
+\r
+ final static public EnumSet<CRUD> READ = EnumSet.of(CRUD.READ);\r
+\r
+ final static public EnumSet<CRUD> UPDATE = EnumSet.of(CRUD.UPDATE);\r
+\r
+ final static public EnumSet<CRUD> DELETE = EnumSet.of(CRUD.DELETE);\r
+\r
+ final static public EnumSet<CRUD> ALL = EnumSet.allOf(CRUD.class);\r
+\r
+ final static public EnumSet<CRUD> ADMIN = ALL; // FIXME remove?\r
+\r
+ final static public EnumSet<CRUD> NONE = EnumSet.noneOf(CRUD.class);\r
+\r
+ public static EnumSet<CRUD> fromString(String string){\r
+ if(string.equals("ALL")){\r
+ return ALL;\r
+ }\r
+ if(string.equals("ADMIN")){\r
+ return ADMIN;\r
+ }\r
+ if(string.equals("NONE")){\r
+ return NONE;\r
+ }\r
+ return EnumSet.of(CRUD.valueOf(string));\r
+ }\r
+\r
+ public static boolean isOperation(Object o){\r
+ try {\r
+ return o instanceof EnumSet<?> && ALL.containsAll((EnumSet<?>)o);\r
+ } catch (Throwable e){\r
+ return false;\r
+ }\r
+ }\r
+\r
+}\r
+\r
+\r
--- /dev/null
+// $Id$
+/**
+* Copyright (C) 2012 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.persistence.hibernate.permission.voter;
+
+import java.util.Collection;
+
+import org.apache.log4j.Logger;
+import org.springframework.security.access.AccessDecisionVoter;
+import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+
+import sun.security.provider.PolicyParser.ParsingException;
+
+import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
+import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;
+import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionClass;
+
+/**
+ * The <code>CdmPermissionVoter</code> provides access control votes for {@link CdmBase} objects.
+ *
+ * @author andreas kohlbecker
+ * @date Sep 4, 2012
+ *
+ */
+public abstract class CdmPermissionVoter implements AccessDecisionVoter {
+
+ public static final Logger logger = Logger.getLogger(CdmPermissionVoter.class);
+
+ /* (non-Javadoc)
+ * @see org.springframework.security.access.AccessDecisionVoter#supports(org.springframework.security.access.ConfigAttribute)
+ */
+ public boolean supports(ConfigAttribute attribute) {
+ // all CdmPermissionVoter support CdmAuthority
+ return attribute instanceof CdmAuthority;
+ }
+
+ /* (non-Javadoc)
+ * @see org.springframework.security.access.AccessDecisionVoter#supports(java.lang.Class)
+ */
+ public boolean supports(Class<?> clazz) {
+ /* NOTE!!!
+ * Do not change this, all CdmPermissionVoters must support CdmBase.class
+ */
+ return clazz.isInstance(CdmBase.class);
+ }
+
+ /**
+ * Sets the Cdm type, or super type this Voter is responsible for.
+ */
+ abstract public Class<? extends CdmBase> getResponsibilityClass();
+
+
+ protected boolean isResponsibleFor(Object securedObject) {
+ return getResponsibilityClass().isAssignableFrom(securedObject.getClass());
+ }
+
+ protected boolean isResponsibleFor(CdmPermissionClass permissionClass) {
+ return getResponsibility().equals(permissionClass);
+ }
+
+ /**
+ * Get the according CdmPermissionClass matching {@link #getResponsibilityClass()} the cdm class this voter is responsible for.
+ * @return
+ */
+ protected CdmPermissionClass getResponsibility() {
+ return CdmPermissionClass.getValueOf(getResponsibilityClass());
+ }
+
+ /* (non-Javadoc)
+ * @see org.springframework.security.access.AccessDecisionVoter#vote(org.springframework.security.core.Authentication, java.lang.Object, java.util.Collection)
+ */
+ public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
+
+ if(!isResponsibleFor(object)){
+ logger.debug("class missmatch => ACCESS_ABSTAIN");
+ return ACCESS_ABSTAIN;
+ }
+
+ if (logger.isDebugEnabled()){
+ logger.debug("authentication: " + authentication.getName() + ", object : " + object.toString() + ", attribute[0]:" + ((CdmAuthority)attributes.iterator().next()).getAttribute());
+ }
+
+ int fallThroughVote = ACCESS_DENIED;
+
+ // loop over all attributes = permissions of which at least one must match
+ // usually there is only one element in the collection!
+ for(ConfigAttribute attribute : attributes){
+ if(!(attribute instanceof CdmAuthority)){
+ throw new RuntimeException("attributes must contain only CdmAuthority");
+ }
+ CdmAuthority evalPermission = (CdmAuthority)attribute;
+
+ for (GrantedAuthority authority: authentication.getAuthorities()){
+
+ CdmAuthority ap;
+ try {
+ ap = new CdmAuthority(authority.getAuthority());
+ } catch (ParsingException e) {
+ logger.debug("skipping " + authority.getAuthority() + " due to ParsingException");
+ continue;
+ }
+
+ // check if the voter is responsible for the permission to be evaluated
+ if( ! isResponsibleFor(evalPermission.getPermissionClass())){
+ logger.debug(getResponsibility() + " not responsible for " + evalPermission.getPermissionClass() + " -> skipping");
+ continue;
+ }
+
+ ValidationResult vr = new ValidationResult();
+
+ boolean isALL = ap.getPermissionClass().equals(CdmPermissionClass.ALL);
+
+ vr.isClassMatch = isALL || ap.getPermissionClass().equals(evalPermission.getPermissionClass());
+ vr.isPermissionMatch = ap.getOperation().containsAll(evalPermission.getOperation());
+ vr.isUuidMatch = ap.hasTargetUuid() && ap.getTargetUUID().equals(((CdmBase)object).getUuid());
+
+ //
+ // only vote if no property is defined.
+ // Authorities with properties must be voted by type specific voters.
+ //
+ if(!ap.hasProperty()){
+ if ( !ap.hasTargetUuid() && vr.isClassMatch && vr.isPermissionMatch){
+ logger.debug("no tragetUuid, class & permission match => ACCESS_GRANTED");
+ return ACCESS_GRANTED;
+ }
+ if ( vr.isUuidMatch && vr.isClassMatch && vr.isPermissionMatch){
+ logger.debug("permission, class and uuid are matching => ACCESS_GRANTED");
+ return ACCESS_GRANTED;
+ }
+ } else {
+ //
+ // If the authority contains a property AND the voter is responsible for this class
+ // we must change the fallThroughVote
+ // to ABSTAIN, since no decision can be made in this case at this point
+ //
+ if(vr.isClassMatch){
+ fallThroughVote = ACCESS_ABSTAIN;
+ }
+ }
+
+ //
+ // ask subclasses for further voting decisions
+ // subclasses will cast votes for specific Cdm Types
+ //
+ Integer furtherVotingResult = furtherVotingDescisions(ap, object, attributes, vr);
+ if(furtherVotingResult != null && furtherVotingResult != ACCESS_ABSTAIN){
+ logger.debug("furtherVotingResult => " + furtherVotingResult);
+ return furtherVotingResult;
+ }
+
+ } // END Authorities loop
+ } // END attributes loop
+
+ // the value of fallThroughVote depends on whether the authority had an property or not, see above
+ logger.debug("fallThroughVote => " + fallThroughVote);
+ return fallThroughVote;
+ }
+
+ /**
+ * Override this method to implement specific decisions.
+ * Implementations of this method will be executed in {@link #vote(Authentication, Object, Collection)}.
+ *
+ * @param CdmAuthority
+ * @param object
+ * @param attributes
+ * @param validationResult
+ * @return A return value of ACCESS_ABSTAIN or null will be ignored in {@link #vote(Authentication, Object, Collection)}
+ */
+ protected Integer furtherVotingDescisions(CdmAuthority CdmAuthority, Object object, Collection<ConfigAttribute> attributes,
+ ValidationResult validationResult) {
+ return null;
+ }
+
+ /**
+ * Holds various flags with validation results.
+ * Is used to pass this information from
+ * {@link CdmPermissionVoter#vote(Authentication, Object, Collection)}
+ * to {@link CdmPermissionVoter#furtherVotingDescisions(CdmAuthority, Object, Collection, ValidationResult)}
+ *
+ * @author andreas kohlbecker
+ * @date Sep 5, 2012
+ *
+ */
+ protected class ValidationResult {
+ boolean isPermissionMatch = false;
+ boolean isPropertyMatch = false;
+ boolean isUuidMatch = false;
+ boolean isClassMatch = false;
+ }
+
+}
--- /dev/null
+package eu.etaxonomy.cdm.persistence.hibernate.permission.voter;
+
+import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.cdm.model.description.DescriptionBase;
+
+public class DescriptionBaseVoter extends CdmPermissionVoter {
+
+ @Override
+ public Class<? extends CdmBase> getResponsibilityClass() {
+ return DescriptionBase.class;
+ }
+
+}
--- /dev/null
+package eu.etaxonomy.cdm.persistence.hibernate.permission.voter;
+
+import java.util.Collection;
+import java.util.UUID;
+
+import org.springframework.security.access.ConfigAttribute;
+
+import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.cdm.model.description.DescriptionBase;
+import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
+import eu.etaxonomy.cdm.model.description.Feature;
+import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
+
+public class DescriptionElementVoter extends CdmPermissionVoter {
+
+ @Override
+ public Class<? extends CdmBase> getResponsibilityClass() {
+ return DescriptionElementBase.class;
+ }
+
+ @Override
+ protected Integer furtherVotingDescisions(CdmAuthority ap, Object object, Collection<ConfigAttribute> attributes,
+ ValidationResult vr) {
+
+ // we only need to implement the case where a property is contained in the authority
+ // the other case is covered by the CdmPermissionVoter
+ if(ap.hasProperty() && object instanceof DescriptionElementBase){
+
+ Feature feature = ((DescriptionElementBase)object).getFeature();
+
+ if(feature == null){
+ // if the user is granted for a specific feature
+ // he should not be granted for DescriptoinElements without a feature
+ return ACCESS_DENIED;
+ }
+ boolean isPropertyMatch = false;
+
+ try {
+ UUID featureUUID = UUID.fromString(ap.getProperty());
+ isPropertyMatch = featureUUID.equals(feature.getUuid());
+ // FIXME uuids as property not yes supported in AuhorityPermission !!!!
+ } catch (IllegalArgumentException e) {
+ // Property is not a uuid, so treat is as Label:
+ isPropertyMatch = ap.getProperty().equals(feature.getLabel());
+ }
+
+ if ( !ap.hasTargetUuid() && vr.isClassMatch && vr.isPermissionMatch && isPropertyMatch){
+ logger.debug("no tragetUuid, class & permission match => ACCESS_GRANTED");
+ return ACCESS_GRANTED;
+ }
+ if ( vr.isUuidMatch && vr.isClassMatch && vr.isPermissionMatch && isPropertyMatch){
+ logger.debug("permission, class and uuid are matching => ACCESS_GRANTED");
+ return ACCESS_GRANTED;
+ }
+ }
+
+ return ACCESS_DENIED;
+ }
+
+}
--- /dev/null
+// $Id$
+/**
+* Copyright (C) 2012 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.persistence.hibernate.permission.voter;
+
+import java.util.Collection;
+
+import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.access.vote.UnanimousBased;
+import org.springframework.security.core.Authentication;
+
+import eu.etaxonomy.cdm.model.common.CdmBase;
+
+/**
+ * This voter always returns {@link #ACCESS_GRANTED}.
+ * It is needed as default voter when using the {@link UnanimousBased}
+ * @author andreas kohlbecker
+ * @date Sep 4, 2012
+ *
+ */
+public class GrantAlwaysVoter extends CdmPermissionVoter {
+
+ /* (non-Javadoc)
+ * @see org.springframework.security.access.AccessDecisionVoter#vote(org.springframework.security.core.Authentication, java.lang.Object, java.util.Collection)
+ */
+ @Override
+ public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
+ return ACCESS_GRANTED;
+ }
+
+ @Override
+ public Class<? extends CdmBase> getResponsibilityClass() {
+ return CdmBase.class;
+ }
+
+}
--- /dev/null
+// $Id$
+/**
+* Copyright (C) 2012 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.persistence.hibernate.permission.voter;
+
+import org.apache.log4j.Logger;
+
+import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.cdm.model.taxon.TaxonBase;
+
+/**
+ * @author andreas kohlbecker
+ * @date Sep 4, 2012
+ *
+ */
+public class TaxonBaseVoter extends CdmPermissionVoter {
+
+ public static final Logger logger = Logger.getLogger(TaxonBaseVoter.class);
+
+ @Override
+ public Class<? extends CdmBase> getResponsibilityClass() {
+ return TaxonBase.class;
+ }
+
+}
--- /dev/null
+// $Id$
+/**
+* Copyright (C) 2012 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.persistence.hibernate.permission.voter;
+
+import java.util.Collection;
+import java.util.UUID;
+
+import org.apache.log4j.Logger;
+import org.springframework.security.access.ConfigAttribute;
+
+import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.cdm.model.taxon.TaxonNode;
+import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
+
+/**
+ * @author andreas kohlbecker
+ * @date Sep 4, 2012
+ *
+ */
+public class TaxonNodeVoter extends CdmPermissionVoter {
+
+ public static final Logger logger = Logger.getLogger(TaxonNodeVoter.class);
+
+ @Override
+ public Class<? extends CdmBase> getResponsibilityClass() {
+ return TaxonNode.class;
+ }
+
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.persistence.hibernate.permission.voter.CdmPermissionVoter#furtherVotingDescisions(org.springframework.security.core.Authentication, java.lang.Object, java.util.Collection, eu.etaxonomy.cdm.persistence.hibernate.permission.voter.TaxonBaseVoter.ValidationResult)
+ */
+ @Override
+ protected Integer furtherVotingDescisions(CdmAuthority CdmAuthority, Object object, Collection<ConfigAttribute> attributes,
+ ValidationResult validationResult) {
+
+ boolean isUuidMatchInParentNodes = CdmAuthority.hasTargetUuid() && findTargetUuidInParentNodes(CdmAuthority.getTargetUUID(), (TaxonNode)object);
+ if ( isUuidMatchInParentNodes && validationResult.isClassMatch && validationResult.isPermissionMatch){
+ logger.debug("permission, class and uuid in parent nodes are matching => ACCESS_GRANTED");
+ return ACCESS_GRANTED;
+ }
+ return null;
+ }
+
+ /**
+ * @param targetUuid
+ * @param node
+ * @return
+ */
+ private boolean findTargetUuidInParentNodes(UUID targetUuid, TaxonNode node){
+ if (targetUuid.equals(node.getUuid()))
+ return true;
+ else if (node.getParent()!= null){
+ return findTargetUuidInParentNodes(targetUuid, node.getParent());
+ }
+ return false;
+ }
+
+}
<?xml version="1.0" encoding="UTF-8"?>\r
<beans xmlns="http://www.springframework.org/schema/beans"\r
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"\r
- xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"\r
- xsi:schemaLocation="http://www.springframework.org/schema/beans\r
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"\r
+ xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"\r
+ xsi:schemaLocation="http://www.springframework.org/schema/beans\r
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\r
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd\r
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd\r
">\r
\r
- <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">\r
- <property name="sessionFactory" ref="sessionFactory" />\r
- </bean>\r
-\r
- <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" depends-on="tableGeneratorGlobalOverride">\r
- <property name="namingStrategy">\r
- <bean class="org.hibernate.cfg.DefaultComponentSafeNamingStrategy" />\r
- </property>\r
-\r
- <property name="entityInterceptor">\r
- <bean class="eu.etaxonomy.cdm.persistence.hibernate.CdmSecurityHibernateInterceptor"/>\r
- </property>\r
- \r
- <property name="configLocation" value="classpath:eu/etaxonomy/cdm/hibernate.cfg.xml"/>\r
- <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"/>\r
- <!--\r
- If dataSource is set, this will override corresponding settings in Hibernate properties.\r
- If this is set, the Hibernate settings should not define a connection provider to\r
- avoid meaningless double configuration.\r
-\r
- see also org.springframework.orm.hibernate3.AbstractSessionFactoryBean.setDataSource(DataSource dataSource)\r
- -->\r
- <property name="dataSource" ref="dataSource"/>\r
- <property name="hibernateProperties" ref="hibernateProperties"/>\r
- </bean>\r
-\r
- <!--\r
- Configuration for the BeanInitialization\r
- -->\r
- <bean id="titleCacheAutoInitializer" class="eu.etaxonomy.cdm.persistence.dao.TitleCacheAutoInitializer"></bean>\r
+ <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">\r
+ <property name="sessionFactory" ref="sessionFactory" />\r
+ </bean>\r
+\r
+ <bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">\r
+ <property name="decisionVoters">\r
+ <list>\r
+ <bean class="eu.etaxonomy.cdm.persistence.hibernate.permission.voter.GrantAlwaysVoter" />\r
+ <bean class="eu.etaxonomy.cdm.persistence.hibernate.permission.voter.TaxonNodeVoter" />\r
+ <bean class="eu.etaxonomy.cdm.persistence.hibernate.permission.voter.TaxonBaseVoter" />\r
+ <bean class="eu.etaxonomy.cdm.persistence.hibernate.permission.voter.DescriptionBaseVoter" />\r
+ <bean class="eu.etaxonomy.cdm.persistence.hibernate.permission.voter.DescriptionElementVoter" />\r
+ </list>\r
+ </property>\r
+ </bean>\r
+\r
+ <!--\r
+ CdmPermissionEvaluator.hasPermissions() evaluates the CdmPermissions like TAXONNODE.UPDATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}\r
+ -->\r
+ <bean id="cdmPermissionEvaluator" class="eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator">\r
+ <property name="accessDecisionManager" ref="accessDecisionManager" />\r
+ </bean>\r
+\r
+ <!-- The CdmSecurityHibernateInterceptor checks onSave() and on flushDirty() if the currently authenticated principal or token has\r
+ sufficient permissions on the entity to be persisted -->\r
+ <bean id="securityHibernateInterceptor" class="eu.etaxonomy.cdm.persistence.hibernate.CdmSecurityHibernateInterceptor">\r
+ <property name="permissionEvaluator" ref="cdmPermissionEvaluator" />\r
+ </bean>\r
+\r
+ <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" depends-on="tableGeneratorGlobalOverride">\r
+ <property name="namingStrategy">\r
+ <bean class="org.hibernate.cfg.DefaultComponentSafeNamingStrategy" />\r
+ </property>\r
+\r
+ <property name="entityInterceptor" ref="securityHibernateInterceptor" />\r
+\r
+ <property name="configLocation" value="classpath:eu/etaxonomy/cdm/hibernate.cfg.xml"/>\r
+ <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"/>\r
+ <!--\r
+ If dataSource is set, this will override corresponding settings in Hibernate properties.\r
+ If this is set, the Hibernate settings should not define a connection provider to\r
+ avoid meaningless double configuration.\r
+\r
+ see also org.springframework.orm.hibernate3.AbstractSessionFactoryBean.setDataSource(DataSource dataSource)\r
+ -->\r
+ <property name="dataSource" ref="dataSource"/>\r
+ <property name="hibernateProperties" ref="hibernateProperties"/>\r
+ </bean>\r
+\r
+ <!--\r
+ Configuration for the BeanInitialization\r
+ -->\r
+ <bean id="titleCacheAutoInitializer" class="eu.etaxonomy.cdm.persistence.dao.TitleCacheAutoInitializer"></bean>\r
<bean id="annotationTypeAutoInitializer" class="eu.etaxonomy.cdm.persistence.dao.AnnotationTypeAutoInitializer"></bean>\r
- <bean id="defaultBeanInitializer" class="eu.etaxonomy.cdm.persistence.dao.hibernate.HibernateBeanInitializer">\r
- <property name="beanAutoInitializers">\r
- <map>\r
- <entry key="eu.etaxonomy.cdm.model.common.IdentifiableEntity" value-ref="titleCacheAutoInitializer" />\r
+ <bean id="defaultBeanInitializer" class="eu.etaxonomy.cdm.persistence.dao.hibernate.HibernateBeanInitializer">\r
+ <property name="beanAutoInitializers">\r
+ <map>\r
+ <entry key="eu.etaxonomy.cdm.model.common.IdentifiableEntity" value-ref="titleCacheAutoInitializer" />\r
<entry key="eu.etaxonomy.cdm.model.common.Annotation" value-ref="annotationTypeAutoInitializer" />\r
- </map>\r
- </property>\r
- </bean>\r
+ </map>\r
+ </property>\r
+ </bean>\r
\r
\r
</beans>\r
import org.springframework.security.authentication.AuthenticationManager;\r
import org.springframework.security.authentication.TestingAuthenticationToken;\r
import org.springframework.security.core.Authentication;\r
+import org.springframework.security.core.context.SecurityContext;\r
import org.springframework.security.core.context.SecurityContextHolder;\r
import org.springframework.security.core.context.SecurityContextImpl;\r
import org.unitils.database.annotations.Transactional;\r
*/\r
public class CdmEntityDaoBaseTest extends CdmTransactionalIntegrationTestWithSecurity {\r
\r
- private UUID uuid;\r
- private TaxonBase cdmBase;\r
+ private static final UUID UUID_USER_BEN = UUID.fromString("dbac0f20-07f2-11de-8c30-0800200c9a66");\r
+ private UUID uuid;\r
+ private TaxonBase cdmBase;\r
\r
- @SpringBeanByType\r
- private ITaxonDao cdmEntityDaoBase;\r
+ @SpringBeanByType\r
+ private ITaxonDao cdmEntityDaoBase;\r
\r
- @SpringBeanByType\r
+ @SpringBeanByType\r
private AuthenticationManager authenticationManager;\r
\r
- @SpringBeanByType\r
- private IUserDao userDao;\r
+ @SpringBeanByType\r
+ private IUserDao userDao;\r
\r
- /**\r
- * @throws java.lang.Exception\r
- */\r
- @Before\r
- public void setUp() throws Exception {\r
- uuid = UUID.fromString("8d77c380-c76a-11dd-ad8b-0800200c9a66");\r
- cdmBase = Taxon.NewInstance(null, null);\r
- cdmBase.setUuid(UUID.fromString("e463b270-c76b-11dd-ad8b-0800200c9a66"));\r
- \r
+ private TestingAuthenticationToken taxonEditorToken;\r
+ private TestingAuthenticationToken adminToken;\r
+ private TestingAuthenticationToken testerToken;\r
\r
- // Clear the context prior to each test\r
- SecurityContextHolder.clearContext();\r
- }\r
\r
- private void setAuthentication(User user) {\r
- TestingAuthenticationToken token = new TestingAuthenticationToken(user, "password", new GrantedAuthorityImpl[0]);\r
- Authentication authentication = authenticationManager.authenticate(token);\r
\r
- SecurityContextImpl secureContext = new SecurityContextImpl();\r
- secureContext.setAuthentication(authentication);\r
- SecurityContextHolder.setContext(secureContext);\r
- }\r
+ /**\r
+ * @throws java.lang.Exception\r
+ */\r
+ @Before\r
+ public void setUp() throws Exception {\r
+ uuid = UUID.fromString("8d77c380-c76a-11dd-ad8b-0800200c9a66");\r
+ cdmBase = Taxon.NewInstance(null, null);\r
+ cdmBase.setUuid(UUID.fromString("e463b270-c76b-11dd-ad8b-0800200c9a66"));\r
+\r
+ taxonEditorToken = new TestingAuthenticationToken("taxonEditor", "password", "TAXONBASE.CREATE", "TAXONBASE.UPDATE");\r
+ adminToken = new TestingAuthenticationToken("admin", "password", "ALL.ADMIN");\r
+ testerToken = new TestingAuthenticationToken("tester", "password");\r
+\r
+\r
+ // Clear the context prior to each test\r
+ SecurityContextHolder.clearContext();\r
+ }\r
+\r
+ private void setAuthentication(TestingAuthenticationToken token) {\r
+ Authentication authentication = authenticationManager.authenticate(token);\r
+\r
+ SecurityContextImpl secureContext = new SecurityContextImpl();\r
+ SecurityContextHolder.setContext(secureContext);\r
+ secureContext.setAuthentication(authentication);\r
+ }\r
\r
/************ TESTS ********************************/\r
\r
\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#CdmEntityDaoBase(java.lang.Class)}.\r
- * @throws Exception\r
- */\r
- @Test\r
- public void testCdmEntityDaoBase() throws Exception {\r
- assertNotNull("cdmEntityDaoBase should exist",cdmEntityDaoBase);\r
- }\r
-\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#saveOrUpdate(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- @ExpectedDataSet\r
- public void testSaveOrUpdate() {\r
- TaxonBase cdmBase = cdmEntityDaoBase.findByUuid(uuid);\r
- cdmBase.setDoubtful(true);\r
- cdmEntityDaoBase.saveOrUpdate(cdmBase);\r
- }\r
-\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#saveOrUpdate(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- @ExpectedDataSet\r
- public void testSaveOrUpdateWithAuthentication() {\r
- User user = userDao.findByUuid(UUID.fromString("dbac0f20-07f2-11de-8c30-0800200c9a66"));\r
- assert user != null : "User cannot be null";\r
- setAuthentication(user);\r
- TaxonBase cdmBase = cdmEntityDaoBase.findByUuid(uuid);\r
- cdmBase.setDoubtful(true);\r
- cdmEntityDaoBase.saveOrUpdate(cdmBase);\r
- }\r
-\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#saveOrUpdate(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#CdmEntityDaoBase(java.lang.Class)}.\r
+ * @throws Exception\r
+ */\r
+ @Test\r
+ public void testCdmEntityDaoBase() throws Exception {\r
+ assertNotNull("cdmEntityDaoBase should exist",cdmEntityDaoBase);\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#saveOrUpdate(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ @ExpectedDataSet\r
+ public void testSaveOrUpdate() {\r
+ TaxonBase cdmBase = cdmEntityDaoBase.findByUuid(uuid);\r
+ cdmBase.setDoubtful(true);\r
+ cdmEntityDaoBase.saveOrUpdate(cdmBase);\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#saveOrUpdate(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
@ExpectedDataSet\r
- public void testSaveOrUpdateNewObjectWithAuthentication() {\r
+ public void testSaveOrUpdateWithAuthentication() {\r
+\r
+ setAuthentication(taxonEditorToken);\r
+ TaxonBase cdmBase = cdmEntityDaoBase.findByUuid(uuid);\r
+ cdmBase.setDoubtful(true);\r
+ cdmEntityDaoBase.saveOrUpdate(cdmBase);\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#saveOrUpdate(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ @ExpectedDataSet\r
+ public void testSaveOrUpdateNewObjectWithAuthentication() {\r
// printDataSet(System.err, new String[]{"TAXONBASE", "HIBERNATE_SEQUENCES"});\r
- User user = userDao.findByUuid(UUID.fromString("dbac0f20-07f2-11de-8c30-0800200c9a66"));\r
- assert user != null : "User cannot be null";\r
- setAuthentication(user);\r
- cdmEntityDaoBase.saveOrUpdate(cdmBase);\r
- cdmBase.setDoubtful(true);\r
- cdmEntityDaoBase.saveOrUpdate(cdmBase);\r
- \r
- }\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#save(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- @ExpectedDataSet\r
- public void testSave() throws Exception {\r
- cdmEntityDaoBase.save(cdmBase);\r
- }\r
- \r
- \r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#save(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- public void testSaveWithAuthenticationFailedPermissionEvaluation() throws Exception {\r
- User user = userDao.findByUuid(UUID.fromString("04f43bec-ff0e-4263-b4f8-24d763e590eb"));\r
- assert user != null : "User cannot be null";\r
- setAuthentication(user);\r
- \r
- \r
- try{\r
- cdmEntityDaoBase.save(cdmBase);\r
- Assert.fail();\r
- }catch(EvaluationFailedException e){\r
- \r
- }\r
- }\r
-\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#save(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- @ExpectedDataSet\r
- public void testSaveWithAuthentication() throws Exception {\r
- User user = userDao.findByUuid(UUID.fromString("dbac0f20-07f2-11de-8c30-0800200c9a66"));\r
- assert user != null : "User cannot be null";\r
- setAuthentication(user);\r
- cdmEntityDaoBase.save(cdmBase);\r
- }\r
-\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#update(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- @ExpectedDataSet\r
- public void testUpdate() {\r
- TaxonBase cdmBase = cdmEntityDaoBase.findByUuid(uuid);\r
- cdmBase.setDoubtful(true);\r
- cdmEntityDaoBase.update(cdmBase);\r
- }\r
-\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- @ExpectedDataSet\r
- public void testUpdateWithAuthentication() {\r
- User user = userDao.findByUuid(UUID.fromString("dbac0f20-07f2-11de-8c30-0800200c9a66"));\r
- assert user != null : "User cannot be null";\r
-\r
- setAuthentication(user);\r
- TaxonBase cdmBase = cdmEntityDaoBase.findByUuid(uuid);\r
- cdmBase.setDoubtful(true);\r
- cdmEntityDaoBase.update(cdmBase);\r
- }\r
-\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#findById(int)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- public void testFindById() {\r
- CdmBase cdmBase = cdmEntityDaoBase.findById(1);\r
- assertNotNull("There should be an entity with an id of 1",cdmBase);\r
- }\r
-\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#findByUuid(java.util.UUID)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- public void testFindByUuid() {\r
- CdmBase cdmBase = cdmEntityDaoBase.findByUuid(uuid);\r
- assertNotNull("testFindByUuid() an entity with a uuid of " + uuid.toString(),cdmBase);\r
- }\r
-\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#exists(java.util.UUID)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- public void testExists() {\r
- boolean exists = cdmEntityDaoBase.exists(uuid);\r
- assertTrue("exists() should return true for uuid " + uuid.toString(), exists);\r
- boolean existsRandom = cdmEntityDaoBase.exists(UUID.randomUUID());\r
- assertFalse("exists() should return false for any other uuid", existsRandom);\r
- }\r
-\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#list(int, int)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- public void testList() {\r
- List<TaxonBase> list = cdmEntityDaoBase.list(1000, 0);\r
- assertNotNull("list() should not return null",list);\r
- assertEquals("list() should return a list with two entities in it",list.size(),2);\r
- }\r
-\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#list(int, int)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- public void testRandomOrder() {\r
- List<OrderHint> orderHints = new ArrayList<OrderHint>();\r
- orderHints.add(new RandomOrder());\r
- List<TaxonBase> list = cdmEntityDaoBase.list(null,1000, 0,orderHints,null);\r
- assertNotNull("list() should not return null",list);\r
- assertEquals("list() should return a list with two entities in it",list.size(),2);\r
- }\r
-\r
- /**\r
- * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#delete(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
- */\r
- @Test\r
- @DataSet("CdmEntityDaoBaseTest.xml")\r
- @ExpectedDataSet\r
- public void testDelete() {\r
- TaxonBase cdmBase = cdmEntityDaoBase.findByUuid(uuid);\r
- assertNotNull(cdmBase);\r
- cdmEntityDaoBase.delete(cdmBase);\r
- }\r
+ setAuthentication(taxonEditorToken);\r
+ RuntimeException securityException = null;\r
+\r
+ // 1) test create\r
+ try{\r
+ cdmEntityDaoBase.saveOrUpdate(cdmBase);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.error("Unexpected failure of evaluation.", e);\r
+ Assert.fail();\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+\r
+ // 1) test update\r
+ cdmBase = cdmEntityDaoBase.findByUuid(cdmBase.getUuid());\r
+ cdmBase.setDoubtful(true);\r
+ try{\r
+ cdmEntityDaoBase.saveOrUpdate(cdmBase);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.error("Unexpected failure of evaluation.", e);\r
+ Assert.fail();\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+\r
+ }\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#save(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ @ExpectedDataSet\r
+ public void testSave() throws Exception {\r
+ cdmEntityDaoBase.save(cdmBase);\r
+ }\r
+\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#save(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ public void testSaveWithAuthenticationFailedPermissionEvaluation() throws Exception {\r
+ setAuthentication(testerToken);\r
+ RuntimeException securityException = null;\r
+ try{\r
+ cdmEntityDaoBase.save(cdmBase);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.error("Unexpected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNotNull("evaluation must fail since the user has no permission", securityException);\r
+\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#save(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ @ExpectedDataSet\r
+ public void testSaveWithAuthentication() throws Exception {\r
+ setAuthentication(taxonEditorToken);\r
+ RuntimeException securityException = null;\r
+ try {\r
+ cdmEntityDaoBase.save(cdmBase);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.error("Unexpected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#update(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ @ExpectedDataSet\r
+ public void testUpdate() {\r
+ TaxonBase cdmBase = cdmEntityDaoBase.findByUuid(uuid);\r
+ cdmBase.setDoubtful(true);\r
+ cdmEntityDaoBase.update(cdmBase);\r
+ }\r
+\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ @ExpectedDataSet\r
+ public void testUpdateWithAuthentication() {\r
+\r
+ setAuthentication(taxonEditorToken);\r
+ TaxonBase cdmBase = cdmEntityDaoBase.findByUuid(uuid);\r
+ cdmBase.setDoubtful(true);\r
+ RuntimeException securityException = null;\r
+ try {\r
+ cdmEntityDaoBase.update(cdmBase);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.error("Unexpected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);\r
+\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#findById(int)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ public void testFindById() {\r
+ CdmBase cdmBase = cdmEntityDaoBase.findById(1);\r
+ assertNotNull("There should be an entity with an id of 1",cdmBase);\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#findByUuid(java.util.UUID)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ public void testFindByUuid() {\r
+ CdmBase cdmBase = cdmEntityDaoBase.findByUuid(uuid);\r
+ assertNotNull("testFindByUuid() an entity with a uuid of " + uuid.toString(),cdmBase);\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#exists(java.util.UUID)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ public void testExists() {\r
+ boolean exists = cdmEntityDaoBase.exists(uuid);\r
+ assertTrue("exists() should return true for uuid " + uuid.toString(), exists);\r
+ boolean existsRandom = cdmEntityDaoBase.exists(UUID.randomUUID());\r
+ assertFalse("exists() should return false for any other uuid", existsRandom);\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#list(int, int)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ public void testList() {\r
+ List<TaxonBase> list = cdmEntityDaoBase.list(1000, 0);\r
+ assertNotNull("list() should not return null",list);\r
+ assertEquals("list() should return a list with two entities in it",list.size(),2);\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#list(int, int)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ public void testRandomOrder() {\r
+ List<OrderHint> orderHints = new ArrayList<OrderHint>();\r
+ orderHints.add(new RandomOrder());\r
+ List<TaxonBase> list = cdmEntityDaoBase.list(null,1000, 0,orderHints,null);\r
+ assertNotNull("list() should not return null",list);\r
+ assertEquals("list() should return a list with two entities in it",list.size(),2);\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase#delete(eu.etaxonomy.cdm.model.common.CdmBase)}.\r
+ */\r
+ @Test\r
+ @DataSet("CdmEntityDaoBaseTest.xml")\r
+ @ExpectedDataSet\r
+ public void testDelete() {\r
+ TaxonBase cdmBase = cdmEntityDaoBase.findByUuid(uuid);\r
+ assertNotNull(cdmBase);\r
+ cdmEntityDaoBase.delete(cdmBase);\r
+ }\r
}\r
public void printDataSet(OutputStream out, String[] tableNames) {\r
IDatabaseConnection connection = null;\r
\r
+ if(tableNames == null){\r
+ return;\r
+ }\r
+\r
try {\r
connection = getConnection();\r
IDataSet actualDataSet = connection.createDataSet(tableNames);\r
FlatXmlDataSet.write(actualDataSet, out);\r
\r
-\r
} catch (Exception e) {\r
logger.error(e);\r
} finally {\r
\r
@Transactional(TransactionMode.DISABLED) // NOTE: we are handling transaction by ourself in this class, thus we prevent unitils from creating transactions\r
public abstract class CdmTransactionalIntegrationTest extends CdmIntegrationTest {\r
+\r
protected static final Logger logger = Logger.getLogger(CdmTransactionalIntegrationTest.class);\r
\r
/**\r
\r
if (this.transactionStatus != null) {\r
try {\r
+ logger.debug("Trying to commit or rollback");\r
if (commit) {\r
this.transactionManager.commit(this.transactionStatus);\r
logger.debug("Committed transaction after execution of test");\r
}\r
}\r
finally {\r
+ logger.debug("Clearing transactionStatus");\r
this.transactionStatus = null;\r
}\r
}\r
\r
if (this.transactionStatus != null) {\r
try {\r
+ logger.debug("trying to rollback");\r
this.transactionManager.rollback(this.transactionStatus);\r
logger.debug("Rolled back transaction after execution of test.");\r
}\r
finally {\r
+ logger.debug("Clearing transactionStatus");\r
this.transactionStatus = null;\r
}\r
}\r
* </pre>\r
*/\r
protected void commitAndStartNewTransaction(final String[] tableNames) {\r
- setComplete();\r
- endTransaction();\r
+ commit();\r
if(logger.isDebugEnabled()){\r
printDataSet(System.out, tableNames);\r
}\r
startNewTransaction();\r
}\r
\r
+ /**\r
+ *\r
+ */\r
+ protected void commit() {\r
+ setComplete();\r
+ endTransaction();\r
+ }\r
+\r
}\r
package eu.etaxonomy.cdm.test.integration;\r
\r
+import org.apache.log4j.Logger;\r
import org.junit.After;\r
import org.junit.Before;\r
+import org.springframework.security.access.AccessDeniedException;\r
import org.springframework.security.core.context.SecurityContextHolder;\r
import org.unitils.spring.annotation.SpringApplicationContext;\r
\r
@SpringApplicationContext("file:./target/test-classes/eu/etaxonomy/cdm/applicationContext-securityTest.xml")\r
public abstract class CdmTransactionalIntegrationTestWithSecurity extends CdmTransactionalIntegrationTest {\r
\r
- /**\r
- * Finds a nested {@link EvaluationFailedException} or returns <code>null</code> \r
- * @param exception\r
- * @return\r
- */\r
- public static EvaluationFailedException findEvaluationFailedExceptionIn(Throwable exception) {\r
- if( EvaluationFailedException.class.isInstance(exception) ){\r
- return (EvaluationFailedException)exception;\r
- } else if(exception != null ){\r
- return findEvaluationFailedExceptionIn(exception.getCause());\r
- }\r
- return null;\r
- }\r
+ public static final Logger logger = Logger.getLogger(CdmTransactionalIntegrationTestWithSecurity.class);\r
\r
+ /**\r
+ * Finds a nested RuntimeExceptions of the types {@link EvaluationFailedException}, {@link AccessDeniedException}\r
+ * or returns null.\r
+ * @param exception\r
+ * @return\r
+ */\r
+ public static RuntimeException findSecurityRuntimeException(Throwable exception) {\r
\r
+ if( EvaluationFailedException.class.isInstance(exception) || AccessDeniedException.class.isInstance(exception) ){\r
+ return (RuntimeException) exception;\r
+ } else if(exception != null ){\r
+ return findSecurityRuntimeException(exception.getCause());\r
+ }\r
+ return null;\r
+\r
+ }\r
+\r
+\r
+ /**\r
+ * find in the nested <code>exception</code> the exception of type <code>clazz</code>\r
+ * or returns <code>null</code> if no such exception is found.\r
+ *\r
+ * @param clazz\r
+ * @param exception the nested <code>Throwable</code> to search in.\r
+ * @return\r
+ */\r
+ public <T extends Throwable> T findThrowableOfTypeIn(Class<T> clazz, Throwable exception) {\r
+ if( EvaluationFailedException.class.isInstance(exception) ){\r
+ return (T)exception;\r
+ } else if(exception != null ){\r
+ return findThrowableOfTypeIn(clazz, exception.getCause());\r
+ }\r
+ return null;\r
+ }\r
\r
}\r
<?xml version='1.0' encoding='UTF-8'?>\r
<dataset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../dataset.xsd">\r
- <TAXONBASE DTYPE="Taxon" ID="1" SEC_ID="1" UUID="8d77c380-c76a-11dd-ad8b-0800200c9a66" TITLECACHE=" sec. ???" PROTECTEDTITLECACHE="true" DOUBTFUL="true" TAXONOMICCHILDRENCOUNT="1" NAME_ID="1" UPDATEDBY_ID="5"/>\r
+ <TAXONBASE DTYPE="Taxon" ID="1" SEC_ID="1" UUID="8d77c380-c76a-11dd-ad8b-0800200c9a66" TITLECACHE=" sec. ???" PROTECTEDTITLECACHE="true" DOUBTFUL="true" TAXONOMICCHILDRENCOUNT="1" NAME_ID="1" UPDATEDBY_ID="1"/>\r
<TAXONBASE DTYPE="Taxon" ID="2" SEC_ID="1" UUID="822d98dc-9ef7-44b7-a870-94573a3bcb46" TITLECACHE=" sec. ???" PROTECTEDTITLECACHE="true" DOUBTFUL="false" TAXONOMICCHILDRENCOUNT="0" NAME_ID="2" UPDATEDBY_ID="1" />\r
</dataset>
\ No newline at end of file
<TAXONRELATIONSHIP ID="1" CREATED="2008-12-10 09:56:07.0" UUID="25064dff-f526-408e-b851-670d7770e337" UPDATED="2008-12-10 09:56:07.253" CITATIONMICROREFERENCE="Lorem ipsum dolor" TYPE_ID="889" RELATEDTO_ID="1" RELATEDFROM_ID="2" DOUBTFUL="false"/>
<TAXONRELATIONSHIP_AUD ID="1" REV="1000" REVTYPE="0" CREATED="2008-12-10 09:56:07.0" UUID="25064dff-f526-408e-b851-670d7770e337" UPDATED="2008-12-10 09:56:07.253" CITATIONMICROREFERENCE="Lorem ipsum dolor" TYPE_ID="889" RELATEDTO_ID="1" RELATEDFROM_ID="2" DOUBTFUL="false"/>\r
\r
- <USERACCOUNT ID="5" UUID="dbac0f20-07f2-11de-8c30-0800200c9a66" USERNAME="ben" ACCOUNTNONEXPIRED="true" ACCOUNTNONLOCKED="true" CREATED="2008-12-10 09:56:07.0" CREATEDBY_ID="1" CREDENTIALSNONEXPIRED="true" EMAILADDRESS="b.clark@example.org" ENABLED="true" PASSWORD="xyz"/>\r
- <USERACCOUNT_AUD ID="5" REV="1000" REVTYPE="0" UUID="dbac0f20-07f2-11de-8c30-0800200c9a66" USERNAME="ben" ACCOUNTNONEXPIRED="true" ACCOUNTNONLOCKED="true" CREATED="2008-12-10 09:56:07.0" CREATEDBY_ID="1" CREDENTIALSNONEXPIRED="true" EMAILADDRESS="b.clark@example.org" ENABLED="true"/>\r
<USERACCOUNT ID="1" UUID="c026b289-1a36-4afc-8673-92ffe8ed05b6" USERNAME="admin" ACCOUNTNONEXPIRED="true" ACCOUNTNONLOCKED="true" CREATED="2008-12-10 09:56:07.0" CREATEDBY_ID="1" CREDENTIALSNONEXPIRED="true" EMAILADDRESS="admin@example.org" ENABLED="true" PASSWORD="xyz"/>\r
<USERACCOUNT_AUD ID="1" REV="1000" REVTYPE="0" UUID="c026b289-1a36-4afc-8673-92ffe8ed05b6" USERNAME="admin" ACCOUNTNONEXPIRED="true" ACCOUNTNONLOCKED="true" CREATED="2008-12-10 09:56:07.0" CREATEDBY_ID="1" CREDENTIALSNONEXPIRED="true" EMAILADDRESS="admin@example.org" ENABLED="true"/>\r
+ <USERACCOUNT ID="5" UUID="dbac0f20-07f2-11de-8c30-0800200c9a66" USERNAME="taxoneditor" ACCOUNTNONEXPIRED="true" ACCOUNTNONLOCKED="true" CREATED="2008-12-10 09:56:07.0" CREATEDBY_ID="1" CREDENTIALSNONEXPIRED="true" EMAILADDRESS="b.clark@example.org" ENABLED="true" PASSWORD="xyz"/>\r
+ <USERACCOUNT_AUD ID="5" REV="1000" REVTYPE="0" UUID="dbac0f20-07f2-11de-8c30-0800200c9a66" USERNAME="taxoneditor" ACCOUNTNONEXPIRED="true" ACCOUNTNONLOCKED="true" CREATED="2008-12-10 09:56:07.0" CREATEDBY_ID="1" CREDENTIALSNONEXPIRED="true" EMAILADDRESS="taxoneditor@example.org" ENABLED="true"/>\r
<USERACCOUNT ID="6" UUID="04f43bec-ff0e-4263-b4f8-24d763e590eb" USERNAME="tester" ACCOUNTNONEXPIRED="true" ACCOUNTNONLOCKED="true" CREATED="2008-12-10 09:56:07.0" CREATEDBY_ID="1" CREDENTIALSNONEXPIRED="true" EMAILADDRESS="admin@example.org" ENABLED="true" PASSWORD="xyz"/>\r
<USERACCOUNT_AUD ID="6" REV="1000" REVTYPE="0" UUID="04f43bec-ff0e-4263-b4f8-24d763e590eb" USERNAME="tester" ACCOUNTNONEXPIRED="true" ACCOUNTNONLOCKED="true" CREATED="2008-12-10 09:56:07.0" CREATEDBY_ID="1" CREDENTIALSNONEXPIRED="true" EMAILADDRESS="admin@example.org" ENABLED="true"/>\r
<GRANTEDAUTHORITYIMPL ID="1" UUID="9a37ef49-0c22-44f8-982f-24a8423269cd" CREATED="2009-02-03 17:52:26.0" AUTHORITY="ALL.ADMIN"/>\r
<GRANTEDAUTHORITYIMPL ID="2" UUID="a3b3ebd0-2f88-4050-aaa9-2000cf7bc41d" CREATED="2009-02-03 17:52:26.0" AUTHORITY="TAXONBASE.UPDATE"/>\r
<GRANTEDAUTHORITYIMPL ID="3" UUID="5fe558c2-a77c-4dfc-8a17-dfb220af597c" CREATED="2009-02-03 17:52:26.0" AUTHORITY="TAXONBASE.CREATE"/>\r
+ <USERACCOUNT_GRANTEDAUTHORITYIMPL USERACCOUNT_ID="1" GRANTEDAUTHORITIES_ID="1"/>\r
<USERACCOUNT_GRANTEDAUTHORITYIMPL USERACCOUNT_ID="5" GRANTEDAUTHORITIES_ID="2"/>\r
<USERACCOUNT_GRANTEDAUTHORITYIMPL USERACCOUNT_ID="5" GRANTEDAUTHORITIES_ID="3"/>\r
- <USERACCOUNT_GRANTEDAUTHORITYIMPL USERACCOUNT_ID="1" GRANTEDAUTHORITIES_ID="1"/>\r
</dataset>
\ No newline at end of file
#log4j.logger.org.springframework.FileSystemXmlApplicationContext = warn
#log4j.logger.org.springframework.core.io.support = info
+#### log spring security #####
+log4j.logger.eu.etaxonomy.cdm.persistence.hibernate.permission=debug
+log4j.logger.eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority=warn
+log4j.logger.eu.etaxonomy.cdm.persistence.hibernate.CdmSecurityHibernateInterceptor=debug
+log4j.logger.org.springframework.security.access.intercept=debug
+log4j.logger.org.springframework.security.access.vote=debug
+#log4j.logger.eu.etaxonomy.cdm.test.integration.CdmTransactionalIntegrationTest=debug
+
### ***HIBERNATE ************ ###
// $Id$\r
/**\r
* Copyright (C) 2007 EDIT\r
-* European Distributed Institute of Taxonomy \r
+* European Distributed Institute of Taxonomy\r
* http://www.e-taxonomy.eu\r
-* \r
+*\r
* The contents of this file are subject to the Mozilla Public License Version 1.1\r
* See LICENSE.TXT at the top of this package for the full license terms.\r
*/\r
\r
\r
import java.util.Collection;\r
+import java.util.EnumSet;\r
import java.util.List;\r
import java.util.Map;\r
import java.util.Set;\r
import eu.etaxonomy.cdm.api.service.pager.Pager;\r
import eu.etaxonomy.cdm.model.common.ICdmBase;\r
import eu.etaxonomy.cdm.persistence.dao.BeanInitializer;\r
-import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermission;\r
+import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;\r
+import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;\r
import eu.etaxonomy.cdm.persistence.query.Grouping;\r
import eu.etaxonomy.cdm.persistence.query.OrderHint;\r
\r
*/\r
public interface IService<T extends ICdmBase>{\r
\r
- // FIXME what does this method do?\r
- public void clear();\r
- \r
- /**\r
- * Obtain the specified lock mode on the given object t\r
- */\r
- public void lock(T t, LockMode lockMode);\r
- \r
- /**\r
- * Refreshes a given object t using the specified lockmode\r
- * \r
+ // FIXME what does this method do?\r
+ public void clear();\r
+\r
+ /**\r
+ * Obtain the specified lock mode on the given object t\r
+ */\r
+ public void lock(T t, LockMode lockMode);\r
+\r
+ /**\r
+ * Refreshes a given object t using the specified lockmode\r
+ *\r
* All bean properties given in the <code>propertyPaths</code> parameter are recursively initialized.\r
- * <p>\r
- * For detailed description and examples <b>please refer to:</b> \r
- * {@link BeanInitializer#initialize(Object, List)}\r
- * \r
- * NOTE: in the case of lockmodes that hit the database (e.g. LockMode.READ), you will need to re-initialize\r
- * child propertiesto avoid a HibernateLazyInitializationException (even if the properties of the child \r
- * were initialized prior to the refresh).\r
- * \r
- * @param t\r
- * @param lockMode\r
- */\r
- public void refresh(T t, LockMode lockMode, List<String> propertyPaths);\r
- \r
- /**\r
- * Returns a count of all entities of type <T> optionally restricted\r
- * to objects belonging to a class that that extends <T>\r
- * \r
- * @param clazz the class of entities to be counted (can be null to count all entities of type <T>)\r
- * @return a count of entities\r
- */\r
- public int count(Class<? extends T> clazz);\r
- \r
- /**\r
- * Delete an existing persistent object\r
- * \r
- * @param persistentObject the object to be deleted\r
- * @return the unique identifier of the deleted entity\r
- */\r
- public UUID delete(T persistentObject);\r
- \r
- /**\r
- * Returns true if an entity of type <T> with a unique identifier matching the \r
- * identifier supplied exists in the database, or false if no such entity can be \r
- * found. \r
- * @param uuid the unique identifier of the entity required\r
- * @return an entity of type <T> matching the uuid, or null if that entity does not exist\r
- */\r
- public boolean exists(UUID uuid);\r
- \r
- /**\r
- * Return a list of persisted entities that match the unique identifier\r
- * set supplied as an argument\r
- * \r
- * @param uuidSet the set of unique identifiers of the entities required\r
- * @return a list of entities of type <T>\r
- */\r
- public List<T> find(Set<UUID> uuidSet);\r
- \r
- /**\r
- * Return a persisted entity that matches the unique identifier\r
- * supplied as an argument, or null if the entity does not exist\r
- * \r
- * @param uuid the unique identifier of the entity required\r
- * @return an entity of type <T>, or null if the entity does not exist\r
- */\r
- public T find(UUID uuid);\r
- \r
- /**\r
- * Return a persisted entity that matches the database identifier\r
- * supplied as an argument, or null if the entity does not exist\r
- * \r
- * @param id the database identifier of the entity required\r
- * @return an entity of type <T>, or null if the entity does not exist\r
- */\r
- public T find(int id);\r
- \r
- /**\r
- * Returns a set of persisted entities that match the database identifiers.\r
- * Returns an empty list if no identifier matches.\r
- * @param idSet\r
- * @return\r
- */\r
- public List<T> findById(Set<Integer> idSet); //can't be called find(Set<Integer>) as this conflicts with find(Set<UUID)\r
-\r
- \r
- // FIXME should we expose this method?\r
- public Session getSession();\r
- \r
- /**\r
+ * <p>\r
+ * For detailed description and examples <b>please refer to:</b>\r
+ * {@link BeanInitializer#initialize(Object, List)}\r
+ *\r
+ * NOTE: in the case of lockmodes that hit the database (e.g. LockMode.READ), you will need to re-initialize\r
+ * child propertiesto avoid a HibernateLazyInitializationException (even if the properties of the child\r
+ * were initialized prior to the refresh).\r
+ *\r
+ * @param t\r
+ * @param lockMode\r
+ */\r
+ public void refresh(T t, LockMode lockMode, List<String> propertyPaths);\r
+\r
+ /**\r
+ * Returns a count of all entities of type <T> optionally restricted\r
+ * to objects belonging to a class that that extends <T>\r
+ *\r
+ * @param clazz the class of entities to be counted (can be null to count all entities of type <T>)\r
+ * @return a count of entities\r
+ */\r
+ public int count(Class<? extends T> clazz);\r
+\r
+ /**\r
+ * Delete an existing persistent object\r
+ *\r
+ * @param persistentObject the object to be deleted\r
+ * @return the unique identifier of the deleted entity\r
+ */\r
+ public UUID delete(T persistentObject);\r
+\r
+ /**\r
+ * Returns true if an entity of type <T> with a unique identifier matching the\r
+ * identifier supplied exists in the database, or false if no such entity can be\r
+ * found.\r
+ * @param uuid the unique identifier of the entity required\r
+ * @return an entity of type <T> matching the uuid, or null if that entity does not exist\r
+ */\r
+ public boolean exists(UUID uuid);\r
+\r
+ /**\r
+ * Return a list of persisted entities that match the unique identifier\r
+ * set supplied as an argument\r
+ *\r
+ * @param uuidSet the set of unique identifiers of the entities required\r
+ * @return a list of entities of type <T>\r
+ */\r
+ public List<T> find(Set<UUID> uuidSet);\r
+\r
+ /**\r
+ * Return a persisted entity that matches the unique identifier\r
+ * supplied as an argument, or null if the entity does not exist\r
+ *\r
+ * @param uuid the unique identifier of the entity required\r
+ * @return an entity of type <T>, or null if the entity does not exist\r
+ */\r
+ public T find(UUID uuid);\r
+\r
+ /**\r
+ * Return a persisted entity that matches the database identifier\r
+ * supplied as an argument, or null if the entity does not exist\r
+ *\r
+ * @param id the database identifier of the entity required\r
+ * @return an entity of type <T>, or null if the entity does not exist\r
+ */\r
+ public T find(int id);\r
+\r
+ /**\r
+ * Returns a set of persisted entities that match the database identifiers.\r
+ * Returns an empty list if no identifier matches.\r
+ * @param idSet\r
+ * @return\r
+ */\r
+ public List<T> findById(Set<Integer> idSet); //can't be called find(Set<Integer>) as this conflicts with find(Set<UUID)\r
+\r
+\r
+ // FIXME should we expose this method?\r
+ public Session getSession();\r
+\r
+ /**\r
* Returns a sublist of objects matching the grouping projections supplied using the groups parameter\r
- * \r
+ *\r
* It would be nice to be able to return a pager, but for the moment hibernate doesn't\r
* seem to support this (HHH-3238 - impossible to get the rowcount for a criteria that has projections)\r
- * \r
+ *\r
* @param clazz Restrict the query to objects of a certain class, or null for all objects of type T or subclasses\r
* @param limit the maximum number of entities returned (can be null to return\r
- * all entities)\r
+ * all entities)\r
* @param start The (0-based) offset from the start of the recordset (can be null, equivalent of starting at the beginning of the recordset)\r
* @param groups The grouping objects representing a projection, plus an optional ordering on that projected property\r
* @param propertyPaths paths initialized on the returned objects - only applied to the objects returned from the first grouping\r
* @return a list of arrays of objects, each matching the grouping objects supplied in the parameters.\r
*/\r
- public List<Object[]> group(Class<? extends T> clazz,Integer limit, Integer start, List<Grouping> groups, List<String> propertyPaths);\r
- \r
- /**\r
- * Returns a list of entities of type <T> optionally restricted\r
- * to objects belonging to a class that that extends <T>\r
- * \r
- * @param type The type of entities to return (can be null to count all entities of type <T>)\r
- * @param limit The maximum number of objects returned (can be null for all matching objects)\r
- * @param start The offset from the start of the result set (0 - based, can be null - equivalent of starting at the beginning of the recordset)\r
- * @param orderHints\r
- * Supports path like <code>orderHints.propertyNames</code> which\r
- * include *-to-one properties like createdBy.username or\r
- * authorTeam.persistentTitleCache\r
- * @param propertyPaths properties to be initialized\r
- * @return\r
- */\r
- public List<T> list(Class<? extends T> type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths);\r
- \r
- /**\r
- * Finds the cdm entity specified by the <code>uuid</code> parameter and\r
- * initializes all its *ToOne relations.\r
- * \r
- * @param uuid\r
- * @return\r
- */\r
- public T load(UUID uuid);\r
- \r
- /**\r
- * Finds the cdm entity specified by the <code>uuid</code> parameter and\r
- * recursively initializes all bean properties given in the\r
- * <code>propertyPaths</code> parameter.\r
- * <p>\r
- * For detailed description and examples <b>please refer to:</b> \r
- * {@link BeanInitializer#initialize(Object, List)}\r
- * \r
- * @param uuid\r
- * @return\r
- */\r
- public T load(UUID uuid, List<String> propertyPaths);\r
- \r
- /**\r
- * Copy the state of the given object onto the persistent object with the same identifier.\r
- * \r
- * @param transientObject the entity to be merged\r
- * @return The unique identifier of the persisted entity\r
- */\r
- public T merge(T transientObject);\r
- \r
- /**\r
- * Returns a paged list of entities of type <T> optionally restricted\r
- * to objects belonging to a class that that extends <T>\r
- * \r
- * @param type The type of entities to return (can be null to count all entities of type <T>)\r
- * @param pageSize The maximum number of objects returned (can be null for all matching objects)\r
- * @param pageNumber The offset (in pageSize chunks) from the start of the result set (0 - based, \r
- * can be null, equivalent of starting at the beginning of the recordset)\r
- * @param orderHints\r
- * Supports path like <code>orderHints.propertyNames</code> which\r
- * include *-to-one properties like createdBy.username or\r
- * authorTeam.persistentTitleCache\r
- * @param propertyPaths properties to be initialized\r
- * @return a pager of objects of type <T>\r
- */\r
- public Pager<T> page(Class<? extends T> type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths);\r
- \r
- /**\r
- * Re-read the state of the given instance from the underlying database.\r
- * \r
- * Hibernate claims that it is inadvisable to use refresh in long-running-sessions. \r
- * I don't really see where we would get into a situation where problems as discussed\r
- * this forum thread would apply for our scenario \r
- * \r
- * http://forum.hibernate.org/viewtopic.php?t=974544 \r
- * \r
- * @param persistentObject the object to be refreshed\r
- * @return the unique identifier\r
- */\r
- public UUID refresh(T persistentObject);\r
- \r
- public List<T> rows(String tableName, int limit, int start);\r
-\r
- /**\r
- * Save a collection containing new entities (persists the entities)\r
- * @param newInstances the new entities to be persisted\r
- * @return A Map containing the new entities, keyed using the generated UUID's\r
- * of those entities\r
- */\r
- public Map<UUID,T> save(Collection<T> newInstances); \r
- \r
- /**\r
- * Save a new entity (persists the entity)\r
- * @param newInstance the new entity to be persisted\r
- * @return A generated UUID for the new persistent entity\r
- */\r
- public UUID save(T newInstance);\r
- \r
- /**\r
- * Save a new entity or update the persistent state of an existing \r
- * transient entity that has been persisted previously\r
- * \r
- * @param transientObject the entity to be persisted\r
- * @return The unique identifier of the persisted entity\r
- */\r
- public UUID saveOrUpdate(T transientObject);\r
- \r
- /**\r
- * Save new entities or update the persistent state of existing \r
- * transient entities that have been persisted previously\r
- * \r
- * @param transientObjects the entities to be persisted\r
- * @return The unique identifier of the persisted entity\r
- */\r
- public Map<UUID,T> saveOrUpdate(Collection<T> transientObjects);\r
- \r
+ public List<Object[]> group(Class<? extends T> clazz,Integer limit, Integer start, List<Grouping> groups, List<String> propertyPaths);\r
+\r
+ /**\r
+ * Returns a list of entities of type <T> optionally restricted\r
+ * to objects belonging to a class that that extends <T>\r
+ *\r
+ * @param type The type of entities to return (can be null to count all entities of type <T>)\r
+ * @param limit The maximum number of objects returned (can be null for all matching objects)\r
+ * @param start The offset from the start of the result set (0 - based, can be null - equivalent of starting at the beginning of the recordset)\r
+ * @param orderHints\r
+ * Supports path like <code>orderHints.propertyNames</code> which\r
+ * include *-to-one properties like createdBy.username or\r
+ * authorTeam.persistentTitleCache\r
+ * @param propertyPaths properties to be initialized\r
+ * @return\r
+ */\r
+ public List<T> list(Class<? extends T> type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths);\r
+\r
+ /**\r
+ * Finds the cdm entity specified by the <code>uuid</code> parameter and\r
+ * initializes all its *ToOne relations.\r
+ *\r
+ * @param uuid\r
+ * @return\r
+ */\r
+ public T load(UUID uuid);\r
+\r
+ /**\r
+ * Finds the cdm entity specified by the <code>uuid</code> parameter and\r
+ * recursively initializes all bean properties given in the\r
+ * <code>propertyPaths</code> parameter.\r
+ * <p>\r
+ * For detailed description and examples <b>please refer to:</b>\r
+ * {@link BeanInitializer#initialize(Object, List)}\r
+ *\r
+ * @param uuid\r
+ * @return\r
+ */\r
+ public T load(UUID uuid, List<String> propertyPaths);\r
+\r
+ /**\r
+ * Copy the state of the given object onto the persistent object with the same identifier.\r
+ *\r
+ * @param transientObject the entity to be merged\r
+ * @return The unique identifier of the persisted entity\r
+ */\r
+ public T merge(T transientObject);\r
+\r
+ /**\r
+ * Returns a paged list of entities of type <T> optionally restricted\r
+ * to objects belonging to a class that that extends <T>\r
+ *\r
+ * @param type The type of entities to return (can be null to count all entities of type <T>)\r
+ * @param pageSize The maximum number of objects returned (can be null for all matching objects)\r
+ * @param pageNumber The offset (in pageSize chunks) from the start of the result set (0 - based,\r
+ * can be null, equivalent of starting at the beginning of the recordset)\r
+ * @param orderHints\r
+ * Supports path like <code>orderHints.propertyNames</code> which\r
+ * include *-to-one properties like createdBy.username or\r
+ * authorTeam.persistentTitleCache\r
+ * @param propertyPaths properties to be initialized\r
+ * @return a pager of objects of type <T>\r
+ */\r
+ public Pager<T> page(Class<? extends T> type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths);\r
+\r
+ /**\r
+ * Re-read the state of the given instance from the underlying database.\r
+ *\r
+ * Hibernate claims that it is inadvisable to use refresh in long-running-sessions.\r
+ * I don't really see where we would get into a situation where problems as discussed\r
+ * this forum thread would apply for our scenario\r
+ *\r
+ * http://forum.hibernate.org/viewtopic.php?t=974544\r
+ *\r
+ * @param persistentObject the object to be refreshed\r
+ * @return the unique identifier\r
+ */\r
+ public UUID refresh(T persistentObject);\r
+\r
+ public List<T> rows(String tableName, int limit, int start);\r
+\r
+ /**\r
+ * Save a collection containing new entities (persists the entities)\r
+ * @param newInstances the new entities to be persisted\r
+ * @return A Map containing the new entities, keyed using the generated UUID's\r
+ * of those entities\r
+ */\r
+ public Map<UUID,T> save(Collection<T> newInstances);\r
+\r
+ /**\r
+ * Save a new entity (persists the entity)\r
+ * @param newInstance the new entity to be persisted\r
+ * @return A generated UUID for the new persistent entity\r
+ */\r
+ public UUID save(T newInstance);\r
+\r
/**\r
- * Update the persistent state of an existing transient entity \r
- * that has been persisted previously\r
- * \r
- * @param transientObject the entity to be persisted\r
- * @return The unique identifier of the persisted entity\r
- */\r
- public UUID update(T transientObject);\r
- \r
- /**\r
- * Method that lists the objects matching the example provided. \r
- * The includeProperties property is used to specify which properties of the example are used.\r
- * \r
- * If includeProperties is null or empty, then all literal properties are used (restrictions are\r
- * applied as in the Hibernate Query-By-Example API call Example.create(object)).\r
- * \r
- * If includeProperties is not empty then only literal properties that are named in the set are used to \r
- * create restrictions, *PLUS* any *ToOne related entities. Related entities are matched on ID, not by \r
- * their internal literal values (e.g. the call is criteria.add(Restrictions.eq(property,relatedObject)), not \r
- * criteria.createCriteria(property).add(Example.create(relatedObject)))\r
- * \r
- * @param example\r
- * @param includeProperties\r
- * @param limit the maximum number of entities returned (can be null to return\r
- * all entities)\r
+ * Save a new entity or update the persistent state of an existing\r
+ * transient entity that has been persisted previously\r
+ *\r
+ * @param transientObject the entity to be persisted\r
+ * @return The unique identifier of the persisted entity\r
+ */\r
+ public UUID saveOrUpdate(T transientObject);\r
+\r
+ /**\r
+ * Save new entities or update the persistent state of existing\r
+ * transient entities that have been persisted previously\r
+ *\r
+ * @param transientObjects the entities to be persisted\r
+ * @return The unique identifier of the persisted entity\r
+ */\r
+ public Map<UUID,T> saveOrUpdate(Collection<T> transientObjects);\r
+\r
+ /**\r
+ * Update the persistent state of an existing transient entity\r
+ * that has been persisted previously\r
+ *\r
+ * @param transientObject the entity to be persisted\r
+ * @return The unique identifier of the persisted entity\r
+ */\r
+ public UUID update(T transientObject);\r
+\r
+ /**\r
+ * Method that lists the objects matching the example provided.\r
+ * The includeProperties property is used to specify which properties of the example are used.\r
+ *\r
+ * If includeProperties is null or empty, then all literal properties are used (restrictions are\r
+ * applied as in the Hibernate Query-By-Example API call Example.create(object)).\r
+ *\r
+ * If includeProperties is not empty then only literal properties that are named in the set are used to\r
+ * create restrictions, *PLUS* any *ToOne related entities. Related entities are matched on ID, not by\r
+ * their internal literal values (e.g. the call is criteria.add(Restrictions.eq(property,relatedObject)), not\r
+ * criteria.createCriteria(property).add(Example.create(relatedObject)))\r
+ *\r
+ * @param example\r
+ * @param includeProperties\r
+ * @param limit the maximum number of entities returned (can be null to return\r
+ * all entities)\r
* @param start The (0-based) offset from the start of the recordset\r
* @param orderHints\r
- * Supports path like <code>orderHints.propertyNames</code> which\r
- * include *-to-one properties like createdBy.username or\r
+ * Supports path like <code>orderHints.propertyNames</code> which\r
+ * include *-to-one properties like createdBy.username or\r
* @param propertyPaths paths initialized on the returned objects - only applied to the objects returned from the first grouping\r
- * @return a list of matching objects\r
- */\r
- public List<T> list(T example, Set<String> includeProperties, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths);\r
- \r
- /**\r
+ * @return a list of matching objects\r
+ */\r
+ public List<T> list(T example, Set<String> includeProperties, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths);\r
+\r
+ /**\r
* Evaluates whether the authenticated user has the rights to perform an specific action on the target object\r
* @param authentication\r
* @param target\r
* @param permission\r
* @return\r
*/\r
- public boolean hasPermission(Authentication authentication, T target, CdmPermission permission);\r
+ @Deprecated // FIXME hasPermission(Authentication authentication, T target, EnumSet<CRUD> operation); should be in the CdmApplicationController\r
+ public boolean hasPermission(Authentication authentication, T target, EnumSet<CRUD> operation);\r
\r
}
\ No newline at end of file
// $Id$
/**
* Copyright (C) 2007 EDIT
-* European Distributed Institute of Taxonomy
+* European Distributed Institute of Taxonomy
* http://www.e-taxonomy.eu
-*
+*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* See LICENSE.TXT at the top of this package for the full license terms.
*/
/**
* Quick and dirty implementation of a location service as needed by the editor
- *
+ *
* @author n.hoffman
* @created 08.04.2009
* @version 1.0
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class LocationServiceImpl extends ServiceBase<DefinedTermBase,IDefinedTermDao> implements ILocationService {
- private static final Logger logger = Logger
- .getLogger(LocationServiceImpl.class);
-
- @Autowired
- protected ITermVocabularyDao vocabularyDao;
-
- @Autowired
- protected IDefinedTermDao definedTermDao;
-
- @Autowired
- protected IOrderedTermVocabularyDao orderedVocabularyDao;
-
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.ServiceBase#setDao(eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao)
- */
- @Override
- protected void setDao(IDefinedTermDao dao) {
- this.dao = dao;
- }
-
- /**
- * (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.ILocationService#getAbsenceTerms()
- * FIXME Candidate for harmonization
- * is this method a duplicate of termService.getVocabulary(VocabularyEnum.AbsenceTerm)?
- */
- public OrderedTermVocabulary<AbsenceTerm> getAbsenceTermVocabulary() {
- String uuidString = "5cd438c8-a8a1-4958-842e-169e83e2ceee";
- UUID uuid = UUID.fromString(uuidString);
- OrderedTermVocabulary<AbsenceTerm> absenceTermVocabulary =
- (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
- return absenceTermVocabulary;
- }
-
-
- /**
- * (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.ILocationService#getPresenceTermVocabulary()
- * FIXME Candidate for harmonization
- * is this method a duplicate of termService.getVocabulary(VocabularyEnum.PresenceTerm)
- */
- public OrderedTermVocabulary<PresenceTerm> getPresenceTermVocabulary() {
- String uuidString = "adbbbe15-c4d3-47b7-80a8-c7d104e53a05";
- UUID uuid = UUID.fromString(uuidString);
- OrderedTermVocabulary<PresenceTerm> presenceTermVocabulary =
- (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
- return presenceTermVocabulary;
- }
-
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.ILocationService#getNamedAreaVocabularyTypes()
- */
- public List<NamedAreaVocabularyType> getNamedAreaVocabularyTypes() {
- List<NamedAreaVocabularyType> result = new ArrayList<NamedAreaVocabularyType>(3);
- result.add(NamedAreaVocabularyType.TDWG_AREA);
- result.add(NamedAreaVocabularyType.WATERBODY_OR_COUNTRY);
- result.add(NamedAreaVocabularyType.CONTINENT);
- return result;
- }
-
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.ILocationService#getNamedAreas(java.lang.Object)
- */
- public OrderedTermVocabulary<NamedArea> getNamedAreaVocabulary(NamedAreaVocabularyType vocabularyType) {
-
- UUID namedAreaVocabularyUuid = null;
-
- if(vocabularyType == NamedAreaVocabularyType.TDWG_AREA){
- namedAreaVocabularyUuid = UUID.fromString("1fb40504-d1d7-44b0-9731-374fbe6cac77");
- }
- if(vocabularyType == NamedAreaVocabularyType.CONTINENT){
- namedAreaVocabularyUuid = UUID.fromString("e72cbcb6-58f8-4201-9774-15d0c6abc128");
- }
- if(vocabularyType == NamedAreaVocabularyType.WATERBODY_OR_COUNTRY){
- namedAreaVocabularyUuid = UUID.fromString("006b1870-7347-4624-990f-e5ed78484a1a");
- }
-
- return (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(namedAreaVocabularyUuid);
- }
-
- /* (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.ILocationService#getNamedAreaLevelVocabulary()
- */
- public OrderedTermVocabulary<NamedAreaLevel> getNamedAreaLevelVocabulary() {
- // TODO return namedAreaLevel filtered by NamedAreaVocabularyType
- String uuidString = "49034253-27c8-4219-97e8-f8d987d3d122";
- UUID uuid = UUID.fromString(uuidString);
- OrderedTermVocabulary<NamedAreaLevel> namedAreaLevelVocabulary =
- (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
- return namedAreaLevelVocabulary;
- }
-
- /**
- * (non-Javadoc)
- * @see eu.etaxonomy.cdm.api.service.ILocationService#getNamedAreaTypeVocabulary()
- * FIXME Candidate for harmonization
- * is this method a duplicate of termService.getVocabulary(VocabularyEnum.NamedAreaType)
- */
- public TermVocabulary<NamedAreaType> getNamedAreaTypeVocabulary() {
- String uuidString = "e51d52d6-965b-4f7d-900f-4ba9c6f5dd33";
- UUID uuid = UUID.fromString(uuidString);
- TermVocabulary<NamedAreaType> namedAreaTypeVocabulary =
- (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
- return namedAreaTypeVocabulary;
- }
-
- public List<NamedArea> getTopLevelNamedAreasByVocabularyType(NamedAreaVocabularyType vocabularyType){
-
- OrderedTermVocabulary<NamedArea> vocabulary = getNamedAreaVocabulary(vocabularyType);
-
- List<NamedArea> topLevelTerms = new ArrayList<NamedArea>();
-
-// for(NamedArea area : vocabulary){
- Iterator<NamedArea> it = vocabulary.iterator();
- while(it.hasNext()){
-
- NamedArea area = HibernateProxyHelper.deproxy(it.next(), NamedArea.class);
- if(area.getPartOfWorkaround() == null){
- topLevelTerms.add(area);
- }
- }
-
- return topLevelTerms;
- }
+
+ private static final Logger logger = Logger.getLogger(LocationServiceImpl.class);
+
+ @Autowired
+ protected ITermVocabularyDao vocabularyDao;
+
+ @Autowired
+ protected IDefinedTermDao definedTermDao;
+
+ @Autowired
+ protected IOrderedTermVocabularyDao orderedVocabularyDao;
+
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.api.service.ServiceBase#setDao(eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao)
+ */
+ @Override
+ protected void setDao(IDefinedTermDao dao) {
+ this.dao = dao;
+ }
+
+ /**
+ * (non-Javadoc)
+ * @see eu.etaxonomy.cdm.api.service.ILocationService#getAbsenceTerms()
+ * FIXME Candidate for harmonization
+ * is this method a duplicate of termService.getVocabulary(VocabularyEnum.AbsenceTerm)?
+ */
+ public OrderedTermVocabulary<AbsenceTerm> getAbsenceTermVocabulary() {
+ String uuidString = "5cd438c8-a8a1-4958-842e-169e83e2ceee";
+ UUID uuid = UUID.fromString(uuidString);
+ OrderedTermVocabulary<AbsenceTerm> absenceTermVocabulary =
+ (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
+ return absenceTermVocabulary;
+ }
+
+
+ /**
+ * (non-Javadoc)
+ * @see eu.etaxonomy.cdm.api.service.ILocationService#getPresenceTermVocabulary()
+ * FIXME Candidate for harmonization
+ * is this method a duplicate of termService.getVocabulary(VocabularyEnum.PresenceTerm)
+ */
+ public OrderedTermVocabulary<PresenceTerm> getPresenceTermVocabulary() {
+ String uuidString = "adbbbe15-c4d3-47b7-80a8-c7d104e53a05";
+ UUID uuid = UUID.fromString(uuidString);
+ OrderedTermVocabulary<PresenceTerm> presenceTermVocabulary =
+ (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
+ return presenceTermVocabulary;
+ }
+
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.api.service.ILocationService#getNamedAreaVocabularyTypes()
+ */
+ public List<NamedAreaVocabularyType> getNamedAreaVocabularyTypes() {
+ List<NamedAreaVocabularyType> result = new ArrayList<NamedAreaVocabularyType>(3);
+ result.add(NamedAreaVocabularyType.TDWG_AREA);
+ result.add(NamedAreaVocabularyType.WATERBODY_OR_COUNTRY);
+ result.add(NamedAreaVocabularyType.CONTINENT);
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.api.service.ILocationService#getNamedAreas(java.lang.Object)
+ */
+ public OrderedTermVocabulary<NamedArea> getNamedAreaVocabulary(NamedAreaVocabularyType vocabularyType) {
+
+ UUID namedAreaVocabularyUuid = null;
+
+ if(vocabularyType == NamedAreaVocabularyType.TDWG_AREA){
+ namedAreaVocabularyUuid = UUID.fromString("1fb40504-d1d7-44b0-9731-374fbe6cac77");
+ }
+ if(vocabularyType == NamedAreaVocabularyType.CONTINENT){
+ namedAreaVocabularyUuid = UUID.fromString("e72cbcb6-58f8-4201-9774-15d0c6abc128");
+ }
+ if(vocabularyType == NamedAreaVocabularyType.WATERBODY_OR_COUNTRY){
+ namedAreaVocabularyUuid = UUID.fromString("006b1870-7347-4624-990f-e5ed78484a1a");
+ }
+
+ return (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(namedAreaVocabularyUuid);
+ }
+
+ /* (non-Javadoc)
+ * @see eu.etaxonomy.cdm.api.service.ILocationService#getNamedAreaLevelVocabulary()
+ */
+ public OrderedTermVocabulary<NamedAreaLevel> getNamedAreaLevelVocabulary() {
+ // TODO return namedAreaLevel filtered by NamedAreaVocabularyType
+ String uuidString = "49034253-27c8-4219-97e8-f8d987d3d122";
+ UUID uuid = UUID.fromString(uuidString);
+ OrderedTermVocabulary<NamedAreaLevel> namedAreaLevelVocabulary =
+ (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
+ return namedAreaLevelVocabulary;
+ }
+
+ /**
+ * (non-Javadoc)
+ * @see eu.etaxonomy.cdm.api.service.ILocationService#getNamedAreaTypeVocabulary()
+ * FIXME Candidate for harmonization
+ * is this method a duplicate of termService.getVocabulary(VocabularyEnum.NamedAreaType)
+ */
+ public TermVocabulary<NamedAreaType> getNamedAreaTypeVocabulary() {
+ String uuidString = "e51d52d6-965b-4f7d-900f-4ba9c6f5dd33";
+ UUID uuid = UUID.fromString(uuidString);
+ TermVocabulary<NamedAreaType> namedAreaTypeVocabulary =
+ (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
+ return namedAreaTypeVocabulary;
+ }
+
+ public List<NamedArea> getTopLevelNamedAreasByVocabularyType(NamedAreaVocabularyType vocabularyType){
+
+ OrderedTermVocabulary<NamedArea> vocabulary = getNamedAreaVocabulary(vocabularyType);
+
+ List<NamedArea> topLevelTerms = new ArrayList<NamedArea>();
+
+// for(NamedArea area : vocabulary){
+ Iterator<NamedArea> it = vocabulary.iterator();
+ while(it.hasNext()){
+
+ NamedArea area = HibernateProxyHelper.deproxy(it.next(), NamedArea.class);
+ if(area.getPartOfWorkaround() == null){
+ topLevelTerms.add(area);
+ }
+ }
+
+ return topLevelTerms;
+ }
// $Id$\r
/**\r
* Copyright (C) 2007 EDIT\r
-* European Distributed Institute of Taxonomy \r
+* European Distributed Institute of Taxonomy\r
* http://www.e-taxonomy.eu\r
-* \r
+*\r
* The contents of this file are subject to the Mozilla Public License Version 1.1\r
* See LICENSE.TXT at the top of this package for the full license terms.\r
*/\r
\r
import java.util.ArrayList;\r
import java.util.Collection;\r
+import java.util.EnumSet;\r
import java.util.List;\r
import java.util.Map;\r
import java.util.Set;\r
import java.util.UUID;\r
\r
+import javax.management.relation.RoleUnresolvedList;\r
+\r
import org.apache.log4j.Logger;\r
import org.hibernate.LockMode;\r
import org.hibernate.Session;\r
import eu.etaxonomy.cdm.model.common.CdmBase;\r
\r
import eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao;\r
-import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermission;\r
+import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;\r
+import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;\r
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator;\r
import eu.etaxonomy.cdm.persistence.query.Grouping;\r
import eu.etaxonomy.cdm.persistence.query.OrderHint;\r
\r
public abstract class ServiceBase<T extends CdmBase, DAO extends ICdmEntityDao<T>> implements IService<T>, ApplicationContextAware {\r
- @SuppressWarnings("unused")\r
- private static final Logger logger = Logger.getLogger(ServiceBase.class);\r
- \r
- //flush after saving this number of objects\r
- int flushAfterNo = 2000;\r
- protected ApplicationContext appContext;\r
-\r
- protected DAO dao;\r
-\r
- @Transactional(readOnly = true)\r
- public void lock(T t, LockMode lockMode) {\r
- dao.lock(t, lockMode);\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public void refresh(T t, LockMode lockMode, List<String> propertyPaths) {\r
- dao.refresh(t, lockMode, propertyPaths);\r
- }\r
-\r
- @Transactional(readOnly = false)\r
- public void clear() {\r
- dao.clear();\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public int count(Class<? extends T> clazz) {\r
- return dao.count(clazz);\r
- }\r
-\r
- @Transactional(readOnly = false)\r
- public UUID delete(T persistentObject) {\r
- return dao.delete(persistentObject);\r
- }\r
-\r
- @Transactional(readOnly = true)\r
- public boolean exists(UUID uuid) {\r
- return dao.exists(uuid);\r
- }\r
-\r
- @Transactional(readOnly = true)\r
- public List<T> find(Set<UUID> uuidSet) {\r
- return dao.findByUuid(uuidSet);\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public List<T> findById(Set<Integer> idSet) { //can't be called find(Set<Integer>) as this conflicts with find(Set<UUID)\r
- return dao.findById(idSet);\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public T find(UUID uuid) {\r
- return dao.findByUuid(uuid);\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public T find(int id) {\r
- return dao.findById(id);\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public Session getSession() {\r
- return dao.getSession();\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public List<Object[]> group(Class<? extends T> clazz,Integer limit, Integer start, List<Grouping> groups, List<String> propertyPaths) {\r
- return dao.group(clazz, limit, start, groups, propertyPaths);\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public List<T> list(Class<? extends T> type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths){\r
- return dao.list(type,limit, start, orderHints,propertyPaths);\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public T load(UUID uuid) {\r
- return dao.load(uuid);\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public T load(UUID uuid, List<String> propertyPaths){\r
- return dao.load(uuid, propertyPaths);\r
- }\r
-\r
- @Transactional(readOnly = false)\r
- public T merge(T newInstance) {\r
- return dao.merge(newInstance);\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public Pager<T> page(Class<? extends T> type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){\r
- Integer numberOfResults = dao.count(type);\r
- List<T> results = new ArrayList<T>();\r
- pageNumber = pageNumber == null ? 0 : pageNumber;\r
- if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)\r
- Integer start = pageSize == null ? 0 : pageSize * pageNumber;\r
- results = dao.list(type, pageSize, start, orderHints,propertyPaths);\r
- }\r
- return new DefaultPagerImpl<T>(pageNumber, numberOfResults, pageSize, results);\r
- }\r
- \r
- @Transactional(readOnly = true)\r
+ @SuppressWarnings("unused")\r
+ private static final Logger logger = Logger.getLogger(ServiceBase.class);\r
+\r
+ //flush after saving this number of objects\r
+ int flushAfterNo = 2000;\r
+ protected ApplicationContext appContext;\r
+\r
+ protected DAO dao;\r
+\r
+ @Transactional(readOnly = true)\r
+ public void lock(T t, LockMode lockMode) {\r
+ dao.lock(t, lockMode);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public void refresh(T t, LockMode lockMode, List<String> propertyPaths) {\r
+ dao.refresh(t, lockMode, propertyPaths);\r
+ }\r
+\r
+ @Transactional(readOnly = false)\r
+ public void clear() {\r
+ dao.clear();\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public int count(Class<? extends T> clazz) {\r
+ return dao.count(clazz);\r
+ }\r
+\r
+ @Transactional(readOnly = false)\r
+ public UUID delete(T persistentObject) {\r
+ return dao.delete(persistentObject);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public boolean exists(UUID uuid) {\r
+ return dao.exists(uuid);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public List<T> find(Set<UUID> uuidSet) {\r
+ return dao.findByUuid(uuidSet);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public List<T> findById(Set<Integer> idSet) { //can't be called find(Set<Integer>) as this conflicts with find(Set<UUID)\r
+ return dao.findById(idSet);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public T find(UUID uuid) {\r
+ return dao.findByUuid(uuid);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public T find(int id) {\r
+ return dao.findById(id);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public Session getSession() {\r
+ return dao.getSession();\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public List<Object[]> group(Class<? extends T> clazz,Integer limit, Integer start, List<Grouping> groups, List<String> propertyPaths) {\r
+ return dao.group(clazz, limit, start, groups, propertyPaths);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public List<T> list(Class<? extends T> type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths){\r
+ return dao.list(type,limit, start, orderHints,propertyPaths);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public T load(UUID uuid) {\r
+ return dao.load(uuid);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public T load(UUID uuid, List<String> propertyPaths){\r
+ return dao.load(uuid, propertyPaths);\r
+ }\r
+\r
+ @Transactional(readOnly = false)\r
+ public T merge(T newInstance) {\r
+ return dao.merge(newInstance);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public Pager<T> page(Class<? extends T> type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){\r
+ Integer numberOfResults = dao.count(type);\r
+ List<T> results = new ArrayList<T>();\r
+ pageNumber = pageNumber == null ? 0 : pageNumber;\r
+ if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)\r
+ Integer start = pageSize == null ? 0 : pageSize * pageNumber;\r
+ results = dao.list(type, pageSize, start, orderHints,propertyPaths);\r
+ }\r
+ return new DefaultPagerImpl<T>(pageNumber, numberOfResults, pageSize, results);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
public UUID refresh(T persistentObject) {\r
- return dao.refresh(persistentObject);\r
- }\r
- \r
- /**\r
- * FIXME Candidate for harmonization\r
- * is this method used, and if so, should it be exposed in the service layer?\r
- * it seems a bit incongruous that we use an ORM to hide the fact that there is a \r
- * database, then expose a method that talks about "rows" . . .\r
- */\r
- @Transactional(readOnly = true)\r
- public List<T> rows(String tableName, int limit, int start) {\r
- return dao.rows(tableName, limit, start);\r
- }\r
- \r
- @Transactional(readOnly = false)\r
- public Map<UUID, T> save(Collection<T> newInstances) {\r
- return dao.saveAll(newInstances);\r
- }\r
-\r
- @Transactional(readOnly = false)\r
- public UUID save(T newInstance) {\r
- return dao.save(newInstance);\r
- }\r
-\r
- @Transactional(readOnly = false)\r
- public UUID saveOrUpdate(T transientObject) {\r
- return dao.saveOrUpdate(transientObject);\r
- }\r
- \r
- @Transactional(readOnly = false)\r
- public Map<UUID, T> saveOrUpdate(Collection<T> transientInstances) {\r
- return dao.saveOrUpdateAll(transientInstances);\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see eu.etaxonomy.cdm.api.service.Iyyy#setApplicationContext(org.springframework.context.ApplicationContext)\r
- */\r
- public void setApplicationContext(ApplicationContext appContext){\r
- this.appContext = appContext;\r
- }\r
-\r
-\r
- protected abstract void setDao(DAO dao);\r
- \r
- @Transactional(readOnly = false)\r
- public UUID update(T transientObject) {\r
- return dao.update(transientObject);\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public List<T> list(T example, Set<String> includeProperties, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
- return dao.list(example, includeProperties, limit, start, orderHints, propertyPaths);\r
- }\r
- \r
- @Transactional(readOnly = true)\r
- public boolean hasPermission(Authentication authentication, T target, CdmPermission permission) {\r
- CdmPermissionEvaluator permissionEvaluator = new CdmPermissionEvaluator();\r
- return permissionEvaluator.hasPermission(authentication, target, permission);\r
- \r
- }\r
+ return dao.refresh(persistentObject);\r
+ }\r
+\r
+ /**\r
+ * FIXME Candidate for harmonization\r
+ * is this method used, and if so, should it be exposed in the service layer?\r
+ * it seems a bit incongruous that we use an ORM to hide the fact that there is a\r
+ * database, then expose a method that talks about "rows" . . .\r
+ */\r
+ @Transactional(readOnly = true)\r
+ public List<T> rows(String tableName, int limit, int start) {\r
+ return dao.rows(tableName, limit, start);\r
+ }\r
+\r
+ @Transactional(readOnly = false)\r
+ public Map<UUID, T> save(Collection<T> newInstances) {\r
+ return dao.saveAll(newInstances);\r
+ }\r
+\r
+ @Transactional(readOnly = false)\r
+ public UUID save(T newInstance) {\r
+ return dao.save(newInstance);\r
+ }\r
+\r
+ @Transactional(readOnly = false)\r
+ public UUID saveOrUpdate(T transientObject) {\r
+ return dao.saveOrUpdate(transientObject);\r
+ }\r
+\r
+ @Transactional(readOnly = false)\r
+ public Map<UUID, T> saveOrUpdate(Collection<T> transientInstances) {\r
+ return dao.saveOrUpdateAll(transientInstances);\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see eu.etaxonomy.cdm.api.service.Iyyy#setApplicationContext(org.springframework.context.ApplicationContext)\r
+ */\r
+ public void setApplicationContext(ApplicationContext appContext){\r
+ this.appContext = appContext;\r
+ }\r
+\r
+\r
+ protected abstract void setDao(DAO dao);\r
+\r
+ @Transactional(readOnly = false)\r
+ public UUID update(T transientObject) {\r
+ return dao.update(transientObject);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public List<T> list(T example, Set<String> includeProperties, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+ return dao.list(example, includeProperties, limit, start, orderHints, propertyPaths);\r
+ }\r
+\r
+ @Transactional(readOnly = true)\r
+ public boolean hasPermission(Authentication authentication, T target, EnumSet<CRUD> operation) {\r
+ throw new RuntimeException("hasPermissio() is umimplemented - do not use");\r
+// CdmPermissionEvaluator permissionEvaluator = new CdmPermissionEvaluator();\r
+// return permissionEvaluator.hasPermission(authentication, target, operation);\r
+\r
+ }\r
}\r
// $Id$\r
/**\r
* Copyright (C) 2007 EDIT\r
- * European Distributed Institute of Taxonomy \r
+ * European Distributed Institute of Taxonomy\r
* http://www.e-taxonomy.eu\r
- * \r
+ *\r
* The contents of this file are subject to the Mozilla Public License Version 1.1\r
* See LICENSE.TXT at the top of this package for the full license terms.\r
*/\r
@Service\r
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)\r
public class UserService extends ServiceBase<User,IUserDao> implements IUserService {\r
- \r
- protected IGroupDao groupDao;\r
- \r
- protected IGrantedAuthorityDao grantedAuthorityDao;\r
- \r
- private SaltSource saltSource = new ReflectionSaltSource();\r
- \r
- private PasswordEncoder passwordEncoder = new Md5PasswordEncoder();\r
- \r
- private AuthenticationManager authenticationManager;\r
- \r
- private UserCache userCache = new NullUserCache();\r
- \r
- @Autowired(required = false)\r
- public void setUserCache(UserCache userCache) {\r
- Assert.notNull(userCache, "userCache cannot be null");\r
- this.userCache = userCache;\r
- }\r
- \r
- @Autowired(required = false)\r
- public void setPasswordEncoder(PasswordEncoder passwordEncoder) {\r
- \r
- this.passwordEncoder = passwordEncoder;\r
- }\r
-\r
- @Autowired(required = false)\r
- public void setSaltSource(SaltSource saltSource) {\r
- this.saltSource = saltSource;\r
- }\r
- \r
- @Autowired(required= false)\r
- public void setAuthenticationManager(AuthenticationManager authenticationManager) {\r
- this.authenticationManager = authenticationManager;\r
- }\r
- \r
- @Override\r
- @Autowired\r
- protected void setDao(IUserDao dao) {\r
- this.dao = dao;\r
- }\r
- \r
- @Autowired\r
- public void setGroupDao(IGroupDao groupDao) {\r
- this.groupDao = groupDao;\r
- }\r
- \r
- @Autowired\r
- public void setGrantedAuthorityDao(IGrantedAuthorityDao grantedAuthorityDao) {\r
- this.grantedAuthorityDao = grantedAuthorityDao;\r
- }\r
- \r
- @Transactional(readOnly=false)\r
- protected Authentication createNewAuthentication(Authentication currentAuth, String newPassword) {\r
- UserDetails user = loadUserByUsername(currentAuth.getName());\r
- \r
- UsernamePasswordAuthenticationToken newAuthentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());\r
- newAuthentication.setDetails(currentAuth.getDetails());\r
- \r
- return newAuthentication;\r
- }\r
- \r
- @Override\r
- @Transactional(readOnly=false)\r
- \r
- public void changePassword(String oldPassword, String newPassword) {\r
- Assert.hasText(oldPassword);\r
- Assert.hasText(newPassword);\r
- Authentication authentication = SecurityContextHolder.getContext().getAuthentication();\r
- if(authentication != null && authentication.getPrincipal() != null && authentication.getPrincipal() instanceof User) {\r
- User user = (User)authentication.getPrincipal();\r
- \r
- authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), oldPassword));\r
- \r
- Object salt = this.saltSource.getSalt(user);\r
- \r
- String password = passwordEncoder.encodePassword(newPassword, salt);\r
- ((User)user).setPassword(password);\r
- \r
- dao.update((User)user);\r
- SecurityContextHolder.getContext().setAuthentication(createNewAuthentication(authentication, newPassword));\r
- userCache.removeUserFromCache(user.getUsername());\r
- } else {\r
- throw new AccessDeniedException("Can't change password as no Authentication object found in context for current user.");\r
- } \r
- }\r
- \r
- @Override\r
- @Transactional(readOnly=false)\r
- public void changePasswordForUser(String username, String newPassword) {\r
- Assert.hasText(username);\r
- Assert.hasText(newPassword);\r
- \r
- try {\r
- User user = dao.findUserByUsername(username);\r
- if(user == null) {\r
- throw new UsernameNotFoundException(username);\r
- }\r
- \r
+\r
+ protected IGroupDao groupDao;\r
+\r
+ protected IGrantedAuthorityDao grantedAuthorityDao;\r
+\r
+ private SaltSource saltSource; // = new ReflectionSaltSource();\r
+\r
+ private PasswordEncoder passwordEncoder; // = new Md5PasswordEncoder();\r
+\r
+ private AuthenticationManager authenticationManager;\r
+\r
+ private UserCache userCache = new NullUserCache();\r
+\r
+ @Autowired(required = false)\r
+ public void setUserCache(UserCache userCache) {\r
+ Assert.notNull(userCache, "userCache cannot be null");\r
+ this.userCache = userCache;\r
+ }\r
+\r
+ @Autowired(required = false)\r
+ public void setPasswordEncoder(PasswordEncoder passwordEncoder) {\r
+\r
+ this.passwordEncoder = passwordEncoder;\r
+ }\r
+\r
+ @Autowired(required = false)\r
+ public void setSaltSource(SaltSource saltSource) {\r
+ this.saltSource = saltSource;\r
+ }\r
+\r
+ @Autowired(required= false)\r
+ public void setAuthenticationManager(AuthenticationManager authenticationManager) {\r
+ this.authenticationManager = authenticationManager;\r
+ }\r
+\r
+ @Override\r
+ @Autowired\r
+ protected void setDao(IUserDao dao) {\r
+ this.dao = dao;\r
+ }\r
+\r
+ @Autowired\r
+ public void setGroupDao(IGroupDao groupDao) {\r
+ this.groupDao = groupDao;\r
+ }\r
+\r
+ @Autowired\r
+ public void setGrantedAuthorityDao(IGrantedAuthorityDao grantedAuthorityDao) {\r
+ this.grantedAuthorityDao = grantedAuthorityDao;\r
+ }\r
+\r
+ @Transactional(readOnly=false)\r
+ protected Authentication createNewAuthentication(Authentication currentAuth, String newPassword) {\r
+ UserDetails user = loadUserByUsername(currentAuth.getName());\r
+\r
+ UsernamePasswordAuthenticationToken newAuthentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());\r
+ newAuthentication.setDetails(currentAuth.getDetails());\r
+\r
+ return newAuthentication;\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly=false)\r
+ public void changePassword(String oldPassword, String newPassword) {\r
+ Assert.hasText(oldPassword);\r
+ Assert.hasText(newPassword);\r
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();\r
+ if(authentication != null && authentication.getPrincipal() != null && authentication.getPrincipal() instanceof User) {\r
+ User user = (User)authentication.getPrincipal();\r
+\r
+ authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), oldPassword));\r
+\r
Object salt = this.saltSource.getSalt(user);\r
- \r
- String password = passwordEncoder.encodePassword(newPassword, salt);\r
- ((User)user).setPassword(password);\r
- \r
- dao.update((User)user);\r
- userCache.removeUserFromCache(user.getUsername());\r
- } catch(NonUniqueResultException nure) {\r
- throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);\r
- }\r
- }\r
-\r
- @Override\r
- @Transactional(readOnly=false)\r
- public void createUser(UserDetails user) {\r
- Assert.isInstanceOf(User.class, user);\r
- \r
- String rawPassword = user.getPassword();\r
- Object salt = this.saltSource.getSalt(user);\r
- \r
- String password = passwordEncoder.encodePassword(rawPassword, salt);\r
- ((User)user).setPassword(password);\r
- \r
- dao.save((User)user);\r
- }\r
-\r
- @Override\r
- @Transactional(readOnly=false)\r
- public void deleteUser(String username) {\r
- Assert.hasLength(username);\r
- \r
- User user = dao.findUserByUsername(username); \r
- if(user != null) { \r
- dao.delete((User)user);\r
+\r
+ String password = passwordEncoder.encodePassword(newPassword, salt);\r
+ ((User)user).setPassword(password);\r
+\r
+ dao.update((User)user);\r
+ SecurityContextHolder.getContext().setAuthentication(createNewAuthentication(authentication, newPassword));\r
+ userCache.removeUserFromCache(user.getUsername());\r
+ } else {\r
+ throw new AccessDeniedException("Can't change password as no Authentication object found in context for current user.");\r
}\r
- \r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly=false)\r
+ @PreAuthorize("#username == authentication.name or hasRole('ROLE_ADMIN')")\r
+ public void changePasswordForUser(String username, String newPassword) {\r
+ Assert.hasText(username);\r
+ Assert.hasText(newPassword);\r
+\r
+ try {\r
+ User user = dao.findUserByUsername(username);\r
+ if(user == null) {\r
+ throw new UsernameNotFoundException(username);\r
+ }\r
+\r
+ Object salt = this.saltSource.getSalt(user);\r
+\r
+ String password = passwordEncoder.encodePassword(newPassword, salt);\r
+ ((User)user).setPassword(password);\r
+\r
+ dao.update((User)user);\r
+ userCache.removeUserFromCache(user.getUsername());\r
+ } catch(NonUniqueResultException nure) {\r
+ throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly=false)\r
+ public void createUser(UserDetails user) {\r
+ Assert.isInstanceOf(User.class, user);\r
+\r
+ String rawPassword = user.getPassword();\r
+ Object salt = this.saltSource.getSalt(user);\r
+\r
+ String password = passwordEncoder.encodePassword(rawPassword, salt);\r
+ ((User)user).setPassword(password);\r
+\r
+ dao.save((User)user);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly=false)\r
+ public void deleteUser(String username) {\r
+ Assert.hasLength(username);\r
+\r
+ User user = dao.findUserByUsername(username);\r
+ if(user != null) {\r
+ dao.delete((User)user);\r
+ }\r
+\r
userCache.removeUserFromCache(username);\r
- }\r
-\r
- @Override\r
- @Transactional(readOnly=false)\r
- public void updateUser(UserDetails user) {\r
- Assert.isInstanceOf(User.class, user);\r
- \r
- dao.update((User)user);\r
- userCache.removeUserFromCache(user.getUsername());\r
- }\r
-\r
- @Override\r
- public boolean userExists(String username) {\r
- Assert.hasText(username);\r
- \r
- User user = dao.findUserByUsername(username);\r
- return user != null;\r
- }\r
-\r
- /**\r
- * DO NOT CALL THIS METHOD IN LONG RUNNING SESSIONS OR CONVERSATIONS\r
- * A THROWN UsernameNotFoundException WILL RENDER THE CONVERSATION UNUSABLE\r
- */\r
- public UserDetails loadUserByUsername(String username)\r
- throws UsernameNotFoundException, DataAccessException {\r
- Assert.hasText(username);\r
- try {\r
- User user = dao.findUserByUsername(username);\r
- if(user == null) {\r
- throw new UsernameNotFoundException(username);\r
- }\r
- return user;\r
- } catch(NonUniqueResultException nure) {\r
- throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);\r
- }\r
- }\r
-\r
- @Deprecated // use GroupService instead\r
- @Transactional(readOnly=false)\r
- public void addGroupAuthority(String groupName, GrantedAuthority authority) {\r
- Assert.hasText(groupName);\r
- Assert.notNull(authority);\r
- \r
- Group group = groupDao.findGroupByName(groupName);\r
- if(group.getGrantedAuthorities().add(authority)) {\r
- groupDao.update(group);\r
- }\r
- }\r
-\r
- @Deprecated // use GroupService instead\r
- @Transactional(readOnly=false)\r
- public void addUserToGroup(String username, String groupName) {\r
- Assert.hasText(username);\r
- Assert.hasText(groupName);\r
- \r
- Group group = groupDao.findGroupByName(groupName);\r
- User user = dao.findUserByUsername(username);\r
- \r
- if(group.addMember(user)) {\r
- groupDao.update(group);\r
- userCache.removeUserFromCache(user.getUsername());\r
- } \r
- }\r
-\r
- @Deprecated // use GroupService instead\r
- @Transactional(readOnly=false)\r
- public void createGroup(String groupName, List<GrantedAuthority> authorities) {\r
- Assert.hasText(groupName);\r
- Assert.notNull(authorities);\r
- \r
- Group group = Group.NewInstance(groupName);\r
- \r
- for(GrantedAuthority authority : authorities) {\r
- group.getGrantedAuthorities().add(authority);\r
- }\r
- \r
- groupDao.save(group);\r
- }\r
-\r
- @Deprecated // use GroupService instead\r
- @Transactional(readOnly=false)\r
- public void deleteGroup(String groupName) {\r
- Assert.hasText(groupName);\r
- \r
- Group group = groupDao.findGroupByName(groupName);\r
- groupDao.delete(group);\r
- }\r
-\r
- @Deprecated // use GroupService instead\r
- public List<String> findAllGroups() {\r
- return groupDao.listNames(null,null);\r
- }\r
-\r
- @Deprecated // use GroupService instead\r
- public List<GrantedAuthority> findGroupAuthorities(String groupName) {\r
- Assert.hasText(groupName);\r
- Group group = groupDao.findGroupByName(groupName);\r
- \r
- return new ArrayList<GrantedAuthority>(group.getGrantedAuthorities());\r
- }\r
-\r
- @Deprecated // use GroupService instead\r
- public List<String> findUsersInGroup(String groupName) {\r
- Assert.hasText(groupName);\r
- Group group = groupDao.findGroupByName(groupName);\r
- \r
- List<String> users = groupDao.listMembers(group, null, null);\r
- \r
- return users;\r
- }\r
-\r
- @Deprecated // use GroupService instead\r
- @Transactional(readOnly=false)\r
- public void removeGroupAuthority(String groupName, GrantedAuthority authority) {\r
- Assert.hasText(groupName);\r
- Assert.notNull(authority);\r
- \r
- Group group = groupDao.findGroupByName(groupName);\r
- \r
- if(group.getGrantedAuthorities().remove(authority)) {\r
- groupDao.update(group);\r
- }\r
- }\r
-\r
- @Deprecated // use GroupService instead\r
- @Transactional(readOnly=false)\r
- public void removeUserFromGroup(String username, String groupName) {\r
- Assert.hasText(username);\r
- Assert.hasText(groupName);\r
- \r
- Group group = groupDao.findGroupByName(groupName);\r
- User user = dao.findUserByUsername(username);\r
- \r
- if(group.removeMember(user)) {\r
- groupDao.update(group);\r
- userCache.removeUserFromCache(user.getUsername());\r
- }\r
- }\r
-\r
- @Deprecated // use GroupService instead\r
- @Transactional(readOnly=false)\r
- public void renameGroup(String oldName, String newName) {\r
- Assert.hasText(oldName);\r
- Assert.hasText(newName);\r
- \r
- Group group = groupDao.findGroupByName(oldName);\r
- \r
- group.setName(newName);\r
- groupDao.update(group);\r
- }\r
- \r
- @Transactional(readOnly=false)\r
- public UUID save(User user) {\r
- if(user.getId() == 0 || dao.load(user.getUuid()) == null){\r
- createUser(user);\r
- }else{\r
- updateUser(user);\r
- }\r
- return user.getUuid(); \r
- }\r
-\r
- @Override\r
- public UUID update(User user) {\r
- updateUser(user);\r
- return user.getUuid(); \r
- }\r
-\r
- @Override\r
- @Transactional(readOnly=false)\r
- public UUID saveGrantedAuthority(GrantedAuthority grantedAuthority) {\r
- return grantedAuthorityDao.save((GrantedAuthorityImpl)grantedAuthority);\r
- }\r
- \r
- @Deprecated // use GroupService instead\r
- @Transactional(readOnly=false)\r
- public UUID saveGroup(Group group) {\r
- return groupDao.save(group);\r
- }\r
- \r
- @Override\r
- @Transactional(readOnly = true)\r
- public List<User> listByUsername(String queryString,MatchMode matchmode, List<Criterion> criteria, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
- Integer numberOfResults = dao.countByUsername(queryString, matchmode, criteria);\r
- \r
- List<User> results = new ArrayList<User>();\r
- if(numberOfResults > 0) { \r
- results = dao.findByUsername(queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths); \r
- }\r
- return results;\r
- }\r
-\r
- \r
-\r
- \r
-} \r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly=false)\r
+ public void updateUser(UserDetails user) {\r
+ Assert.isInstanceOf(User.class, user);\r
+\r
+ dao.update((User)user);\r
+ userCache.removeUserFromCache(user.getUsername());\r
+ }\r
+\r
+ @Override\r
+ public boolean userExists(String username) {\r
+ Assert.hasText(username);\r
+\r
+ User user = dao.findUserByUsername(username);\r
+ return user != null;\r
+ }\r
+\r
+ /**\r
+ * DO NOT CALL THIS METHOD IN LONG RUNNING SESSIONS OR CONVERSATIONS\r
+ * A THROWN UsernameNotFoundException WILL RENDER THE CONVERSATION UNUSABLE\r
+ */\r
+ public UserDetails loadUserByUsername(String username)\r
+ throws UsernameNotFoundException, DataAccessException {\r
+ Assert.hasText(username);\r
+ try {\r
+ User user = dao.findUserByUsername(username);\r
+ if(user == null) {\r
+ throw new UsernameNotFoundException(username);\r
+ }\r
+ return user;\r
+ } catch(NonUniqueResultException nure) {\r
+ throw new IncorrectResultSizeDataAccessException("More than one user found with name '" + username + "'", 1);\r
+ }\r
+ }\r
+\r
+ @Deprecated // use GroupService instead\r
+ @Transactional(readOnly=false)\r
+ public void addGroupAuthority(String groupName, GrantedAuthority authority) {\r
+ Assert.hasText(groupName);\r
+ Assert.notNull(authority);\r
+\r
+ Group group = groupDao.findGroupByName(groupName);\r
+ if(group.getGrantedAuthorities().add(authority)) {\r
+ groupDao.update(group);\r
+ }\r
+ }\r
+\r
+ @Deprecated // use GroupService instead\r
+ @Transactional(readOnly=false)\r
+ public void addUserToGroup(String username, String groupName) {\r
+ Assert.hasText(username);\r
+ Assert.hasText(groupName);\r
+\r
+ Group group = groupDao.findGroupByName(groupName);\r
+ User user = dao.findUserByUsername(username);\r
+\r
+ if(group.addMember(user)) {\r
+ groupDao.update(group);\r
+ userCache.removeUserFromCache(user.getUsername());\r
+ }\r
+ }\r
+\r
+ @Deprecated // use GroupService instead\r
+ @Transactional(readOnly=false)\r
+ public void createGroup(String groupName, List<GrantedAuthority> authorities) {\r
+ Assert.hasText(groupName);\r
+ Assert.notNull(authorities);\r
+\r
+ Group group = Group.NewInstance(groupName);\r
+\r
+ for(GrantedAuthority authority : authorities) {\r
+ group.getGrantedAuthorities().add(authority);\r
+ }\r
+\r
+ groupDao.save(group);\r
+ }\r
+\r
+ @Deprecated // use GroupService instead\r
+ @Transactional(readOnly=false)\r
+ public void deleteGroup(String groupName) {\r
+ Assert.hasText(groupName);\r
+\r
+ Group group = groupDao.findGroupByName(groupName);\r
+ groupDao.delete(group);\r
+ }\r
+\r
+ @Deprecated // use GroupService instead\r
+ public List<String> findAllGroups() {\r
+ return groupDao.listNames(null,null);\r
+ }\r
+\r
+ @Deprecated // use GroupService instead\r
+ public List<GrantedAuthority> findGroupAuthorities(String groupName) {\r
+ Assert.hasText(groupName);\r
+ Group group = groupDao.findGroupByName(groupName);\r
+\r
+ return new ArrayList<GrantedAuthority>(group.getGrantedAuthorities());\r
+ }\r
+\r
+ @Deprecated // use GroupService instead\r
+ public List<String> findUsersInGroup(String groupName) {\r
+ Assert.hasText(groupName);\r
+ Group group = groupDao.findGroupByName(groupName);\r
+\r
+ List<String> users = groupDao.listMembers(group, null, null);\r
+\r
+ return users;\r
+ }\r
+\r
+ @Deprecated // use GroupService instead\r
+ @Transactional(readOnly=false)\r
+ public void removeGroupAuthority(String groupName, GrantedAuthority authority) {\r
+ Assert.hasText(groupName);\r
+ Assert.notNull(authority);\r
+\r
+ Group group = groupDao.findGroupByName(groupName);\r
+\r
+ if(group.getGrantedAuthorities().remove(authority)) {\r
+ groupDao.update(group);\r
+ }\r
+ }\r
+\r
+ @Deprecated // use GroupService instead\r
+ @Transactional(readOnly=false)\r
+ public void removeUserFromGroup(String username, String groupName) {\r
+ Assert.hasText(username);\r
+ Assert.hasText(groupName);\r
+\r
+ Group group = groupDao.findGroupByName(groupName);\r
+ User user = dao.findUserByUsername(username);\r
+\r
+ if(group.removeMember(user)) {\r
+ groupDao.update(group);\r
+ userCache.removeUserFromCache(user.getUsername());\r
+ }\r
+ }\r
+\r
+ @Deprecated // use GroupService instead\r
+ @Transactional(readOnly=false)\r
+ public void renameGroup(String oldName, String newName) {\r
+ Assert.hasText(oldName);\r
+ Assert.hasText(newName);\r
+\r
+ Group group = groupDao.findGroupByName(oldName);\r
+\r
+ group.setName(newName);\r
+ groupDao.update(group);\r
+ }\r
+\r
+ @Transactional(readOnly=false)\r
+ public UUID save(User user) {\r
+ if(user.getId() == 0 || dao.load(user.getUuid()) == null){\r
+ createUser(user);\r
+ }else{\r
+ updateUser(user);\r
+ }\r
+ return user.getUuid();\r
+ }\r
+\r
+ @Override\r
+ public UUID update(User user) {\r
+ updateUser(user);\r
+ return user.getUuid();\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly=false)\r
+ public UUID saveGrantedAuthority(GrantedAuthority grantedAuthority) {\r
+ return grantedAuthorityDao.save((GrantedAuthorityImpl)grantedAuthority);\r
+ }\r
+\r
+ @Deprecated // use GroupService instead\r
+ @Transactional(readOnly=false)\r
+ public UUID saveGroup(Group group) {\r
+ return groupDao.save(group);\r
+ }\r
+\r
+ @Override\r
+ @Transactional(readOnly = true)\r
+ public List<User> listByUsername(String queryString,MatchMode matchmode, List<Criterion> criteria, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+ Integer numberOfResults = dao.countByUsername(queryString, matchmode, criteria);\r
+\r
+ List<User> results = new ArrayList<User>();\r
+ if(numberOfResults > 0) {\r
+ results = dao.findByUsername(queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths);\r
+ }\r
+ return results;\r
+ }\r
+\r
+\r
+\r
+\r
+}\r
<?xml version="1.0" encoding="UTF-8"?>\r
<beans xmlns="http://www.springframework.org/schema/beans"\r
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
- xmlns:context="http://www.springframework.org/schema/context"\r
- xmlns:security="http://www.springframework.org/schema/security"\r
- xsi:schemaLocation="http://www.springframework.org/schema/beans \r
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+ xmlns:context="http://www.springframework.org/schema/context"\r
+ xmlns:security="http://www.springframework.org/schema/security"\r
+ xsi:schemaLocation="http://www.springframework.org/schema/beans\r
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
http://www.springframework.org/schema/context\r
http://www.springframework.org/schema/context/spring-context-2.5.xsd\r
- http://www.springframework.org/schema/security \r
+ http://www.springframework.org/schema/security\r
http://www.springframework.org/schema/security/spring-security-3.0.4.xsd">\r
- \r
+\r
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">\r
<property name="providers">\r
<list>\r
</list>\r
</property>\r
</bean>\r
- \r
+\r
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">\r
<property name="userDetailsService" ref="userService"/>\r
<property name="saltSource" ref="saltSource"/>\r
<property name="passwordEncoder" ref="passwordEncoder"/>\r
</bean>\r
- \r
+\r
<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"/>\r
- \r
+\r
<bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource">\r
<property name="userPropertyToUse" value="getUsername"/>\r
</bean>\r
- \r
- <!-- Disabling in trunk. Method security is currently beeing developed in http://dev.e-taxonomy.eu/svn/branches/cdmlib/security/ -->\r
- <!-- \r
+\r
+ <!-- Disabling in trunk. Method security is currently being developed in http://dev.e-taxonomy.eu/svn/branches/cdmlib/security/ -->\r
+ <!--\r
<security:global-method-security pre-post-annotations="enabled">\r
- <security:expression-handler ref="expressionHandler"/>\r
- </security:global-method-security>\r
+ <security:expression-handler ref="expressionHandler"/>\r
+ </security:global-method-security>\r
\r
- <bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">\r
- <property name="permissionEvaluator" ref="cdmPermissionEvaluator"/>\r
- </bean>\r
- \r
- \r
- <bean class="eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator" id="cdmPermissionEvaluator"/>\r
+ <bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">\r
+ <property name="permissionEvaluator" ref="cdmPermissionEvaluator"/>\r
+ </bean>\r
+ <bean class="eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator" id="cdmPermissionEvaluator"/>\r
-->\r
+\r
</beans>
\ No newline at end of file
package eu.etaxonomy.cdm.api.service;\r
\r
import static org.junit.Assert.assertEquals;\r
-import static org.junit.Assert.assertFalse;\r
import static org.junit.Assert.assertTrue;\r
\r
-\r
-import java.util.ArrayList;\r
import java.util.Collection;\r
-import java.util.Iterator;\r
-import java.util.List;\r
import java.util.Set;\r
import java.util.UUID;\r
\r
import javax.sql.DataSource;\r
\r
import org.apache.log4j.Logger;\r
-\r
import org.junit.Assert;\r
import org.junit.Before;\r
import org.junit.Ignore;\r
import org.junit.Test;\r
-import org.junit.runner.RunWith;\r
-\r
-import org.springframework.beans.factory.annotation.Autowired;\r
-import org.springframework.orm.hibernate3.HibernateSystemException;\r
-import org.springframework.security.access.vote.RoleVoter;\r
+import org.springframework.security.access.AccessDeniedException;\r
import org.springframework.security.authentication.AuthenticationManager;\r
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\r
import org.springframework.security.authentication.dao.ReflectionSaltSource;\r
+import org.springframework.security.authentication.dao.SaltSource;\r
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;\r
+import org.springframework.security.authentication.encoding.PasswordEncoder;\r
import org.springframework.security.core.Authentication;\r
import org.springframework.security.core.GrantedAuthority;\r
import org.springframework.security.core.context.SecurityContext;\r
import org.springframework.security.core.context.SecurityContextHolder;\r
-import org.springframework.test.annotation.ExpectedException;\r
import org.springframework.transaction.PlatformTransactionManager;\r
-\r
-\r
-import org.unitils.database.annotations.Transactional;\r
-import org.unitils.UnitilsJUnit4TestClassRunner;\r
import org.unitils.database.annotations.TestDataSource;\r
-import org.unitils.database.util.TransactionMode;\r
import org.unitils.dbunit.annotation.DataSet;\r
-import org.unitils.spring.annotation.SpringApplicationContext;\r
-import org.unitils.spring.annotation.SpringBeanByName;\r
+import org.unitils.spring.annotation.SpringBean;\r
import org.unitils.spring.annotation.SpringBeanByType;\r
\r
-\r
-import eu.etaxonomy.cdm.api.service.config.IFindTaxaAndNamesConfigurator;\r
-import eu.etaxonomy.cdm.api.service.config.FindTaxaAndNamesConfiguratorImpl;\r
-import eu.etaxonomy.cdm.api.service.pager.Pager;\r
import eu.etaxonomy.cdm.database.EvaluationFailedException;\r
-import eu.etaxonomy.cdm.model.common.Language;\r
import eu.etaxonomy.cdm.model.common.User;\r
-\r
-\r
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;\r
import eu.etaxonomy.cdm.model.description.Distribution;\r
import eu.etaxonomy.cdm.model.description.Feature;\r
import eu.etaxonomy.cdm.model.description.TaxonDescription;\r
import eu.etaxonomy.cdm.model.description.TextData;\r
-\r
-import eu.etaxonomy.cdm.model.media.Media;\r
import eu.etaxonomy.cdm.model.name.BotanicalName;\r
import eu.etaxonomy.cdm.model.name.Rank;\r
import eu.etaxonomy.cdm.model.taxon.Synonym;\r
-\r
-import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;\r
import eu.etaxonomy.cdm.model.taxon.Taxon;\r
import eu.etaxonomy.cdm.model.taxon.TaxonBase;\r
import eu.etaxonomy.cdm.model.taxon.TaxonNode;\r
-import eu.etaxonomy.cdm.persistence.dao.BeanInitializer;\r
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator;\r
-import eu.etaxonomy.cdm.test.integration.CdmTransactionalIntegrationTest;\r
import eu.etaxonomy.cdm.test.integration.CdmTransactionalIntegrationTestWithSecurity;\r
-import eu.etaxonomy.cdm.test.unitils.CleanSweepInsertLoadStrategy;\r
\r
\r
@DataSet\r
public class SecurityTest extends CdmTransactionalIntegrationTestWithSecurity{\r
\r
+ private static final UUID UUID_ACHERONTINII = UUID.fromString("928a0167-98cd-4555-bf72-52116d067625");\r
+\r
+ private static final UUID UUID_ACHERONTIA_STYX = UUID.fromString("7b8b5cb3-37ba-4dba-91ac-4c6ffd6ac331");\r
+\r
+ private static final UUID PART_EDITOR_UUID = UUID.fromString("38a251bd-0ba4-426f-8fcb-5c09560749a7");\r
+\r
+ private static final String PASSWORD_TAXON_EDITOR = "test2";\r
+\r
+ private static final String PASSWORD_ADMIN = "sPePhAz6";\r
+\r
private static final UUID ACHERONTIA_NODE_UUID = UUID.fromString("20c8f083-5870-4cbd-bf56-c5b2b98ab6a7");\r
\r
private static final UUID ACHERONTIINI_NODE_UUID = UUID.fromString("cecfa77f-f26a-4476-9d87-a8d993cb55d9");\r
@SpringBeanByType\r
private AuthenticationManager authenticationManager;\r
\r
+ @SpringBeanByType\r
+ private SaltSource saltSource;\r
+\r
+ @SpringBeanByType\r
+ private PasswordEncoder passwordEncoder;\r
+\r
+ @SpringBean("cdmPermissionEvaluator")\r
+ private CdmPermissionEvaluator permissionEvaluator;\r
\r
+ private UsernamePasswordAuthenticationToken tokenForAdmin;\r
\r
- private UsernamePasswordAuthenticationToken token;\r
+ private UsernamePasswordAuthenticationToken tokenForTaxonEditor;\r
+\r
+ private UsernamePasswordAuthenticationToken tokenForDescriptionEditor;\r
+\r
+ private UsernamePasswordAuthenticationToken tokenForPartEditor;\r
+\r
+ private UsernamePasswordAuthenticationToken tokenForTaxonomist;\r
\r
\r
@Before\r
public void setUp(){\r
- token = new UsernamePasswordAuthenticationToken("ben", "sPePhAz6");\r
+ /* User 'admin':\r
+ - ROLE_ADMIN\r
+ - ALL.ADMIN\r
+ - TAXONBASE.READ\r
+ - TAXONBASE.CREATE\r
+ - TAXONBASE.DELETE\r
+ - TAXONBASE.UPDATE\r
+ */\r
+ tokenForAdmin = new UsernamePasswordAuthenticationToken("admin", PASSWORD_ADMIN);\r
+\r
+ /* User 'taxonEditor':\r
+ - TAXONBASE.CREATE\r
+ - TAXONBASE.UPDATE\r
+ */\r
+ tokenForTaxonEditor = new UsernamePasswordAuthenticationToken("taxonEditor", PASSWORD_TAXON_EDITOR);\r
+\r
+ /* User 'descriptionEditor':\r
+ - DESCRIPTIONBASE.CREATE\r
+ - DESCRIPTIONBASE.UPDATE\r
+ - DESCRIPTIONELEMENT(Ecology).CREATE\r
+ - DESCRIPTIONELEMENT(Ecology).UPDATE\r
+ */\r
+ tokenForDescriptionEditor = new UsernamePasswordAuthenticationToken("descriptionEditor", "test");\r
+\r
+ /* User 'partEditor':\r
+ - TAXONBASE.ADMIN\r
+ - TAXONNODE.CREATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}\r
+ - TAXONNODE.UPDATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}\r
+ */\r
+ tokenForPartEditor = new UsernamePasswordAuthenticationToken("partEditor", "test4");\r
+\r
+ /* User 'taxonomist':\r
+ - TAXONBASE.READ\r
+ - TAXONBASE.CREATE\r
+ - TAXONBASE.DELETE\r
+ - TAXONBASE.UPDATE\r
+ */\r
+ tokenForTaxonomist = new UsernamePasswordAuthenticationToken("taxonomist", "test4");\r
}\r
\r
+ /**\r
+ * no assertions in this test, since it is only used to create password hashes for test data\r
+ */\r
+ @Test\r
+ public void testEncryptPassword(){\r
+\r
+ String password = PASSWORD_ADMIN;\r
+ User user = User.NewInstance("admin", "");\r
+\r
+ Object salt = this.saltSource.getSalt(user);\r
+ String passwordEncrypted = passwordEncoder.encodePassword(password, salt);\r
+ logger.info("encrypted password: " + passwordEncrypted );\r
+ }\r
\r
/**\r
* Test method for {@link eu.etaxonomy.cdm.api.service.TaxonServiceImpl#saveTaxon(eu.etaxonomy.cdm.model.taxon.TaxonBase)}.\r
System.err.println(encoder.encodePassword("test4", saltSource.getSalt(user)));\r
\r
*/\r
- authentication = authenticationManager.authenticate(token);\r
+ authentication = authenticationManager.authenticate(tokenForAdmin);\r
SecurityContext context = SecurityContextHolder.getContext();\r
context.setAuthentication(authentication);\r
\r
Taxon expectedTaxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);\r
UUID uuid = taxonService.save(expectedTaxon);\r
+ commitAndStartNewTransaction(null);\r
//taxonService.getSession().flush();\r
TaxonBase<?> actualTaxon = taxonService.load(uuid);\r
assertEquals(expectedTaxon, actualTaxon);\r
\r
- token = new UsernamePasswordAuthenticationToken("taxonEditor", "test2");\r
- authentication = authenticationManager.authenticate(token);\r
+ authentication = authenticationManager.authenticate(tokenForTaxonEditor);\r
context = SecurityContextHolder.getContext();\r
context.setAuthentication(authentication);\r
expectedTaxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()), null);\r
taxonService.saveOrUpdate(actualTaxon);\r
+ commitAndStartNewTransaction(null);\r
\r
}\r
\r
+ @Test\r
+ @Ignore //FIXME no need to test this, no access controll needed for userService.changePassword\r
+ public void testChangeOwnPassword(){\r
+\r
+ SecurityContext context = SecurityContextHolder.getContext();\r
+ // authenticate as admin\r
+ authentication = authenticationManager.authenticate(tokenForTaxonEditor);\r
+ context.setAuthentication(authentication);\r
+\r
+// User currentUser = (User) context.getAuthentication().getPrincipal();\r
+\r
+ String newPass = "poiweorijo";\r
+ userService.changePassword(PASSWORD_TAXON_EDITOR, newPass);\r
+ commitAndStartNewTransaction(null);\r
+\r
+ // try to re-authenticate user with changed password\r
+ UsernamePasswordAuthenticationToken newTokenForTaxonEditor = new UsernamePasswordAuthenticationToken("taxonEditor", newPass);\r
+ authentication = authenticationManager.authenticate(newTokenForTaxonEditor);\r
+ }\r
+\r
+ @Test\r
+ public void testChangeOthersPassword(){\r
+\r
+ SecurityContext context = SecurityContextHolder.getContext();\r
+ // (1) authenticate as admin\r
+ authentication = authenticationManager.authenticate(tokenForAdmin);\r
+ context.setAuthentication(authentication);\r
+\r
+ RuntimeException exception = null;\r
+\r
+ try{\r
+ userService.changePasswordForUser("taxonomist", "zuaisd");\r
+ commitAndStartNewTransaction(null);\r
+ } catch (AccessDeniedException e){\r
+ logger.error("Unexpected failure of evaluation.", e);\r
+ exception = e;\r
+ } catch (RuntimeException e){\r
+ exception = findThrowableOfTypeIn(EvaluationFailedException.class, e);\r
+ logger.debug("Unexpected failure of evaluation.", exception);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNull("must not fail here!", exception);\r
+\r
+ // ok, now try authenticating taxonomist with new password\r
+ UsernamePasswordAuthenticationToken newToken = new UsernamePasswordAuthenticationToken("taxonomist", "zuaisd");\r
+ authentication = authenticationManager.authenticate(newToken);\r
+\r
+ // (2) authenticate as under privileged user - not an admin !!!\r
+ authentication = authenticationManager.authenticate(tokenForDescriptionEditor);\r
+ context.setAuthentication(authentication);\r
+\r
+ // check test preconditions user name and authorities\r
+ Assert.assertEquals("descriptionEditor", context.getAuthentication().getName());\r
+ Collection<GrantedAuthority> authorities = context.getAuthentication().getAuthorities();\r
+ for(GrantedAuthority authority: authorities){\r
+ // role prefix 'ROLE_' is defined in org.springframework.security.access.vote.RoleVoter !!!\r
+ Assert.assertNotSame("user must not have authority 'ROLE_ADMIN'", "ROLE_ADMIN", authority.getAuthority());\r
+ }\r
+ // finally perform the test :\r
+ try{\r
+ userService.changePasswordForUser("partEditor", "poiweorijo");\r
+ commitAndStartNewTransaction(null);\r
+ } catch (AccessDeniedException e){\r
+ logger.debug("Expected failure of evaluation.", e);\r
+ exception = e;\r
+ } catch (RuntimeException e){\r
+ exception = findThrowableOfTypeIn(EvaluationFailedException.class, e);\r
+ logger.debug("Expected failure of evaluation.", exception);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNotNull("must fail here!", exception);\r
+ }\r
+\r
@Test\r
public void testUpdateUser(){\r
\r
- authentication = authenticationManager.authenticate(token);\r
+ authentication = authenticationManager.authenticate(tokenForAdmin);\r
SecurityContext context = SecurityContextHolder.getContext();\r
context.setAuthentication(authentication);\r
String username = "standardUser";\r
userService.updateUser(user);\r
userService.update(user);\r
userService.saveOrUpdate(user);\r
+ commitAndStartNewTransaction(null);\r
\r
}\r
\r
@Test\r
public final void testSaveOrUpdateTaxon() {\r
- authentication = authenticationManager.authenticate(token);\r
SecurityContext context = SecurityContextHolder.getContext();\r
+\r
+ // 1) test with admin account - should succeed\r
+ authentication = authenticationManager.authenticate(tokenForAdmin);\r
context.setAuthentication(authentication);\r
- Taxon expectedTaxon = Taxon.NewInstance(null, null);\r
- UUID uuid = taxonService.save(expectedTaxon);\r
- TaxonBase<?> actualTaxon = taxonService.load(uuid);\r
- assertEquals(expectedTaxon, actualTaxon);\r
\r
- actualTaxon.setName(BotanicalName.NewInstance(Rank.SPECIES()));\r
- taxonService.saveOrUpdate(actualTaxon);\r
+ TaxonBase<?> taxon = taxonService.load(UUID_ACHERONTIA_STYX);\r
+ taxon.setDoubtful(true);\r
+ RuntimeException securityException= null;\r
+ try{\r
+ taxonService.saveOrUpdate(taxon);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.error("Unexpected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);\r
+ // reload taxon\r
+ taxon = taxonService.load(UUID_ACHERONTIA_STYX);\r
+ Assert.assertTrue("The change must be persited", taxon.isDoubtful());\r
\r
- token = new UsernamePasswordAuthenticationToken("taxonEditor", "test2");\r
- authentication = authenticationManager.authenticate(token);\r
- context = SecurityContextHolder.getContext();\r
+ // 2) test with taxonEditor account - should succeed\r
+ authentication = authenticationManager.authenticate(tokenForTaxonEditor);\r
context.setAuthentication(authentication);\r
- actualTaxon = taxonService.load(uuid);\r
\r
- actualTaxon.setDoubtful(true);\r
- taxonService.saveOrUpdate(actualTaxon);\r
+ taxon = taxonService.load(UUID_ACHERONTIA_STYX);\r
+ taxon.setDoubtful(false);\r
+ securityException= null;\r
+ try{\r
+ taxonService.saveOrUpdate(taxon);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Unexpected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);\r
+ // reload taxon\r
+ taxon = taxonService.load(UUID_ACHERONTIA_STYX);\r
+ Assert.assertFalse("The change must be persited", taxon.isDoubtful());\r
+\r
+ // 3) test with tokenForDescriptionEditor account - should fail\r
+// authentication = authenticationManager.authenticate(tokenForTaxonEditor);\r
+// context.setAuthentication(authentication);\r
+// taxon = taxonService.load(uuid);\r
+//\r
+// taxon.setDoubtful(true);\r
+// taxonService.saveOrUpdate(taxon);\r
+// commitAndStartNewTransaction(null);\r
\r
}\r
\r
@Test\r
- public void testCascadingInSpringSecurityAccesDenied(){\r
- /*authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("partEditor", "test4"));\r
- SecurityContext context = SecurityContextHolder.getContext();\r
- context.setAuthentication(authentication);\r
- */\r
+ @Ignore //FIXME: adding taxa to a description must be protected at the side of the Description itself!!\r
+ // => protecting method TaxonDescription.setTaxon() ?\r
+ public void testAddDescriptionToTaxon(){\r
\r
- authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("taxonEditor", "test2"));\r
SecurityContext context = SecurityContextHolder.getContext();\r
+ authentication = authenticationManager.authenticate(tokenForDescriptionEditor);\r
context.setAuthentication(authentication);\r
- CdmPermissionEvaluator permissionEvaluator = new CdmPermissionEvaluator();\r
-\r
- Taxon taxon =(Taxon) taxonService.load(ACHERONTIA_LACHESIS_UUID);\r
- taxon.setDoubtful(false);\r
- assertTrue(permissionEvaluator.hasPermission(authentication, taxon, "UPDATE"));\r
- taxonService.save(taxon);\r
- taxon = null;\r
- commitAndStartNewTransaction(null);\r
\r
- //during cascading the permissions are not evaluated, but with hibernate listener every database transaction can be interrupted, but how to manage it,\r
- //when someone has the rights to save descriptions, but not taxa (the editor always saves everything by saving the taxon)\r
- //taxonService.saveOrUpdate(taxon);\r
+ RuntimeException securityException = null;\r
\r
-\r
- authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("descriptionEditor", "test"));\r
- context = SecurityContextHolder.getContext();\r
- context.setAuthentication(authentication);\r
-\r
- //taxonService.saveOrUpdate(taxon);\r
-\r
- taxon =(Taxon) taxonService.load(ACHERONTIA_LACHESIS_UUID);\r
+ Taxon taxon = (Taxon)taxonService.load(ACHERONTIA_LACHESIS_UUID);\r
\r
TaxonDescription description = TaxonDescription.NewInstance(taxon);\r
description.setTitleCache("test");\r
- descriptionService.saveOrUpdate(description);\r
- commitAndStartNewTransaction(null);\r
+ try {\r
+ descriptionService.saveOrUpdate(description);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Expected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ /*\r
+ * Expectation:\r
+ * The user should not be granted to add the Description to a taxon\r
+ */\r
+ Assert.assertNotNull("evaluation should fail since the user is not permitted to edit Taxa", securityException);\r
taxon = (Taxon)taxonService.load(ACHERONTIA_LACHESIS_UUID);\r
assertTrue(taxon.getDescriptions().contains(description));\r
}\r
\r
@Test\r
- public void testCascadingInSpring(){\r
- authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("descriptionEditor", "test"));\r
+ public void testCreateDescriptionWithElement(){\r
+ authentication = authenticationManager.authenticate(tokenForDescriptionEditor);\r
SecurityContext context = SecurityContextHolder.getContext();\r
context.setAuthentication(authentication);\r
\r
- Taxon taxon = (Taxon)taxonService.load(UUID.fromString("928a0167-98cd-4555-bf72-52116d067625"));\r
- TaxonDescription description = TaxonDescription.NewInstance(taxon);\r
- description.addElement(Distribution.NewInstance());\r
- CdmPermissionEvaluator permissionEvaluator = new CdmPermissionEvaluator();\r
- assertTrue(permissionEvaluator.hasPermission(authentication, description, "UPDATE"));\r
+ Taxon taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);\r
+ Assert.assertTrue("taxon must not yet have descriptions", taxon.getDescriptions().size() == 0);\r
+\r
+ TaxonDescription description = null;\r
\r
- descriptionService.saveOrUpdate(description);\r
+ // 1) test for failure - description element but no feature\r
+ description = TaxonDescription.NewInstance(taxon);\r
+ DescriptionElementBase textdataNoFeature = TextData.NewInstance();\r
+ description.addElement(textdataNoFeature);\r
\r
- taxon = (Taxon)taxonService.load(UUID.fromString("928a0167-98cd-4555-bf72-52116d067625"));\r
+ RuntimeException securityException = null;\r
+ assertTrue(permissionEvaluator.hasPermission(authentication, description, "UPDATE"));\r
+ try{\r
+ descriptionService.saveOrUpdate(description);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Expected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+\r
+ Assert.assertNotNull("evaluation should fail", securityException);\r
+ taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);\r
Set<TaxonDescription> descriptions = taxon.getDescriptions();\r
- assertTrue(descriptions.contains(description));\r
+ assertTrue("taxon must not have any description", descriptions.size() == 0);\r
+\r
+ // 2) test for failure - description element but not granted feature\r
+ description = TaxonDescription.NewInstance(taxon);\r
+ DescriptionElementBase descriptionText = TextData.NewInstance(Feature.DESCRIPTION());\r
+ description.addElement(descriptionText);\r
+\r
+ securityException = null;\r
+ assertTrue(permissionEvaluator.hasPermission(authentication, description, "UPDATE"));\r
+ try{\r
+ descriptionService.saveOrUpdate(description);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Expected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+\r
+ Assert.assertNotNull("evaluation should fail", securityException);\r
+ taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);\r
+ descriptions = taxon.getDescriptions();\r
+ assertTrue("taxon must not have any description", descriptions.size() == 0);\r
+\r
+ // 3) test for failure\r
+ description = TaxonDescription.NewInstance(taxon);\r
+ DescriptionElementBase ecologyText = TextData.NewInstance(Feature.ECOLOGY());\r
+ description.addElement(ecologyText);\r
+\r
+ securityException = null;\r
+ assertTrue(permissionEvaluator.hasPermission(authentication, description, "UPDATE"));\r
+ try{\r
+ descriptionService.saveOrUpdate(description);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Unexpected failure of evaluation.", e);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+\r
+ Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);\r
+ taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);\r
+ descriptions = taxon.getDescriptions();\r
+ assertTrue("taxon must now have one description", descriptions.size() == 1);\r
+ assertTrue("description should have one description element", descriptions.iterator().next().getElements().size() == 1);\r
\r
}\r
\r
@Test\r
public void testSaveSynonym(){\r
- authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("taxonomist", "test4"));\r
+\r
SecurityContext context = SecurityContextHolder.getContext();\r
+\r
+ // 1) test for success\r
+ authentication = authenticationManager.authenticate(tokenForTaxonomist);\r
context.setAuthentication(authentication);\r
\r
+ RuntimeException securityException = null;\r
Synonym syn = Synonym.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);\r
- taxonService.saveOrUpdate(syn);\r
+ UUID synUuid = UUID.randomUUID();\r
+ syn.setUuid(synUuid);\r
+ try{\r
+ taxonService.saveOrUpdate(syn);\r
+ logger.debug("will commit ...");\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Unexpected failure of evaluation.", e);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);\r
+ Assert.assertNotNull("The new Synonym must be persited", taxonService.find(synUuid));\r
+\r
+ // 2) test for denial\r
+ authentication = authenticationManager.authenticate(tokenForDescriptionEditor);\r
+ context.setAuthentication(authentication);\r
+ securityException = null;\r
+ syn = Synonym.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);\r
+ synUuid = syn.getUuid();\r
+ try{\r
+ taxonService.saveOrUpdate(syn);\r
+ logger.debug("will commit ...");\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Expected failure of evaluation: " + securityException.getClass());\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+\r
+ Assert.assertNotNull("evaluation must fail since the user is not permitted", securityException);\r
+ Assert.assertNull("The Synonym must not be persited", taxonService.find(synUuid));\r
}\r
\r
@Test\r
- @Ignore //FIXME test must not fail !!!!!\r
public void testEditPartOfClassification(){\r
/*\r
* the user 'partEditor' has the following authorities:\r
* that is 'partEditor' is granted to edit the subtree of\r
* which ACHERONTIA_NODE_UUID [20c8f083-5870-4cbd-bf56-c5b2b98ab6a7] is the root node.\r
*/\r
- authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("partEditor", "test4"));\r
+\r
+ authentication = authenticationManager.authenticate(tokenForPartEditor);\r
SecurityContext context = SecurityContextHolder.getContext();\r
context.setAuthentication(authentication);\r
\r
// test for success\r
+ RuntimeException securityException = null;\r
TaxonNode acherontia_node = taxonNodeService.load(ACHERONTIA_NODE_UUID);\r
long numOfChildNodes = acherontia_node.getChildNodes().size();\r
TaxonNode childNode = acherontia_node.addChildTaxon(Taxon.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null), null, null, null);\r
- EvaluationFailedException evaluationFailedException = null;\r
+\r
try{\r
taxonNodeService.saveOrUpdate(acherontia_node);\r
commitAndStartNewTransaction(null);\r
} catch (RuntimeException e){\r
- evaluationFailedException = findEvaluationFailedExceptionIn(e);\r
- logger.debug("Unexpected failure of evaluation.", evaluationFailedException);\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Unexpected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
}\r
- Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + evaluationFailedException.getMessage(), evaluationFailedException);\r
+\r
+ acherontia_node = taxonNodeService.load(ACHERONTIA_NODE_UUID);\r
+ Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);\r
Assert.assertEquals("the acherontia_node must now have one more child node ", numOfChildNodes + 1 , acherontia_node.getChildNodes().size());\r
\r
// test for denial\r
- evaluationFailedException = null;\r
+ securityException = null;\r
TaxonNode acherontiini_node = taxonNodeService.load(ACHERONTIINI_NODE_UUID);\r
numOfChildNodes = acherontiini_node.getCountChildren();\r
acherontiini_node.addChildTaxon(Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()), null), null, null, null);\r
+\r
try{\r
+ logger.debug("==============================");\r
taxonNodeService.saveOrUpdate(acherontiini_node);\r
commitAndStartNewTransaction(null);\r
} catch (RuntimeException e){\r
- evaluationFailedException = findEvaluationFailedExceptionIn(e);\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Expected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
}\r
- Assert.assertNotNull("evaluation must fail since the user is not permitted", evaluationFailedException);\r
+\r
+ acherontiini_node = taxonNodeService.load(ACHERONTIINI_NODE_UUID);\r
+ Assert.assertNotNull("evaluation must fail since the user is not permitted", securityException);\r
Assert.assertEquals("the number of child nodes must be unchanged ", numOfChildNodes , acherontiini_node.getChildNodes().size());\r
\r
}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2011 EDIT\r
+ * European Distributed Institute of Taxonomy\r
+ * http://www.e-taxonomy.eu\r
+ *\r
+ * The contents of this file are subject to the Mozilla Public License Version 1.1\r
+ * See LICENSE.TXT at the top of this package for the full license terms.\r
+ */\r
+package eu.etaxonomy.cdm.api.service;\r
+\r
+import static org.junit.Assert.assertEquals;\r
+import static org.junit.Assert.assertTrue;\r
+\r
+import java.util.Collection;\r
+import java.util.Set;\r
+import java.util.UUID;\r
+\r
+import javax.sql.DataSource;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.junit.Assert;\r
+import org.junit.Before;\r
+import org.junit.Ignore;\r
+import org.junit.Test;\r
+import org.springframework.security.access.AccessDeniedException;\r
+import org.springframework.security.authentication.AuthenticationManager;\r
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\r
+import org.springframework.security.authentication.dao.ReflectionSaltSource;\r
+import org.springframework.security.authentication.dao.SaltSource;\r
+import org.springframework.security.authentication.encoding.Md5PasswordEncoder;\r
+import org.springframework.security.authentication.encoding.PasswordEncoder;\r
+import org.springframework.security.core.Authentication;\r
+import org.springframework.security.core.GrantedAuthority;\r
+import org.springframework.security.core.context.SecurityContext;\r
+import org.springframework.security.core.context.SecurityContextHolder;\r
+import org.springframework.transaction.PlatformTransactionManager;\r
+import org.unitils.database.annotations.TestDataSource;\r
+import org.unitils.dbunit.annotation.DataSet;\r
+import org.unitils.spring.annotation.SpringBean;\r
+import org.unitils.spring.annotation.SpringBeanByType;\r
+\r
+import eu.etaxonomy.cdm.database.EvaluationFailedException;\r
+import eu.etaxonomy.cdm.model.common.User;\r
+import eu.etaxonomy.cdm.model.description.DescriptionElementBase;\r
+import eu.etaxonomy.cdm.model.description.Distribution;\r
+import eu.etaxonomy.cdm.model.description.Feature;\r
+import eu.etaxonomy.cdm.model.description.TaxonDescription;\r
+import eu.etaxonomy.cdm.model.description.TextData;\r
+import eu.etaxonomy.cdm.model.name.BotanicalName;\r
+import eu.etaxonomy.cdm.model.name.Rank;\r
+import eu.etaxonomy.cdm.model.taxon.Synonym;\r
+import eu.etaxonomy.cdm.model.taxon.Taxon;\r
+import eu.etaxonomy.cdm.model.taxon.TaxonBase;\r
+import eu.etaxonomy.cdm.model.taxon.TaxonNode;\r
+import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator;\r
+import eu.etaxonomy.cdm.test.integration.CdmTransactionalIntegrationTestWithSecurity;\r
+\r
+\r
+@DataSet\r
+public class SecurityTest extends CdmTransactionalIntegrationTestWithSecurity{\r
+\r
+ private static final UUID UUID_ACHERONTINII = UUID.fromString("928a0167-98cd-4555-bf72-52116d067625");\r
+\r
+ private static final UUID UUID_ACHERONTIA_STYX = UUID.fromString("7b8b5cb3-37ba-4dba-91ac-4c6ffd6ac331");\r
+\r
+ private static final UUID PART_EDITOR_UUID = UUID.fromString("38a251bd-0ba4-426f-8fcb-5c09560749a7");\r
+\r
+ private static final String PASSWORD_TAXON_EDITOR = "test2";\r
+\r
+ private static final String PASSWORD_ADMIN = "sPePhAz6";\r
+\r
+ private static final UUID ACHERONTIA_NODE_UUID = UUID.fromString("20c8f083-5870-4cbd-bf56-c5b2b98ab6a7");\r
+\r
+ private static final UUID ACHERONTIINI_NODE_UUID = UUID.fromString("cecfa77f-f26a-4476-9d87-a8d993cb55d9");\r
+\r
+ private static final UUID ACHERONTIA_LACHESIS_UUID = UUID.fromString("bc09aca6-06fd-4905-b1e7-cbf7cc65d783");\r
+\r
+ private static final Logger logger = Logger.getLogger(SecurityTest.class);\r
+\r
+ /**\r
+ * The transaction manager to use\r
+ */\r
+ @SpringBeanByType\r
+ PlatformTransactionManager transactionManager;\r
+\r
+ @SpringBeanByType\r
+ private ITaxonService taxonService;\r
+\r
+ @SpringBeanByType\r
+ private ITaxonNodeService taxonNodeService;\r
+\r
+ @SpringBeanByType\r
+ private IDescriptionService descriptionService;\r
+\r
+ @SpringBeanByType\r
+ private IUserService userService;\r
+\r
+\r
+ @TestDataSource\r
+ protected DataSource dataSource;\r
+\r
+ private Authentication authentication;\r
+\r
+ @SpringBeanByType\r
+ private AuthenticationManager authenticationManager;\r
+\r
+ @SpringBeanByType\r
+ private SaltSource saltSource;\r
+\r
+ @SpringBeanByType\r
+ private PasswordEncoder passwordEncoder;\r
+\r
+ @SpringBean("cdmPermissionEvaluator")\r
+ private CdmPermissionEvaluator permissionEvaluator;\r
+\r
+ private UsernamePasswordAuthenticationToken tokenForAdmin;\r
+\r
+ private UsernamePasswordAuthenticationToken tokenForTaxonEditor;\r
+\r
+ private UsernamePasswordAuthenticationToken tokenForDescriptionEditor;\r
+\r
+ private UsernamePasswordAuthenticationToken tokenForPartEditor;\r
+\r
+ private UsernamePasswordAuthenticationToken tokenForTaxonomist;\r
+\r
+\r
+ @Before\r
+ public void setUp(){\r
+ /* User 'admin':\r
+ - ROLE_ADMIN\r
+ - ALL.ADMIN\r
+ - TAXONBASE.READ\r
+ - TAXONBASE.CREATE\r
+ - TAXONBASE.DELETE\r
+ - TAXONBASE.UPDATE\r
+ */\r
+ tokenForAdmin = new UsernamePasswordAuthenticationToken("admin", PASSWORD_ADMIN);\r
+\r
+ /* User 'taxonEditor':\r
+ - TAXONBASE.CREATE\r
+ - TAXONBASE.UPDATE\r
+ */\r
+ tokenForTaxonEditor = new UsernamePasswordAuthenticationToken("taxonEditor", PASSWORD_TAXON_EDITOR);\r
+\r
+ /* User 'descriptionEditor':\r
+ - DESCRIPTIONBASE.CREATE\r
+ - DESCRIPTIONBASE.UPDATE\r
+ - DESCRIPTIONELEMENT(Ecology).CREATE\r
+ - DESCRIPTIONELEMENT(Ecology).UPDATE\r
+ */\r
+ tokenForDescriptionEditor = new UsernamePasswordAuthenticationToken("descriptionEditor", "test");\r
+\r
+ /* User 'partEditor':\r
+ - TAXONBASE.ADMIN\r
+ - TAXONNODE.CREATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}\r
+ - TAXONNODE.UPDATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}\r
+ */\r
+ tokenForPartEditor = new UsernamePasswordAuthenticationToken("partEditor", "test4");\r
+\r
+ /* User 'taxonomist':\r
+ - TAXONBASE.READ\r
+ - TAXONBASE.CREATE\r
+ - TAXONBASE.DELETE\r
+ - TAXONBASE.UPDATE\r
+ */\r
+ tokenForTaxonomist = new UsernamePasswordAuthenticationToken("taxonomist", "test4");\r
+ }\r
+\r
+ /**\r
+ * no assertions in this test, since it is only used to create password hashes for test data\r
+ */\r
+ @Test\r
+ public void testEncryptPassword(){\r
+\r
+ String password = PASSWORD_ADMIN;\r
+ User user = User.NewInstance("admin", "");\r
+\r
+ Object salt = this.saltSource.getSalt(user);\r
+ String passwordEncrypted = passwordEncoder.encodePassword(password, salt);\r
+ logger.info("encrypted password: " + passwordEncrypted );\r
+ }\r
+\r
+ /**\r
+ * Test method for {@link eu.etaxonomy.cdm.api.service.TaxonServiceImpl#saveTaxon(eu.etaxonomy.cdm.model.taxon.TaxonBase)}.\r
+ */\r
+ @Test\r
+ public final void testSaveTaxon() {\r
+ /*\r
+ Md5PasswordEncoder encoder =new Md5PasswordEncoder();\r
+ ReflectionSaltSource saltSource = new ReflectionSaltSource();\r
+ saltSource.setUserPropertyToUse("getUsername");\r
+ User user = User.NewInstance("partEditor", "test4");\r
+ System.err.println(encoder.encodePassword("test4", saltSource.getSalt(user)));\r
+\r
+ */\r
+ authentication = authenticationManager.authenticate(tokenForAdmin);\r
+ SecurityContext context = SecurityContextHolder.getContext();\r
+ context.setAuthentication(authentication);\r
+\r
+ Taxon expectedTaxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);\r
+ UUID uuid = taxonService.save(expectedTaxon);\r
+ commitAndStartNewTransaction(null);\r
+ //taxonService.getSession().flush();\r
+ TaxonBase<?> actualTaxon = taxonService.load(uuid);\r
+ assertEquals(expectedTaxon, actualTaxon);\r
+\r
+ authentication = authenticationManager.authenticate(tokenForTaxonEditor);\r
+ context = SecurityContextHolder.getContext();\r
+ context.setAuthentication(authentication);\r
+ expectedTaxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()), null);\r
+ taxonService.saveOrUpdate(actualTaxon);\r
+ commitAndStartNewTransaction(null);\r
+\r
+ }\r
+\r
+ @Test\r
+ @Ignore //FIXME no need to test this, no access controll needed for userService.changePassword\r
+ public void testChangeOwnPassword(){\r
+\r
+ SecurityContext context = SecurityContextHolder.getContext();\r
+ // authenticate as admin\r
+ authentication = authenticationManager.authenticate(tokenForTaxonEditor);\r
+ context.setAuthentication(authentication);\r
+\r
+// User currentUser = (User) context.getAuthentication().getPrincipal();\r
+\r
+ String newPass = "poiweorijo";\r
+ userService.changePassword(PASSWORD_TAXON_EDITOR, newPass);\r
+ commitAndStartNewTransaction(null);\r
+\r
+ // try to re-authenticate user with changed password\r
+ UsernamePasswordAuthenticationToken newTokenForTaxonEditor = new UsernamePasswordAuthenticationToken("taxonEditor", newPass);\r
+ authentication = authenticationManager.authenticate(newTokenForTaxonEditor);\r
+ }\r
+\r
+ @Test\r
+ public void testChangeOthersPassword(){\r
+\r
+ SecurityContext context = SecurityContextHolder.getContext();\r
+ // (1) authenticate as admin\r
+ authentication = authenticationManager.authenticate(tokenForAdmin);\r
+ context.setAuthentication(authentication);\r
+\r
+ RuntimeException exception = null;\r
+\r
+ try{\r
+ userService.changePasswordForUser("taxonomist", "zuaisd");\r
+ commitAndStartNewTransaction(null);\r
+ } catch (AccessDeniedException e){\r
+ logger.error("Unexpected failure of evaluation.", e);\r
+ exception = e;\r
+ } catch (RuntimeException e){\r
+ exception = findThrowableOfTypeIn(EvaluationFailedException.class, e);\r
+ logger.debug("Unexpected failure of evaluation.", exception);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNull("must not fail here!", exception);\r
+\r
+ // ok, now try authenticating taxonomist with new password\r
+ UsernamePasswordAuthenticationToken newToken = new UsernamePasswordAuthenticationToken("taxonomist", "zuaisd");\r
+ authentication = authenticationManager.authenticate(newToken);\r
+\r
+ // (2) authenticate as under privileged user - not an admin !!!\r
+ authentication = authenticationManager.authenticate(tokenForDescriptionEditor);\r
+ context.setAuthentication(authentication);\r
+\r
+ // check test preconditions user name and authorities\r
+ Assert.assertEquals("descriptionEditor", context.getAuthentication().getName());\r
+ Collection<GrantedAuthority> authorities = context.getAuthentication().getAuthorities();\r
+ for(GrantedAuthority authority: authorities){\r
+ // role prefix 'ROLE_' is defined in org.springframework.security.access.vote.RoleVoter !!!\r
+ Assert.assertNotSame("user must not have authority 'ROLE_ADMIN'", "ROLE_ADMIN", authority.getAuthority());\r
+ }\r
+ // finally perform the test :\r
+ try{\r
+ userService.changePasswordForUser("partEditor", "poiweorijo");\r
+ commitAndStartNewTransaction(null);\r
+ } catch (AccessDeniedException e){\r
+ logger.debug("Expected failure of evaluation.", e);\r
+ exception = e;\r
+ } catch (RuntimeException e){\r
+ exception = findThrowableOfTypeIn(EvaluationFailedException.class, e);\r
+ logger.debug("Expected failure of evaluation.", exception);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNotNull("must fail here!", exception);\r
+ }\r
+\r
+ @Test\r
+ public void testUpdateUser(){\r
+\r
+ authentication = authenticationManager.authenticate(tokenForAdmin);\r
+ SecurityContext context = SecurityContextHolder.getContext();\r
+ context.setAuthentication(authentication);\r
+ String username = "standardUser";\r
+ String password = "pw";\r
+ User user = User.NewInstance(username, password);\r
+\r
+ userService.createUser(user);\r
+ user.setEmailAddress("test@bgbm.org");\r
+\r
+ userService.updateUser(user);\r
+ userService.update(user);\r
+ userService.saveOrUpdate(user);\r
+ commitAndStartNewTransaction(null);\r
+\r
+ }\r
+\r
+ @Test\r
+ public final void testSaveOrUpdateTaxon() {\r
+ SecurityContext context = SecurityContextHolder.getContext();\r
+\r
+ // 1) test with admin account - should succeed\r
+ authentication = authenticationManager.authenticate(tokenForAdmin);\r
+ context.setAuthentication(authentication);\r
+\r
+ TaxonBase<?> taxon = taxonService.load(UUID_ACHERONTIA_STYX);\r
+ taxon.setDoubtful(true);\r
+ RuntimeException securityException= null;\r
+ try{\r
+ taxonService.saveOrUpdate(taxon);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.error("Unexpected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);\r
+ // reload taxon\r
+ taxon = taxonService.load(UUID_ACHERONTIA_STYX);\r
+ Assert.assertTrue("The change must be persited", taxon.isDoubtful());\r
+\r
+ // 2) test with taxonEditor account - should succeed\r
+ authentication = authenticationManager.authenticate(tokenForTaxonEditor);\r
+ context.setAuthentication(authentication);\r
+\r
+ taxon = taxonService.load(UUID_ACHERONTIA_STYX);\r
+ taxon.setDoubtful(false);\r
+ securityException= null;\r
+ try{\r
+ taxonService.saveOrUpdate(taxon);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Unexpected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);\r
+ // reload taxon\r
+ taxon = taxonService.load(UUID_ACHERONTIA_STYX);\r
+ Assert.assertFalse("The change must be persited", taxon.isDoubtful());\r
+\r
+ // 3) test with tokenForDescriptionEditor account - should fail\r
+// authentication = authenticationManager.authenticate(tokenForTaxonEditor);\r
+// context.setAuthentication(authentication);\r
+// taxon = taxonService.load(uuid);\r
+//\r
+// taxon.setDoubtful(true);\r
+// taxonService.saveOrUpdate(taxon);\r
+// commitAndStartNewTransaction(null);\r
+\r
+ }\r
+\r
+ @Test\r
+ @Ignore //FIXME: adding taxa to a description must be protected at the side of the Description itself!!\r
+ // => protecting method TaxonDescription.setTaxon() ?\r
+ public void testAddDescriptionToTaxon(){\r
+\r
+ SecurityContext context = SecurityContextHolder.getContext();\r
+ authentication = authenticationManager.authenticate(tokenForDescriptionEditor);\r
+ context.setAuthentication(authentication);\r
+\r
+ RuntimeException securityException = null;\r
+\r
+ Taxon taxon = (Taxon)taxonService.load(ACHERONTIA_LACHESIS_UUID);\r
+\r
+ TaxonDescription description = TaxonDescription.NewInstance(taxon);\r
+ description.setTitleCache("test");\r
+ try {\r
+ descriptionService.saveOrUpdate(description);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Expected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ /*\r
+ * Expectation:\r
+ * The user should not be granted to add the Description to a taxon\r
+ */\r
+ Assert.assertNotNull("evaluation should fail since the user is not permitted to edit Taxa", securityException);\r
+ taxon = (Taxon)taxonService.load(ACHERONTIA_LACHESIS_UUID);\r
+ assertTrue(taxon.getDescriptions().contains(description));\r
+ }\r
+\r
+ @Test\r
+ public void testCreateDescriptionWithElement(){\r
+ authentication = authenticationManager.authenticate(tokenForDescriptionEditor);\r
+ SecurityContext context = SecurityContextHolder.getContext();\r
+ context.setAuthentication(authentication);\r
+\r
+ Taxon taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);\r
+ Assert.assertTrue("taxon must not yet have descriptions", taxon.getDescriptions().size() == 0);\r
+\r
+ TaxonDescription description = null;\r
+\r
+ // 1) test for failure - description element but no feature\r
+ description = TaxonDescription.NewInstance(taxon);\r
+ DescriptionElementBase textdataNoFeature = TextData.NewInstance();\r
+ description.addElement(textdataNoFeature);\r
+\r
+ RuntimeException securityException = null;\r
+ assertTrue(permissionEvaluator.hasPermission(authentication, description, "UPDATE"));\r
+ try{\r
+ descriptionService.saveOrUpdate(description);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Expected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+\r
+ Assert.assertNotNull("evaluation should fail", securityException);\r
+ taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);\r
+ Set<TaxonDescription> descriptions = taxon.getDescriptions();\r
+ assertTrue("taxon must not have any description", descriptions.size() == 0);\r
+\r
+ // 2) test for failure - description element but not granted feature\r
+ description = TaxonDescription.NewInstance(taxon);\r
+ DescriptionElementBase descriptionText = TextData.NewInstance(Feature.DESCRIPTION());\r
+ description.addElement(descriptionText);\r
+\r
+ securityException = null;\r
+ assertTrue(permissionEvaluator.hasPermission(authentication, description, "UPDATE"));\r
+ try{\r
+ descriptionService.saveOrUpdate(description);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Expected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+\r
+ Assert.assertNotNull("evaluation should fail", securityException);\r
+ taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);\r
+ descriptions = taxon.getDescriptions();\r
+ assertTrue("taxon must not have any description", descriptions.size() == 0);\r
+\r
+ // 3) test for failure\r
+ description = TaxonDescription.NewInstance(taxon);\r
+ DescriptionElementBase ecologyText = TextData.NewInstance(Feature.ECOLOGY());\r
+ description.addElement(ecologyText);\r
+\r
+ securityException = null;\r
+ assertTrue(permissionEvaluator.hasPermission(authentication, description, "UPDATE"));\r
+ try{\r
+ descriptionService.saveOrUpdate(description);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Unexpected failure of evaluation.", e);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+\r
+ Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);\r
+ taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);\r
+ descriptions = taxon.getDescriptions();\r
+ assertTrue("taxon must now have one description", descriptions.size() == 1);\r
+ assertTrue("description should have one description element", descriptions.iterator().next().getElements().size() == 1);\r
+\r
+ }\r
+\r
+ @Test\r
+ public void testSaveSynonym(){\r
+\r
+ SecurityContext context = SecurityContextHolder.getContext();\r
+\r
+ // 1) test for success\r
+ authentication = authenticationManager.authenticate(tokenForTaxonomist);\r
+ context.setAuthentication(authentication);\r
+\r
+ RuntimeException securityException = null;\r
+ Synonym syn = Synonym.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);\r
+ UUID synUuid = UUID.randomUUID();\r
+ syn.setUuid(synUuid);\r
+ try{\r
+ taxonService.saveOrUpdate(syn);\r
+ logger.debug("will commit ...");\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Unexpected failure of evaluation.", e);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+ Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);\r
+ Assert.assertNotNull("The new Synonym must be persited", taxonService.find(synUuid));\r
+\r
+ // 2) test for denial\r
+ authentication = authenticationManager.authenticate(tokenForDescriptionEditor);\r
+ context.setAuthentication(authentication);\r
+ securityException = null;\r
+ syn = Synonym.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);\r
+ synUuid = syn.getUuid();\r
+ try{\r
+ taxonService.saveOrUpdate(syn);\r
+ logger.debug("will commit ...");\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Expected failure of evaluation: " + securityException.getClass());\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+\r
+ Assert.assertNotNull("evaluation must fail since the user is not permitted", securityException);\r
+ Assert.assertNull("The Synonym must not be persited", taxonService.find(synUuid));\r
+ }\r
+\r
+ @Test\r
+<<<<<<< HEAD
+ @Ignore //FIXME test must not fail !!!!!\r
+=======
+>>>>>>> methodSecurityExpressions
+ public void testEditPartOfClassification(){\r
+ /*\r
+ * the user 'partEditor' has the following authorities:\r
+ *\r
+ * - TAXONNODE.CREATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}\r
+ * - TAXONNODE.UPDATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}\r
+ *\r
+ * that is 'partEditor' is granted to edit the subtree of\r
+ * which ACHERONTIA_NODE_UUID [20c8f083-5870-4cbd-bf56-c5b2b98ab6a7] is the root node.\r
+ */\r
+\r
+ authentication = authenticationManager.authenticate(tokenForPartEditor);\r
+ SecurityContext context = SecurityContextHolder.getContext();\r
+ context.setAuthentication(authentication);\r
+\r
+ // test for success\r
+ RuntimeException securityException = null;\r
+ TaxonNode acherontia_node = taxonNodeService.load(ACHERONTIA_NODE_UUID);\r
+ long numOfChildNodes = acherontia_node.getChildNodes().size();\r
+ TaxonNode childNode = acherontia_node.addChildTaxon(Taxon.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null), null, null, null);\r
+\r
+ try{\r
+ taxonNodeService.saveOrUpdate(acherontia_node);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Unexpected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+\r
+ acherontia_node = taxonNodeService.load(ACHERONTIA_NODE_UUID);\r
+ Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);\r
+ Assert.assertEquals("the acherontia_node must now have one more child node ", numOfChildNodes + 1 , acherontia_node.getChildNodes().size());\r
+\r
+ // test for denial\r
+ securityException = null;\r
+ TaxonNode acherontiini_node = taxonNodeService.load(ACHERONTIINI_NODE_UUID);\r
+ numOfChildNodes = acherontiini_node.getCountChildren();\r
+ acherontiini_node.addChildTaxon(Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()), null), null, null, null);\r
+\r
+ try{\r
+ logger.debug("==============================");\r
+ taxonNodeService.saveOrUpdate(acherontiini_node);\r
+ commitAndStartNewTransaction(null);\r
+ } catch (RuntimeException e){\r
+ securityException = findSecurityRuntimeException(e);\r
+ logger.debug("Expected failure of evaluation.", securityException);\r
+ } finally {\r
+ // needed in case saveOrUpdate was interrupted by the RuntimeException\r
+ // commitAndStartNewTransaction() would raise an UnexpectedRollbackException\r
+ endTransaction();\r
+ startNewTransaction();\r
+ }\r
+\r
+ acherontiini_node = taxonNodeService.load(ACHERONTIINI_NODE_UUID);\r
+ Assert.assertNotNull("evaluation must fail since the user is not permitted", securityException);\r
+ Assert.assertEquals("the number of child nodes must be unchanged ", numOfChildNodes , acherontiini_node.getChildNodes().size());\r
+\r
+ }\r
+\r
+ public static void main(String[] args){\r
+ Md5PasswordEncoder encoder =new Md5PasswordEncoder();\r
+\r
+ ReflectionSaltSource saltSource = new ReflectionSaltSource();\r
+ saltSource.setUserPropertyToUse("getUsername");\r
+ User user = User.NewInstance("taxonomist", "test4");\r
+ System.err.println(encoder.encodePassword("test4", saltSource.getSalt(user)));\r
+ }\r
+\r
+\r
+\r
+\r
+}\r
\r
@Before\r
public void setUp(){\r
- token = new UsernamePasswordAuthenticationToken("ben", "sPePhAz6");\r
+ token = new UsernamePasswordAuthenticationToken("admin", "sPePhAz6");\r
}\r
\r
@Test\r
import eu.etaxonomy.cdm.api.service.search.ICdmMassIndexer;\r
import eu.etaxonomy.cdm.api.service.search.SearchResult;\r
import eu.etaxonomy.cdm.common.monitor.DefaultProgressMonitor;\r
+import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;\r
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;\r
import eu.etaxonomy.cdm.model.common.Language;\r
import eu.etaxonomy.cdm.model.description.CategoricalData;\r
nameCache = ((NonViralName<?>) list.get(i)).getNameCache();\r
} else if (list.get(i) instanceof TaxonBase) {\r
TaxonNameBase taxonNameBase = ((TaxonBase) list.get(i)).getName();\r
- nameCache = ((NonViralName) taxonNameBase).getNameCache();\r
+ nameCache = HibernateProxyHelper.deproxy(taxonNameBase, NonViralName.class).getNameCache();\r
} else {\r
}\r
logger.debug(list.get(i).getClass() + "(" + i + ")" + ": Name Cache = " + nameCache + ", Title Cache = "\r
import eu.etaxonomy.cdm.model.name.BotanicalName;\r
import eu.etaxonomy.cdm.model.name.Rank;\r
import eu.etaxonomy.cdm.model.taxon.Taxon;\r
-import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermission;\r
+import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;\r
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator;\r
import eu.etaxonomy.cdm.persistence.query.MatchMode;\r
import eu.etaxonomy.cdm.test.integration.CdmIntegrationTest;\r
@DataSet\r
public void testHasPermission(){\r
Taxon taxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()),null);\r
- boolean hasPermission = taxonService.hasPermission(authentication, taxon, CdmPermission.UPDATE);\r
+ boolean hasPermission = taxonService.hasPermission(authentication, taxon, Operation.UPDATE);\r
assertFalse(hasPermission);\r
User testUser = User.NewInstance("username123", "1234");\r
- hasPermission = userService.hasPermission(authentication, testUser, CdmPermission.UPDATE);\r
+ hasPermission = userService.hasPermission(authentication, testUser, Operation.UPDATE);\r
assertTrue(hasPermission);\r
}\r
\r
<PERMISSIONGROUP_GRANTEDAUTHORITYIMPL PERMISSIONGROUP_ID="2" GRANTEDAUTHORITIES_ID="4"/>\r
<PERMISSIONGROUP_GRANTEDAUTHORITYIMPL PERMISSIONGROUP_ID="3" GRANTEDAUTHORITIES_ID="8"/>\r
<PERMISSIONGROUP_GRANTEDAUTHORITYIMPL PERMISSIONGROUP_ID="3" GRANTEDAUTHORITIES_ID="9"/>\r
- <!-- <PERMISSIONGROUP_GRANTEDAUTHORITYIMPL PERMISSIONGROUP_ID="3" GRANTEDAUTHORITIES_ID="10"/> -->\r
+ <PERMISSIONGROUP_GRANTEDAUTHORITYIMPL PERMISSIONGROUP_ID="3" GRANTEDAUTHORITIES_ID="10"/>\r
\r
\r
<GRANTEDAUTHORITYIMPL ID="1" UUID="441a3c40-0c84-11de-8c30-0800200c9a66" CREATED="2009-02-03 17:52:26.0" AUTHORITY="TAXONBASE.READ"/>\r
<GRANTEDAUTHORITYIMPL ID="4" UUID="e5354c0e-657b-4b4d-bb2f-791612199711" CREATED="2009-02-03 17:52:26.0" AUTHORITY="TAXONBASE.DELETE"/>\r
<GRANTEDAUTHORITYIMPL ID="10" UUID="2fbcbdd4-97f0-4561-b635-1e479dd00375" CREATED="2009-02-03 17:52:26.0" AUTHORITY="TAXONBASE.ADMIN"/>\r
<GRANTEDAUTHORITYIMPL ID="5" UUID="9eabd2c6-0590-4a1e-95f5-99cc58b63aa7" CREATED="2009-02-03 17:52:26.0" AUTHORITY="ALL.ADMIN"/>\r
+ <GRANTEDAUTHORITYIMPL ID="14" UUID="56eac992-67ba-40be-896c-4e992ca2afc0" CREATED="2009-02-03 17:52:26.0" AUTHORITY="ROLE_ADMIN"/><!-- role prefix 'ROLE_' defined in RoleVoter !!! -->\r
<GRANTEDAUTHORITYIMPL ID="7" UUID="2fc19d6c-a227-41d8-94e4-7c31accebc26" CREATED="2009-02-03 17:52:26.0" AUTHORITY="DESCRIPTIONBASE.UPDATE"/>\r
<GRANTEDAUTHORITYIMPL ID="13" UUID="2883374b-9556-4f3b-9b17-08fdf3d4bba6" CREATED="2009-02-03 17:52:26.0" AUTHORITY="DESCRIPTIONBASE.CREATE"/>\r
- <GRANTEDAUTHORITYIMPL ID="11" UUID="fc8088cf-cf96-42b6-9aa5-7c1ec5ccf145" CREATED="2009-02-03 17:52:26.0" AUTHORITY="DESCRIPTIONBASE.Ecology.UPDATE"/>\r
- <GRANTEDAUTHORITYIMPL ID="12" UUID="8d131171-d281-4911-a960-16992de384c7" CREATED="2009-02-03 17:52:26.0" AUTHORITY="DESCRIPTIONBASE.Ecology.CREATE"/>\r
+ <GRANTEDAUTHORITYIMPL ID="11" UUID="fc8088cf-cf96-42b6-9aa5-7c1ec5ccf145" CREATED="2009-02-03 17:52:26.0" AUTHORITY="DESCRIPTIONELEMENTBASE(Ecology).UPDATE"/>\r
+ <GRANTEDAUTHORITYIMPL ID="12" UUID="8d131171-d281-4911-a960-16992de384c7" CREATED="2009-02-03 17:52:26.0" AUTHORITY="DESCRIPTIONELEMENTBASE(Ecology).CREATE"/>\r
<GRANTEDAUTHORITYIMPL ID="8" UUID="45b40e93-88b0-40eb-92a4-ffdd8f1d7bc3" CREATED="2009-02-03 17:52:26.0" AUTHORITY="TAXONNODE.UPDATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}"/>\r
<GRANTEDAUTHORITYIMPL ID="9" UUID="8696ef0f-e98c-4842-b9d2-456b82584c25" CREATED="2009-02-03 17:52:26.0" AUTHORITY="TAXONNODE.CREATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}"/>\r
\r
- <USERACCOUNT USERNAME="ben" ID="1" CREATED="2009-06-18 13:47:59.0" UUID="e4acf200-63b6-11dd-ad8b-0800200c9a66" PASSWORD="e141bbb8bb7f4579aa3156fdbe0d1226" ENABLED="true" ACCOUNTNONEXPIRED="true" CREDENTIALSNONEXPIRED="true" ACCOUNTNONLOCKED="true"/>\r
+ <USERACCOUNT USERNAME="admin" ID="1" CREATED="2009-06-18 13:47:59.0" UUID="e4acf200-63b6-11dd-ad8b-0800200c9a66" PASSWORD="656a8bc965ac42adc800013e1a8612b9" ENABLED="true" ACCOUNTNONEXPIRED="true" CREDENTIALSNONEXPIRED="true" ACCOUNTNONLOCKED="true"/>\r
<USERACCOUNT USERNAME="descriptionEditor" ID="2" CREATED="2009-06-18 13:47:59.0" UUID="49efface-4c2b-40d2-84bb-e3915c0e77b1" PASSWORD="d211b476c3f3795f801c959fb9671b0c" ENABLED="true" ACCOUNTNONEXPIRED="true" CREDENTIALSNONEXPIRED="true" ACCOUNTNONLOCKED="true"/>\r
<USERACCOUNT USERNAME="taxonEditor" ID="3" CREATED="2009-06-18 13:47:59.0" UUID="56eac992-67ba-40be-896c-4e992ca2afc0" PASSWORD="c949cc3b8939be4643577db7e9830e5b" ENABLED="true" ACCOUNTNONEXPIRED="true" CREDENTIALSNONEXPIRED="true" ACCOUNTNONLOCKED="true"/>\r
<USERACCOUNT USERNAME="taxonomist" ID="4" CREATED="2009-06-18 13:47:59.0" UUID="0595de98-5e6e-4194-ab3b-3cb158716d4c" PASSWORD="3b49d0610ddde62faea639c35fb70a9c" ENABLED="true" ACCOUNTNONEXPIRED="true" CREDENTIALSNONEXPIRED="true" ACCOUNTNONLOCKED="true"/>\r
<USERACCOUNT USERNAME="partEditor" ID="5" CREATED="2009-06-18 13:47:59.0" UUID="38a251bd-0ba4-426f-8fcb-5c09560749a7" PASSWORD="41af8a6dac9f86b1081aa5840df75a53" ENABLED="true" ACCOUNTNONEXPIRED="true" CREDENTIALSNONEXPIRED="true" ACCOUNTNONLOCKED="true"/>\r
<USERACCOUNT_GRANTEDAUTHORITYIMPL USERACCOUNT_ID="1" GRANTEDAUTHORITIES_ID="5"/>\r
+ <USERACCOUNT_GRANTEDAUTHORITYIMPL USERACCOUNT_ID="1" GRANTEDAUTHORITIES_ID="14"/>\r
<USERACCOUNT_GRANTEDAUTHORITYIMPL USERACCOUNT_ID="2" GRANTEDAUTHORITIES_ID="7"/>\r
<USERACCOUNT_GRANTEDAUTHORITYIMPL USERACCOUNT_ID="2" GRANTEDAUTHORITIES_ID="11"/>\r
<USERACCOUNT_GRANTEDAUTHORITYIMPL USERACCOUNT_ID="2" GRANTEDAUTHORITIES_ID="13"/>\r
<CLASSIFICATION ID="1" CREATED="2009-06-18 13:47:59.0" UUID="aeee7448-5298-4991-b724-8d5b75a0a7a9" PROTECTEDTITLECACHE="false" TITLECACHE="TestBaum" NAME_ID="1"/>\r
<CLASSIFICATION_AUD ID="1" REV="1025" REVTYPE="0" CREATED="2009-06-18 13:47:59.0" UUID="aeee7448-5298-4991-b724-8d5b75a0a7a9" PROTECTEDTITLECACHE="false" TITLECACHE="TestBaum" NAME_ID="1"/>\r
\r
- <DESCRIPTIONBASE DTYPE="TaxonDescription" ID="3" CREATED="2009-06-25 18:26:26.0" UUID="eb17b80a-9be6-4642-a6a8-b19a318925e6" PROTECTEDTITLECACHE="true" TITLECACHE="desc3" IMAGEGALLERY="false" TAXON_ID="37"/>\r
+ <DESCRIPTIONBASE DTYPE="TaxonDescription" ID="3" CREATED="2009-06-25 18:26:26.0" UUID="eb17b80a-9be6-4642-a6a8-b19a318925e6" PROTECTEDTITLECACHE="true" TITLECACHE="desc3" IMAGEGALLERY="false" TAXON_ID="37"/>\r
<DESCRIPTIONELEMENTBASE DTYPE="TextData" ID="1" INDESCRIPTION_ID="3" CREATED="2008-12-10 09:56:07.0" UUID="31a0160a-51b2-4565-85cf-2be58cb561d6" UPDATED="2008-12-10 09:56:07.253" FEATURE_ID="940"/>\r
<DESCRIPTIONELEMENTBASE_LANGUAGESTRING DESCRIPTIONELEMENTBASE_ID="1" MULTILANGUAGETEXT_ID="2" MULTILANGUAGETEXT_MAPKEY_ID="406"/>\r
<LANGUAGESTRING ID="2" CREATED="2008-12-10 09:56:07.0" UUID="2a5ceebb-4830-4524-b330-78461bf8cb6b" UPDATED="2008-12-10 09:56:07.253" LANGUAGE_ID="352" TEXT="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/>\r
so we only need to add additional beans here:\r
-->\r
\r
+ <!--\r
+ we need to repeat the security configuration here only for test since it is disabled in\r
+ cdmlib-services/src/main/resources !!!\r
+ -->\r
<security:global-method-security pre-post-annotations="enabled">\r
<security:expression-handler ref="expressionHandler" />\r
</security:global-method-security>\r
\r
- <bean id="expressionHandler"\r
- class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">\r
+ <!--\r
+ To use "hasPermission()" in the Spring EL method annotations like @PreAuthorize we explicitly configure the permissionEvaluator\r
+ the cdmPermissionEvaluator is already defined in the persistence security context\r
+ -->\r
+ <bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">\r
<property name="permissionEvaluator" ref="cdmPermissionEvaluator" />\r
</bean>\r
\r
\r
- <bean class="eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator" id="cdmPermissionEvaluator" />\r
<bean id="userService" class="eu.etaxonomy.cdm.api.service.UserService">\r
</bean>\r
\r
-\r
<bean id="groupServiceImpl" class="eu.etaxonomy.cdm.api.service.GroupServiceImpl">\r
</bean>\r
+\r
</beans>\r
log4j.logger.eu.etaxonomy.cdm.test.function = info
log4j.logger.eu.etaxonomy.cdm.test.integration = info
log4j.logger.eu.etaxonomy.cdm.api.application = warn
-log4j.logger.eu.etaxonomy.cdm.api.service = info
+log4j.logger.eu.etaxonomy.cdm.api.service = debug
#log4j.logger.eu.etaxonomy.cdm.database.VocabularyStoreImpl = warn
#
log4j.logger.eu.etaxonomy.cdm.database.init = warn
+
### *** SPRING ************ ###
log4j.logger.org.springframework.transaction = warn
log4j.logger.org.hibernate.engine.LoadContexts = warn
#log4j.logger.org.dbunit.operation.DeleteAllOperation=debug
#### log spring security #####
-#log4j.logger.eu.etaxonomy.cdm.permission.CdmPermissionEvaluator=debug
+log4j.logger.eu.etaxonomy.cdm.persistence.hibernate.permission=debug
+log4j.logger.eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority=warn
+log4j.logger.eu.etaxonomy.cdm.persistence.hibernate.CdmSecurityHibernateInterceptor=debug
+log4j.logger.org.springframework.security.access.intercept=debug
+log4j.logger.org.springframework.security.access.vote=debug
+#log4j.logger.eu.etaxonomy.cdm.test.integration.CdmTransactionalIntegrationTest=debug
#### Lucene Fulltext index and cdmlib search facility####
#log4j.logger.org.apache.lucene=debug