← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 11648: (web-api) external access, allows certain types to be accessed externally without login, wip

 

------------------------------------------------------------
revno: 11648
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Tue 2013-08-13 09:18:45 +0200
message:
  (web-api) external access, allows certain types to be accessed externally without login, wip
added:
  dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/vote/ExternalAccessVoter.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/Access.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseIdentifiableObject.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/CodeGenerator.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/IdentifiableObject.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/IdentifiableObjectManager.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/SharingUtils.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/common/DefaultIdentifiableObjectManager.java
  dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/security.xml
  dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/mapping/hibernate/Map.hbm.xml
  dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/chart/hibernate/Chart.hbm.xml
  dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/reporttable/hibernate/ReportTable.hbm.xml
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AbstractCrudController.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/SharingController.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/webdomain/sharing/Meta.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/webdomain/sharing/SharingObject.java
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.sharing.js
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/macros.vm
  dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/GhostAutomaticAccessProvider.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-commons/src/main/resources/i18n_global.properties


--
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-api/src/main/java/org/hisp/dhis/common/Access.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/Access.java	2013-03-15 17:37:07 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/Access.java	2013-08-13 07:18:45 +0000
@@ -39,6 +39,8 @@
 {
     private boolean manage;
 
+    private boolean externalize;
+
     private boolean write;
 
     private boolean read;
@@ -64,6 +66,18 @@
     }
 
     @JsonProperty
+    @JacksonXmlProperty( localName = "manage", namespace = DxfNamespaces.DXF_2_0 )
+    public boolean isExternalize()
+    {
+        return externalize;
+    }
+
+    public void setExternalize( boolean externalize )
+    {
+        this.externalize = externalize;
+    }
+
+    @JsonProperty
     @JacksonXmlProperty( localName = "write", namespace = DxfNamespaces.DXF_2_0 )
     public boolean isWrite()
     {

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseIdentifiableObject.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseIdentifiableObject.java	2013-08-12 08:56:50 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseIdentifiableObject.java	2013-08-13 07:18:45 +0000
@@ -90,6 +90,11 @@
     protected Date lastUpdated;
 
     /**
+     * This object is available as external read-only
+     */
+    protected boolean externalAccess;
+
+    /**
      * Access string for public access.
      */
     protected String publicAccess;
@@ -121,14 +126,14 @@
     public BaseIdentifiableObject()
     {
     }
-    
+
     public BaseIdentifiableObject( int id, String uid, String name )
     {
         this.id = id;
         this.uid = uid;
         this.name = name;
     }
-    
+
     public BaseIdentifiableObject( String uid, String code, String name )
     {
         this.uid = uid;
@@ -256,6 +261,20 @@
         this.publicAccess = publicAccess;
     }
 
+    @Override
+    @JsonProperty
+    @JsonView({ DetailedView.class, ExportView.class })
+    @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0)
+    public boolean getExternalAccess()
+    {
+        return externalAccess;
+    }
+
+    public void setExternalAccess( Boolean externalAccess )
+    {
+        this.externalAccess = externalAccess == null ? false : externalAccess;
+    }
+
     /*
     @Override
     @JsonProperty
@@ -446,12 +465,12 @@
     {
         return "[IdentifiableObject: " +
             "id='" + id +
-            "', uid='" + uid + 
-            "', code='" + code + 
-            "', name='" + name + 
-            "', created='" + created + 
-            "', lastUpdated='" + lastUpdated + 
-            "', class='" + getClass().getSimpleName() + 
+            "', uid='" + uid +
+            "', code='" + code +
+            "', name='" + name +
+            "', created='" + created +
+            "', lastUpdated='" + lastUpdated +
+            "', class='" + getClass().getSimpleName() +
             "']";
     }
 

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/CodeGenerator.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/CodeGenerator.java	2013-01-28 18:38:14 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/CodeGenerator.java	2013-08-13 07:18:45 +0000
@@ -87,7 +87,7 @@
      * @param code the code to validate.
      * @return true if the code is valid.
      */
-    public boolean isValidCode( String code )
+    public static boolean isValidCode( String code )
     {
         return code != null && CODE_PATTERN.matcher( code ).matches();
     }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/IdentifiableObject.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/IdentifiableObject.java	2013-03-15 17:37:07 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/IdentifiableObject.java	2013-08-13 07:18:45 +0000
@@ -49,9 +49,7 @@
 
     String getName();
 
-    boolean haveUniqueNames();
-
-    boolean isAutoGenerated();
+    String getDisplayName();
 
     String getCode();
 
