com.jaspersoft.jasperserver.remote.services.impl.PermissionsServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.jasperserver.remote.services.impl.PermissionsServiceImpl.java

Source

/*
 * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com.
 *
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 *
 * 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 com.jaspersoft.jasperserver.remote.services.impl;

import com.jaspersoft.jasperserver.api.common.domain.ExecutionContext;
import com.jaspersoft.jasperserver.api.common.domain.impl.ExecutionContextImpl;
import com.jaspersoft.jasperserver.api.metadata.common.domain.InternalURI;
import com.jaspersoft.jasperserver.api.metadata.common.domain.Resource;
import com.jaspersoft.jasperserver.api.metadata.common.service.RepositoryService;
import com.jaspersoft.jasperserver.api.metadata.common.service.ResourceFactory;
import com.jaspersoft.jasperserver.api.metadata.common.service.impl.hibernate.PersistentObjectResolver;
import com.jaspersoft.jasperserver.api.metadata.security.JasperServerAclEntry;
import com.jaspersoft.jasperserver.api.metadata.user.domain.ObjectPermission;
import com.jaspersoft.jasperserver.api.metadata.user.domain.Role;
import com.jaspersoft.jasperserver.api.metadata.user.domain.TenantQualified;
import com.jaspersoft.jasperserver.api.metadata.user.domain.User;
import com.jaspersoft.jasperserver.api.metadata.user.domain.client.ObjectPermissionImpl;
import com.jaspersoft.jasperserver.api.metadata.user.domain.client.RoleImpl;
import com.jaspersoft.jasperserver.api.metadata.user.domain.client.UserImpl;
import com.jaspersoft.jasperserver.api.metadata.user.domain.impl.client.MetadataUserDetails;
import com.jaspersoft.jasperserver.api.metadata.user.service.ObjectPermissionService;
import com.jaspersoft.jasperserver.api.metadata.user.service.UserAuthorityService;
import com.jaspersoft.jasperserver.api.metadata.user.service.impl.AclService;
import com.jaspersoft.jasperserver.api.metadata.user.service.impl.ObjectPermissionServiceImpl;
import com.jaspersoft.jasperserver.remote.exception.AccessDeniedException;
import com.jaspersoft.jasperserver.remote.exception.IllegalParameterValueException;
import com.jaspersoft.jasperserver.remote.exception.ModificationNotAllowedException;
import com.jaspersoft.jasperserver.remote.exception.RemoteException;
import com.jaspersoft.jasperserver.remote.exception.ResourceAlreadyExistsException;
import com.jaspersoft.jasperserver.remote.exception.ResourceNotFoundException;
import com.jaspersoft.jasperserver.remote.helpers.PermissionsRecipientIdentity;
import com.jaspersoft.jasperserver.remote.services.PermissionsService;
import com.jaspersoft.jasperserver.remote.services.ResourcesManagementRemoteService;
import com.jaspersoft.jasperserver.remote.utils.AuditHelper;
import com.jaspersoft.jasperserver.search.model.permission.Permission;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.Authentication;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.acl.AclProvider;
import org.springframework.security.acl.basic.AclObjectIdentity;
import org.springframework.security.acl.basic.BasicAclEntry;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * @author Volodya Sabadosh (vsabadosh@jaspersoft.com)
 * @author Zakhar Tomchenco (ztomchenco@jaspersoft.com)
 * @version $Id: PermissionsServiceImpl.java 47331 2014-07-18 09:13:06Z kklein $
 */
@Component("permissionsService")
@Transactional(rollbackFor = Exception.class)
public class PermissionsServiceImpl implements PermissionsService {
    protected static final Set<Integer> ALLOWED_MASKS;

    static {
        Set<Integer> set = new HashSet<Integer>();
        for (Permission perm : Permission.values()) {
            set.add(perm.getMask());
        }
        ALLOWED_MASKS = Collections.unmodifiableSet(set);
    }

    @javax.annotation.Resource(name = "objectPermissionService")
    protected ObjectPermissionService objectPermissionService;
    @javax.annotation.Resource(name = "objectPermissionService")
    protected AclProvider aclService;
    @javax.annotation.Resource(name = "objectPermissionService")
    protected AclService ourAclService;
    @javax.annotation.Resource(name = "objectPermissionService")
    protected PersistentObjectResolver persistentObjectResolver;
    @javax.annotation.Resource(name = "concreteRepository")
    protected RepositoryService repositoryService;
    @javax.annotation.Resource
    private AuditHelper auditHelper;
    @javax.annotation.Resource
    private ResourcesManagementRemoteService resourcesManagementRemoteService;
    @javax.annotation.Resource(name = "mappingResourceFactory")
    private ResourceFactory resourceFactory;
    @javax.annotation.Resource(name = "concreteUserAuthorityService")
    protected UserAuthorityService userAuthorityService;

