/*
* #%L
* BroadleafCommerce Open Admin Platform
* %%
* Copyright (C) 2009 - 2013 Broadleaf Commerce
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.broadleafcommerce.openadmin.server.security.service.navigation;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.broadleafcommerce.common.extensibility.jpa.SiteDiscriminator;
import org.broadleafcommerce.common.site.domain.Site;
import org.broadleafcommerce.common.web.BroadleafRequestContext;
import org.broadleafcommerce.openadmin.server.security.dao.AdminNavigationDao;
import org.broadleafcommerce.openadmin.server.security.domain.AdminMenu;
import org.broadleafcommerce.openadmin.server.security.domain.AdminModule;
import org.broadleafcommerce.openadmin.server.security.domain.AdminModuleDTO;
import org.broadleafcommerce.openadmin.server.security.domain.AdminModuleImpl;
import org.broadleafcommerce.openadmin.server.security.domain.AdminPermission;
import org.broadleafcommerce.openadmin.server.security.domain.AdminRole;
import org.broadleafcommerce.openadmin.server.security.domain.AdminSection;
import org.broadleafcommerce.openadmin.server.security.domain.AdminUser;
import org.broadleafcommerce.openadmin.server.security.service.AdminSecurityService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.annotation.Resource;
/**
* This service is used to build the left hand navigation for the admin
* @author elbertbautista
*/
@Service("blAdminNavigationService")
public class AdminNavigationServiceImpl implements AdminNavigationService {
private static final Log LOG = LogFactory.getLog(AdminNavigationServiceImpl.class);
private static final String PATTERN = "_";
@Resource(name = "blAdminNavigationDao")
protected AdminNavigationDao adminNavigationDao;
@Resource(name="blAdditionalSectionAuthorizations")
protected List<SectionAuthorization> additionalSectionAuthorizations = new ArrayList<SectionAuthorization>();
@Override
@Transactional("blTransactionManager")
public AdminSection save(AdminSection adminSection) {
return adminNavigationDao.save(adminSection);
}
@Override
public void remove(AdminSection adminSection) {
adminNavigationDao.remove(adminSection);
}
@Override
public AdminMenu buildMenu(AdminUser adminUser) {
AdminMenu adminMenu = new AdminMenu();
List<AdminModule> modules = adminNavigationDao.readAllAdminModules();
populateAdminMenu(adminUser, adminMenu, modules);
return adminMenu;
}
protected void populateAdminMenu(AdminUser adminUser, AdminMenu adminMenu, List<AdminModule> modules) {
for (AdminModule module : modules) {
List<AdminSection> authorizedSections = buildAuthorizedSectionsList(adminUser, module);
if (authorizedSections != null && authorizedSections.size() > 0) {
AdminModuleDTO adminModuleDto = ((AdminModuleImpl) module).getAdminModuleDTO();
adminMenu.getAdminModules().add(adminModuleDto);
adminModuleDto.setSections(authorizedSections);
}
}
// Sort the authorized modules
BeanComparator displayComparator = new BeanComparator("displayOrder");
Collections.sort(adminMenu.getAdminModules(), displayComparator);
}
protected List<AdminSection> buildAuthorizedSectionsList(AdminUser adminUser, AdminModule module) {
List<AdminSection> authorizedSections = new ArrayList<AdminSection>();
BroadleafRequestContext broadleafRequestContext = BroadleafRequestContext.getBroadleafRequestContext();
Site site = broadleafRequestContext.getNonPersistentSite();
Long siteId = site == null ? null : site.getId();
for (AdminSection section : module.getSections()) {
if (isUserAuthorizedToViewSection(adminUser, section)) {
if(section instanceof SiteDiscriminator){
Long sectionSiteId = ((SiteDiscriminator)section).getSiteDiscriminator();
if(sectionSiteId == null || sectionSiteId.equals(siteId)){
authorizedSections.add(section);
}
} else{
authorizedSections.add(section);
}
}
}
Collections.sort(authorizedSections, SECTION_COMPARATOR);
return authorizedSections;
}
@Override
public boolean isUserAuthorizedToViewModule(AdminUser adminUser, AdminModule module) {
List<AdminSection> moduleSections = module.getSections();
if (moduleSections != null && !moduleSections.isEmpty()) {
for (AdminSection section : moduleSections) {
if (isUserAuthorizedToViewSection(adminUser, section)) {
return true;
}
}
}
return false;
}
@Override
public AdminSection findAdminSectionByURI(String uri) {
return adminNavigationDao.readAdminSectionByURI(uri);
}
@Override
public AdminSection findAdminSectionByClassAndSectionId(String className, String sectionId) {
try {
return findAdminSectionByClassAndSectionId(Class.forName(className), sectionId);
} catch (ClassNotFoundException e) {
LOG.warn("Invalid classname received. This likely points to a configuration error.");
return null;
}
}
@Override
public AdminSection findAdminSectionByClassAndSectionId(Class<?> clazz, String sectionId) {
return adminNavigationDao.readAdminSectionByClassAndSectionId(clazz, sectionId);
}
@Override
public AdminSection findAdminSectionBySectionKey(String sectionKey) {
return adminNavigationDao.readAdminSectionBySectionKey(sectionKey);
}
@Override
public boolean isUserAuthorizedToViewSection(AdminUser adminUser, AdminSection section) {
boolean response = false;
List<AdminPermission> authorizedPermissions = section.getPermissions();
checkAuth: {
if (!CollectionUtils.isEmpty(adminUser.getAllRoles())) {
for (AdminRole role : adminUser.getAllRoles()) {
for (AdminPermission permission : role.getAllPermissions()){
if (checkPermissions(authorizedPermissions, permission)) {
response = true;
break checkAuth;
}
}
}
}
if (!CollectionUtils.isEmpty(adminUser.getAllPermissions())) {
for (AdminPermission permission : adminUser.getAllPermissions()){
if (checkPermissions(authorizedPermissions, permission)) {
response = true;
break checkAuth;
}
}
}
for (String defaultPermission : AdminSecurityService.DEFAULT_PERMISSIONS) {
for (AdminPermission authorizedPermission : authorizedPermissions) {
if (authorizedPermission.getName().equals(defaultPermission)) {
response = true;
break checkAuth;
}
}
}
}
if (response) {
for (SectionAuthorization sectionAuthorization : additionalSectionAuthorizations) {
if (!sectionAuthorization.isUserAuthorizedToViewSection(adminUser, section)) {
response = false;
break;
}
}
}
return response;
}
@Override
public List<AdminSection> findAllAdminSections() {
List<AdminSection> sections = adminNavigationDao.readAllAdminSections();
Collections.sort(sections, SECTION_COMPARATOR);
return sections;
}
protected boolean checkPermissions(List<AdminPermission> authorizedPermissions, AdminPermission permission) {
if (authorizedPermissions != null) {
if (authorizedPermissions.contains(permission)){
return true;
}
for (AdminPermission authorizedPermission : authorizedPermissions) {
if (permission.getName().equals(parseForAllPermission(authorizedPermission.getName()))) {
return true;
}
}
}
return false;
}
protected String parseForAllPermission(String currentPermission) {
String[] pieces = currentPermission.split(PATTERN);
StringBuilder builder = new StringBuilder(50);
builder.append(pieces[0]);
builder.append("_ALL_");
for (int j = 2; j<pieces.length; j++) {
builder.append(pieces[j]);
if (j < pieces.length - 1) {
builder.append('_');
}
}
return builder.toString();
}
private static SectionComparator SECTION_COMPARATOR = new SectionComparator();
private static class SectionComparator implements Comparator<AdminSection> {
@Override
public int compare(AdminSection section, AdminSection section2) {
if (section.getDisplayOrder() != null) {
if (section2.getDisplayOrder() != null) {
return section.getDisplayOrder().compareTo(section2.getDisplayOrder());
}
else
return -1;
} else if (section2.getDisplayOrder() != null) {
return 1;
}
return section.getId().compareTo(section2.getId());
}
}
public List<SectionAuthorization> getAdditionalSectionAuthorizations() {
return additionalSectionAuthorizations;
}
public void setAdditionalSectionAuthorizations(List<SectionAuthorization> additionalSectionAuthorizations) {
this.additionalSectionAuthorizations = additionalSectionAuthorizations;
}
}