@@ -59,13 +57,17 @@
 
     Date getLastUpdated();
 
+    boolean haveUniqueNames();
+
+    boolean isAutoGenerated();
+
     String getPublicAccess();
 
+    boolean getExternalAccess();
+
     User getUser();
 
     Set<UserGroupAccess> getUserGroupAccesses();
 
-    String getDisplayName();
-
     Access getAccess();
 }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/IdentifiableObjectManager.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/IdentifiableObjectManager.java	2013-08-06 10:26:03 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/IdentifiableObjectManager.java	2013-08-13 07:18:45 +0000
@@ -47,6 +47,8 @@
 
     <T extends IdentifiableObject> T get( Class<T> clazz, String uid );
 
+    <T extends IdentifiableObject> boolean exists( Class<T> clazz, String uid );
+
     <T extends IdentifiableObject> T getByCode( Class<T> clazz, String code );
 
     <T extends IdentifiableObject> T getByName( Class<T> clazz, String name );

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/SharingUtils.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/SharingUtils.java	2013-07-19 09:29:54 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/SharingUtils.java	2013-08-13 07:18:45 +0000
@@ -57,6 +57,8 @@
  */
 public final class SharingUtils
 {
+    public static Map<Class<? extends IdentifiableObject>, String> EXTERNAL_AUTHORITIES = new HashMap<Class<? extends IdentifiableObject>, String>();
+
     public static Map<Class<? extends IdentifiableObject>, String> PUBLIC_AUTHORITIES = new HashMap<Class<? extends IdentifiableObject>, String>();
 
     public static Map<Class<? extends IdentifiableObject>, String> PRIVATE_AUTHORITIES = new HashMap<Class<? extends IdentifiableObject>, String>();
@@ -65,13 +67,18 @@
 
     public static final List<String> SHARING_OVERRIDE_AUTHORITIES = Arrays.asList( "ALL", "F_METADATA_IMPORT" );
 
-    private static void addType( Class<? extends IdentifiableObject> clazz, String name, String publicAuth, String privateAuth )
+    private static void addType( Class<? extends IdentifiableObject> clazz, String name, String externalAuth, String publicAuth, String privateAuth )
     {
         Assert.notNull( clazz );
         Assert.hasLength( name );
 
         SUPPORTED_TYPES.put( name, clazz );
 
+        if ( externalAuth != null )
+        {
+            EXTERNAL_AUTHORITIES.put( clazz, externalAuth );
+        }
+
         if ( publicAuth != null )
         {
             PUBLIC_AUTHORITIES.put( clazz, publicAuth );
@@ -85,20 +92,21 @@
 
     static
     {
-        addType( Document.class, "document", "F_DOCUMENT_PUBLIC_ADD", "F_DOCUMENT_PRIVATE_ADD" );
-        addType( Report.class, "report", "F_REPORT_PUBLIC_ADD", "F_REPORT_PRIVATE_ADD" );
-        addType( DataSet.class, "dataSet", "F_DATASET_PUBLIC_ADD", "F_DATASET_PRIVATE_ADD" );
-        addType( DataDictionary.class, "dataDictionary", "F_DATADICTIONARY_PUBLIC_ADD", "F_DATADICTIONARY_PRIVATE_ADD" );
-        addType( Indicator.class, "indicator", "F_INDICATOR_PUBLIC_ADD", "F_INDICATOR_PRIVATE_ADD" );
-        addType( IndicatorGroup.class, "indicatorGroup", "F_INDICATORGROUP_PUBLIC_ADD", "F_INDICATORGROUP_PRIVATE_ADD" );
-        addType( IndicatorGroupSet.class, "indicatorGroupSet", "F_INDICATORGROUPSET_PUBLIC_ADD", "F_INDICATORGROUPSET_PRIVATE_ADD" );
-        addType( Program.class, "program", "F_PROGRAM_PUBLIC_ADD", "F_PROGRAM_PRIVATE_ADD" );
-        addType( UserGroup.class, "userGroup", "F_USERGROUP_PUBLIC_ADD", null );
-        addType( ReportTable.class, "reportTable", "F_REPORTTABLE_PUBLIC_ADD", null );
-        addType( org.hisp.dhis.mapping.Map.class, "map", "F_MAP_PUBLIC_ADD", null );
-        addType( Chart.class, "chart", "F_CHART_PUBLIC_ADD", null );
-        addType( PatientTabularReport.class, "patientTabularReport", "F_PATIENT_TABULAR_REPORT_PUBLIC_ADD", null );
-        addType( PatientAggregateReport.class, "patientAggregateReport", "F_PATIENT_TABULAR_REPORT_PUBLIC_ADD", null );
+        addType( Document.class, "document", null, "F_DOCUMENT_PUBLIC_ADD", "F_DOCUMENT_PRIVATE_ADD" );
+        addType( Report.class, "report", null, "F_REPORT_PUBLIC_ADD", "F_REPORT_PRIVATE_ADD" );
+        addType( DataSet.class, "dataSet", null, "F_DATASET_PUBLIC_ADD", "F_DATASET_PRIVATE_ADD" );
+        addType( DataDictionary.class, "dataDictionary", null, "F_DATADICTIONARY_PUBLIC_ADD", "F_DATADICTIONARY_PRIVATE_ADD" );
+        addType( Indicator.class, "indicator", null, "F_INDICATOR_PUBLIC_ADD", "F_INDICATOR_PRIVATE_ADD" );
+        addType( IndicatorGroup.class, "indicatorGroup", null, "F_INDICATORGROUP_PUBLIC_ADD", "F_INDICATORGROUP_PRIVATE_ADD" );
+        addType( IndicatorGroupSet.class, "indicatorGroupSet", null, "F_INDICATORGROUPSET_PUBLIC_ADD", "F_INDICATORGROUPSET_PRIVATE_ADD" );
+        addType( Program.class, "program", null, "F_PROGRAM_PUBLIC_ADD", "F_PROGRAM_PRIVATE_ADD" );
+        addType( UserGroup.class, "userGroup", null, "F_USERGROUP_PUBLIC_ADD", null );
+        addType( PatientTabularReport.class, "patientTabularReport", null, "F_PATIENT_TABULAR_REPORT_PUBLIC_ADD", null );
+        addType( PatientAggregateReport.class, "patientAggregateReport", null, "F_PATIENT_TABULAR_REPORT_PUBLIC_ADD", null );
+
+        addType( org.hisp.dhis.mapping.Map.class, "map", "F_MAP_EXTERNAL_ADD", "F_MAP_PUBLIC_ADD", null );
+        addType( Chart.class, "chart", "F_CHART_PUBLIC_ADD", "F_CHART_PUBLIC_ADD", null );
+        addType( ReportTable.class, "reportTable", "F_REPORTTABLE_OPEN_ADD", "F_REPORTTABLE_PUBLIC_ADD", null );
     }
 
     public static boolean isSupported( String type )
@@ -277,7 +285,7 @@
     }
 
     /**
-     * Can user read this object
+     * Can user manage (make public) this object
      * <p/>
      * 1. Does user have SHARING_OVERRIDE_AUTHORITY authority?
      * 2. Can user write to this object?
@@ -308,6 +316,20 @@
         return false;
     }
 
+    /**
+     * Can user make this object external? (read with no login)
+     *
+     * @param user   User to check against
+     * @param object Object to check
+     * @return Result of test
+     */
+    public static <T extends IdentifiableObject> boolean canExternalize( User user, T object )
+    {
+        return (object.getClass().isAssignableFrom( org.hisp.dhis.mapping.Map.class ) ||
+            object.getClass().isAssignableFrom( ReportTable.class ) ||
+            object.getClass().isAssignableFrom( Chart.class )) && sharingOverrideAuthority( user );
+    }
+
     private static boolean sharingOverrideAuthority( User user )
     {
         return user == null || CollectionUtils.containsAny( user.getUserCredentials().getAllAuthorities(), SHARING_OVERRIDE_AUTHORITIES );

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/common/DefaultIdentifiableObjectManager.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/common/DefaultIdentifiableObjectManager.java	2013-08-06 10:26:03 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/common/DefaultIdentifiableObjectManager.java	2013-08-13 07:18:45 +0000
@@ -125,7 +125,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> T get( Class<T> clazz, String uid )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );
@@ -139,7 +139,13 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    public <T extends IdentifiableObject> boolean exists( Class<T> clazz, String uid )
+    {
+        return get( clazz, uid ) != null;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> T getByCode( Class<T> clazz, String code )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );
@@ -153,7 +159,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> T getByName( Class<T> clazz, String name )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );
@@ -214,7 +220,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> Collection<T> getAll( Class<T> clazz )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );
@@ -228,7 +234,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> Collection<T> getAllSorted( Class<T> clazz )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );
@@ -242,7 +248,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> List<T> getByUid( Class<T> clazz, Collection<String> uids )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );
@@ -256,7 +262,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> Collection<T> getLikeName( Class<T> clazz, String name )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );
@@ -270,7 +276,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> Collection<T> getLikeShortName( Class<T> clazz, String shortName )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );
@@ -284,7 +290,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> List<T> getBetween( Class<T> clazz, int first, int max )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );
@@ -298,7 +304,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> List<T> getBetweenByName( Class<T> clazz, String name, int first, int max )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );
@@ -312,7 +318,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> Collection<T> getByLastUpdated( Class<T> clazz, Date lastUpdated )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );
@@ -326,7 +332,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> Collection<T> getByLastUpdatedSorted( Class<T> clazz, Date lastUpdated )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );
@@ -360,7 +366,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> Map<String, T> getIdMap( Class<T> clazz, IdentifiableProperty property )
     {
         Map<String, T> map = new HashMap<String, T>();
@@ -410,7 +416,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends NameableObject> Map<String, T> getIdMap( Class<T> clazz, NameableProperty property )
     {
         Map<String, T> map = new HashMap<String, T>();
@@ -434,7 +440,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> T getObject( Class<T> clazz, IdentifiableProperty property, String id )
     {
         GenericIdentifiableObjectStore<T> store = (GenericIdentifiableObjectStore<T>) getIdentifiableObjectStore( clazz );
@@ -507,7 +513,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public <T extends IdentifiableObject> T getNoAcl( Class<T> clazz, String uid )
     {
         GenericIdentifiableObjectStore<IdentifiableObject> store = getIdentifiableObjectStore( clazz );

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/security.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/security.xml	2012-12-14 13:46:47 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/security.xml	2013-08-13 07:18:45 +0000
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
-  xmlns:sec="http://www.springframework.org/schema/security";
-  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
-      http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd";>
+  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd";>
 
   <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />
   <bean id="usernameSaltSource" class="org.hisp.dhis.security.DefaultUsernameSaltSource" />
@@ -22,12 +20,4 @@
     <property name="userService" ref="org.hisp.dhis.user.UserService" />
     <property name="systemSettingManager" ref="org.hisp.dhis.setting.SystemSettingManager" />
   </bean>
-
-  <sec:authentication-manager alias="authenticationManager">
-    <sec:authentication-provider user-service-ref="userDetailsService">
-      <sec:password-encoder hash="md5">
-        <sec:salt-source ref="usernameSaltSource" />
-      </sec:password-encoder>
-    </sec:authentication-provider>
-  </sec:authentication-manager>
 </beans>

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/mapping/hibernate/Map.hbm.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/mapping/hibernate/Map.hbm.xml	2013-03-13 15:03:10 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/mapping/hibernate/Map.hbm.xml	2013-08-13 07:18:45 +0000
@@ -37,6 +37,8 @@
     </list>
 
     <!-- Access properties -->
+    <property name="externalAccess" />
+
     <many-to-one name="user" class="org.hisp.dhis.user.User" column="userid" foreign-key="fk_mapview_userid" />
 
     <property name="publicAccess" length="8" />

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/chart/hibernate/Chart.hbm.xml'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/chart/hibernate/Chart.hbm.xml	2013-08-09 14:10:43 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/chart/hibernate/Chart.hbm.xml	2013-08-13 07:18:45 +0000
@@ -146,6 +146,8 @@
     <property name="rewindRelativePeriods" />
 
     <!-- Access properties -->
+    <property name="externalAccess" />
+
     <many-to-one name="user" class="org.hisp.dhis.user.User" column="userid" foreign-key="fk_chart_userid" />
 
     <property name="publicAccess" length="8" />

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/reporttable/hibernate/ReportTable.hbm.xml'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/reporttable/hibernate/ReportTable.hbm.xml	2013-08-09 14:10:43 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/reporttable/hibernate/ReportTable.hbm.xml	2013-08-13 07:18:45 +0000
@@ -79,7 +79,7 @@
       <many-to-many column="categorydimensionid" class="org.hisp.dhis.dataelement.DataElementCategoryDimension"
         foreign-key="fk_reporttable_categorydimensions_categorydimensionid" />
     </list>
-    
+
     <list name="dataElementGroups" table="reporttable_dataelementgroups">
       <cache usage="read-write" />
       <key column="reporttableid" foreign-key="fk_reporttable_dataelementgroups_reporttableid" />
@@ -135,29 +135,31 @@
     <property name="sortOrder" />
 
     <property name="topLimit" />
-    
+
     <property name="totals" />
-    
+
     <property name="subtotals" />
-    
+
     <property name="hideEmptyRows" />
-    
+
     <property name="digitGroupSeparator" />
-    
+
     <property name="displayDensity" />
-    
+
     <property name="fontSize" />
-    
+
     <property name="userOrganisationUnit" />
-    
+
     <property name="userOrganisationUnitChildren" />
-    
+
     <property name="organisationUnitLevel" />
 
     <many-to-one name="legendSet" class="org.hisp.dhis.mapping.MapLegendSet" column="legendsetid"
-		foreign-key="fk_reporttable_legendsetid" />
+      foreign-key="fk_reporttable_legendsetid" />
 
     <!-- Access properties -->
+    <property name="externalAccess" />
+
     <many-to-one name="user" class="org.hisp.dhis.user.User" column="userid" foreign-key="fk_reporttable_userid" />
 
     <property name="publicAccess" length="8" />

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AbstractCrudController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AbstractCrudController.java	2013-08-06 09:40:40 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AbstractCrudController.java	2013-08-13 07:18:45 +0000
@@ -324,6 +324,7 @@
     {
         Access access = new Access();
         access.setManage( SharingUtils.canManage( currentUserService.getCurrentUser(), object ) );
+        access.setExternalize( SharingUtils.canExternalize( currentUserService.getCurrentUser(), object ) );
         access.setWrite( SharingUtils.canWrite( currentUserService.getCurrentUser(), object ) );
         access.setRead( SharingUtils.canRead( currentUserService.getCurrentUser(), object ) );
         access.setUpdate( SharingUtils.canUpdate( currentUserService.getCurrentUser(), object ) );

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/SharingController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/SharingController.java	2013-03-22 09:55:41 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/SharingController.java	2013-08-13 07:18:45 +0000
@@ -61,7 +61,7 @@
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
  */
 @Controller
-@RequestMapping(value = SharingController.RESOURCE_PATH, method = RequestMethod.GET)
+@RequestMapping( value = SharingController.RESOURCE_PATH, method = RequestMethod.GET )
 public class SharingController
 {
     private static final Log log = LogFactory.getLog( SharingController.class );
@@ -83,7 +83,7 @@
     @Autowired
     private UserGroupAccessService userGroupAccessService;
 
-    @RequestMapping(value = "", produces = { "application/json", "text/*" })
+    @RequestMapping( value = "", produces = { "application/json", "text/*" } )
     public void getSharing( @RequestParam String type, @RequestParam String id, HttpServletResponse response ) throws IOException
     {
         if ( !SharingUtils.isSupported( type ) )
@@ -108,9 +108,11 @@
         Sharing sharing = new Sharing();
 
         sharing.getMeta().setAllowPublicAccess( SharingUtils.canCreatePublic( currentUserService.getCurrentUser(), object ) );
+        sharing.getMeta().setAllowExternalAccess( SharingUtils.canExternalize( currentUserService.getCurrentUser(), object ) );
 
         sharing.getObject().setId( object.getUid() );
         sharing.getObject().setName( object.getDisplayName() );
+        sharing.getObject().setExternalAccess( object.getExternalAccess() );
 
         if ( object.getPublicAccess() == null )
         {
@@ -151,7 +153,7 @@
         JacksonUtils.toJson( response.getOutputStream(), sharing );
     }
 
-    @RequestMapping(value = "", method = { RequestMethod.POST, RequestMethod.PUT }, consumes = "application/json")
+    @RequestMapping( value = "", method = { RequestMethod.POST, RequestMethod.PUT }, consumes = "application/json" )
     public void setSharing( @RequestParam String type, @RequestParam String id, HttpServletResponse response, HttpServletRequest request ) throws IOException
     {
         BaseIdentifiableObject object = (BaseIdentifiableObject) manager.get( SharingUtils.classForType( type ), id );
@@ -169,8 +171,13 @@
 
         Sharing sharing = JacksonUtils.fromJson( request.getInputStream(), Sharing.class );
 
+        // Ignore externalAccess if user is not allowed to make objects external
+        if ( SharingUtils.canExternalize( currentUserService.getCurrentUser(), object ) )
+        {
+            object.setExternalAccess( sharing.getObject().hasExternalAccess() );
+        }
+
         // Ignore publicAccess if user is not allowed to make objects public
-
         if ( SharingUtils.canCreatePublic( currentUserService.getCurrentUser(), object ) )
         {
             object.setPublicAccess( sharing.getObject().getPublicAccess() );
@@ -215,6 +222,7 @@
         builder.append( " update sharing on " ).append( object.getClass().getName() );
         builder.append( ", uid: " ).append( object.getUid() ).append( ", name: " ).append( object.getName() );
         builder.append( ", publicAccess: " ).append( object.getPublicAccess() );
+        builder.append( ", externalAccess: " ).append( object.getExternalAccess() );
 
         if ( !object.getUserGroupAccesses().isEmpty() )
         {
@@ -234,7 +242,7 @@
         ContextUtils.okResponse( response, "Access control set" );
     }
 
-    @RequestMapping(value = "/search", produces = { "application/json", "text/*" })
+    @RequestMapping( value = "/search", produces = { "application/json", "text/*" } )
     public void searchUserGroups( @RequestParam String key, HttpServletResponse response ) throws IOException
     {
         SharingUserGroups sharingUserGroups = new SharingUserGroups();

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/webdomain/sharing/Meta.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/webdomain/sharing/Meta.java	2013-01-18 15:54:53 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/webdomain/sharing/Meta.java	2013-08-13 07:18:45 +0000
@@ -37,6 +37,9 @@
     @JsonProperty
     private boolean allowPublicAccess;
 
+    @JsonProperty
+    private boolean allowExternalAccess;
+
     public Meta()
     {
     }
@@ -50,4 +53,14 @@
     {
         this.allowPublicAccess = allowPublicAccess;
     }
+
+    public boolean isAllowExternalAccess()
+    {
+        return allowExternalAccess;
+    }
+
+    public void setAllowExternalAccess( boolean allowExternalAccess )
+    {
+        this.allowExternalAccess = allowExternalAccess;
+    }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/webdomain/sharing/SharingObject.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/webdomain/sharing/SharingObject.java	2013-01-18 12:58:45 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/webdomain/sharing/SharingObject.java	2013-08-13 07:18:45 +0000
@@ -47,6 +47,9 @@
     private String publicAccess;
 
     @JsonProperty
+    private boolean externalAccess;
+
+    @JsonProperty
     private SharingUser user = new SharingUser();
 
     @JsonProperty
@@ -86,6 +89,16 @@
         this.publicAccess = publicAccess;
     }
 
+    public boolean hasExternalAccess()
+    {
+        return externalAccess;
+    }
+
+    public void setExternalAccess( boolean externalAccess )
+    {
+        this.externalAccess = externalAccess;
+    }
+
     public SharingUser getUser()
     {
         return user;

=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.sharing.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.sharing.js	2013-05-02 13:55:39 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.sharing.js	2013-08-13 07:18:45 +0000
@@ -109,6 +109,18 @@
     return $( '#sharingPublicAccess' ).val();
 }
 
+function setExternalAccess(access) {
+    if(access) {
+        $('#sharingExternalAccess').attr('checked', true);
+    } else {
+        $('#sharingExternalAccess').removeAttr('checked');
+    }
+}
+
+function getExternalAccess() {
+    return $('#sharingExternalAccess').is(':checked');
+}
+
 function getUserGroupAccesses() {
     var v = [];
 
@@ -131,14 +143,20 @@
 function showSharingDialog( type, uid ) {
     loadSharingSettings( type, uid ).done( function ( data ) {
         setPublicAccess( data.object.publicAccess );
+        setExternalAccess( data.object.externalAccess );
         setUserGroupAccesses( data.object.userGroupAccesses );
 
         $( '#sharingName' ).text( data.object.name );
 
+        if ( !data.meta.allowExternalAccess ) {
+            $( '#sharingExternalAccess' ).attr( 'disabled', true );
+        }
+
         if ( !data.meta.allowPublicAccess ) {
             $( '#sharingPublicAccess' ).attr( 'disabled', true );
         }
 
+
         $( '.removeUserGroupAccess' ).unbind( 'click' );
         $( document ).on( 'click', '.removeUserGroupAccess', removeUserGroupAccess );
         $( '#addUserGroupAccess' ).unbind( 'click' ).bind( 'click', addUserGroupAccessSelectedItem );
@@ -200,6 +218,7 @@
                     var me = $( this );
 
                     data.object.publicAccess = getPublicAccess();
+                    data.object.externalAccess = getExternalAccess();
                     data.object.userGroupAccesses = getUserGroupAccesses();
 
                     saveSharingSettings( type, uid, data ).done( function () {

=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/macros.vm'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/macros.vm	2013-07-18 05:21:15 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/macros.vm	2013-08-13 07:18:45 +0000
@@ -335,17 +335,24 @@
 
     <table id="sharingAccessTable" style="width: 100%;">
         <tbody>
-            <tr>
-                <td style="width: 300px;">$i18n.getString( "public_access" )</td>
-                <td>
-                    <select id="sharingPublicAccess" style="width: 150px;">
-                        <option selected="selected" value="--------">$i18n.getString( "none" )</option>
-                        <option value="r-------">$i18n.getString( "can_view" )</option>
-                        <option value="rw------">$i18n.getString( "can_edit_and_view" )</option>
-                    </select>
-                </td>
-                <td style="width: 25px; text-align: center;"></td>
-            </tr>
+        <tr>
+            <td style="width: 300px;">$i18n.getString( "external_access" )</td>
+            <td style="text-align: right;">
+                <input id="sharingExternalAccess" type="checkbox" value="true" />
+            </td>
+            <td style="width: 25px; text-align: center;"></td>
+        </tr>
+        <tr>
+            <td style="width: 300px;">$i18n.getString( "public_access" )</td>
+            <td>
+                <select id="sharingPublicAccess" style="width: 150px;">
+                    <option selected="selected" value="--------">$i18n.getString( "none" )</option>
+                    <option value="r-------">$i18n.getString( "can_view" )</option>
+                    <option value="rw------">$i18n.getString( "can_edit_and_view" )</option>
+                </select>
+            </td>
+            <td style="width: 25px; text-align: center;"></td>
+        </tr>
         </tbody>
     </table>
 </div>

=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/GhostAutomaticAccessProvider.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/GhostAutomaticAccessProvider.java	2011-12-26 10:07:59 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/GhostAutomaticAccessProvider.java	2013-08-13 07:18:45 +0000
@@ -30,13 +30,14 @@
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
 import org.springframework.security.core.userdetails.UserDetails;
 
 /**
  * This access provider will put an Authentication object with all GrantedAuthorities
  * in the SecurityContext in any case. This means that any user will be authenticated
- * and the login effectively bypassed. 
- * 
+ * and the login effectively bypassed.
+ *
  * @author Torgeir Lorange Ostby
  * @version $Id: GhostAutomaticAccessProvider.java 3160 2007-03-24 20:15:06Z torgeilo $
  */
@@ -54,7 +55,7 @@
         String username = "ghost_admin";
         String password = "";
 
-        UserDetails user = new org.springframework.security.core.userdetails.User( username, password, true, true, true, true,
+        UserDetails user = new User( username, password, true, true, true, true,
             getGrantedAuthorities() );
 
         authentication = new UsernamePasswordAuthenticationToken( user, user.getPassword(), user.getAuthorities() );

=== 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 13:32:15 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/vote/ActionAccessVoter.java	2013-08-13 07:18:45 +0000
@@ -1,7 +1,7 @@
 package org.hisp.dhis.security.vote;
 
 /*
- * Copyright (c) 2004-2012, University of Oslo
+ * Copyright (c) 2004-2013, University of Oslo
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without

=== added file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/vote/ExternalAccessVoter.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/vote/ExternalAccessVoter.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/vote/ExternalAccessVoter.java	2013-08-13 07:18:45 +0000
@@ -0,0 +1,122 @@
+package org.hisp.dhis.security.vote;
+
+/*
+ * Copyright (c) 2004-2013, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ *   list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.chart.Chart;
+import org.hisp.dhis.common.CodeGenerator;
+import org.hisp.dhis.common.IdentifiableObject;
+import org.hisp.dhis.common.IdentifiableObjectManager;
+import org.hisp.dhis.reporttable.ReportTable;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.AccessDecisionVoter;
+import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.FilterInvocation;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Allows certain type/uid combinations to be externally accessed (no login required).
+ *
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public class ExternalAccessVoter implements AccessDecisionVoter<FilterInvocation>
+{
+    private static final Log LOG = LogFactory.getLog( ExternalAccessVoter.class );
+
+    // this should probably be moved somewhere else, but leaving it here for now
+    private static final Map<String, Class<? extends IdentifiableObject>> externalClasses = new HashMap<String, Class<? extends IdentifiableObject>>();
+
+    static
+    {
+        externalClasses.put( "charts", Chart.class );
+        externalClasses.put( "maps", org.hisp.dhis.mapping.Map.class );
+        externalClasses.put( "reportTables", ReportTable.class );
+    }
+
+    // -------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------
+
+    @Autowired
+    private IdentifiableObjectManager manager;
+
+    // -------------------------------------------------------------------------
+    // AccessDecisionVoter Implementation
+    // -------------------------------------------------------------------------
+
+    @Override
+    public boolean supports( ConfigAttribute attribute )
+    {
+        return false;
+    }
+
+    @Override
+    public boolean supports( Class<?> clazz )
+    {
+        return clazz.isAssignableFrom( FilterInvocation.class );
+    }
+
+    @Override
+    public int vote( Authentication authentication, FilterInvocation filterInvocation, Collection<ConfigAttribute> attributes )
+    {
+        if ( authentication.getPrincipal().equals( "anonymousUser" ) && authentication.isAuthenticated() &&
+            filterInvocation.getRequest().getMethod().equals( RequestMethod.GET.name() ) )
+        {
+            String requestUrl = filterInvocation.getRequestUrl();
+            String[] urlSplit = requestUrl.split( "/" );
+            String type = urlSplit[2];
+
+            if ( urlSplit[1].equals( "api" ) && externalClasses.get( type ) != null )
+            {
+                String uid = urlSplit[3];
+
+                if ( CodeGenerator.isValidCode( uid ) )
+                {
+                    IdentifiableObject identifiableObject = manager.get( externalClasses.get( type ), uid );
+
+                    if ( identifiableObject != null && identifiableObject.getExternalAccess() )
+                    {
+                        LOG.debug( "ACCESS_GRANTED [" + filterInvocation.toString() + "]" );
+
+                        return ACCESS_GRANTED;
+                    }
+                }
+            }
+        }
+
+        LOG.debug( "ACCESS_ABSTAIN [" + filterInvocation.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-04-03 15:09:54 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/resources/META-INF/dhis/security.xml	2013-08-13 07:18:45 +0000
@@ -68,6 +68,16 @@
     <property name="userService" ref="org.hisp.dhis.user.UserService" />
   </bean>
 
+  <!-- Security : Authentication providers -->
+
+  <sec:authentication-manager alias="authenticationManager">
+    <sec:authentication-provider user-service-ref="userDetailsService">
+      <sec:password-encoder hash="md5">
+        <sec:salt-source ref="usernameSaltSource" />
+      </sec:password-encoder>
+    </sec:authentication-provider>
+  </sec:authentication-manager>
+
   <!-- Security : AccessProvider -->
 
   <bean id="databaseAutomaticAccessProvider" class="org.hisp.dhis.security.DatabaseAutomaticAccessProvider">
@@ -83,12 +93,17 @@
 
   <!-- Security : AccessDecision/Voter -->
 
+  <bean id="authenticatedVoter" class="org.springframework.security.access.vote.AuthenticatedVoter" />
+  <bean id="webExpressionVoter" class="org.springframework.security.web.access.expression.WebExpressionVoter" />
+  <bean id="externalAccessVoter" class="org.hisp.dhis.security.vote.ExternalAccessVoter" />
+
   <bean id="accessDecisionManager" class="org.hisp.dhis.security.vote.LogicalOrAccessDecisionManager">
     <property name="accessDecisionManagers">
       <list>
         <ref local="adminAccessDecisionVoting" />
         <ref local="regularAccessDecisionVoting" />
         <ref local="webAccessDecisionVoting" />
+        <ref local="externalAccessDecisionVoting" />
       </list>
     </property>
   </bean>
@@ -113,6 +128,14 @@
     </constructor-arg>
   </bean>
 
+  <bean id="externalAccessDecisionVoting" class="org.springframework.security.access.vote.UnanimousBased">
+    <constructor-arg name="decisionVoters">
+      <list>
+        <ref local="externalAccessVoter" />
+      </list>
+    </constructor-arg>
+  </bean>
+
   <bean id="regularAccessDecisionVoting" class="org.springframework.security.access.vote.UnanimousBased">
     <constructor-arg name="decisionVoters">
       <list>
@@ -123,9 +146,6 @@
     </constructor-arg>
   </bean>
 
-  <bean id="authenticatedVoter" class="org.springframework.security.access.vote.AuthenticatedVoter" />
-  <bean id="webExpressionVoter" class="org.springframework.security.web.access.expression.WebExpressionVoter" />
-
   <bean id="actionAccessVoter" class="org.hisp.dhis.security.vote.ActionAccessVoter">
     <property name="attributePrefix" value="F_" />
     <property name="requiredAuthoritiesKey" value="requiredAuthorities" />

=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/resources/i18n_global.properties'
--- dhis-2/dhis-web/dhis-web-commons/src/main/resources/i18n_global.properties	2013-07-26 13:53:21 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/resources/i18n_global.properties	2013-08-13 07:18:45 +0000
@@ -644,7 +644,8 @@
 
 #-- Sharing  ------------------------------------------------------------------#
 
-public_access=Public access
+public_access=Public access (with login)
+external_access=External access (without login)
 user_group_access=Us
 ajax_login_failed=Login failed, check your username and password and try againer group access
 group_name=Group name