Skip to content
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

[VIVO-1436] Implementation of Advanced Role Management #80

Closed
wants to merge 12 commits into from

Conversation

grahamtriggs
Copy link
Member

VIVO-1436:

What does this pull request do?

This pull request provides the framework for permissions to view, edit and publish properties to be assigned discretely to roles, rather than as a hierarchy of super-user > user > public.

What's new?

It replaces the Policy code for granting access to properties such that the roles can be given access to or denied access for properties independent of there being a "hierarchy" of roles.

It includes a migration startup listener that will take any old policies defined on existing properties, and convert them to the equivalent role permissions.

The editing of properties has been updated to provide checkboxes for assigning properties to roles, rather than a drop-down of a role hierarchy.

Property permissions are now stored in the User Accounts model, along with the other role and permission settings.

How should this be tested?

After upgrading, an existing installation should still have the same permissions as before (i.e. the same people should have the same access to view / edit content).

The edit pages for the properties should show checkboxes for the permissions granted, and any changes to the permissions should be honoured.

Creating new properties should default to a "sensible" set of checkboxes being already selected (e.g. all view permissions and editors can update).

Additional Notes:

Documentation will need to be updated for the new permissions.
This should not be merged without also merging the equivalent VIVO pull request.

Interested parties

@VIVO-project/vivo-committers

Copy link
Member

@awoods awoods left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should AdditionalURIsForClassGroupChangesTest and VClassGroupCacheTest be updated to remove reference to "hiddenFromDisplayBelowRoleLevelAnnot and "prohibitedFromUpdateBelowRoleLevelAnnot"?

/**
* Create a list of all known non-public PermissionSets.
*/
protected static List<PermissionSet> buildListOfSelectableRoles(WebappDaoFactory wadf) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this method be private?

Copy link
Member

@j2blake j2blake left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attached comments for substantive issues to a number of files. Additional comments to follow.

}
} finally {
qexec.close();
query.clone();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What purpose does it serve to clone the query?

* Instance fields for each EntityPermission
*/
private final Set<PropertyDao.FullPropertyKey> authorizedKeys = new HashSet<>();
private final Set<String> authorizedResources = new HashSet<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears that authorizedResources is never used. Am I missing something?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because authorisation checks on resources in the existing code always results in authorisation being granted, and so this branch reflects that behaviour.

It's an open question as to whether we should fully implement resource checks - I can see cases where it would be required, but it may also cause a significant issue for upgrading existing sites.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a reason to keep a private final variable whose value is never accessed. If we need it in the future, we'll add it.

}

public abstract boolean isRelated(OntModel ontModel, List<String> fromUris, List<String> toUris);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter ontModel is not documented. What model is being passed in here? The subclasses that are required to implement this method will need to know.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true, although the previous version of the class took an ontModel in the constructor and stored it as a field - and it wasn't documented as to what model is being passed in there.

Substantively, the only change to this class has been to have the ontModel passed in as part of the check, rather than to rely on one having been set in the constructor.

Off-hand I can't remember specifically why this change was required, but it will be something to do with needing to move where the construction takes place.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that you can't be responsible for the shortcomings of any code that you touch. But you created this method signature. It should not be a challenge for you to say what it does.

@@ -104,4 +106,5 @@
*/
Collection<PermissionSet> getAllPermissionSets();

void setEntityPermissions(String entityKey, Collection<PermissionSet> displaySets, Collection<PermissionSet> editSets, Collection<PermissionSet> publishSets);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An interface method must be documented, or no-one will know how to implement it. What is entityKey? Is it a URL? What is an entity in this context? Will the method accept null arguments?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting question there - now that we have migrated to and require JDK 8+, should we start introducing @nullable / @NotNull annotations?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's another interesting question, but not the one that I was raising.

You have modified an interface with 11 public methods, all documented, by adding a 12th method with no documentation. Aside from it being bad practice, what happened to that "consistency with existing code" that you mention in your other responses?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved

}
}

public static boolean anyRelated(OntModel ontModel, List<String> fromUris, List<String> toUris) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter ontModel is not documented, nor is it self-evident. What model do callers need to pass in here?

Copy link
Member

@j2blake j2blake left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

home/src/main/resources/rdf/tbox/filegraph/vitro-0.7.owl still contains references to
http://vitro.mannlib.cornell.edu/ns/vitro/0.7#hiddenFromDisplayBelowRoleLevelAnnot,
http://vitro.mannlib.cornell.edu/ns/vitro/0.7#prohibitedFromUpdateBelowRoleLevelAnnot, and
http://vitro.mannlib.cornell.edu/ns/vitro/0.7#hiddenFromDisplayBelowRoleLevelAnnot

Copy link
Member