    protected Comparator<BasicAclEntry> aclCompartor = new Comparator<BasicAclEntry>() {
        @Override
        public int compare(BasicAclEntry o1, BasicAclEntry o2) {
            // 1 is the highest mask value
            int mask1 = o1.getMask() == JasperServerAclEntry.ADMINISTRATION ? Integer.MAX_VALUE : o1.getMask();
            int mask2 = o2.getMask() == JasperServerAclEntry.ADMINISTRATION ? Integer.MAX_VALUE : o2.getMask();
            // 32 is a lowest except 0
            mask1 = mask1 == JasperServerAclEntry.EXECUTE ? 1 : mask1;
            mask2 = mask2 == JasperServerAclEntry.EXECUTE ? 1 : mask2;

            int result = mask1 - mask2;
            if (result == 0) {
                //if masks are equal, closest(longer identity's uri) is bigger
                result = ((ObjectPermissionServiceImpl.URIObjectIdentity) o1.getAclObjectIdentity()).getURI()
                        .length()
                        - ((ObjectPermissionServiceImpl.URIObjectIdentity) o2.getAclObjectIdentity()).getURI()
                                .length();
            }
            return result;
        }
    };

    public void setResourcesManagementRemoteService(
            ResourcesManagementRemoteService resourcesManagementRemoteService) {
        this.resourcesManagementRemoteService = resourcesManagementRemoteService;
    }

    public void setAuditHelper(AuditHelper auditHelper) {
        this.auditHelper = auditHelper;
    }

    public List<ObjectPermission> getPermissions(String resourceURI) throws RemoteException {
        Resource resource = resourcesManagementRemoteService.locateResource(resourceURI);
        return objectPermissionService.getObjectPermissionsForObject(makeExecutionContext(), resource);
    }

    public List<ObjectPermission> getPermissions(String resourceURI, Class<?> recipientType, String recipientId,
            boolean effectivePermissions, boolean resolveAll) throws RemoteException {
        List<ObjectPermission> result;
        if (resolveAll) {
            result = resolveAll(resourceURI, recipientType, recipientId, effectivePermissions);
        } else {
            Resource resource = resolveResource(resourceURI);
            if (effectivePermissions) {
                result = objectPermissionService.getEffectivePermissionsForObject(makeExecutionContext(), resource);
            } else {
                result = objectPermissionService.getObjectPermissionsForObject(makeExecutionContext(), resource);
            }
            if (recipientType != null) {
                result = filterByType(result, recipientType);
                if (recipientId != null) {
                    //just to make sure, that recipient exists
                    resolveRecipientObject(recipientType, recipientId);
                    result = filterById(result, recipientId);
                }
            }
        }
        return result;
    }

    public ObjectPermission getPermission(String resourceURI, Class<?> recipientType, String recipientId)
            throws RemoteException {
        Object recipient = resolveRecipientObject(recipientType, recipientId);
        Resource object = resolveResource(resourceURI);
        List<ObjectPermission> permissions = objectPermissionService
                .getObjectPermissionsForObjectAndRecipient(makeExecutionContext(), object, recipient);
        return permissions.size() > 0 ? (ObjectPermission) permissions.get(0) : null;
    }

    public ObjectPermission getEffectivePermission(Resource resource, Role role) {
        Authentication authentication = createAuthentication(role);
        ObjectPermission permission = getEffectivePermission(resource, authentication);
        permission.setPermissionRecipient(role);
        return permission;
    }

    public ObjectPermission getEffectivePermission(Resource resource, User user) {
        Authentication authentication = createAuthentication(user);
        return getEffectivePermission(resource, authentication);
    }

    public ObjectPermission getEffectivePermission(Resource resource, Authentication authentication) {
        ObjectPermission permission = new ObjectPermissionImpl();
        permission.setPermissionRecipient(authentication.getPrincipal());
        BasicAclEntry[] effectiveAcls = (BasicAclEntry[]) aclService.getAcls(resource, authentication);

        if (effectiveAcls != null) {
            BasicAclEntry entry = Collections.max(Arrays.asList(effectiveAcls), aclCompartor);

            permission.setPermissionMask(entry.getMask());
            permission.setURI(extractUriFromEntry(entry));
        } else {
            permission.setPermissionMask(JasperServerAclEntry.NOTHING);
        }
        return permission;
    }

