Java tutorial
/* * R Service Bus * * Copyright (c) Copyright of Open Analytics NV, 2010-2015 * * =========================================================================== * * 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 eu.openanalytics.rsb.security; import static eu.openanalytics.rsb.Constants.ADMIN_PATH; import static eu.openanalytics.rsb.component.AdminResource.ADMIN_CATALOG_PATH; import static eu.openanalytics.rsb.component.AdminResource.ADMIN_SYSTEM_PATH; import java.io.Serializable; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.annotation.Resource; import org.apache.commons.lang3.StringUtils; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.util.CollectionUtils; import eu.openanalytics.rsb.component.AdminResource; import eu.openanalytics.rsb.config.Configuration; import eu.openanalytics.rsb.config.Configuration.AdminSecurityAuthorization; import eu.openanalytics.rsb.config.Configuration.ApplicationSecurityAuthorization; import eu.openanalytics.rsb.message.AbstractFunctionCallJob; import eu.openanalytics.rsb.message.AbstractJob; import eu.openanalytics.rsb.message.MultiFilesJob; /** * Defines a {@link PermissionEvaluator} that considers the applications a user is granted to use. * * @author "OpenAnalytics <rsb.development@openanalytics.eu>" */ public class ApplicationPermissionEvaluator implements PermissionEvaluator { public static final String NO_AUTHENTICATED_USERNAME = null; @Resource private Configuration configuration; @Override public boolean hasPermission(final Authentication authentication, final Object targetDomainObject, final Object permission) { if ("CATALOG_USER".equals(permission)) { return hasCatalogUserPermission(authentication, targetDomainObject); } else if ("CATALOG_ADMIN".equals(permission)) { return hasCatalogAdminPermission(authentication, targetDomainObject); } if (targetDomainObject == null) { return false; } if ("APPLICATION_JOB".equals(permission)) { final AbstractJob job = (AbstractJob) targetDomainObject; return hasApplicationJobPermission(authentication, job); } else if ("APPLICATION_USER".equals(permission)) { final String applicationName = (String) targetDomainObject; return hasApplicationUserOrAdminPermission(authentication, applicationName); } else if ("APPLICATION_ADMIN".equals(permission)) { final String applicationName = (String) targetDomainObject; return hasApplicationAdminPermission(authentication, applicationName); } else if ("RSB_RESOURCE".equals(permission)) { final String resourceName = targetDomainObject.toString(); return hasRsbResourcePermission(authentication, resourceName); } else { throw new SecurityException("Unknown permission: " + permission); } } private boolean hasCatalogAdminPermission(final Authentication authentication, final Object targetDomainObject) { if (configuration.isApplicationAwareCatalog()) { // in secure-mode with an application aware catalog, only admins of a specific // application can modify the application's catalog return hasPermission(authentication, targetDomainObject, "APPLICATION_ADMIN"); } else { // in secure-mode with a non-application aware catalog, only RSB admins can // modify the catalog return hasRsbResourcePermission(authentication, AdminResource.ADMIN_CATALOG_PATH); } } private boolean hasCatalogUserPermission(final Authentication authentication, final Object targetDomainObject) { if (configuration.isApplicationAwareCatalog()) { // in secure-mode with an application aware catalog, only users of a specific // application can read the application's catalog return hasPermission(authentication, targetDomainObject, "APPLICATION_USER"); } else { // in secure-mode with a non-application aware catalog, anyone authenticated can // read the catalog return true; } } private boolean hasApplicationUserOrAdminPermission(final Authentication authentication, final String applicationName) { return hasApplicationUserPermission(authentication, applicationName) || hasApplicationAdminPermission(authentication, applicationName); } private boolean hasApplicationJobPermission(final Authentication authentication, final AbstractJob job) { return hasApplicationAdminPermission(authentication, job.getApplicationName()) || (hasApplicationUserPermission(authentication, job.getApplicationName()) && isJobAuthorized(job)); } public boolean hasApplicationUserPermission(final Authentication authentication, final String applicationName) { final Map<String, ApplicationSecurityAuthorization> applicationSecurityConfigurations = configuration .getApplicationSecurityConfiguration(); if (applicationSecurityConfigurations != null) { final ApplicationSecurityAuthorization applicationSecurityConfiguration = applicationSecurityConfigurations .get(applicationName); return isAuthenticationUser(authentication, applicationSecurityConfiguration); } else { return false; } } public boolean hasApplicationAdminPermission(final Authentication authentication, final String applicationName) { // RSB admins are application admins if (isAuthenticationAdmin(authentication, configuration.getRsbSecurityConfiguration())) { return true; } final Map<String, ApplicationSecurityAuthorization> applicationSecurityConfigurations = configuration .getApplicationSecurityConfiguration(); if (applicationSecurityConfigurations != null) { final ApplicationSecurityAuthorization applicationSecurityConfiguration = applicationSecurityConfigurations .get(applicationName); return isAuthenticationAdmin(authentication, applicationSecurityConfiguration); } else { return false; } } private boolean isJobAuthorized(final AbstractJob job) { final Map<String, ApplicationSecurityAuthorization> applicationSecurityConfigurations = configuration .getApplicationSecurityConfiguration(); if (applicationSecurityConfigurations == null) { return false; } final String applicationName = job.getApplicationName(); final ApplicationSecurityAuthorization applicationSecurityConfiguration = applicationSecurityConfigurations .get(applicationName); if (applicationSecurityConfiguration == null) { return false; } if (job instanceof AbstractFunctionCallJob) { return applicationSecurityConfiguration.isFunctionCallAllowed(); } else { final MultiFilesJob multiFilesJob = (MultiFilesJob) job; if (multiFilesJob.getRScriptFile() != null) { return applicationSecurityConfiguration.isScriptSubmissionAllowed(); } else { return true; } } } private boolean hasRsbResourcePermission(final Authentication authentication, final String resourceName) { if (ADMIN_SYSTEM_PATH.equals(resourceName) || ADMIN_CATALOG_PATH.equals(resourceName) || ADMIN_PATH.equals(resourceName)) { return isAuthenticationAdmin(authentication, configuration.getRsbSecurityConfiguration()); } else { return false; } } private boolean isAuthenticationAdmin(final Authentication authentication, final AdminSecurityAuthorization adminSecurityAuthorization) { if (adminSecurityAuthorization == null) { return false; } return isAuthenticationAuthorized(authentication, adminSecurityAuthorization.getAdminPrincipals(), adminSecurityAuthorization.getAdminRoles()); } private boolean isAuthenticationUser(final Authentication authentication, final ApplicationSecurityAuthorization applicationSecurityAuthorization) { if (applicationSecurityAuthorization == null) { return false; } return isAuthenticationAuthorized(authentication, applicationSecurityAuthorization.getUserPrincipals(), applicationSecurityAuthorization.getUserRoles()); } private boolean isAuthenticationAuthorized(final Authentication authentication, final Set<String> authorizedPrincipals, final Set<String> authorizedRoles) { final String userName = getUserName(authentication); if ((StringUtils.isNotBlank(userName)) && (!CollectionUtils.isEmpty(authorizedPrincipals)) && (authorizedPrincipals.contains(userName))) { return true; } final Set<String> roles = new HashSet<String>(); for (final GrantedAuthority authority : authentication.getAuthorities()) { roles.add(authority.getAuthority()); } return CollectionUtils.containsAny(authorizedRoles, roles); } private String getUserName(final Authentication authentication) { if (authentication.getPrincipal() instanceof UserDetails) { return ((UserDetails) authentication.getPrincipal()).getUsername(); } else { return null; } } @Override public boolean hasPermission(final Authentication authentication, final Serializable targetId, final String targetType, final Object permission) { throw new UnsupportedOperationException("Application permission verification can only be done on objects"); } }