Commit 9d74d5e2 authored by Matija Obreza's avatar Matija Obreza

Merge branch 'owner-entity-permissions-on-folders' into 'master'

RepositoryFolder: inherit permissions from alternative ACL OID

See merge request !28
parents d514b734 e2b2fa91
...@@ -139,6 +139,13 @@ ...@@ -139,6 +139,13 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<version>${spring.security.version}</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>javax.inject</groupId> <groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId> <artifactId>javax.inject</artifactId>
......
...@@ -35,6 +35,7 @@ import javax.persistence.Transient; ...@@ -35,6 +35,7 @@ import javax.persistence.Transient;
import org.genesys.blocks.model.JsonViews; import org.genesys.blocks.model.JsonViews;
import org.genesys.blocks.model.UuidModel; import org.genesys.blocks.model.UuidModel;
import org.genesys.blocks.security.model.AclAwareModel; import org.genesys.blocks.security.model.AclAwareModel;
import org.genesys.blocks.security.model.AclObjectIdentity;
import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.InvalidRepositoryPathException;
import org.genesys.filerepository.service.impl.PathValidator; import org.genesys.filerepository.service.impl.PathValidator;
import org.hibernate.annotations.Type; import org.hibernate.annotations.Type;
...@@ -115,6 +116,11 @@ public class RepositoryFolder extends UuidModel implements AclAwareModel { ...@@ -115,6 +116,11 @@ public class RepositoryFolder extends UuidModel implements AclAwareModel {
@Transient @Transient
private Path folderPath; private Path folderPath;
/** The parent ACL OID */
@JsonIgnore
@ManyToOne(cascade = {}, fetch = FetchType.LAZY)
private AclObjectIdentity parentOid;
/** /**
* Pre persist. * Pre persist.
*/ */
...@@ -135,6 +141,11 @@ public class RepositoryFolder extends UuidModel implements AclAwareModel { ...@@ -135,6 +141,11 @@ public class RepositoryFolder extends UuidModel implements AclAwareModel {
public AclAwareModel aclParentObject() { public AclAwareModel aclParentObject() {
return this.parent; return this.parent;
} }
@Override
public AclObjectIdentity aclParentObjectIdentity() {
return this.parentOid;
}
/** /**
* Gets the parent. * Gets the parent.
...@@ -154,6 +165,24 @@ public class RepositoryFolder extends UuidModel implements AclAwareModel { ...@@ -154,6 +165,24 @@ public class RepositoryFolder extends UuidModel implements AclAwareModel {
this.parent = parent; this.parent = parent;
} }
/**
* Sets the ACL parent object identity of the folder.
*
* @param parentOid the new parent OID
*/
public void setParentOid(AclObjectIdentity parentOid) {
this.parentOid = parentOid;
}
/**
* Gets the ACL parent object identity of the folder.
*
* @return the parent OID
*/
public AclObjectIdentity getParentOid() {
return parentOid;
}
/** /**
* Gets the children. * Gets the children.
* *
......
...@@ -22,6 +22,7 @@ import java.util.List; ...@@ -22,6 +22,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.genesys.blocks.security.model.AclAwareModel;
import org.genesys.filerepository.FolderNotEmptyException; import org.genesys.filerepository.FolderNotEmptyException;
import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryFileDataException;
import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.InvalidRepositoryPathException;
...@@ -302,6 +303,16 @@ public interface RepositoryService { ...@@ -302,6 +303,16 @@ public interface RepositoryService {
*/ */
RepositoryFolder ensureFolder(Path path) throws InvalidRepositoryPathException; RepositoryFolder ensureFolder(Path path) throws InvalidRepositoryPathException;
/**
* Ensure folder exists with specified ACL parent object
*
* @param path the folder path in repository
* @param aclParentObject business entity "owning" the folder
* @return
* @throws InvalidRepositoryPathException
*/
RepositoryFolder ensureFolder(Path path, AclAwareModel aclParentObject) throws InvalidRepositoryPathException;
/** /**
* Delete an empty folder (no children, no files). * Delete an empty folder (no children, no files).
* *
......
...@@ -34,6 +34,8 @@ import javax.imageio.ImageIO; ...@@ -34,6 +34,8 @@ import javax.imageio.ImageIO;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.apache.tika.Tika; import org.apache.tika.Tika;
import org.genesys.blocks.security.SecurityContextUtil; import org.genesys.blocks.security.SecurityContextUtil;
import org.genesys.blocks.security.model.AclAwareModel;
import org.genesys.blocks.security.service.CustomAclService;
import org.genesys.filerepository.FolderNotEmptyException; import org.genesys.filerepository.FolderNotEmptyException;
import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryFileDataException;
import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.InvalidRepositoryPathException;
...@@ -96,6 +98,10 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea ...@@ -96,6 +98,10 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
@Autowired @Autowired
private BytesStorageService bytesStorageService; private BytesStorageService bytesStorageService;
/** The ACL service */
@Autowired
private CustomAclService aclService;
/* /*
* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
...@@ -805,6 +811,51 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea ...@@ -805,6 +811,51 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
return folderRepository.findByPath(nPath.toString()); return folderRepository.findByPath(nPath.toString());
} }
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR')")
public RepositoryFolder ensureFolder(Path folderPath, AclAwareModel parentEntity) throws InvalidRepositoryPathException {
assert(folderPath != null);
assert(parentEntity != null);
PathValidator.checkValidPath(folderPath);
folderPath = folderPath.normalize().toAbsolutePath();
PathValidator.checkValidPath(folderPath.toString());
if ("/".equals(folderPath.toString())) {
// Root folder
if (! SecurityContextUtil.hasRole("ADMINISTRATOR")) {
// Only administrator can create folders on root
throw new AccessDeniedException("No WRITE permission on /");
}
return null;
} else {
PathValidator.checkValidFolderName(folderPath.getFileName().toString());
}
RepositoryFolder folder = folderRepository.findByPath(folderPath.toString());
if (folder == null) {
// Create new folder
folder = new RepositoryFolder();
folder.setName(folderPath.getFileName().toString());
// This checks permissions on parent, but we're running as ADMIN
folder.setParent(ensureFolder(folderPath.getParent()));
folder.setParentOid(aclService.getObjectIdentity(parentEntity));
if (folder.getParentOid() == null) {
throw new RuntimeException("Parent entity does not have an ACL OID: " + parentEntity);
}
folder = folderRepository.save(folder);
} else {
// Update parent OID
folder.setParentOid(aclService.getObjectIdentity(parentEntity));
folder = folderRepository.save(folder);
}
return folder;
}
/* /*
* (non-Javadoc) * (non-Javadoc)
......
...@@ -49,7 +49,7 @@ import com.querydsl.jpa.impl.JPAQueryFactory; ...@@ -49,7 +49,7 @@ import com.querydsl.jpa.impl.JPAQueryFactory;
@PropertySources({ @PropertySource("classpath:/spring/spring.properties"), @PropertySource("classpath:/application.properties") }) @PropertySources({ @PropertySource("classpath:/spring/spring.properties"), @PropertySource("classpath:/application.properties") })
@EnableTransactionManagement @EnableTransactionManagement
@EnableJpaRepositories(basePackages = { "org.genesys.blocks.model", @EnableJpaRepositories(basePackages = { "org.genesys.blocks.model",
"org.genesys.filerepository.persistence" }, entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager") "org.genesys.filerepository.persistence", "org.genesys.blocks.security.persistence" }, entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager")
public class DatabaseConfig { public class DatabaseConfig {
/** The env. */ /** The env. */
...@@ -108,7 +108,7 @@ public class DatabaseConfig { ...@@ -108,7 +108,7 @@ public class DatabaseConfig {
bean.setDataSource(dataSource()); bean.setDataSource(dataSource());
bean.setPersistenceUnitName("spring-jpa"); bean.setPersistenceUnitName("spring-jpa");
bean.setPackagesToScan("org.genesys.filerepository.model"); bean.setPackagesToScan("org.genesys.filerepository.model", "org.genesys.blocks.security.model");
bean.setPersistenceProvider(new HibernatePersistenceProvider()); bean.setPersistenceProvider(new HibernatePersistenceProvider());
final HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter(); final HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
......
...@@ -19,6 +19,8 @@ package org.genesys.filerepository.config; ...@@ -19,6 +19,8 @@ package org.genesys.filerepository.config;
import java.io.File; import java.io.File;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.genesys.blocks.security.service.CustomAclService;
import org.genesys.blocks.security.service.impl.CustomAclServiceImpl;
import org.genesys.filerepository.service.BytesStorageService; import org.genesys.filerepository.service.BytesStorageService;
import org.genesys.filerepository.service.ImageGalleryService; import org.genesys.filerepository.service.ImageGalleryService;
import org.genesys.filerepository.service.RepositoryService; import org.genesys.filerepository.service.RepositoryService;
...@@ -166,4 +168,8 @@ public class ServiceBeanConfig implements InitializingBean, DisposableBean { ...@@ -166,4 +168,8 @@ public class ServiceBeanConfig implements InitializingBean, DisposableBean {
return new ThumbnailGenerator1(); return new ThumbnailGenerator1();
} }
@Bean
public CustomAclService aclService() {
return new CustomAclServiceImpl();
}
} }
...@@ -29,3 +29,4 @@ log4j.category.org.genesys.filerepository=info ...@@ -29,3 +29,4 @@ log4j.category.org.genesys.filerepository=info
# Internal Hibernate logging is at ERROR # Internal Hibernate logging is at ERROR
log4j.category.org.hibernate.engine.jdbc=fatal log4j.category.org.hibernate.engine.jdbc=fatal
log4j.category.org.genesys.blocks.security.SecurityContextUtil=error
...@@ -65,6 +65,13 @@ ...@@ -65,6 +65,13 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<version>${spring.security.version}</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>commons-net</groupId> <groupId>commons-net</groupId>
<artifactId>commons-net</artifactId> <artifactId>commons-net</artifactId>
...@@ -73,6 +80,12 @@ ...@@ -73,6 +80,12 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.genesys-pgr</groupId>
<artifactId>application-blocks-security</artifactId>
<version>1.5-SNAPSHOT</version>
</dependency>
<dependency> <dependency>
<groupId>org.genesys-pgr</groupId> <groupId>org.genesys-pgr</groupId>
<artifactId>file-repository-core</artifactId> <artifactId>file-repository-core</artifactId>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment