-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TRUNK-6203: Global properties access should be privileged #4601
Changes from 19 commits
da8d953
36add4c
4cc16f2
1a8b789
b4a7b9b
d0f3b9b
5a2f188
574c6da
566eb78
0085916
959ccfb
8440366
8bd9bd9
be1b829
081220d
de74e91
3c9d1e4
7d4fe94
eae0e9b
c0912d9
5ad79d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,6 @@ | |
import static org.junit.jupiter.api.Assertions.assertNull; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
import static org.junit.jupiter.api.Assertions.fail; | ||
import static org.mockito.Mockito.mock; | ||
|
||
import java.util.ArrayList; | ||
|
@@ -40,7 +39,6 @@ | |
import org.openmrs.User; | ||
import org.openmrs.api.context.Context; | ||
import org.openmrs.api.context.Credentials; | ||
import org.openmrs.api.context.UserContext; | ||
import org.openmrs.api.context.UsernamePasswordCredentials; | ||
import org.openmrs.customdatatype.datatype.BooleanDatatype; | ||
import org.openmrs.customdatatype.datatype.DateDatatype; | ||
|
@@ -554,7 +552,7 @@ public void filterGlobalPropertiesByViewPrivilege_shouldFilterGlobalPropertiesIf | |
GlobalProperty property = new GlobalProperty(); | ||
property.setProperty("test_property"); | ||
property.setPropertyValue("test_property_value"); | ||
property.setViewPrivilege(Context.getUserService().getPrivilege("Some Privilege For View Global Properties")); | ||
property.setViewPrivilege(Context.getUserService().getPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES)); | ||
adminService.saveGlobalProperty(property); | ||
// assert new test global property is saved properly | ||
List<GlobalProperty> properties = adminService.getAllGlobalProperties(); | ||
|
@@ -588,9 +586,8 @@ public void getGlobalProperty_shouldFailIfUserHasNoPrivileges() { | |
Context.logout(); | ||
Context.authenticate(getTestUserCredentials()); | ||
|
||
APIException exception = assertThrows(APIException.class, () -> adminService.getGlobalProperty(property.getProperty())); | ||
assertEquals(exception.getMessage(), String.format("Privilege: %s, required to view globalProperty: %s", | ||
property.getViewPrivilege(), property.getProperty())); | ||
APIAuthenticationException exception = assertThrows(APIAuthenticationException.class, () -> adminService.getGlobalProperty(property.getProperty())); | ||
assertEquals(exception.getMessage(), String.format("Privileges required: %s", property.getViewPrivilege())); | ||
} | ||
|
||
/** | ||
|
@@ -608,7 +605,6 @@ public void getGlobalProperty_shouldReturnGlobalPropertyIfUserIsAllowedToView() | |
Role role = Context.getUserService().getRole("Provider"); | ||
role.addPrivilege(property.getViewPrivilege()); | ||
Context.getAuthenticatedUser().addRole(role); | ||
|
||
assertNotNull(adminService.getGlobalProperty(property.getProperty())); | ||
} | ||
|
||
|
@@ -625,8 +621,8 @@ public void getGlobalPropertyObject_shouldFailIfUserHasNoPrivileges() { | |
Context.authenticate(getTestUserCredentials()); | ||
|
||
APIException exception = assertThrows(APIException.class, () -> adminService.getGlobalPropertyObject(property.getProperty())); | ||
assertEquals(exception.getMessage(), String.format("Privilege: %s, required to view globalProperty: %s", | ||
property.getViewPrivilege(), property.getProperty())); | ||
assertEquals(exception.getMessage(), String.format("Privileges required: %s", | ||
property.getViewPrivilege())); | ||
} | ||
|
||
/** | ||
|
@@ -662,8 +658,8 @@ public void updateGlobalProperty_shouldFailIfUserIsNotAllowedToEditGlobalPropert | |
Context.authenticate(getTestUserCredentials()); | ||
|
||
APIException exception = assertThrows(APIException.class, () -> adminService.updateGlobalProperty(property.getProperty(), "new-value")); | ||
assertEquals(exception.getMessage(), String.format("Privilege: %s, required to edit globalProperty: %s", | ||
property.getEditPrivilege(), property.getProperty())); | ||
assertEquals(exception.getMessage(), String.format("Privileges required: %s", | ||
property.getEditPrivilege())); | ||
} | ||
|
||
/** | ||
|
@@ -673,6 +669,7 @@ public void updateGlobalProperty_shouldFailIfUserIsNotAllowedToEditGlobalPropert | |
public void updateGlobalProperty_shouldUpdateIfUserIsAllowedToEditGlobalProperty() { | ||
executeDataSet(ADMIN_INITIAL_DATA_XML); | ||
GlobalProperty property = getGlobalPropertyWithEditPrivilege(); | ||
GlobalProperty globalPropertyWithViewPrivilege = getGlobalPropertyWithViewPrivilege(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why get this from here when we are going to use it way below. It would be great to fetch it closest to the point of usage. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This allows us to call the getGlobalPropertyWithViewPrivilege method without adding the proxy privilege to the user. Otherwise, we'll have to add proxy privilege before calling this method. |
||
assertEquals("anothervalue", property.getPropertyValue()); | ||
|
||
// authenticate new user without privileges | ||
|
@@ -681,6 +678,9 @@ public void updateGlobalProperty_shouldUpdateIfUserIsAllowedToEditGlobalProperty | |
// add required privilege to user | ||
Role role = Context.getUserService().getRole("Provider"); | ||
role.addPrivilege(property.getEditPrivilege()); | ||
|
||
role.addPrivilege(globalPropertyWithViewPrivilege.getViewPrivilege()); | ||
|
||
Context.getAuthenticatedUser().addRole(role); | ||
|
||
adminService.updateGlobalProperty(property.getProperty(), "new-value"); | ||
|
@@ -735,7 +735,7 @@ private GlobalProperty getGlobalPropertyWithViewPrivilege() { | |
GlobalProperty property = adminService.getGlobalPropertyObject("another-global-property"); | ||
assertNotNull(property); | ||
|
||
Privilege viewPrivilege = Context.getUserService().getPrivilege("Some Privilege For View Global Properties"); | ||
Privilege viewPrivilege = Context.getUserService().getPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES); | ||
property.setViewPrivilege(viewPrivilege); | ||
property = adminService.saveGlobalProperty(property); | ||
assertNotNull(property.getViewPrivilege()); | ||
|
@@ -752,7 +752,7 @@ private GlobalProperty getGlobalPropertyWithEditPrivilege() { | |
GlobalProperty property = adminService.getGlobalPropertyObject("another-global-property"); | ||
assertNotNull(property); | ||
|
||
Privilege editPrivilege = Context.getUserService().getPrivilege("Some Privilege For Edit Global Properties"); | ||
Privilege editPrivilege = Context.getUserService().getPrivilege(PrivilegeConstants.MANAGE_GLOBAL_PROPERTIES); | ||
property.setEditPrivilege(editPrivilege); | ||
property = adminService.saveGlobalProperty(property); | ||
assertNotNull(property.getEditPrivilege()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,7 @@ | |
import org.openmrs.api.context.ContextAuthenticationException; | ||
import org.openmrs.api.db.hibernate.HibernateContextDAO; | ||
import org.openmrs.test.jupiter.BaseContextSensitiveTest; | ||
import org.openmrs.util.PrivilegeConstants; | ||
import org.springframework.stereotype.Component; | ||
|
||
/** | ||
|
@@ -279,6 +280,7 @@ public void authenticate_shouldPassRegressionTestFor1580() { | |
Context.logout(); | ||
|
||
// first we fail a login attempt | ||
Context.addProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES); | ||
try { | ||
dao.authenticate("admin", "not the right password"); | ||
fail("Not sure why this username/password combo worked"); | ||
|
@@ -309,7 +311,13 @@ public void authenticate_shouldPassRegressionTestFor1580() { | |
|
||
// those were the first eight, now the ninth request | ||
// (with the same user and right pw) should fail | ||
assertThrows(ContextAuthenticationException.class, () -> dao.authenticate("admin", "test")); | ||
assertThrows(ContextAuthenticationException.class, () -> { | ||
Context.addProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES); | ||
wikumChamith marked this conversation as resolved.
Show resolved
Hide resolved
|
||
dao.authenticate("admin", "test"); | ||
Context.removeProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After removing the proxy privilege above, do we again need to remove it below? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we need to remove it again. The code inside the lambda function only adds or removes the value to that context. I tested this using |
||
}); | ||
|
||
Context.removeProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES); | ||
} | ||
|
||
@Test | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -27,6 +27,7 @@ | |||||||||||
import org.openmrs.module.ModuleInteroperabilityTest; | ||||||||||||
import org.openmrs.module.ModuleUtil; | ||||||||||||
import org.openmrs.util.OpenmrsClassLoader; | ||||||||||||
import org.openmrs.util.PrivilegeConstants; | ||||||||||||
import org.slf4j.Logger; | ||||||||||||
import org.slf4j.LoggerFactory; | ||||||||||||
import org.springframework.beans.factory.config.BeanDefinition; | ||||||||||||
|
@@ -89,12 +90,16 @@ public void prepareTestInstance(TestContext testContext) throws Exception { | |||||||||||
Properties props = BaseContextSensitiveTest.runtimeProperties; | ||||||||||||
props.setProperty(ModuleConstants.RUNTIMEPROPERTY_MODULE_LIST_TO_LOAD, modulesToLoad); | ||||||||||||
try { | ||||||||||||
Context.addProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES); | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not like this. It is too permissive. Why do we need to add the proxy privilege for the entire module startup process? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without adding this we get test errors similar to this:
Module startup needs access to global properties when getting the module repository: openmrs-core/api/src/main/java/org/openmrs/module/ModuleUtil.java Lines 481 to 485 in e962f22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This still does not mean that we give the privilege to the entire module startup. Not so? :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We only give the privilege in tests. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even then, we could mask bugs. We need to locate the specific places that need them. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should add privileges within the ModuleFactory as it is not a test class. |
||||||||||||
ModuleUtil.startup(props); | ||||||||||||
} | ||||||||||||
catch (Exception e) { | ||||||||||||
log.error("Error while starting modules: ", e); | ||||||||||||
throw e; | ||||||||||||
} | ||||||||||||
finally { | ||||||||||||
Context.removeProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES); | ||||||||||||
} | ||||||||||||
assertTrue("Some of the modules did not start successfully for " | ||||||||||||
+ testContext.getTestClass().getSimpleName() + ". Only " + ModuleFactory.getStartedModules().size() | ||||||||||||
+ " modules started instead of " + startModuleAnnotation.value().length, startModuleAnnotation | ||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ | |
import org.openmrs.module.ModuleUtil; | ||
import org.openmrs.test.StartModule; | ||
import org.openmrs.util.OpenmrsClassLoader; | ||
import org.openmrs.util.PrivilegeConstants; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.beans.factory.config.BeanDefinition; | ||
|
@@ -78,6 +79,7 @@ public void prepareTestInstance(TestContext testContext) throws Exception { | |
if (!Context.isSessionOpen()) | ||
Context.openSession(); | ||
|
||
|
||
ModuleUtil.shutdown(); | ||
|
||
// load the omods that the dev defined for this class | ||
|
@@ -86,12 +88,16 @@ public void prepareTestInstance(TestContext testContext) throws Exception { | |
Properties props = BaseContextSensitiveTest.runtimeProperties; | ||
props.setProperty(ModuleConstants.RUNTIMEPROPERTY_MODULE_LIST_TO_LOAD, modulesToLoad); | ||
try { | ||
Context.addProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above. |
||
ModuleUtil.startup(props); | ||
} | ||
catch (Exception e) { | ||
log.error("Error while starting modules: ", e); | ||
throw e; | ||
} | ||
finally { | ||
Context.removeProxyPrivilege(PrivilegeConstants.GET_GLOBAL_PROPERTIES); | ||
} | ||
assertTrue("Some of the modules did not start successfully for " | ||
+ testContext.getTestClass().getSimpleName() + ". Only " + ModuleFactory.getStartedModules().size() | ||
+ " modules started instead of " + startModuleAnnotation.value().length, startModuleAnnotation | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -21,8 +21,8 @@ | |||||||||||||||||||||||||||||
<global_property property="valid.integer" property_value="1234" uuid="b7225607-d0c4-4e44-8be5-31e1ac7e1fda"/> | ||||||||||||||||||||||||||||||
<global_property property="valid.double" property_value="1234.54" uuid="b7225607-d0c4-4e44-8be6-31e1ac7e1fda"/> | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
<privilege privilege="Some Privilege For View Global Properties" description="This is a test privilege for view global properties" uuid="d979d066-15e6-467c-9d4b-cb575ef12345"/> | ||||||||||||||||||||||||||||||
<privilege privilege="Some Privilege For Edit Global Properties" description="This is a test privilege for edit global properties" uuid="d979d066-15e6-467c-9d4b-cb575ef54321"/> | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not think we should change this file. Can't we do without these changes? The tests that expect these values should still do so. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not changing this could lead to problems with tests. For an example let's consider the following test. openmrs-core/api/src/test/java/org/openmrs/api/AdministrationServiceTest.java Lines 636 to 649 in 7d70503
If we keep the privilege name as "Some Privilege For View Global Properties," this test will fail with an error message stating:
We could mitigate the error by adding |
||||||||||||||||||||||||||||||
<privilege privilege="Get Global Properties" description="This is a test privilege for view global properties" uuid="d979d066-15e6-467c-9d4b-cb575ef12345"/> | ||||||||||||||||||||||||||||||
<privilege privilege="Manage Global Properties" description="This is a test privilege for edit global properties" uuid="d979d066-15e6-467c-9d4b-cb575ef54321"/> | ||||||||||||||||||||||||||||||
<privilege privilege="Some Privilege For Delete Global Properties" description="This is a test privilege for delete global properties" uuid="d979d066-15e6-467c-9d4b-cb575ef67890"/> | ||||||||||||||||||||||||||||||
<users user_id="5506" person_id="501" system_id="7-5" username="test_user" password="4a1750c8607d0fa237de36c6305715c223415189" salt="c788c6ad82a157b712392ca695dfcf2eed193d7f" secret_question="" creator="1" date_created="2008-08-15 15:57:09.0" changed_by="1" date_changed="2008-08-18 11:51:56.0" retired="false" retire_reason="" uuid="06d05314-e132-11de-babe-001e37123456"/> | ||||||||||||||||||||||||||||||
</dataset> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mind explaining why you changed the contents of
String.format()
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The format of the exception message changes after adding the authorization.