    public List<ObjectPermission> getPermissionsForObject(String targetURI) throws RemoteException {
        if (!objectPermissionService.isObjectAdministrable(makeExecutionContext(), targetURI)) {
            throw new AccessDeniedException("Access is denied");
        }
        Resource res = repositoryService.getResource(makeExecutionContext(), targetURI);
        if (res == null) {
            res = repositoryService.getFolder(makeExecutionContext(), targetURI);

            if (res == null) {
                throw new RemoteException("There is no resource or folder for target URI \"" + targetURI + "\"");
            }
        }

        return objectPermissionService.getObjectPermissionsForObject(makeExecutionContext(), res);
    }

    public ObjectPermission createPermission(ObjectPermission objectPermission) throws RemoteException {
        return doPutPermission(objectPermission, false);
    }

    public ObjectPermission putPermission(ObjectPermission objectPermission) throws RemoteException {
        return doPutPermission(objectPermission, true);
    }

    public List<ObjectPermission> putPermissions(String uri, List<ObjectPermission> objectPermissions)
            throws RemoteException {
        // make sure that permissions will be definitely assigned to this resource
        for (ObjectPermission permission : objectPermissions) {
            permission.setURI(REPO_URI_PREFIX + uri);
        }
        return doPutPermissions(REPO_URI_PREFIX + uri, objectPermissions, false);
    }

    public List<ObjectPermission> createPermissions(List<ObjectPermission> objectPermissions)
            throws RemoteException {
        return doPutPermissions(null, objectPermissions, true);
    }

    public void deletePermission(ObjectPermission objectPermission) throws RemoteException {
        changePermissionConsistencyCheck(objectPermission);

        auditHelper.createAuditEvent("deletePermission");
        objectPermissionService.deleteObjectPermission(makeExecutionContext(), objectPermission);
        auditHelper.closeAuditEvent("deletePermission");
    }

    public ObjectPermission newObjectPermission() {
        return objectPermissionService.newObjectPermission(makeExecutionContext());
    }

    /**
     * Returns permission mask for resource with <strong>targetURI</strong></> for current user.
     *
     * @param targetURI resource URI.
     * @return
     * @throws RemoteException
     */
    public int getAppliedPermissionMaskForObjectAndCurrentUser(String targetURI) throws RemoteException {
        Resource resource = repositoryService.getResource(makeExecutionContext(), targetURI);
        if (resource == null) {
            resource = repositoryService.getFolder(makeExecutionContext(), targetURI);

            if (resource == null) {
                throw new RemoteException("There is no resource or folder for target URI \"" + targetURI + "\"");
            }
        }

        Set<Integer> allUserPermissions = null;

        List<Object> currentUserRecipients = getCurrentUserRecipients();
        if (currentUserRecipients != null && currentUserRecipients.size() > 0) {
            allUserPermissions = new HashSet<Integer>();
            for (Object recipient : getCurrentUserRecipients()) {
                BasicAclEntry[] acls = ourAclService.getAcls(resource, recipient);
                for (BasicAclEntry acl : acls) {
                    allUserPermissions.add(acl.getMask());
                }
            }
        }
        if (allUserPermissions != null && allUserPermissions.size() > 0) {
            JasperServerAclEntry jasperServerAclEntry = new JasperServerAclEntry();
            // returns permissions mask
            return jasperServerAclEntry.printPermissionsOverlappingBlock(allUserPermissions);
        } else {
            // returns no permissions.
            return 0;
        }
    }

    protected List<Object> getCurrentUserRecipients() {
        Authentication authenticationToken = SecurityContextHolder.getContext().getAuthentication();
        List<Object> recipients = new ArrayList<Object>();
        if (authenticationToken.getPrincipal() instanceof User) {
            User user = (User) authenticationToken.getPrincipal();
            recipients.add(user);
            recipients.addAll(user.getRoles());

            return recipients;
        } else {
            return null;
        }
    }

