=== added file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsSecurityManager.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsSecurityManager.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsSecurityManager.java 2014-04-14 08:42:46 +0000 @@ -0,0 +1,25 @@ +package org.hisp.dhis.analytics; + +import org.hisp.dhis.common.IllegalQueryException; + +public interface AnalyticsSecurityManager +{ + /** + * Decides whether the current user has privileges to execute the given query. + * + * @param params the data query params. + * @throws IllegalQueryException if the current user does not have privileges + * to execute the given query. + */ + void decideAccess( DataQueryParams params ); + + /** + * Applies dimension constraints to the given params. Dimension constraints + * with all accessible dimension items will be added as filters to this query. + * If current user has no dimension constraints, no action is taken. If the + * constraint dimensions are already specified with accessible items in the + * query, no action is taken. If the current user does not have accessible + * items in any dimension constraint, an IllegalQueryException is thrown. + */ + void applyDimensionConstraints( DataQueryParams params ); +} === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java 2014-04-10 21:12:18 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java 2014-04-14 08:42:46 +0000 @@ -175,6 +175,11 @@ * Organisation units which were explicitly part of the original request. */ private List organisationUnits = new ArrayList(); + + /** + * Mapping of organisation unit sub-hierarchy roots and lowest available data approval levels. + */ + private Map approvalLevels = new HashMap(); // ------------------------------------------------------------------------- // Constructors @@ -202,6 +207,7 @@ params.dataPeriodType = this.dataPeriodType; params.skipPartitioning = this.skipPartitioning; params.organisationUnits = new ArrayList( this.organisationUnits ); + params.approvalLevels = new HashMap( this.approvalLevels ); return params; } @@ -864,6 +870,14 @@ return filterItems; } + /** + * Indicates whether this params specifies data approval levels. + */ + public boolean isDataApproval() + { + return approvalLevels != null && !approvalLevels.isEmpty(); + } + // ------------------------------------------------------------------------- // Static methods // ------------------------------------------------------------------------- @@ -1130,6 +1144,16 @@ this.skipPartitioning = skipPartitioning; } + public Map getApprovalLevels() + { + return approvalLevels; + } + + public void setApprovalLevels( Map approvalLevels ) + { + this.approvalLevels = approvalLevels; + } + // ------------------------------------------------------------------------- // Get and set helpers for dimensions or filter // ------------------------------------------------------------------------- === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java 2014-04-11 07:50:58 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java 2014-04-14 08:42:46 +0000 @@ -111,23 +111,4 @@ * names respectively. */ List groupByPeriodType( DataQueryParams params ); - - /** - * Decides whether the current user has privileges to execute the given query. - * - * @param params the data query params. - * @throws IllegalQueryException if the current user does not have privileges - * to execute the given query. - */ - void decideAccess( DataQueryParams params ); - - /** - * Applies dimension constraints to the given params. Dimension constraints - * with all accessible dimension items will be added as filters to this query. - * If current user has no dimension constraints, no action is taken. If the - * constraint dimensions are already specified with accessible items in the - * query, no action is taken. If the current user does not have accessible - * items in any dimension constraint, an IllegalQueryException is thrown. - */ - void applyDimensionConstraints( DataQueryParams params ); } === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java 2014-04-11 07:50:58 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java 2014-04-14 08:42:46 +0000 @@ -82,6 +82,7 @@ import org.apache.commons.logging.LogFactory; import org.hisp.dhis.analytics.AggregationType; import org.hisp.dhis.analytics.AnalyticsManager; +import org.hisp.dhis.analytics.AnalyticsSecurityManager; import org.hisp.dhis.analytics.AnalyticsService; import org.hisp.dhis.analytics.DataQueryGroups; import org.hisp.dhis.analytics.DataQueryParams; @@ -159,6 +160,9 @@ private AnalyticsManager analyticsManager; @Autowired + private AnalyticsSecurityManager securityManager; + + @Autowired private QueryPlanner queryPlanner; @Autowired @@ -203,9 +207,9 @@ @Override public Grid getAggregatedDataValues( DataQueryParams params ) { - queryPlanner.decideAccess( params ); + securityManager.decideAccess( params ); - queryPlanner.applyDimensionConstraints( params ); + securityManager.applyDimensionConstraints( params ); queryPlanner.validate( params ); === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java 2014-04-11 07:50:58 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java 2014-04-14 08:42:46 +0000 @@ -47,7 +47,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -58,7 +57,6 @@ import org.hisp.dhis.analytics.QueryPlanner; import org.hisp.dhis.analytics.table.PartitionUtils; import org.hisp.dhis.common.BaseDimensionalObject; -import org.hisp.dhis.common.DimensionService; import org.hisp.dhis.common.DimensionType; import org.hisp.dhis.common.DimensionalObject; import org.hisp.dhis.common.IllegalQueryException; @@ -71,8 +69,6 @@ import org.hisp.dhis.period.PeriodType; import org.hisp.dhis.system.util.MathUtils; import org.hisp.dhis.system.util.PaginatedList; -import org.hisp.dhis.user.CurrentUserService; -import org.hisp.dhis.user.User; import org.springframework.beans.factory.annotation.Autowired; /** @@ -88,12 +84,6 @@ @Autowired private OrganisationUnitService organisationUnitService; - @Autowired - private DimensionService dimensionService; - - @Autowired - private CurrentUserService currentUserService; - // ------------------------------------------------------------------------- // DefaultQueryPlanner implementation // ------------------------------------------------------------------------- @@ -295,129 +285,6 @@ // Dimension constraints methods // ------------------------------------------------------------------------- - public void decideAccess( DataQueryParams params ) - { - // --------------------------------------------------------------------- - // Check current user data view access to org units - // --------------------------------------------------------------------- - - User user = currentUserService.getCurrentUser(); - - List queryOrgUnits = params.getDimensionOrFilter( DimensionalObject.ORGUNIT_DIM_ID ); - - if ( queryOrgUnits == null || user == null || !user.hasDataViewOrganisationUnit() ) - { - return; - } - - Set viewOrgUnits = user.getDataViewOrganisationUnits(); - - for ( NameableObject object : queryOrgUnits ) - { - OrganisationUnit queryOrgUnit = (OrganisationUnit) object; - - if ( !queryOrgUnit.isEqualOrChildOf( viewOrgUnits ) ) - { - throw new IllegalQueryException( "Org unit is not viewable for current user: " + queryOrgUnit.getUid() ); - } - } - } - - public void applyDimensionConstraints( DataQueryParams params ) - { - applyOrganisationUnitConstraint( params ); - applyUserConstraints( params ); - } - - private void applyOrganisationUnitConstraint( DataQueryParams params ) - { - User user = currentUserService.getCurrentUser(); - - // --------------------------------------------------------------------- - // Check if current user has data view organisation units - // --------------------------------------------------------------------- - - if ( params == null || user == null || !user.hasDataViewOrganisationUnit() ) - { - return; - } - - // --------------------------------------------------------------------- - // Check if request already has organisation units specified - // --------------------------------------------------------------------- - - if ( params.hasDimensionOrFilterWithItems( DimensionalObject.ORGUNIT_DIM_ID ) ) - { - return; - } - - // ----------------------------------------------------------------- - // Apply constraint as filter, and remove potential all-dimension - // ----------------------------------------------------------------- - - params.removeDimensionOrFilter( DimensionalObject.ORGUNIT_DIM_ID ); - - List orgUnits = new ArrayList( user.getDataViewOrganisationUnits() ); - - DimensionalObject constraint = new BaseDimensionalObject( DimensionalObject.ORGUNIT_DIM_ID, DimensionType.ORGANISATIONUNIT, orgUnits ); - - params.getFilters().add( constraint ); - - log.info( "User: " + user.getUsername() + " constrained by data view organisation units" ); - } - - private void applyUserConstraints( DataQueryParams params ) - { - User user = currentUserService.getCurrentUser(); - - // --------------------------------------------------------------------- - // Check if current user has dimension constraints - // --------------------------------------------------------------------- - - if ( params == null || user == null || user.getUserCredentials() == null || !user.getUserCredentials().hasDimensionConstraints() ) - { - return; - } - - Set dimensionConstraints = user.getUserCredentials().getDimensionConstraints(); - - for ( DimensionalObject dimension : dimensionConstraints ) - { - // ----------------------------------------------------------------- - // Check if constraint already is specified with items - // ----------------------------------------------------------------- - - if ( params.hasDimensionOrFilterWithItems( dimension.getUid() ) ) - { - continue; - } - - List canReadItems = dimensionService.getCanReadDimensionItems( dimension.getDimension() ); - - // ----------------------------------------------------------------- - // Check if current user has access to any items from constraint - // ----------------------------------------------------------------- - - if ( canReadItems == null || canReadItems.isEmpty() ) - { - throw new IllegalQueryException( "Current user is constrained by a dimension but has access to no associated dimension items: " + dimension.getDimension() ); - } - - // ----------------------------------------------------------------- - // Apply constraint as filter, and remove potential all-dimension - // ----------------------------------------------------------------- - - params.removeDimensionOrFilter( dimension.getDimension() ); - - DimensionalObject constraint = new BaseDimensionalObject( dimension.getDimension(), - dimension.getDimensionType(), null, dimension.getDisplayName(), canReadItems ); - - params.getFilters().add( constraint ); - - log.info( "User: " + user.getUsername() + " constrained by dimension: " + constraint.getDimension() ); - } - } - // ------------------------------------------------------------------------- // Supportive methods // ------------------------------------------------------------------------- === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryPlanner.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryPlanner.java 2014-04-11 07:58:35 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryPlanner.java 2014-04-14 08:42:46 +0000 @@ -30,7 +30,6 @@ import java.util.List; -import org.hisp.dhis.analytics.DataQueryParams; import org.hisp.dhis.common.IllegalQueryException; /** @@ -56,13 +55,4 @@ * @param params the query params. */ EventQueryParams planEventQuery( EventQueryParams params ); - - /** - * Decides whether the current user has privileges to execute the given query. - * - * @param params the data query params. - * @throws IllegalQueryException if the current user does not have privileges - * to execute the given query. - */ - void decideAccess( DataQueryParams params ); } === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java 2014-04-11 07:58:35 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java 2014-04-14 08:42:46 +0000 @@ -44,6 +44,7 @@ import java.util.Map; import java.util.Set; +import org.hisp.dhis.analytics.AnalyticsSecurityManager; import org.hisp.dhis.analytics.AnalyticsService; import org.hisp.dhis.analytics.SortOrder; import org.hisp.dhis.analytics.event.EventAnalyticsManager; @@ -114,6 +115,9 @@ private EventAnalyticsManager analyticsManager; @Autowired + private AnalyticsSecurityManager securityManager; + + @Autowired private EventQueryPlanner queryPlanner; @Autowired @@ -128,7 +132,7 @@ public Grid getAggregatedEventData( EventQueryParams params ) { - queryPlanner.decideAccess( params ); + securityManager.decideAccess( params ); queryPlanner.validate( params ); @@ -194,7 +198,7 @@ public Grid getEvents( EventQueryParams params ) { - queryPlanner.decideAccess( params ); + securityManager.decideAccess( params ); queryPlanner.validate( params ); === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventQueryPlanner.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventQueryPlanner.java 2014-04-11 07:58:35 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventQueryPlanner.java 2014-04-14 08:42:46 +0000 @@ -169,11 +169,6 @@ return params; } - public void decideAccess( DataQueryParams params ) - { - queryPlanner.decideAccess( params ); - } - // ------------------------------------------------------------------------- // Supportive methods // ------------------------------------------------------------------------- === added directory 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/security' === added file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/security/DefaultAnalyticsSecurityManager.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/security/DefaultAnalyticsSecurityManager.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/security/DefaultAnalyticsSecurityManager.java 2014-04-14 08:42:46 +0000 @@ -0,0 +1,157 @@ +package org.hisp.dhis.analytics.security; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hisp.dhis.analytics.AnalyticsSecurityManager; +import org.hisp.dhis.analytics.DataQueryParams; +import org.hisp.dhis.common.BaseDimensionalObject; +import org.hisp.dhis.common.DimensionService; +import org.hisp.dhis.common.DimensionType; +import org.hisp.dhis.common.DimensionalObject; +import org.hisp.dhis.common.IllegalQueryException; +import org.hisp.dhis.common.NameableObject; +import org.hisp.dhis.organisationunit.OrganisationUnit; +import org.hisp.dhis.user.CurrentUserService; +import org.hisp.dhis.user.User; +import org.springframework.beans.factory.annotation.Autowired; + +public class DefaultAnalyticsSecurityManager + implements AnalyticsSecurityManager +{ + private static final Log log = LogFactory.getLog( DefaultAnalyticsSecurityManager.class ); + + @Autowired + private CurrentUserService currentUserService; + + @Autowired + private DimensionService dimensionService; + + public void decideAccess( DataQueryParams params ) + { + // --------------------------------------------------------------------- + // Check current user data view access to org units + // --------------------------------------------------------------------- + + User user = currentUserService.getCurrentUser(); + + List queryOrgUnits = params.getDimensionOrFilter( DimensionalObject.ORGUNIT_DIM_ID ); + + if ( queryOrgUnits == null || user == null || !user.hasDataViewOrganisationUnit() ) + { + return; + } + + Set viewOrgUnits = user.getDataViewOrganisationUnits(); + + for ( NameableObject object : queryOrgUnits ) + { + OrganisationUnit queryOrgUnit = (OrganisationUnit) object; + + if ( !queryOrgUnit.isEqualOrChildOf( viewOrgUnits ) ) + { + throw new IllegalQueryException( "Org unit is not viewable for current user: " + queryOrgUnit.getUid() ); + } + } + } + + public void applyDimensionConstraints( DataQueryParams params ) + { + applyOrganisationUnitConstraint( params ); + applyUserConstraints( params ); + } + + private void applyOrganisationUnitConstraint( DataQueryParams params ) + { + User user = currentUserService.getCurrentUser(); + + // --------------------------------------------------------------------- + // Check if current user has data view organisation units + // --------------------------------------------------------------------- + + if ( params == null || user == null || !user.hasDataViewOrganisationUnit() ) + { + return; + } + + // --------------------------------------------------------------------- + // Check if request already has organisation units specified + // --------------------------------------------------------------------- + + if ( params.hasDimensionOrFilterWithItems( DimensionalObject.ORGUNIT_DIM_ID ) ) + { + return; + } + + // ----------------------------------------------------------------- + // Apply constraint as filter, and remove potential all-dimension + // ----------------------------------------------------------------- + + params.removeDimensionOrFilter( DimensionalObject.ORGUNIT_DIM_ID ); + + List orgUnits = new ArrayList( user.getDataViewOrganisationUnits() ); + + DimensionalObject constraint = new BaseDimensionalObject( DimensionalObject.ORGUNIT_DIM_ID, DimensionType.ORGANISATIONUNIT, orgUnits ); + + params.getFilters().add( constraint ); + + log.info( "User: " + user.getUsername() + " constrained by data view organisation units" ); + } + + private void applyUserConstraints( DataQueryParams params ) + { + User user = currentUserService.getCurrentUser(); + + // --------------------------------------------------------------------- + // Check if current user has dimension constraints + // --------------------------------------------------------------------- + + if ( params == null || user == null || user.getUserCredentials() == null || !user.getUserCredentials().hasDimensionConstraints() ) + { + return; + } + + Set dimensionConstraints = user.getUserCredentials().getDimensionConstraints(); + + for ( DimensionalObject dimension : dimensionConstraints ) + { + // ----------------------------------------------------------------- + // Check if constraint already is specified with items + // ----------------------------------------------------------------- + + if ( params.hasDimensionOrFilterWithItems( dimension.getUid() ) ) + { + continue; + } + + List canReadItems = dimensionService.getCanReadDimensionItems( dimension.getDimension() ); + + // ----------------------------------------------------------------- + // Check if current user has access to any items from constraint + // ----------------------------------------------------------------- + + if ( canReadItems == null || canReadItems.isEmpty() ) + { + throw new IllegalQueryException( "Current user is constrained by a dimension but has access to no associated dimension items: " + dimension.getDimension() ); + } + + // ----------------------------------------------------------------- + // Apply constraint as filter, and remove potential all-dimension + // ----------------------------------------------------------------- + + params.removeDimensionOrFilter( dimension.getDimension() ); + + DimensionalObject constraint = new BaseDimensionalObject( dimension.getDimension(), + dimension.getDimensionType(), null, dimension.getDisplayName(), canReadItems ); + + params.getFilters().add( constraint ); + + log.info( "User: " + user.getUsername() + " constrained by dimension: " + constraint.getDimension() ); + } + } + + +} === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/resources/META-INF/dhis/beans.xml' --- dhis-2/dhis-services/dhis-service-analytics/src/main/resources/META-INF/dhis/beans.xml 2014-03-26 18:14:37 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/resources/META-INF/dhis/beans.xml 2014-04-14 08:42:46 +0000 @@ -42,6 +42,8 @@ + +