@j2blake j2blake left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is my full list of review points, including comments on unused code, commented code, undocumented methods, and others.

Since the project doesn't have a style guide, these are simply observations. Act on them or not, as you see fit.

General

Documentation Important classes have no comments at the class level. What is the RelationshipCheckerRegistry? What is an EntityPermission?
Documentation Non-private methods should have comments to establish the semantic contract of the method. What goes in, what comes out, what causes exceptions? This is even more true for abstract methods, where one cannot deduce the contract from the implementation.

Vitro - main

edu.cornell.mannlib.vedit.controller.BaseEditController

line 215 Documentation What is a "permissionsNamespace"? Is this the name of the entity on which permissions are being edited? Comment the arguments, or at least use more descriptive names.
lines 256-281 Documentation The comment says we are creating a list of non-public PermissionSets. The actual list contains both public and non-public PermissionSets.
line 283 Style Why not declare permission as
Class<? extends EntityPermission> permission
Avoid the compiler warning, and enforce a reasonable restriction.
line 288 Style Surely this line is too long to be easily read. Insert line-breaks or break into smaller statements.
line 298 Logic What purpose does it serve to clone the query?

edu.cornell.mannlib.vedit.controller.OperationController

OK

edu.cornell.mannlib.vitro.webapp.auth.permissions.BrokenPermission

OK

edu.cornell.mannlib.vitro.webapp.auth.permissions.EntityPermission

General Documentation What is an EntityPermission? What do the fields represent? I.e., what are keys and what are resources? What does it mean to be limited to a related user? Related to what?