    protected void changePermissionConsistencyCheck(ObjectPermission objectPermission) throws RemoteException {
        if (StringUtils.isBlank(objectPermission.getURI())) {
            throw new IllegalParameterValueException("URI is blank", "uri", objectPermission.getURI());
        }
        // Permission recipient check
        if (objectPermission.getPermissionRecipient() == null) {
            throw new IllegalParameterValueException("recepient", "null");
        }
        if (!ALLOWED_MASKS.contains(objectPermission.getPermissionMask())) {
            throw new IllegalParameterValueException("mask",
                    new Integer(objectPermission.getPermissionMask()).toString());
        }
        if (objectPermission.getPermissionRecipient() instanceof PermissionsRecipientIdentity) {
            PermissionsRecipientIdentity identity = (PermissionsRecipientIdentity) objectPermission
                    .getPermissionRecipient();
            objectPermission
                    .setPermissionRecipient(resolveRecipientObject(identity.getRecipientClass(), identity.getId()));
        } else if (objectPermission.getPermissionRecipient() instanceof TenantQualified) {
            if (persistentObjectResolver.getPersistentObject(objectPermission.getPermissionRecipient()) == null) {
                if (objectPermission.getPermissionRecipient() instanceof User) {
                    User user = (User) objectPermission.getPermissionRecipient();
                    throw new ResourceNotFoundException(user.getUsername());
                }
                if (objectPermission.getPermissionRecipient() instanceof Role) {
                    Role role = (Role) objectPermission.getPermissionRecipient();
                    throw new ResourceNotFoundException(role.getRoleName());
                }
            }
        } else {
            throw new IllegalStateException(
                    "Unknown recipient class:" + objectPermission.getPermissionRecipient().getClass().getName());
        }

        // make sure, that resource exists
        resolveResource(objectPermission.getURI());
    }

    public void setObjectPermissionService(ObjectPermissionService objectPermissionService) {
        this.objectPermissionService = objectPermissionService;
    }

    public void setRepositoryService(RepositoryService repositoryService) {
        this.repositoryService = repositoryService;
    }

    public void setUserAuthorityService(UserAuthorityService userAuthorityService) {
        this.userAuthorityService = userAuthorityService;
    }

    protected ExecutionContext makeExecutionContext() {
        return ExecutionContextImpl.getRuntimeExecutionContext();
    }

    protected ObjectPermission doPutPermission(ObjectPermission objectPermission, boolean allowUpdate)
            throws RemoteException {
        changePermissionConsistencyCheck(objectPermission);

        ObjectPermission existingObjectPermission = objectPermissionService
                .getObjectPermission(makeExecutionContext(), objectPermission);
        String auditEventType;

        if (existingObjectPermission == null) {
            auditEventType = "createPermission";
        } else {
            if (allowUpdate) {
                auditEventType = "updatePermission";
            } else {
                throw new ResourceAlreadyExistsException(objectPermission.getURI() + ";"
                        + ((InternalURI) objectPermission.getPermissionRecipient()).getURI());
            }
        }

        auditHelper.createAuditEvent(auditEventType);
        objectPermissionService.putObjectPermission(makeExecutionContext(), objectPermission);
        auditHelper.closeAuditEvent(auditEventType);

        return objectPermissionService.getObjectPermission(makeExecutionContext(), objectPermission);
    }

    protected List<ObjectPermission> doPutPermissions(String uri, List<ObjectPermission> objectPermissions,
            boolean addTo) throws RemoteException {
        if (!addTo) {
            List<ObjectPermission> existing = this.getPermissions(uri, null, null, false, false);
            for (ObjectPermission permission : existing) {
                this.deletePermission(permission);
            }
        }

        List<ObjectPermission> result = new LinkedList<ObjectPermission>();
        for (ObjectPermission permission : objectPermissions) {
            result.add(this.createPermission(permission));
        }
        return result;
    }

    protected String extractUriFromEntry(BasicAclEntry entry) {
        return ((ObjectPermissionServiceImpl.URIObjectIdentity) entry.getAclObjectIdentity()).getURI();
    }

    protected Object resolveRecipientObject(Class<?> clazz, String id) throws ResourceNotFoundException {
        Object res = null;
        if (Role.class.equals(clazz)) {
            Role role = new RoleImpl();
            role.setRoleName(id);
            res = role;
        }
        if (User.class.equals(clazz)) {
            User user = new UserImpl();
            user.setUsername(id);
            res = user;
        }

        if (persistentObjectResolver.getPersistentObject(res) == null) {
            throw new ResourceNotFoundException(clazz.getSimpleName() + " " + id);
        }

        return res;
    }

