← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 9541: implemented anyAuthorities for struts config, allows OR checking or authorities

 

------------------------------------------------------------
revno: 9541
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2013-01-17 14:32:15 +0100
message:
  implemented anyAuthorities for struts config, allows OR checking or authorities
modified:
  dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/authority/DefaultRequiredAuthoritiesProvider.java
  dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/authority/DetectingSystemAuthoritiesProvider.java
  dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/authority/RequiredAuthoritiesProvider.java
  dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/vote/ActionAccessVoter.java
  dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/security.xml
  dhis-2/dhis-web/dhis-web-reporting/src/main/resources/struts.xml


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/authority/DefaultRequiredAuthoritiesProvider.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/authority/DefaultRequiredAuthoritiesProvider.java	2013-01-17 12:05:04 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/authority/DefaultRequiredAuthoritiesProvider.java	2013-01-17 13:32:15 +0000
@@ -30,12 +30,14 @@
 import com.opensymphony.xwork2.config.entities.ActionConfig;
 import org.hisp.dhis.security.StrutsAuthorityUtils;
 import org.hisp.dhis.security.intercept.SingleSecurityMetadataSource;
+import org.springframework.beans.factory.annotation.Required;
 import org.springframework.security.access.ConfigAttribute;
 import org.springframework.security.access.SecurityMetadataSource;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -51,11 +53,20 @@
 
     private String requiredAuthoritiesKey;
 
+    @Required
     public void setRequiredAuthoritiesKey( String requiredAuthoritiesKey )
     {
         this.requiredAuthoritiesKey = requiredAuthoritiesKey;
     }
 
+    private String anyAuthoritiesKey;
+
+    @Required
+    public void setAnyAuthoritiesKey( String anyAuthoritiesKey )
+    {
+        this.anyAuthoritiesKey = anyAuthoritiesKey;
+    }
+
     private Set<String> globalAttributes = Collections.emptySet();
 
     public void setGlobalAttributes( Set<String> globalAttributes )
@@ -81,8 +92,22 @@
         return new SingleSecurityMetadataSource( object, attributes );
     }
 
+    public Collection<String> getAllAuthorities( ActionConfig actionConfig )
+    {
+        Collection<String> authorities = new HashSet<String>();
+        authorities.addAll( getRequiredAuthorities( actionConfig ) );
+        authorities.addAll( getAnyAuthorities( actionConfig ) );
+
+        return authorities;
+    }
+
     public Collection<String> getRequiredAuthorities( ActionConfig actionConfig )
     {
         return StrutsAuthorityUtils.getAuthorities( actionConfig, requiredAuthoritiesKey );
     }
+
+    public Collection<String> getAnyAuthorities( ActionConfig actionConfig )
+    {
+        return StrutsAuthorityUtils.getAuthorities( actionConfig, anyAuthoritiesKey );
+    }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/authority/DetectingSystemAuthoritiesProvider.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/authority/DetectingSystemAuthoritiesProvider.java	2013-01-17 12:05:04 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/authority/DetectingSystemAuthoritiesProvider.java	2013-01-17 13:32:15 +0000
@@ -27,14 +27,13 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import java.util.Collection;
-import java.util.HashSet;
-
-import org.apache.struts2.dispatcher.Dispatcher;
-
 import com.opensymphony.xwork2.config.Configuration;
 import com.opensymphony.xwork2.config.entities.ActionConfig;
 import com.opensymphony.xwork2.config.entities.PackageConfig;
+import org.apache.struts2.dispatcher.Dispatcher;
+
+import java.util.Collection;
+import java.util.HashSet;
 
 /**
  * @author Torgeir Lorange Ostby
@@ -68,7 +67,7 @@
         {
             for ( ActionConfig actionConfig : packageConfig.getActionConfigs().values() )
             {
-                authorities.addAll( requiredAuthoritiesProvider.getRequiredAuthorities( actionConfig ) );
+                authorities.addAll( requiredAuthoritiesProvider.getAllAuthorities( actionConfig ) );
             }
         }
 

=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/authority/RequiredAuthoritiesProvider.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/authority/RequiredAuthoritiesProvider.java	2013-01-17 12:05:04 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/authority/RequiredAuthoritiesProvider.java	2013-01-17 13:32:15 +0000
@@ -27,12 +27,11 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import com.opensymphony.xwork2.config.entities.ActionConfig;
+import org.springframework.security.access.SecurityMetadataSource;
+
 import java.util.Collection;
 
-import org.springframework.security.access.SecurityMetadataSource;
-
-import com.opensymphony.xwork2.config.entities.ActionConfig;
-
 /**
  * @author Torgeir Lorange Ostby
  * @version $Id: RequiredAuthoritiesProvider.java 3160 2007-03-24 20:15:06Z torgeilo $
@@ -46,7 +45,7 @@
      * needed.
      *
      * @param actionConfig the secure actionConfig to get required authorities
-     *        from.
+     *                     from.
      */
     public SecurityMetadataSource createSecurityMetadataSource( ActionConfig actionConfig );
 