How is an EntityPermission represented in the user accounts model?
line 45, etc. Logic It appears that authorizedResources is never used. Am I missing something?
lines 88, 122, 152 Style When is a line too long to be easily readable? Insert line breaks, or break the line into simpler statements.
lines 69-71, 83, 86 Language and Libraries This check could be done at compile time by changing the method signature to
private static void getAllInstances(Class<? extends EntityPermission> clazz)
That would permit ctor to be declared as
Constructor<? extends EntityPermission>
in line 83, and remove the need for a cast in line 86
line 88, 203 Language and Libraries When testing for the presence of a single statement, simplify the code and clarify the intent by calling contains() instead of listStatements().
lines 94-101 User interaction These exceptions could arise frequently, simply from a typo in the configuration file. They should be handled with more grace. Create a meaningful message and write to the log instead of sysout.
line 110 Documentation Why is updateAllPermissions() public? When might it be called?
line 144, 185 Documentation Why is update() not private? Might a subclass want to override it?
Why is updateFor() not private?
line 186 Style uri should have a more descriptive name, perhaps propertyUri.
line 253 Logic This should read as follows:
if (objectUri != null && userUri.equals(objectUri)) {
Note: this could also be simplified to:
if (userUri.equals(objectUri)) {
Since equals() will return false if objectUri is null.

edu.cornell.mannlib.vitro.webapp.auth.permissions.EntityDisplayPermission

line 10 Style Don't use wild cards in import statements
lines 34-35, 40-43, 47 Documentation Either remove the commented code, or explain why it is there.

edu.cornell.mannlib.vitro.webapp.auth.permissions.EntityPublishPermission

lines 35-36, 41-44, 49 Documentation Either remove the commented code, or explain why it is there.

edu.cornell.mannlib.vitro.webapp.auth.permissions.EntityPublishPermission

OK

edu.cornell.mannlib.vitro.webapp.auth.permissions.PermissionRegistry

OK

edu.cornell.mannlib.vitro.webapp.auth.permissions.Permission

line 34 Documentation In isAuthorized(), the parameter "userUris" is not documented. If someone wants to create a concrete implementaiton of this method, how are they to know what this parameter is or does? If someone calls this method, how do they know what to pass in this parameter? What do the URIs represent? Is the list permitted to be null, or merely empty?

edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission

OK

edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionListener

line 12 Logic import of FullPropertyKey is not used.
lines 30, 42, 54 User interaction The log message still refers to RoleRestrictedProperty, which is no longer correct.

edu.cornell.mannlib.vitro.webapp.auth.policy.setup.CommonPolicyFamilySetup

OK

edu.cornell.mannlib.vitro.webapp.auth.policy.specialrelationships.RelationshipChecker

line 45 Documentation The parameter ontModel is not documented. What model is being passed in here? The subclasses that are required to implement this method might need to know.

edu.cornell.mannlib.vitro.webapp.auth.policy.PermissionsPolicy

OK

edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean

OK

edu.cornell.mannlib.vitro.webapp.beans.DataProperty

OK

edu.cornell.mannlib.vitro.webapp.beans.FauxProperty

OK

edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty

OK

edu.cornell.mannlib.vitro.webapp.beans.ResourceBean

OK

edu.cornell.mannlib.vitro.webapp.controller.authenticate.BasicAuthenticator

line 5 Style Wild-card import statements are not recommended.

edu.cornell.mannlib.vitro.webapp.controller.authenticate.LoginRedirector

OK

edu.cornell.mannlib.vitro.webapp.controller.edit.utils.RoleLevelOptionsSetup

all lines Logic Delete this class. It appears that this class no longer has a purpose.

edu.cornell.mannlib.vitro.webapp.controller.edit.DatapropEditController

OK

edu.cornell.mannlib.vitro.webapp.controller.edit.DatapropRetryController

OK

edu.cornell.mannlib.vitro.webapp.controller.edit.EntityEditController

OK

edu.cornell.mannlib.vitro.webapp.controller.edit.EntityRetryController

OK

edu.cornell.mannlib.vitro.webapp.controller.edit.PropertyEditController

OK (nice fix of previous erroneous comments)

edu.cornell.mannlib.vitro.webapp.controller.edit.PropertyRetryController

OK

edu.cornell.mannlib.vitro.webapp.controller.edit.VclassEditController

OK

edu.cornell.mannlib.vitro.webapp.controller.edit.VclassRetryController

OK

edu.cornell.mannlib.vitro.webapp.dao.PropertyDao

lines 8, 9 Logic These import statements are not used.

edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao

lines 6, 10 Logic These import statements are not used
line 109 Documentation An interface method must be documented, or no-one will know how to implement it. What is entityKey? Is it a URL? What is an entity in this context? Will the method accept null arguments?

edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary

lines 58-65 Documentation Delete these lines, or explain what they are.

edu.cornell.mannlib.vitro.webapp.dao.filtering.DataPropertyFiltering

line 9 Logic This import statement is not used.

edu.cornell.mannlib.vitro.webapp.dao.filtering.IndividualFiltering

line 22 Logic This import statement is not used.

edu.cornell.mannlib.vitro.webapp.dao.filtering.ObjectPropertyFiltering

line 9 Logic This import statement is not used.

edu.cornell.mannlib.vitro.webapp.dao.filtering.UserAccountsDaoFiltering

OK

edu.cornell.mannlib.vitro.webapp.dao.Jena.DataPropertyDaoJena

OK

edu.cornell.mannlib.vitro.webapp.dao.Jena.FauxPropertyDaoJena

OK

edu.cornell.mannlib.vitro.webapp.dao.Jena.JenaBaseDao

OK

edu.cornell.mannlib.vitro.webapp.dao.Jena.JenaBaseDaoCon

OK

edu.cornell.mannlib.vitro.webapp.dao.Jena.ObjectPropertyDaoJena

OK

edu.cornell.mannlib.vitro.webapp.dao.Jena.UserAccountsDaoJena

lines 7, 15, 16 Logic These import statements are not used.

edu.cornell.mannlib.vitro.webapp.dao.Jena.VClassDaoJena

OK

edu.cornell.mannlib.vitro.webapp.dao.Jena.VClassJena

lines 14,16,17,20 Logic These import statements are not used.

edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.FilterByDisplayPermission

general Logic This is a mystery. permissionSetUri is never used. Is that intentional? Is it used by reflection somewhere?
And indeed, this class appears to be referenced only by VitroFilterUtils.getPublicFilter().
If it is not used, then do you need more than one constructor with zero arguments?
lines 35, 69 Logic permissionSetUri is never used
lines 65-67 Logic Given that permissionSetUri is never used, is there any need for this null check? Is there any need to pass the uri parameter at all?
lines 78-79 Logic These lines suggest that this class is incomplete. As a filter, this class seems to have no effect at all.
But wouldn't that affect the contents of the search index, and the vclass cache?
What am I missing?

edu.cornell.mannlib.vitro.webapp.migration.auth.AuthMigrator

lines 270-274 Logic This method is not used.

edu.cornell.mannlib.vitro.webapp.utils.RelationshipCheckerRegistry

line 27 Documentation The parameter ontModel is not documented, nor is it self-evident. What model do callers need to pass in here?

edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.FauxObjectPropertyWrapper

OK

edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.PropertyTemplateModel

OK

Vitro - test

edu.cornell.mannlib.vitro.webapp.auth.identifier.factory.HasPermissionFactoryTest

OK

edu.cornell.mannlib.vitro.webapp.controller.edit.AuthenticateTest

OK

edu.cornell.mannlib.vitro.webapp.dao.jena.DataPropertyDaoJenaTest

OK

edu.cornell.mannlib.vitro.webapp.dao.jena.ObjectPropertyDaoJenaTest

OK

edu.cornell.mannlib.vitro.webapp.dao.jena.VClassDaoTest

OK

edu.cornell.mannlib.vitro.webapp.dao.jena.VClassJenaTest

OK

stubs.edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDaoStub

OK

Vitro - home

src/main/resources/rdf/auth/everytime/permission_config.n3

OK

Vitro - webapp

src/main/webapp/templates/edit/specific/dataprop_retry.jsp

OK

src/main/webapp/templates/edit/specific/fauxProperty_retry.jsp

OK

src/main/webapp/templates/edit/specific/property_retry.jsp

OK

src/main/webapp/templates/edit/specific/vclass_retry.jsp

OK

src/main/webapp/templates/freemarker/lib/lib-properties.ftl

OK

src/main/webapp/WEB-INF/resources/startup_listeners.txt

OK

Copy link
Member

@j2blake j2blake left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete this class: edu.cornell.mannlib.vitro.webapp.controller.edit.utils.RoleLevelOptionsSetup. It is no longer used.

* Create a list of all known non-public PermissionSets.
*/
protected static List<PermissionSet> buildListOfSelectableRoles(WebappDaoFactory wadf) {
List<PermissionSet> list = new ArrayList<PermissionSet>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can safely replace new ArrayList<PermissionSet>() with new ArrayList<>().

}

/**
* Create a list of all known non-public PermissionSets.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment correct? It seems that we are collecting the "public" and "non-public" PermissionSets.

return list;
}

protected static List<String> getGrantedRolesForEntity(OntModel userAccounts, String key, Class permission) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this method be private?

} else if (whatToAuth instanceof DisplayDataPropertyStatement) {
DataPropertyStatement stmt = ((DisplayDataPropertyStatement)whatToAuth).getDataPropertyStatement();
// Check subject as resource
// String subjectUri = stmt.getIndividualURI();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commented-out sections appear to be a "work-in-progress". Please remove dead code as appropriate.

/**
* Static fields for all EntityPermissions
*/
private static final Map<String, EntityPermission> allInstances = new HashMap<String, EntityPermission>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use diamond operator: new HashMap<>()

return p;
}
for (String uri : HasPermissionSet.getPermissionSetUris(ids)) {
return uri;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this for loop is not looping, the logic may be more clear to simply return the first element if the permission-set is not empty.

}

/** Get the DisplayByRolePermission from the request, or use Public. */
public FilterByRoleLevelPermission(HttpServletRequest req) {
this(getPermissionFromRequest(req));
public FilterByDisplayPermission(HttpServletRequest req) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method does not appear to be called... and can likely be removed.

public static final String CURATOR = "http://vitro.mannlib.cornell.edu/ns/vitro/role#curator";
public static final String DB_ADMIN = "http://vitro.mannlib.cornell.edu/ns/vitro/role#dbAdmin";
public static final String NOBODY = "http://vitro.mannlib.cornell.edu/ns/vitro/role#nobody";
// public static final String PUBLIC = "http://vitro.mannlib.cornell.edu/ns/vitro/role#public";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not do delete these unused variables?

/**
* Old ROLE defintions that were used by the hidden / prohibited assertions
*/
public static final String ROLE_PUBLIC = "http://vitro.mannlib.cornell.edu/ns/vitro/role#public";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These can all be private.

}
}