    protected Resource resolveResource(String uri) throws RemoteException {
        if (uri.startsWith(REPO_URI_PREFIX)) {
            uri = uri.substring(REPO_URI_PREFIX.length());
        }

        Resource resource = repositoryService.getResource(makeExecutionContext(), uri);
        if (resource == null) {
            resource = repositoryService.getFolder(makeExecutionContext(), uri);
        }
        if (resource == null) {
            throw new ResourceNotFoundException(uri);
        }

        if (!objectPermissionService.isObjectAdministrable(null, resource)) {
            throw new AccessDeniedException("Access denied", uri);
        }

        return resource;
    }

    protected boolean isSameId(Object permissionRecipient, String recipientId) {
        return permissionRecipient instanceof User && ((User) permissionRecipient).getUsername().equals(recipientId)
                || permissionRecipient instanceof Role
                        && ((Role) permissionRecipient).getRoleName().equals(recipientId);
    }

    protected List<ObjectPermission> filterByType(List<ObjectPermission> data, Class<?> recipientType) {
        List<ObjectPermission> result = new LinkedList<ObjectPermission>();
        for (ObjectPermission permission : data) {
            if (recipientType.isInstance(permission.getPermissionRecipient())) {
                result.add(permission);
            }
        }
        return result;
    }

    protected List<ObjectPermission> filterById(List<ObjectPermission> data, String recipientId) {
        List<ObjectPermission> result = new LinkedList<ObjectPermission>();
        for (ObjectPermission permission : data) {
            if (isSameId(permission.getPermissionRecipient(), recipientId)) {
                result.add(permission);
            }
        }
        return result;
    }

    protected Authentication createAuthentication(Role role) {
        GrantedAuthority[] grantedAuthorities = new GrantedAuthority[] {
                new GrantedAuthorityImpl(role.getRoleName()) };
        MetadataUserDetails dummy = new MetadataUserDetails(new UserImpl());
        dummy.setUsername("dummyUserdummyUserdummyUserdummyUserdummyUser");

        return new UsernamePasswordAuthenticationToken(dummy, null, grantedAuthorities);
    }

    protected Authentication createAuthentication(User user) {
        GrantedAuthority[] grantedAuthorities = new GrantedAuthority[user.getRoles().size()];
        Role[] roles = (Role[]) user.getRoles().toArray(new Role[user.getRoles().size()]);

        for (int i = 0; i < roles.length; i++) {
            grantedAuthorities[i] = new GrantedAuthorityImpl(roles[i].getRoleName());
        }

        return new UsernamePasswordAuthenticationToken(new MetadataUserDetails(user), null, grantedAuthorities);
    }

    private List<ObjectPermission> resolveAll(String resourceURI, Class<?> recipientType, String recipientId,
            boolean effectivePermissions) throws RemoteException {
        List<ObjectPermission> res;
        if (recipientType == null) {
            res = resolveAllUsers(resourceURI, recipientId, effectivePermissions);
            res.addAll(resolveAllRoles(resourceURI, recipientId));
        } else {
            if (recipientType.equals(User.class)) {
                res = resolveAllUsers(resourceURI, recipientId, effectivePermissions);
            } else {
                res = resolveAllRoles(resourceURI, recipientId);
            }
        }
        return res;
    }

    private List<ObjectPermission> resolveAllRoles(String resourceURI, String recipientId) throws RemoteException {
        List<Role> roles = getRolesForResource(resourceURI, recipientId);
        Resource resource = resolveResource(resourceURI);

        List<ObjectPermission> res = new LinkedList<ObjectPermission>();
        for (Role role : roles) {
            res.add(getEffectivePermission(resource, role));
        }

        return res;
    }

    private List<ObjectPermission> resolveAllUsers(String resourceURI, String recipientId,
            boolean effectivePermissions) throws RemoteException {
        List<User> users = getUsersForResource(resourceURI, recipientId);
        Resource resource = resolveResource(resourceURI);

        List<ObjectPermission> res = new LinkedList<ObjectPermission>();
        ObjectPermission permission;
        for (User user : users) {
            if (effectivePermissions) {
                permission = getEffectivePermission(resource, user);
            } else {
                //create authentication without roles, based on user, so result will be for user only
                Authentication authentication = new UsernamePasswordAuthenticationToken(user, null,
                        new GrantedAuthority[0]);
                permission = getEffectivePermission(resource, authentication);
            }
            res.add(permission);
        }
        return res;
    }

    protected List<User> getUsersForResource(String resourceURI, String recipientId) {
        return userAuthorityService.getTenantUsers(null, null, null);
    }

    protected List getRolesForResource(String resourceURI, String recipientId) {
        return userAuthorityService.getTenantRoles(null, null, null);
    }
}