@@ -56,11 +55,16 @@
      * SecurityMetadataSource may include additional attributes if needed.
      *
      * @param actionConfig the actionConfig to get required authorities from.
-     * @param object the secure object.
+     * @param object       the secure object.
      */
     public SecurityMetadataSource createSecurityMetadataSource( ActionConfig actionConfig, Object object );
 
     /**
+     * Returns all authorities of an action configuration.
+     */
+    public Collection<String> getAllAuthorities( ActionConfig actionConfig );
+
+    /**
      * Returns the required authorities of an action configuration.
      */
     public Collection<String> getRequiredAuthorities( ActionConfig actionConfig );

=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/vote/ActionAccessVoter.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/vote/ActionAccessVoter.java	2013-01-17 12:05:04 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/vote/ActionAccessVoter.java	2013-01-17 13:32:15 +0000
@@ -30,6 +30,8 @@
 import com.opensymphony.xwork2.config.entities.ActionConfig;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.security.StrutsAuthorityUtils;
+import org.springframework.beans.factory.annotation.Required;
 import org.springframework.security.access.ConfigAttribute;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
@@ -46,6 +48,26 @@
     private static final Log LOG = LogFactory.getLog( ActionAccessVoter.class );
 
     // -------------------------------------------------------------------------
+    // AccessDecisionVoter Input
+    // -------------------------------------------------------------------------
+
+    private String requiredAuthoritiesKey;
+
+    @Required
+    public void setRequiredAuthoritiesKey( String requiredAuthoritiesKey )
+    {
+        this.requiredAuthoritiesKey = requiredAuthoritiesKey;
+    }
+
+    private String anyAuthoritiesKey;
+
+    @Required
+    public void setAnyAuthoritiesKey( String anyAuthoritiesKey )
+    {
+        this.anyAuthoritiesKey = anyAuthoritiesKey;
+    }
+
+    // -------------------------------------------------------------------------
     // AccessDecisionVoter implementation
     // -------------------------------------------------------------------------
 
@@ -69,6 +91,34 @@
             return ACCESS_ABSTAIN;
         }
 
+        ActionConfig actionConfig = (ActionConfig) object;
+        Collection<ConfigAttribute> requiredAuthorities = StrutsAuthorityUtils.getConfigAttributes( actionConfig, requiredAuthoritiesKey );
+        Collection<ConfigAttribute> anyAuthorities = StrutsAuthorityUtils.getConfigAttributes( actionConfig, anyAuthoritiesKey );
+
+        int allStatus = allAuthorities( authentication, object, requiredAuthorities );
+
+        if ( allStatus == ACCESS_DENIED )
+        {
+            return ACCESS_DENIED;
+        }
+
+        int anyStatus = anyAuthority( authentication, object, anyAuthorities );
+
+        if ( anyStatus == ACCESS_DENIED )
+        {
+            return ACCESS_DENIED;
+        }
+
+        if ( allStatus == ACCESS_GRANTED || anyStatus == ACCESS_GRANTED )
+        {
+            return ACCESS_GRANTED;
+        }
+
+        return ACCESS_ABSTAIN;
+    }
+
+    private int allAuthorities( Authentication authentication, Object object, Collection<ConfigAttribute> attributes )
+    {
         int supported = 0;
 
         for ( ConfigAttribute attribute : attributes )
@@ -107,4 +157,46 @@
 
         return ACCESS_ABSTAIN;
     }
