/**
* Koya is an alfresco module that provides a corporate orientated dataroom.
*
* Copyright (C) Itl Developpement 2014
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see `<http://www.gnu.org/licenses/>`.
*/
package fr.itldev.koya.alfservice.security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.policy.ClassPolicyDelegate;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.invitation.InvitationService;
import org.alfresco.service.cmr.invitation.NominatedInvitation;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.transaction.TransactionService;
import org.apache.log4j.Logger;
import fr.itldev.koya.alfservice.CompanyService;
import fr.itldev.koya.alfservice.KoyaActivityPoster;
import fr.itldev.koya.alfservice.KoyaNodeService;
import fr.itldev.koya.alfservice.ModelService;
import fr.itldev.koya.alfservice.UserService;
import fr.itldev.koya.exception.KoyaServiceException;
import fr.itldev.koya.model.KoyaModel;
import fr.itldev.koya.model.KoyaNode;
import fr.itldev.koya.model.Permissions;
import fr.itldev.koya.model.exceptions.KoyaErrorCodes;
import fr.itldev.koya.model.impl.Company;
import fr.itldev.koya.model.impl.Dossier;
import fr.itldev.koya.model.impl.Space;
import fr.itldev.koya.model.impl.User;
import fr.itldev.koya.model.permissions.KoyaPermission;
import fr.itldev.koya.model.permissions.KoyaPermissionCollaborator;
import fr.itldev.koya.model.permissions.KoyaPermissionConsumer;
import fr.itldev.koya.model.permissions.SitePermission;
import fr.itldev.koya.policies.SharePolicies;
/**
* Spaces Permissions Service
*
*/
public class SpaceAclService {
private final Logger logger = Logger.getLogger(this.getClass());
protected PermissionService permissionService;
protected KoyaNodeService koyaNodeService;
protected NodeService nodeService;
protected AuthenticationService authenticationService;
protected AuthorityService authorityService;
protected SiteService siteService;
protected InvitationService invitationService;
protected UserService userService;
protected PolicyComponent policyComponent;
protected CompanyService companyService;
protected CompanyAclService companyAclService;
protected TransactionService transactionService;
protected FileFolderService fileFolderService;
protected KoyaActivityPoster koyaActivityPoster;
private ModelService modelService;
private OwnableService ownableService;
// sharing delegates
private ClassPolicyDelegate<SharePolicies.BeforeSharePolicy> beforeShareDelegate;
private ClassPolicyDelegate<SharePolicies.AfterSharePolicy> afterShareDelegate;
private ClassPolicyDelegate<SharePolicies.BeforeUnsharePolicy> beforeUnshareDelegate;
private ClassPolicyDelegate<SharePolicies.AfterUnsharePolicy> afterUnshareDelegate;
// <editor-fold defaultstate="collapsed" desc="getters/setters">
public void setPermissionService(PermissionService permissionService) {
this.permissionService = permissionService;
}
public void setKoyaNodeService(KoyaNodeService koyaNodeService) {
this.koyaNodeService = koyaNodeService;
}
public void setNodeService(NodeService nodeService) {
this.nodeService = nodeService;
}
public void setAuthenticationService(AuthenticationService authenticationService) {
this.authenticationService = authenticationService;
}
public void setAuthorityService(AuthorityService authorityService) {
this.authorityService = authorityService;
}
public void setSiteService(SiteService siteService) {
this.siteService = siteService;
}
public void setInvitationService(InvitationService invitationService) {
this.invitationService = invitationService;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
public void setPolicyComponent(PolicyComponent policyComponent) {
this.policyComponent = policyComponent;
}
public void setCompanyService(CompanyService companyService) {
this.companyService = companyService;
}
public void setCompanyAclService(CompanyAclService companyAclService) {
this.companyAclService = companyAclService;
}
public void setTransactionService(TransactionService transactionService) {
this.transactionService = transactionService;
}
public void setFileFolderService(FileFolderService fileFolderService) {
this.fileFolderService = fileFolderService;
}
public void setKoyaActivityPoster(KoyaActivityPoster koyaActivityPoster) {
this.koyaActivityPoster = koyaActivityPoster;
}
public void setModelService(ModelService modelService) {
this.modelService = modelService;
}
public void setOwnableService(OwnableService ownableService) {
this.ownableService = ownableService;
}
// </editor-fold>
/**
* Registers the share policies
*/
public void init() {
// Register the various policies
beforeShareDelegate = policyComponent
.registerClassPolicy(SharePolicies.BeforeSharePolicy.class);
afterShareDelegate = policyComponent
.registerClassPolicy(SharePolicies.AfterSharePolicy.class);
beforeUnshareDelegate = policyComponent
.registerClassPolicy(SharePolicies.BeforeUnsharePolicy.class);
afterUnshareDelegate = policyComponent
.registerClassPolicy(SharePolicies.AfterUnsharePolicy.class);
}
/*
* ========= Consumer Share ===============
*/
/**
* Share Space with Consumer defined by his email adress
*
* if user with such an email address, creates and invite him. Then grant
* Space permission KoyaPermissionConsumer.CLIENT by adding to corresponding
* group
*
* @param space
* @param userMail
* @return
* @throws KoyaServiceException
*/
public NominatedInvitation consumerShare(final Space space, final String userMail,
KoyaPermissionConsumer permission) throws KoyaServiceException {
User inviter = userService.getUserByUsername(authenticationService.getCurrentUserName());
logger.info("[Share] : {'user':'" + inviter.getEmail() + "','invitee':'" + userMail
+ "','koyaNode':'" + space.toString() + "','permission':'" + permission.toString()
+ "}");
beforeShareDelegate.get(nodeService.getType(space.getNodeRef()))
.beforeShareItem(space.getNodeRef(), userMail, inviter);
// Get company the shared Node belongs To
Company company = koyaNodeService.getFirstParentOfType(space.getNodeRef(), Company.class);
SitePermission userPermissionInCompany = null;
User u = null;
try {
u = userService.getUserByEmail(userMail);
} catch (KoyaServiceException kse) {
// silently catch exception
}
if (u != null) {
userPermissionInCompany = companyAclService.getSitePermission(company, u);
}
NominatedInvitation invitation = null;
// If user can't access specified company then invite him even if he
// already exists in alfresco
if (userPermissionInCompany == null) {
logger.info("[Invite] : {'invitee':'" + userMail + "','company':'" + company
+ "','permission':'" + SitePermission.CONSUMER + "}");
invitation = companyAclService.inviteMember(company, userMail, SitePermission.CONSUMER,
space);
u = userService.getUserByUsername(invitation.getInviteeUserName());
userPermissionInCompany = companyAclService.getSitePermission(company, u);
}
if (!userPermissionInCompany.equals(SitePermission.CONSUMER)) {
logger.error("Consumer Share not available for " + userPermissionInCompany.toString()
+ " users");
throw new KoyaServiceException(
KoyaErrorCodes.SECU_USER_MUSTBE_CONSUMER_TO_APPLY_PERMISSION);
}
/**
* User should not already have any permission on node
*
* User should not belong to any group which name contains Current Space
* nodeRef id (cf group naming policy)
*/
Set<String> authorities = authorityService.getAuthoritiesForUser(u.getUserName());
for (String a : authorities) {
if (a.contains(space.getNodeRef().getId())) {
throw new KoyaServiceException(
KoyaErrorCodes.SECU_USER_ALREADY_HAVE_PERMISSION_ON_SPACE);
}
}
addKoyaAuthority(space, permission, u);
afterShareDelegate.get(nodeService.getType(space.getNodeRef()))
.afterShareItem(space.getNodeRef(), u, inviter);
/**
* Post a Share activity using ShareSpaceActivityPoster
*/
koyaActivityPoster.postSpaceShared(u, inviter.getUserName(), space);
return invitation;
}
/**
* Remove KoyaPermissionConsumer. for user defined by email address
*
*
* @param space
* @param userMail
*/
public void consumerUnshare(final Space space, final String userMail,
KoyaPermissionConsumer permission) {
final User u = userService.getUserByEmail(userMail);
User revoker = userService.getUserByUsername(authenticationService.getCurrentUserName());
logger.info("[Unshare] : {'user':'" + revoker.getEmail() + "','unshared':'" + u.getEmail()
+ "','koyaNode':'" + space.toString() + "','permission':'"
+ (permission != null ? permission.toString() : "") + "}");
beforeUnshareDelegate.get(nodeService.getType(space.getNodeRef()))
.beforeUnshareItem(space.getNodeRef(), userMail, revoker);
// Gets the user involved in unsharing - throws exception if not found
if (permission != null) {
removeKoyaAuthority(space, permission, u);
} else {
logger.info("[Unshare] no permission given : try revoke any koya permission");
removeAnyKoyaAuthority(space, u);
}
afterUnshareDelegate.get(nodeService.getType(space.getNodeRef()))
.afterUnshareItem(space.getNodeRef(), u, revoker);
/**
* Post an Unshare activity using UnshareSpaceActivityPoster
*/
koyaActivityPoster.postSpaceUnshared(userMail, revoker.getUserName(), space);
}
/*
* * ========= Collaborator Share ===============
*/
public void collaboratorShare(Space space, User user, KoyaPermissionCollaborator perm)
throws KoyaServiceException {
/**
* TODO generate specific activity if necessary
*
* TODO use this method from web scripts if activity is generated.
* Currently only used from imports
*/
// Get company the shared Node belongs To
Company company = koyaNodeService.getFirstParentOfType(space.getNodeRef(), Company.class);
SitePermission userPermissionInCompany = companyAclService.getSitePermission(company, user);
// user should exist for company as a site Collaborator or site manager
// member
if (userPermissionInCompany.equals(SitePermission.COLLABORATOR)
|| userPermissionInCompany.equals(SitePermission.MANAGER)) {
addKoyaAuthority(space, perm, user);
} else {
logger.error("Collaborator Share not available for "
+ userPermissionInCompany.toString() + " users");
throw new KoyaServiceException(
KoyaErrorCodes.SECU_USER_MUSTBE_COLLABORATOR_OR_ADMIN_TO_APPLY_PERMISSION);
}
}
/*
* ========= Basics permissions and group Grant/revoke Methods=======
*/
public void addKoyaAuthority(Space space, KoyaPermission permission, User user) {
String groupName = "GROUP_" + space.getAuthorityName(permission.toString());
// first check if authority not already exists in group
if (authorityService.getContainedAuthorities(AuthorityType.USER, groupName, true)
.contains(user.getUserName())) {
return;
}
logger.info("[Grant] : {'user':'" + user.getEmail() + "','authority':'"
+ permission.toString() + "','koyaNode':'" + space.toString() + "','permission':'"
+ permission.toString() + "}");
authorityService.addAuthority(groupName, user.getUserName());
}
public void removeKoyaAuthority(Space space, KoyaPermission permission, User user) {
logger.info("[Revoke] : {'user':'" + user.getUserName() + "','koyaNode':'"
+ space.toString() + "','permission':'" + permission.toString() + "}");
authorityService.removeAuthority("GROUP_" + space.getAuthorityName(permission.toString()),
user.getUserName());
}
/**
* Iterates on all KoyaPermissions groups setted on space. Try to remove
* user from group.
*
* Do not test, better silently fail if any error
*
* @param s
* @param u
*/
public void removeAnyKoyaAuthority(Space s, User u) {
for (AccessPermission ap : permissionService.getAllSetPermissions(s.getNodeRef())) {
try {
String grpShortName = ap.getAuthority()
.substring(ap.getAuthority().lastIndexOf("_") + 1);
KoyaPermission kPerm = KoyaPermission.valueOf(grpShortName);
removeKoyaAuthority(s, kPerm, u);
} catch (Exception e) {
}
}
}
public Boolean hasMembers(Space s, KoyaPermission permission) throws KoyaServiceException {
try {
return !authorityService.getContainedAuthorities(AuthorityType.USER,
"GROUP_" + s.getAuthorityName(permission.toString()), true).isEmpty();
} catch (Exception e) {
logger.error("Trying to check if " + s.getName() + " has Members of type "
+ permission.toString() + " : " + e.toString());
return false;
}
}
/*
*
* ================= Spaces Listing methods ============================
*
*/
/**
* List all user available spaces per company
*
* TODO find a way to list only company related authorities : pre filter instead of post filter.
*
* @param u
* @return
*/
private List<Space> getUserAvailableSpaces(User u, Company co,
KoyaPermission permissionFilter) {
List<Space> spaces = new ArrayList<>();
Set<String> authorities = authorityService.getAuthoritiesForUser(u.getUserName());
for (String a : authorities) {
if (permissionFilter == null || a.endsWith(permissionFilter.toString())) {
Space s = getKoyaNodeFromGroupName(a);
if (s != null) {
/*
* Get parent company with system permissions.
*
* If this method is called by pending invitation user, he
* doesn't have any permission on site node but has on space
* : causes permissions exception.
*
*/
final NodeRef spaceNodeRef = s.getNodeRef();
Company parentCompany = AuthenticationUtil
.runAsSystem(new AuthenticationUtil.RunAsWork<Company>() {
@Override
public Company doWork() throws Exception {
return koyaNodeService.getFirstParentOfType(spaceNodeRef,
Company.class);
}
});
if (parentCompany != null && parentCompany.equals(co)) {
spaces.add(s);
}
}
}
}
return spaces;
}
public List<Space> getKoyaUserSpaces(User u, Company co){
return getUserAvailableSpaces(u,co,null);
}
/**
* Get all spaces a user can access with given Koya Permission. Limited to
* company scope
*
* @param u
* @return
*/
public List<Space> getKoyaUserSpaces(User u, KoyaPermission permission, Company c) {
return getUserAvailableSpaces(u,c,permission);
}
/**
* Get all spaces a user can access with any permission. Limited to company
* scope
*
* @param u
* @return
*/
public List<Space> getKoyaUserSpaces(User u, Company co, Class<? extends KoyaNode> typeFilter) {
List<Space> spaces = new ArrayList<>();
for(Space s:getUserAvailableSpaces(u,co,null)){
if (typeFilter == null || s.getClass().equals(typeFilter)) {
spaces.add(s);
}
}
return spaces;
}
/**
* Build KoyaNode that matches group name. Node Id is contained in koya
* Groups string
*
* Pattern is GROUP_<TYPE>_<NodeId>_<KoyaPermission>
*
* @param groupName
* @return
*/
private Space getKoyaNodeFromGroupName(String groupName) {
Pattern p = Pattern.compile("GROUP_.*_(.*)_.*");
try {
Matcher m = p.matcher(groupName);
if (m.find()) {
NodeRef n = new NodeRef("workspace://SpacesStore/" + m.group(1));
return koyaNodeService.getKoyaNode(n, Space.class);
}
} catch (Exception e) {
}
return null;
}
private KoyaPermission getKoyaPermissionFromGroupName(String groupName){
Pattern p = Pattern.compile("GROUP_.*_.*_(.*)");
try {
Matcher m = p.matcher(groupName);
if (m.find()) {
return KoyaPermission.valueOf(m.group(1));
}
} catch (Exception e) {
}
return null;
}
/**
* List users who have rolename role on space
*
* @param space
* @param roleName
* @return
*/
public List<User> listMembership(Space space, KoyaPermission permission) {
List<User> users = new ArrayList<User>();
// TODO user security
for (String username : authorityService.getContainedAuthorities(AuthorityType.USER,
"GROUP_" + space.getAuthorityName(permission.toString()), true)) {
users.add(userService.getUserByUsername(username));
}
return users;
}
/**
* List user authorities involved in permissions on defined node
*
* This method is used for defining activity notification receivers
*
* @param n
* @param permissions
* @return
*/
public Set<String> listUsersAuthorities(final NodeRef n,
final List<KoyaPermission> permissions) {
return AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Set<String>>() {
@Override
public Set<String> doWork() throws Exception {
// first select candidates authorities
// ie Groups which name ends with one of permissions in
// parameter
// Then add all contained user authorities
// cf permissions Groups implementation in
// SpaceAclService
Set<String> usersId = new HashSet<>();
for (AccessPermission ap : permissionService.getAllSetPermissions(n)) {
for (KoyaPermission p : permissions) {
if (ap.getAuthority().endsWith(p.toString())) {
usersId.addAll(authorityService.getContainedAuthorities(
AuthorityType.USER, ap.getAuthority(), true));
break;
}
}
}
return usersId;
}
});
}
/*
* ==================================================================
* =================== Init and delete node =========================
* ==================================================================
*/
/*
* TODO config loading
*/
private static Map<String, String> GROUP_SITE_PERMISSIONS_SPACE = new HashMap<String, String>() {
/**
*
*/
private static final long serialVersionUID = 1L;
{
put(SitePermission.MANAGER.toString(), SitePermission.MANAGER.toString());
put(SitePermission.CONTRIBUTOR.toString(), SitePermission.CONTRIBUTOR.toString());
put(SitePermission.COLLABORATOR.toString(), SitePermission.CONTRIBUTOR.toString());
}
};
private static Map<String, String> GROUP_SITE_PERMISSIONS_DOSSIER = new HashMap<String, String>() {
/**
*
*/
private static final long serialVersionUID = 1L;
{
put(SitePermission.MANAGER.toString(), SitePermission.MANAGER.toString());
put(SitePermission.CONTRIBUTOR.toString(), SitePermission.CONTRIBUTOR.toString());
put(SitePermission.COLLABORATOR.toString(), SitePermission.CONSUMER.toString());
}
};
private static Map<String, String> GROUP_KOYA_PERMISSIONS_SPACE = new HashMap<String, String>() {
/**
*
*/
private static final long serialVersionUID = 1L;
{
put("KoyaResponsible", "KoyaResponsible");
put("KoyaMember", "KoyaMember");
put("KoyaClient", "KoyaClient");
put("KoyaPartner", "KoyaPartner");
put("KoyaSpaceReader", "KoyaClient");
}
};
private static Map<String, String> GROUP_KOYA_PERMISSIONS_DOSSIER = new HashMap<String, String>() {
/**
*
*/
private static final long serialVersionUID = 1L;
{
put("KoyaResponsible", "KoyaResponsible");
put("KoyaMember", "KoyaMember");
put("KoyaClient", "KoyaClient");
put("KoyaPartner", "KoyaPartner");
}
};
private static String[] KOYARESPONSIBLES_BLACKLIST = { "admin", "" };
public void initSpaceAcl(final Space space) {
// getKoyaNodes Hierachy
List<KoyaNode> parents = koyaNodeService.getParentsList(space.getNodeRef(),
KoyaNodeService.NB_ANCESTOR_INFINTE);
Company c = null;
Space firstParentSpace = null;
try {
if (parents.get(0).getClass().isAssignableFrom(Company.class)) {
c = (Company) parents.get(0);
} else {
firstParentSpace = (Space) parents.get(0);
c = (Company) parents.get(parents.size() - 1);
}
} catch (Exception ex) {
logger.error("Error in node hierachy " + ex.toString());
}
// Clear the node inherited permissions
permissionService.setInheritParentPermissions(space.getNodeRef(), false);
Map<String, String> groupSitePermissions = null;
Map<String, String> groupKoyaPermissions = null;
if (Space.class.equals(space.getClass())) {
groupSitePermissions = GROUP_SITE_PERMISSIONS_SPACE;
groupKoyaPermissions = GROUP_KOYA_PERMISSIONS_SPACE;
} else if (Dossier.class.equals(space.getClass())) {
groupSitePermissions = GROUP_SITE_PERMISSIONS_DOSSIER;
groupKoyaPermissions = GROUP_KOYA_PERMISSIONS_DOSSIER;
} else {
logger.error(
"Error Applying default permissions on node creation - unhandled node type : "
+ space.getKtype());
return;
}
/*
* Setting default site permissions on node
*/
for (String permissionGroupName : groupSitePermissions.keySet()) {
permissionService.setPermission(space.getNodeRef(),
siteService.getSiteRoleGroup(c.getName(), permissionGroupName),
groupSitePermissions.get(permissionGroupName), true);
}
String nodeHierachyPath = buildHierachyPath(parents);
String tmpFirstParentSpaceAuthorityName = null;
if (firstParentSpace != null) {
tmpFirstParentSpaceAuthorityName = firstParentSpace.getAuthorityName("KoyaSpaceReader");
}
final String firstParentSpaceAuthorityName = tmpFirstParentSpaceAuthorityName;
/*
*
*
*
* Create master authority group for this node
*/
final String masterGroupAuthorityName = space.getAuthorityName(null);
final String masterGroupDispAuthorityName = buildGroupDispName(space, "", nodeHierachyPath);
// authority creation executed as System user
AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Void>() {
@Override
public Void doWork() throws Exception {
authorityService.createAuthority(AuthorityType.GROUP, masterGroupAuthorityName,
masterGroupDispAuthorityName, null);
// Add this authority to parent KoyaSpaceReader
// authority to allow
// listing permission
if (firstParentSpaceAuthorityName != null) {
authorityService.addAuthority("GROUP_" + firstParentSpaceAuthorityName,
"GROUP_" + masterGroupAuthorityName);
}
return null;
}
});
/*
* Create Groups and Setting default koya permissions on node
*/
for (String permissionGroupName : groupKoyaPermissions.keySet()) {
final String authorityName = space.getAuthorityName(permissionGroupName);
final String dispAuthorityName = buildGroupDispName(space, permissionGroupName,
nodeHierachyPath);
// authority creation executed as System user
AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Void>() {
@Override
public Void doWork() throws Exception {
authorityService.createAuthority(AuthorityType.GROUP, authorityName,
dispAuthorityName, null);
// Add to master authority group for this node
authorityService.addAuthority("GROUP_" + masterGroupAuthorityName,
"GROUP_" + authorityName);
return null;
}
});
// set permission on node
permissionService.setPermission(space.getNodeRef(), "GROUP_" + authorityName,
groupKoyaPermissions.get(permissionGroupName), true);
}
/**
* On node creation, creator is set a responsible if he doesn't belongs
* responsibles blacklist
*
*/
final String spaceResponsiblesGroupName = "GROUP_"
+ space.getAuthorityName("KoyaResponsible");
final String creator = (String) nodeService.getProperty(space.getNodeRef(),
ContentModel.PROP_CREATOR);
if (creator != null && !Arrays.asList(KOYARESPONSIBLES_BLACKLIST).contains(creator)
&& !creator.equals(modelService.getCompanyImporterUsername(c.getName()))) {
AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Void>() {
@Override
public Void doWork() throws Exception {
authorityService.addAuthority(spaceResponsiblesGroupName, creator);
return null;
}
});
}
/*
* Remove node owner. If no owner, node permission can be disable for
* creator.
*/
AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Void>() {
@Override
public Void doWork() throws Exception {
ownableService.setOwner(space.getNodeRef(), OwnableService.NO_OWNER);
return null;
}
});
}
/**
*
* @param dossier
* @param koyaClientDir
*/
public void initSingleDossierSiteConsumerUploadDirAcl(Dossier dossier, NodeRef koyaClientDir) {
permissionService.setPermission(koyaClientDir,
"GROUP_" + dossier.getAuthorityName(KoyaPermissionCollaborator.MEMBER.toString()),
KoyaPermissionCollaborator.MEMBER.toString(), true);
permissionService.setPermission(koyaClientDir,
"GROUP_" + dossier
.getAuthorityName(KoyaPermissionCollaborator.RESPONSIBLE.toString()),
KoyaPermissionCollaborator.RESPONSIBLE.toString(), true);
permissionService.setPermission(koyaClientDir,
"GROUP_" + dossier.getAuthorityName("KoyaClient"),
SitePermission.CONTRIBUTOR.toString(), true);
permissionService.setPermission(koyaClientDir,
"GROUP_" + dossier.getAuthorityName("KoyaPartner"),
SitePermission.CONTRIBUTOR.toString(), true);
}
public void initConsumerUploadedDocument(Dossier dossier, NodeRef documentNodeRef) {
permissionService.setInheritParentPermissions(documentNodeRef, false);
permissionService.setPermission(documentNodeRef,
"GROUP_" + dossier.getAuthorityName(KoyaPermissionCollaborator.MEMBER.toString()),
KoyaPermissionCollaborator.MEMBER.toString(), true);
permissionService.setPermission(documentNodeRef,
"GROUP_" + dossier
.getAuthorityName(KoyaPermissionCollaborator.RESPONSIBLE.toString()),
KoyaPermissionCollaborator.RESPONSIBLE.toString(), true);
}
/**
* Remove all koya Specific authorities Group setted on space
*
* TODO chained deletion if deleted item is a Space.class Object and have
* child dossier (impossible now)
*
* @param space
*/
public void removeAllKoyaGroups(Space space) {
for (AccessPermission ap : permissionService.getAllSetPermissions(space.getNodeRef())) {
try {
String grpShortName = ap.getAuthority()
.substring(ap.getAuthority().lastIndexOf("_") + 1);
KoyaPermission kPerm = KoyaPermission.valueOf(grpShortName);
if (kPerm != null) {
authorityService.deleteAuthority(ap.getAuthority());
}
} catch (Exception e) {
}
}
// delete master node group authority
final String masterGroupAuthorityName = "GROUP_" + space.getAuthorityName(null);
authorityService.deleteAuthority(masterGroupAuthorityName);
}
/*
*
* ================= Private Group Building helpers ==================
*/
private String buildGroupDispName(Space s, String roleName, String hierachyPath) {
String dispName = s.getKtype() + " " + s.getName() + " " + roleName;
if (!hierachyPath.isEmpty()) {
dispName += "(" + hierachyPath + ")";
}
return dispName;
}
private String buildHierachyPath(List<KoyaNode> parents) {
String hierachy = "";
String sep = "";
for (KoyaNode n : parents) {
hierachy += sep + n.getName();
sep = "/";
}
return hierachy;
}
/*
*
* ================= Permissions Getting Methods ==================
*/
/**
* Return user permission set for user on node
* @param s
* @param u
* @return
*/
public KoyaPermission getKoyaPermission(Space s,User u){
Set<String> userAuths = authorityService.getAuthoritiesForUser(u.getUserName());
for (AccessPermission ap : permissionService.getAllSetPermissions(s.getNodeRef())) {
if(userAuths.contains(ap.getAuthority())){
return getKoyaPermissionFromGroupName(ap.getAuthority());
}
}
return null;
}
/**
* Builds Koya permissions on given NodeRef for authenticated user.
*
* @param n
* @return
* @throws fr.itldev.koya.exception.KoyaServiceException
*/
public Permissions getPermissions(NodeRef n) throws KoyaServiceException {
Permissions p = new Permissions(authenticationService.getCurrentUserName(), n);
Set<String> userGroups = authorityService.getAuthoritiesForUser(authenticationService.getCurrentUserName());
List<String> userPermissions = new ArrayList<>();
for (AccessPermission ap : permissionService.getAllSetPermissions(n)) {
try {
if(ap.getAccessStatus().equals(AccessStatus.ALLOWED) && userGroups.contains(ap.getAuthority())){
userPermissions.add(ap.getPermission());
}
} catch (IllegalArgumentException iex) {
}
}
//
p.canReadProperties(permissionService.hasPermission(n, PermissionService.READ_PROPERTIES)
.equals(AccessStatus.ALLOWED));
p.canWriteProperties(permissionService.hasPermission(n, PermissionService.WRITE_PROPERTIES)
.equals(AccessStatus.ALLOWED));
//
p.canCreateChildren(permissionService.hasPermission(n, PermissionService.CREATE_CHILDREN)
.equals(AccessStatus.ALLOWED));
p.canDeleteChildren(permissionService.hasPermission(n, PermissionService.DELETE_CHILDREN)
.equals(AccessStatus.ALLOWED));
p.canReadChildren(permissionService.hasPermission(n, PermissionService.READ_CHILDREN)
.equals(AccessStatus.ALLOWED));
p.canLinkChildren(permissionService.hasPermission(n, PermissionService.LINK_CHILDREN)
.equals(AccessStatus.ALLOWED));
//
p.canReadContent(permissionService.hasPermission(n, PermissionService.READ_CONTENT)
.equals(AccessStatus.ALLOWED));
p.canWriteContent(permissionService.hasPermission(n, PermissionService.WRITE_CONTENT)
.equals(AccessStatus.ALLOWED));
p.canExecuteContent(permissionService.hasPermission(n, PermissionService.EXECUTE_CONTENT)
.equals(AccessStatus.ALLOWED));
//
/**
* Specific permissions on containers. KoyaMember can not delete this type of node.
* TODO
* This is a workaround to avoid defining complex permissions. We have to change permissions
* scheme in order to prevent KoyaMember can delete Containers node but can delete child nodes.
*/
Boolean canDelNode = permissionService.hasPermission(n, PermissionService.DELETE_NODE)
.equals(AccessStatus.ALLOWED);
if (nodeService.getType(n).equals(KoyaModel.TYPE_DOSSIER)
|| nodeService.getType(n).equals(KoyaModel.TYPE_SPACE)) {
p.canDeleteNode(canDelNode
&& !userPermissions.contains(KoyaPermissionCollaborator.MEMBER.toString()));
} else {
p.canDeleteNode(canDelNode);
}
//
p.canDeleteAssociations(
permissionService.hasPermission(n, PermissionService.DELETE_ASSOCIATIONS)
.equals(AccessStatus.ALLOWED));
p.canReadAssociations(
permissionService.hasPermission(n, PermissionService.READ_ASSOCIATIONS)
.equals(AccessStatus.ALLOWED));
p.canCreateAssociations(
permissionService.hasPermission(n, PermissionService.CREATE_ASSOCIATIONS)
.equals(AccessStatus.ALLOWED));
//
p.canReadPermissions(permissionService.hasPermission(n, PermissionService.READ_PERMISSIONS)
.equals(AccessStatus.ALLOWED));
p.canChangePermissions(
permissionService.hasPermission(n, PermissionService.CHANGE_PERMISSIONS)
.equals(AccessStatus.ALLOWED));
/*
* ======= Koya specific permissions ========
*/
p.canShareWithCustomers(p.getCanChangePermissions()
|| userPermissions.contains(KoyaPermissionCollaborator.MEMBER.toString()));
p.canUploadAsConsumer(userPermissions.contains(KoyaPermissionConsumer.CLIENT.toString())
|| userPermissions.contains(KoyaPermissionConsumer.PARTNER.toString()));
return p;
}
/*
*
* ================= Confidential Space methods ==================
*/
/**
* Set or unset confidential flag on Space (ie Space or dossier)
*
* puts or removes koyaConfidential aspect on node and change collaborators
* permissions.
*
* On confidential elements, collaborators don't have any default access.
*
* @param u
* @param i
* @throws KoyaServiceException
*/
public Boolean toggleConfidential(Space space, Boolean confidential)
throws KoyaServiceException {
User u = userService.getUserByUsername(authenticationService.getCurrentUserName());
Company c = koyaNodeService.getFirstParentOfType(space.getNodeRef(), Company.class);
// check user permissions
// only manager or element responsibles can toggle confidential aspect
// on item
List<User> itemResponsibles = listMembership(space, KoyaPermissionCollaborator.RESPONSIBLE);
if (!(itemResponsibles.contains(u) || companyAclService.isCompanyManager(c.getName())
|| authorityService.isAdminAuthority(u.getUserName()))) {
/**
* User must either reponsable of element OR company Manager OR
* Alfresco Administrator
*/
throw new KoyaServiceException(KoyaErrorCodes.SECU_CONFIDENTIAL_USER_CANT_TOGGLE_FLAG);
}
// modify permissions
if (confidential) {
nodeService.addAspect(space.getNodeRef(), KoyaModel.ASPECT_CONFIDENTIAL, null);
permissionService.clearPermission(space.getNodeRef(), siteService
.getSiteRoleGroup(c.getName(), SitePermission.COLLABORATOR.toString()));
} else {
nodeService.removeAspect(space.getNodeRef(), KoyaModel.ASPECT_CONFIDENTIAL);
permissionService.setPermission(space.getNodeRef(),
siteService.getSiteRoleGroup(c.getName(),
SitePermission.COLLABORATOR.toString()),
SitePermission.CONSUMER.toString(), true);
}
return isConfidential(space);
}
public Boolean isConfidential(KoyaNode i) throws KoyaServiceException {
return nodeService.hasAspect(i.getNodeRef(), KoyaModel.ASPECT_CONFIDENTIAL);
}
}