=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/appmanager/AppManager.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/appmanager/AppManager.java 2014-06-16 13:59:43 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/appmanager/AppManager.java 2014-12-16 13:31:39 +0000 @@ -28,6 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import org.hisp.dhis.user.User; + import java.io.File; import java.io.IOException; import java.util.List; @@ -51,6 +53,8 @@ */ List getApps(); + List getAccessibleApps(); + /** * Installs the app. * @@ -126,4 +130,8 @@ * @param appStoreUrl */ void setAppStoreUrl( String appStoreUrl ); + + boolean isAccessible( App app ); + + boolean isAccessible( App app, User user ); } === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/appmanager/DefaultAppManager.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/appmanager/DefaultAppManager.java 2014-09-26 06:26:22 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/appmanager/DefaultAppManager.java 2014-12-16 13:31:39 +0000 @@ -28,16 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import javax.annotation.PostConstruct; - +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.ant.compress.taskdefs.Unzip; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; @@ -45,10 +37,20 @@ import org.apache.commons.logging.LogFactory; import org.hisp.dhis.datavalue.DefaultDataValueService; import org.hisp.dhis.setting.SystemSettingManager; +import org.hisp.dhis.user.CurrentUserService; +import org.hisp.dhis.user.User; +import org.hisp.dhis.user.UserCredentials; import org.springframework.beans.factory.annotation.Autowired; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; /** * @author Saptarshi Purkayastha @@ -72,6 +74,9 @@ @Autowired private SystemSettingManager appSettingManager; + @Autowired + private CurrentUserService currentUserService; + // ------------------------------------------------------------------------- // AppManagerService implementation // ------------------------------------------------------------------------- @@ -90,6 +95,25 @@ } @Override + public List getAccessibleApps() + { + List applications = new ArrayList<>( getApps() ); + Iterator iterator = applications.iterator(); + + while ( iterator.hasNext() ) + { + App app = iterator.next(); + + if ( !isAccessible( app ) ) + { + iterator.remove(); + } + } + + return applications; + } + + @Override public void installApp( File file, String fileName, String rootPath ) throws IOException { @@ -99,7 +123,7 @@ InputStream inputStream = zip.getInputStream( entry ); ObjectMapper mapper = new ObjectMapper(); mapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false ); - + App app = mapper.readValue( inputStream, App.class ); // --------------------------------------------------------------------- @@ -178,7 +202,7 @@ return false; } - + @Override public String getAppFolderPath() { @@ -224,7 +248,7 @@ { return StringUtils.trimToNull( (String) appSettingManager.getSystemSetting( KEY_APP_STORE_URL, DEFAULT_APP_STORE_URL ) ); } - + @Override public void setAppStoreUrl( String appStoreUrl ) { @@ -248,14 +272,17 @@ if ( null != getAppFolderPath() ) { File appFolderPath = new File( getAppFolderPath() ); + if ( appFolderPath.isDirectory() ) { File[] listFiles = appFolderPath.listFiles(); + for ( File folder : listFiles ) { if ( folder.isDirectory() ) { File appManifest = new File( folder, "manifest.webapp" ); + if ( appManifest.exists() ) { try @@ -278,4 +305,25 @@ log.info( "Detected apps: " + apps ); } + + @Override + public boolean isAccessible( App app ) + { + return isAccessible( app, currentUserService.getCurrentUser() ); + } + + @Override + public boolean isAccessible( App app, User user ) + { + if ( user == null || user.getUserCredentials() == null || app == null || app.getName() == null ) + { + return false; + } + + UserCredentials userCredentials = user.getUserCredentials(); + + return userCredentials.getAllAuthorities().contains( "ALL" ) || + userCredentials.getAllAuthorities().contains( "M_dhis-web-maintenance-appmanager" ) || + userCredentials.getAllAuthorities().contains( "See " + app.getName().trim() ); + } } === modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AppController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AppController.java 2014-11-11 12:51:06 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AppController.java 2014-12-16 13:31:39 +0000 @@ -32,6 +32,7 @@ import org.hisp.dhis.appmanager.App; import org.hisp.dhis.appmanager.AppManager; import org.hisp.dhis.dxf2.utils.JacksonUtils; +import org.hisp.dhis.hibernate.exception.ReadAccessDeniedException; import org.hisp.dhis.system.util.DateUtils; import org.hisp.dhis.webapi.utils.ContextUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -101,7 +102,6 @@ } @RequestMapping( value = "/apps/{app}/**", method = RequestMethod.GET ) - @PreAuthorize( "hasRole('ALL') or hasRole('M_dhis-web-maintenance-appmanager')" ) public void renderApp( @PathVariable( "app" ) String app, HttpServletRequest request, HttpServletResponse response ) throws IOException { Iterable locations = Lists.newArrayList( @@ -118,6 +118,12 @@ } App application = JacksonUtils.getJsonMapper().readValue( manifest.getInputStream(), App.class ); + + if ( application.getName() == null || !appManager.isAccessible( application ) ) + { + throw new ReadAccessDeniedException( "You don't have access to application " + app + "." ); + } + String pageName = findPage( request.getPathInfo(), app ); // if request was for manifest.webapp, check for * and replace with host === modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/webportal/module/DefaultModuleManager.java' --- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/webportal/module/DefaultModuleManager.java 2014-10-16 06:17:19 +0000 +++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/webportal/module/DefaultModuleManager.java 2014-12-16 13:31:39 +0000 @@ -28,6 +28,18 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import com.opensymphony.xwork2.config.Configuration; +import com.opensymphony.xwork2.config.entities.PackageConfig; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.struts2.dispatcher.Dispatcher; +import org.hisp.dhis.appmanager.App; +import org.hisp.dhis.appmanager.AppManager; +import org.hisp.dhis.security.ActionAccessResolver; +import org.hisp.dhis.user.CurrentUserService; +import org.hisp.dhis.user.User; +import org.springframework.beans.factory.annotation.Autowired; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -38,17 +50,6 @@ import java.util.Map; import java.util.Set; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.struts2.dispatcher.Dispatcher; -import org.hisp.dhis.appmanager.App; -import org.hisp.dhis.appmanager.AppManager; -import org.hisp.dhis.security.ActionAccessResolver; -import org.springframework.beans.factory.annotation.Autowired; - -import com.opensymphony.xwork2.config.Configuration; -import com.opensymphony.xwork2.config.entities.PackageConfig; - /** * @author Torgeir Lorange Ostby * @version $Id: DefaultModuleManager.java 4883 2008-04-12 13:12:54Z larshelg $ @@ -65,7 +66,7 @@ private Map modulesByNamespace = new HashMap<>(); private List menuModules = new ArrayList<>(); - + private ThreadLocal currentModule = new ThreadLocal<>(); // ------------------------------------------------------------------------- @@ -74,7 +75,10 @@ @Autowired private AppManager appManager; - + + @Autowired + private CurrentUserService currentUserService; + private ActionAccessResolver actionAccessResolver; public void setActionAccessResolver( ActionAccessResolver actionAccessResolver ) @@ -95,14 +99,14 @@ { this.defaultActionName = defaultActionName; } - + private Set menuModuleExclusions = new HashSet<>(); - + public void setMenuModuleExclusions( Set menuModuleExclusions ) { this.menuModuleExclusions = menuModuleExclusions; } - + // ------------------------------------------------------------------------- // ModuleManager // ------------------------------------------------------------------------- @@ -122,7 +126,7 @@ return modulesByNamespace.get( namespace ); } - + @Override public boolean moduleExists( String name ) { @@ -141,22 +145,21 @@ public List getAccessibleMenuModules() { detectModules(); - + return getAccessibleModules( menuModules ); } - + @Override public List getAccessibleMenuModulesAndApps() { List modules = getAccessibleMenuModules(); - - List apps = appManager.getApps(); - + List apps = appManager.getAccessibleApps(); + for ( App app : apps ) - { + { modules.add( Module.getModule( app ) ); } - + return modules; } @@ -167,7 +170,7 @@ return new ArrayList<>( modulesByName.values() ); } - + @Override public Module getCurrentModule() { @@ -192,12 +195,12 @@ } for ( PackageConfig packageConfig : getPackageConfigs() ) - { + { String name = packageConfig.getName(); String namespace = packageConfig.getNamespace(); log.debug( "Package config: " + name + ", " + namespace ); - + if ( packageConfig.getAllActionConfigs().size() == 0 ) { log.debug( "Ignoring action package with no actions: " + name ); @@ -219,14 +222,14 @@ { Module module = modulesByNamespace.get( namespace ); - throw new RuntimeException( "These action packages have the same namespace: " + + throw new RuntimeException( "These action packages have the same namespace: " + name + " and " + module.getName() ); } Module module = new Module( name, namespace ); modulesByName.put( name, module ); modulesByNamespace.put( namespace, module ); - + boolean include = !menuModuleExclusions.contains( name ); if ( packageConfig.getActionConfigs().containsKey( defaultActionName ) && include ) @@ -246,7 +249,7 @@ Collections.sort( menuModules, moduleComparator ); log.debug( "Menu modules detected: " + menuModules ); - + modulesDetected = true; } @@ -262,11 +265,11 @@ return packageConfigs.values(); } - + private List getAccessibleModules( List modules ) { List allowed = new ArrayList<>(); - + for ( Module module : modules ) { if ( module != null && actionAccessResolver.hasAccess( module.getName(), defaultActionName ) ) @@ -274,15 +277,15 @@ allowed.add( module ); } } - + if ( modules.size() > allowed.size() ) { List denied = new ArrayList<>( modules ); denied.removeAll( allowed ); - + log.debug( "User denied access to modules: " + denied ); } - + return allowed; } }