+
+    private int anyAuthority( Authentication authentication, Object object, Collection<ConfigAttribute> attributes )
+    {
+        int supported = 0;
+        boolean found = false;
+
+        for ( ConfigAttribute attribute : attributes )
+        {
+            if ( supports( attribute ) )
+            {
+                ++supported;
+
+                for ( GrantedAuthority authority : authentication.getAuthorities() )
+                {
+                    if ( authority.getAuthority().equals( attribute.getAttribute() ) )
+                    {
+                        found = true;
+                        break;
+                    }
+                }
+
+            }
+        }
+
+        if ( !found && supported > 0 )
+        {
+            LOG.debug( "ACCESS_DENIED [" + object.toString() + "]" );
+
+            return ACCESS_DENIED;
+        }
+
+        if ( supported > 0 )
+        {
+            LOG.debug( "ACCESS_GRANTED [" + object.toString() + "]" );
+
+            return ACCESS_GRANTED;
+        }
+
+        LOG.debug( "ACCESS_ABSTAIN [" + object.toString() + "]: No supported attributes." );
+
+        return ACCESS_ABSTAIN;
+    }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/security.xml'
--- dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/security.xml	2013-01-17 12:05:04 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/security.xml	2013-01-17 13:32:15 +0000
@@ -128,6 +128,8 @@
 
   <bean id="actionAccessVoter" class="org.hisp.dhis.security.vote.ActionAccessVoter">
     <property name="attributePrefix" value="F_" />
+    <property name="requiredAuthoritiesKey" value="requiredAuthorities" />
+    <property name="anyAuthoritiesKey" value="anyAuthorities" />
   </bean>
 
   <bean id="moduleAccessVoter" class="org.hisp.dhis.security.vote.ModuleAccessVoter">
@@ -182,6 +184,7 @@
   <bean id="org.hisp.dhis.security.authority.RequiredAuthoritiesProvider"
     class="org.hisp.dhis.security.authority.DefaultRequiredAuthoritiesProvider">
     <property name="requiredAuthoritiesKey" value="requiredAuthorities" />
+    <property name="anyAuthoritiesKey" value="anyAuthorities" />
     <property name="globalAttributes">
       <set>
         <value>M_MODULE_ACCESS_VOTER_ENABLED</value>

=== modified file 'dhis-2/dhis-web/dhis-web-reporting/src/main/resources/struts.xml'
--- dhis-2/dhis-web/dhis-web-reporting/src/main/resources/struts.xml	2013-01-17 12:05:04 +0000
+++ dhis-2/dhis-web/dhis-web-reporting/src/main/resources/struts.xml	2013-01-17 13:32:15 +0000
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE struts PUBLIC
-"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
-"http://struts.apache.org/dtds/struts-2.0.dtd";>
+  "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
+  "http://struts.apache.org/dtds/struts-2.0.dtd";>
 <struts>
 
   <include file="dhis-web-commons.xml" />
@@ -13,13 +13,14 @@
       <param name="page">/dhis-web-reporting/index.vm</param>
       <param name="menu">/dhis-web-reporting/menu.vm</param>
     </action>
-	    
+
     <!-- Document -->
 
     <action name="saveDocument" class="org.hisp.dhis.reporting.document.action.SaveDocumentAction">
       <result name="success" type="redirect">displayViewDocumentForm.action</result>
       <interceptor-ref name="fileUploadStack" />
       <param name="requiredAuthorities">F_DOCUMENT_ADD</param>
+      <param name="anyAuthorities">F_DOCUMENT_PUBLIC_ADD,F_DOCUMENT_PRIVATE_ADD</param>
     </action>
 
     <action name="removeDocument" class="org.hisp.dhis.reporting.document.action.RemoveDocumentAction">
@@ -53,7 +54,7 @@
       <result name="success" type="velocity-json">/dhis-web-commons/ajax/jsonResponseSuccess.vm</result>
       <param name="onExceptionReturn">plainTextError</param>
     </action>
-    
+
     <!-- Chart -->
 
     <action name="viewChart" class="org.hisp.dhis.reporting.chart.action.ViewChartAction">
@@ -63,7 +64,7 @@
     <action name="generateChart" class="org.hisp.dhis.reporting.chart.action.GenerateChartAction">
       <result name="success" type="chart"></result>
     </action>
-    
+
     <!-- Report -->
 
     <action name="displayAddReportForm" class="org.hisp.dhis.reporting.reportviewer.action.GetReportOptionsAction">
@@ -93,17 +94,17 @@
       <param name="menu">/dhis-web-reporting/menu.vm</param>
       <param name="javascripts">javascript/report.js</param>
     </action>
-	
+
     <action name="getReport" class="org.hisp.dhis.reporting.reportviewer.action.GetReportAction">
       <result name="success" type="velocity-json">/dhis-web-reporting/jsonReport.vm</result>
       <param name="onExceptionReturn">plainTextError</param>
     </action>
-	
+
     <action name="getReports" class="org.hisp.dhis.reporting.reportviewer.action.GetAllReportsAction">
       <result name="success" type="velocity-json">/dhis-web-reporting/jsonReports.vm</result>
       <param name="onExceptionReturn">plainTextError</param>
     </action>