private InputStream makeN3InputStream(Model m) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method is not used and can be removed.

Copy link
Member

@j2blake j2blake left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To reproduce the error, go to a user's profile that has some data, click on the RDF link, the "view profile in RDF format".

@grahamtriggs grahamtriggs changed the base branch from develop to NIHVIVO-56-build-script June 27, 2019 21:45
@grahamtriggs grahamtriggs changed the base branch from NIHVIVO-56-build-script to develop June 27, 2019 21:46
@awoods awoods closed this Jan 28, 2020
@gneissone
Copy link
Member

Reopening this pull request. In an effort to follow current best practices, the VIVO project will now be developed against the master branch. As a result of removing the develop branch, this pull request was automatically closed by GitHub, apologies for any confusion this may have caused.

@gneissone gneissone reopened this Feb 5, 2020
@gneissone gneissone changed the base branch from develop to master February 5, 2020 16:08
Base automatically changed from master to main January 20, 2021 17:29
@litvinovg litvinovg changed the base branch from main to sprint-dynapi-2022-feb-staging March 16, 2022 12:56
@litvinovg litvinovg changed the base branch from sprint-dynapi-2022-feb-staging to main March 16, 2022 12:57
@chenejac
Copy link
Contributor

This is being closed due to inactivity; might be reopened in the future.

@litvinovg
Copy link
Contributor

Superseded by #398

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants