dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #23904
[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