-	
+
     <action name="addReportToDashboard" class="org.hisp.dhis.reporting.reportviewer.action.AddReportToDashboardAction">
       <result name="success" type="velocity-json">/dhis-web-commons/ajax/jsonResponseSuccess.vm</result>
       <param name="onExceptionReturn">plainTextError</param>
@@ -112,17 +113,17 @@
     <action name="getReportDesign" class="org.hisp.dhis.reporting.reportviewer.action.GetReportDesignAction">
       <result name="success" type="outputStreamResult" />
     </action>
-	
-	<action name="validateReport" class="org.hisp.dhis.reporting.reportviewer.action.ValidateReportAction">	  
+
+    <action name="validateReport" class="org.hisp.dhis.reporting.reportviewer.action.ValidateReportAction">
       <result name="success" type="velocity-json">/dhis-web-commons/ajax/jsonResponseSuccess.vm</result>
       <result name="input" type="velocity-json">/dhis-web-commons/ajax/jsonResponseInput.vm</result>
       <param name="onExceptionReturn">plainTextError</param>
     </action>
-	
-	<action name="getReportTemplate" class="org.hisp.dhis.reporting.reportviewer.action.GetReportTemplateAction">
-	  <result name="success" type="outputStreamResult" />
-	</action>
-	
+
+    <action name="getReportTemplate" class="org.hisp.dhis.reporting.reportviewer.action.GetReportTemplateAction">
+      <result name="success" type="outputStreamResult" />
+    </action>
+
     <!-- ReportTable -->
 
     <action name="displayManageTableForm" class="org.hisp.dhis.reporting.tablecreator.action.GetAllTablesAction">
@@ -131,12 +132,12 @@
       <param name="menu">/dhis-web-reporting/menu.vm</param>
       <param name="javascripts">javascript/table.js</param>
     </action>
-	
+
     <action name="getReportTables" class="org.hisp.dhis.reporting.tablecreator.action.GetAllTablesAction">
       <result name="success" type="velocity-json">/dhis-web-reporting/jsonReportTables.vm</result>
       <param name="onExceptionReturn">plainTextError</param>
     </action>
-	
+
     <action name="removeTable" class="org.hisp.dhis.reporting.tablecreator.action.RemoveTableAction">
       <result name="success" type="velocity-json">/dhis-web-commons/ajax/jsonResponseSuccess.vm</result>
       <param name="requiredAuthorities">F_REPORTTABLE_DELETE</param>
@@ -189,14 +190,14 @@
       <param name="page">/dhis-web-reporting/reportTableGrid.vm</param>
       <param name="hideMenu">true</param>
       <param name="javascripts">javascript/generateReport.js</param>
-	  <param name="stylesheets">style/dhis-web-reporting.css</param>
+      <param name="stylesheets">style/dhis-web-reporting.css</param>
     </action>
 
     <action name="getCategoryComboDataElements" class="org.hisp.dhis.reporting.tablecreator.action.GetCategoryComboDataElementsAction">
       <result name="success" type="velocity-xml">../dhis-web-commons/ajax/xmlDataElements.vm</result>
       <param name="onExceptionReturn">plainTextError</param>
     </action>
-    
+
     <!-- PivotTable -->
 
     <action name="displayPivotTableForm" class="org.hisp.dhis.reporting.pivottable.action.GetPivotTableOptionsAction">
@@ -206,12 +207,12 @@
       <param name="javascripts">../dhis-web-commons/oust/oust.js,javascript/pivot.js</param>
     </action>
 
-    <action name="getPivotTable" class="org.hisp.dhis.reporting.pivottable.action.GetPivotTableAction">	  
-	  <result name="xls" type="gridXlsResult"/>
+    <action name="getPivotTable" class="org.hisp.dhis.reporting.pivottable.action.GetPivotTableAction">
+      <result name="xls" type="gridXlsResult" />
       <result name="json" type="velocity-json">/dhis-web-reporting/responsePivotTable.vm</result>
       <param name="onExceptionReturn">plainTextError</param>
     </action>
-        
+
     <!-- Data Completeness -->
 
     <action name="displayViewDataCompletenessForm" class="org.hisp.dhis.reporting.completeness.action.GetDataCompletenessOptionsAction">
@@ -227,8 +228,8 @@
       <result name="xls" type="gridXlsResult" />
       <result name="pdf" type="gridPdfResult" />
       <result name="html" type="velocity">/dhis-web-commons/ajax/htmlGrid.vm</result>
-    </action> 
-    
+    </action>
+
     <!-- DataSet Report -->
 
     <action name="showDataSetReportForm" class="org.hisp.dhis.reporting.dataset.action.GetDataSetReportOptionsAction">
@@ -236,17 +237,17 @@
       <param name="page">/dhis-web-reporting/dataSetReportForm.vm</param>
       <param name="menu">/dhis-web-reporting/menu.vm</param>
       <param name="javascripts">../dhis-web-commons/oust/oust.js,javascript/dataSetReport.js</param>
-	  <param name="stylesheets">style/dhis-web-reporting.css</param>
+      <param name="stylesheets">style/dhis-web-reporting.css</param>
     </action>
 
     <action name="generateDataSetReport" class="org.hisp.dhis.reporting.dataset.action.GenerateDataSetReportAction">
-	  <result name="default" type="velocity">/dhis-web-reporting/renderDefaultDataSetReportForm.vm</result>
-	  <result name="section" type="velocity">/dhis-web-reporting/renderSectionDataSetReportForm.vm</result>
-	  <result name="custom" type="velocity">/dhis-web-reporting/renderCustomDataSetReportForm.vm</result>
+      <result name="default" type="velocity">/dhis-web-reporting/renderDefaultDataSetReportForm.vm</result>
+      <result name="section" type="velocity">/dhis-web-reporting/renderSectionDataSetReportForm.vm</result>
+      <result name="custom" type="velocity">/dhis-web-reporting/renderCustomDataSetReportForm.vm</result>
       <result name="xls" type="gridXlsResult" />
       <result name="pdf" type="gridPdfResult" />
     </action>
-	        
+
     <!-- Organisation Unit Distribution -->
 
     <action name="getOrgUnitDistribution" class="org.hisp.dhis.reporting.orgunitdistribution.action.GetOrgUnitDistributionAction">
@@ -256,7 +257,8 @@
       <result name="html" type="velocity">/dhis-web-commons/ajax/htmlGrid.vm</result>
     </action>
 
-    <action name="displayOrgUnitDistribution" class="org.hisp.dhis.reporting.orgunitdistribution.action.GetOrgUnitDistributionOptionsAction">
+    <action name="displayOrgUnitDistribution"
+      class="org.hisp.dhis.reporting.orgunitdistribution.action.GetOrgUnitDistributionOptionsAction">
       <result name="success" type="velocity">/main.vm</result>
       <param name="page">/dhis-web-reporting/viewOrgUnitDistribution.vm</param>
       <param name="menu">/dhis-web-reporting/menu.vm</param>
@@ -266,24 +268,24 @@
     <action name="getOrgUnitDistributionChart" class="org.hisp.dhis.reporting.orgunitdistribution.action.GetOrgUnitDistributionChartAction">
       <result name="success" type="chart"></result>
     </action>
-	
-	<!-- Data mart -->
-	
-	<action name="displayDataMartForm" class="org.hisp.dhis.reporting.action.NoAction">
-	  <result name="success" type="velocity">/main.vm</result>
+
+    <!-- Data mart -->
+
+    <action name="displayDataMartForm" class="org.hisp.dhis.reporting.action.NoAction">
+      <result name="success" type="velocity">/main.vm</result>
       <param name="page">/dhis-web-reporting/viewDataMartForm.vm</param>
       <param name="menu">/dhis-web-reporting/menu.vm</param>
       <param name="javascripts">javascript/dataMart.js</param>
       <param name="requiredAuthorities">F_DATA_MART_ADMIN</param>
-	</action>
-	
-	<action name="startExport" class="org.hisp.dhis.reporting.datamart.action.StartExportAction">
-	  <result name="success" type="velocity-json">/dhis-web-commons/ajax/jsonResponseSuccess.vm</result>
+    </action>
+
+    <action name="startExport" class="org.hisp.dhis.reporting.datamart.action.StartExportAction">
+      <result name="success" type="velocity-json">/dhis-web-commons/ajax/jsonResponseSuccess.vm</result>
       <param name="onExceptionReturn">plainTextError</param>
       <param name="requiredAuthorities">F_DATA_MART_ADMIN</param>
-	</action>
-	
-	<!-- Datamart CSV Export -->
+    </action>
+
+    <!-- Datamart CSV Export -->
 
     <action name="weeklyDataValues" class="org.hisp.dhis.reporting.exp.ExportDataMartAction">
       <result name="success" type="outputStreamResult" />
@@ -358,6 +360,6 @@
       </result>
       <param name="requiredAuthorities">F_MYDATAMART_VIEW</param>
     </action>
-	
+
   </package>
 </struts>