Skip to content

Commit

Permalink
fixes #47 - changes ApplicationUser#getTenancy to #getAtPath (ditto f…
Browse files Browse the repository at this point in the history
…or the example TenantedEntity entity); renames WithApplicationTenancy to WithAtPath.
  • Loading branch information
danhaywood committed Dec 5, 2016
1 parent 5bea074 commit 69d7e0e
Show file tree
Hide file tree
Showing 11 changed files with 119 additions and 142 deletions.
Expand Up @@ -46,6 +46,7 @@
import org.apache.isis.applib.annotation.SemanticsOf;
import org.apache.isis.applib.annotation.Title;
import org.apache.isis.applib.annotation.Where;
import org.apache.isis.applib.services.factory.FactoryService;
import org.apache.isis.applib.util.ObjectContracts;

import org.isisaddons.module.security.SecurityModule;
Expand Down Expand Up @@ -171,7 +172,6 @@ public static class PathDomainEvent extends PropertyDomainEvent<String> {}

public static class UsersDomainEvent extends CollectionDomainEvent<ApplicationUser> {}

@javax.jdo.annotations.Persistent(mappedBy = "tenancy")
@Collection(
domainEvent = UsersDomainEvent.class,
editing = Editing.DISABLED
Expand All @@ -180,17 +180,17 @@ public static class UsersDomainEvent extends CollectionDomainEvent<ApplicationUs
render = RenderType.EAGERLY
)
@MemberOrder(sequence = "10")
@Getter @Setter
private SortedSet<ApplicationUser> users = new TreeSet<>();

public List<ApplicationUser> getUsers() {
return applicationUserRepository.findByAtPath(getPath());
}

// necessary for integration tests
public void addToUsers(final ApplicationUser applicationUser) {
getUsers().add(applicationUser);
applicationUser.setAtPath(getPath());
}
// necessary for integration tests
public void removeFromUsers(final ApplicationUser applicationUser) {
getUsers().remove(applicationUser);
applicationUser.setAtPath(null);
}
//endregion

Expand All @@ -207,7 +207,7 @@ public static class AddUserDomainEvent extends ActionDomainEvent {}
)
@MemberOrder(name="Users", sequence = "1")
public ApplicationTenancy addUser(final ApplicationUser applicationUser) {
applicationUser.setTenancy(this);
applicationUser.setAtPath(this.getPath());
// no need to add to users set, since will be done by JDO/DN.
return this;
}
Expand All @@ -219,6 +219,8 @@ public List<ApplicationUser> autoComplete0AddUser(final String search) {
return list;
}



//endregion

//region > removeUser (action)
Expand All @@ -234,7 +236,7 @@ public static class RemoveUserDomainEvent extends ActionDomainEvent {}
)
@MemberOrder(name="Users", sequence = "2")
public ApplicationTenancy removeUser(final ApplicationUser applicationUser) {
applicationUser.setTenancy(null);
applicationUser.setAtPath(null);
// no need to add to users set, since will be done by JDO/DN.
return this;
}
Expand Down Expand Up @@ -369,7 +371,7 @@ public static class DeleteDomainEvent extends ActionDomainEvent {}
@MemberOrder(sequence = "1")
public List<ApplicationTenancy> delete() {
for (final ApplicationUser user : getUsers()) {
user.updateTenancy(null);
user.updateAtPath(null);
}
container.removeIfNotAlready(this);
container.flush();
Expand Down Expand Up @@ -397,6 +399,8 @@ public int compareTo(final ApplicationTenancy o) {
@javax.inject.Inject
ApplicationTenancyRepository applicationTenancyRepository;
@javax.inject.Inject
FactoryService factoryService;
@javax.inject.Inject
DomainObjectContainer container;
//endregion
}
Expand Up @@ -17,11 +17,20 @@
package org.isisaddons.module.security.dom.tenancy;

/**
* Role interface for domain objects to implement, indicating whether they are logically &quot;owned&quot; by a
* particular {@link org.isisaddons.module.security.dom.tenancy.ApplicationTenancy}.
* Role interface for domain objects to implement, indicating that these are characteristics of the entity that
* can be used to determine its visibility/editability.
*
* <p>
* The intention here is that the security module can implement instance-based security according to the following table:
* Previously the <code>atPath</code> would have corresponded to the unique path of some particular
* {@link org.isisaddons.module.security.dom.tenancy.ApplicationTenancy} instance. However, this has now been
* generalized; the atPath is simply a string whose interpretation is application-specific (in particular by
* the {@link ApplicationTenancyEvaluator} SPI).
* </p>
*
* <p>
* For applications that still wish to follow the original more specific design (that the <code>atPath</code>
* corresponds to a single {@link ApplicationTenancy}), then the path can be interpreted according to the following
* table:
* </p>
* <table border="1">
* <tr>
Expand Down Expand Up @@ -88,11 +97,11 @@
* <td>/it/car</td><td>null</td><td>not visible</td>
* </tr>
* </table>
* <p>any object that is not tenanted (that is, its class does not implement {@link org.isisaddons.module.security.dom.tenancy.WithApplicationTenancy the WithApplicationTenancy interface} is accessible by any user (usual permission rules apply).
* <p>any object that is not tenanted (that is, its class does not implement {@link WithAtPath the WithApplicationTenancy interface} is accessible by any user (usual permission rules apply).
* </p>
*/
public interface WithApplicationTenancy {
public interface WithAtPath {

ApplicationTenancy getApplicationTenancy();
String getAtPath();

}
Expand Up @@ -24,7 +24,6 @@
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.InheritanceStrategy;
import javax.jdo.annotations.NotPersistent;
import javax.jdo.annotations.VersionStrategy;

import com.google.common.base.Strings;
Expand All @@ -40,7 +39,6 @@
import org.apache.isis.applib.annotation.DomainObject;
import org.apache.isis.applib.annotation.DomainObjectLayout;
import org.apache.isis.applib.annotation.Editing;
import org.apache.isis.applib.annotation.LabelPosition;
import org.apache.isis.applib.annotation.MemberGroupLayout;
import org.apache.isis.applib.annotation.MemberOrder;
import org.apache.isis.applib.annotation.Optionality;
Expand All @@ -57,16 +55,17 @@
import org.apache.isis.applib.services.HasUsername;
import org.apache.isis.applib.util.ObjectContracts;
import org.apache.isis.applib.value.Password;
import org.apache.isis.core.metamodel.services.appfeat.ApplicationFeatureId;

import org.isisaddons.module.security.SecurityModule;
import org.isisaddons.module.security.dom.password.PasswordEncryptionService;
import org.isisaddons.module.security.dom.permission.ApplicationPermission;
import org.isisaddons.module.security.dom.permission.ApplicationPermissionMode;
import org.isisaddons.module.security.dom.permission.ApplicationPermissionRepository;
import org.isisaddons.module.security.dom.permission.ApplicationPermissionValueSet;
import org.isisaddons.module.security.dom.permission.PermissionsEvaluationService;
import org.isisaddons.module.security.dom.role.ApplicationRole;
import org.isisaddons.module.security.dom.role.ApplicationRoleRepository;
import org.isisaddons.module.security.dom.tenancy.ApplicationTenancy;
import org.isisaddons.module.security.seed.scripts.IsisModuleSecurityAdminRoleAndPermissions;
import org.isisaddons.module.security.seed.scripts.IsisModuleSecurityAdminUser;

Expand Down Expand Up @@ -99,6 +98,11 @@
value = "SELECT "
+ "FROM org.isisaddons.module.security.dom.user.ApplicationUser "
+ "WHERE emailAddress == :emailAddress"),
@javax.jdo.annotations.Query(
name = "findByAtPath", language = "JDOQL",
value = "SELECT "
+ "FROM org.isisaddons.module.security.dom.user.ApplicationUser "
+ "WHERE atPath == :atPath"),
@javax.jdo.annotations.Query(
name = "findByName", language = "JDOQL",
value = "SELECT "
Expand Down Expand Up @@ -128,7 +132,7 @@
@MemberGroupLayout(columnSpans = {4,4,4,12},
left = {"Id", "Name", "Metadata"},
middle= {"Contact Details"},
right= {"Status", "Tenancy"}
right= {"Status", "AtPath"}
)
public class ApplicationUser implements Comparable<ApplicationUser>, HasUsername {

Expand Down Expand Up @@ -473,40 +477,41 @@ public String disableUpdateFaxNumber(final String faxNumber) {

//endregion

//region > tenancy (property)
//region > atPath (property)

public static class TenancyDomainEvent extends PropertyDomainEvent<ApplicationTenancy> {}
public static class AtPathDomainEvent extends PropertyDomainEvent<String> {}


@javax.jdo.annotations.Column(name = "atPath", allowsNull="true")
@Property(
domainEvent = TenancyDomainEvent.class,
domainEvent = AtPathDomainEvent.class,
editing = Editing.DISABLED
)
@MemberOrder(name="Tenancy", sequence = "3.4")
@MemberOrder(name="atPath", sequence = "3.4")
@Getter @Setter
private ApplicationTenancy tenancy;
private String atPath;

//endregion

//region > updateTenancy (action)
//region > updateAtPath (action)

public static class UpdateTenancyDomainEvent extends ActionDomainEvent {}
public static class UpdateAtPathDomainEvent extends ActionDomainEvent {}

@Action(
domainEvent = UpdateTenancyDomainEvent.class,
domainEvent = UpdateAtPathDomainEvent.class,
semantics = SemanticsOf.IDEMPOTENT
)
@MemberOrder(name="tenancy", sequence = "1")
public ApplicationUser updateTenancy(
@MemberOrder(name="atPath", sequence = "1")
public ApplicationUser updateAtPath(
@Parameter(optionality = Optionality.OPTIONAL)
final ApplicationTenancy tenancy) {
setTenancy(tenancy);
@ParameterLayout(named = "AtPath")
final String atPath) {
setAtPath(atPath);
return this;
}

public ApplicationTenancy default0UpdateTenancy() {
return getTenancy();
public String default0UpdateAtPath() {
return getAtPath();
}
//endregion

Expand Down Expand Up @@ -977,7 +982,7 @@ public String toString() {

/**
* Optional service, if configured then is used to evaluate permissions within
* {@link org.isisaddons.module.security.dom.permission.ApplicationPermissionValueSet#evaluate(ApplicationFeatureId, org.isisaddons.module.security.dom.permission.ApplicationPermissionMode)},
* {@link org.isisaddons.module.security.dom.permission.ApplicationPermissionValueSet#evaluate(ApplicationFeatureId, ApplicationPermissionMode)}
* else will fallback to a {@link org.isisaddons.module.security.dom.permission.PermissionsEvaluationService#DEFAULT default}
* implementation.
*/
Expand Down
Expand Up @@ -202,6 +202,19 @@ public ApplicationUser newLocalUserBasedOn(
}
//endregion


//region > allUsers

@Programmatic
public List<ApplicationUser> findByAtPath(final String atPath) {
return container.allMatches(new QueryDefault<>(
ApplicationUser.class,
"findByAtPath", "atPath", atPath));
}

//endregion


//region > allUsers

@Programmatic
Expand Down
Expand Up @@ -16,15 +16,16 @@
*/
package org.isisaddons.module.security.facets;

import java.util.concurrent.Callable;

import javax.inject.Inject;

import org.apache.isis.applib.services.queryresultscache.QueryResultsCache;
import org.isisaddons.module.security.dom.tenancy.ApplicationTenancy;

import org.isisaddons.module.security.dom.tenancy.ApplicationTenancyEvaluator;
import org.isisaddons.module.security.dom.tenancy.ApplicationTenancyPathEvaluator;
import org.isisaddons.module.security.dom.user.ApplicationUser;

import javax.inject.Inject;
import java.util.concurrent.Callable;

class ApplicationTenancyEvaluatorUsingPaths implements ApplicationTenancyEvaluator {

private final ApplicationTenancyPathEvaluator evaluator;
Expand Down Expand Up @@ -138,11 +139,7 @@ protected String userTenancyPathFor(final ApplicationUser applicationUser) {
if (evaluator.handles(applicationUser.getClass())) {
return evaluator.applicationTenancyPathFor(applicationUser);
}
final ApplicationTenancy userTenancy = applicationUser.getTenancy();
if (userTenancy == null) {
return null;
}
return userTenancy.getPath();
return applicationUser.getAtPath();
}


Expand Down
Expand Up @@ -32,12 +32,10 @@
import org.isisaddons.module.security.dom.tenancy.ApplicationTenancy;
import org.isisaddons.module.security.dom.tenancy.ApplicationTenancyEvaluator;
import org.isisaddons.module.security.dom.tenancy.ApplicationTenancyPathEvaluator;
import org.isisaddons.module.security.dom.tenancy.WithApplicationTenancy;
import org.isisaddons.module.security.dom.tenancy.WithAtPath;
import org.isisaddons.module.security.dom.user.ApplicationUserRepository;

import javax.annotation.Nullable;
import java.util.List;
import java.util.stream.Collectors;

public class TenantedAuthorizationFacetFactory extends FacetFactoryAbstract implements ServicesInjectorAware {

Expand Down Expand Up @@ -119,16 +117,14 @@ static class ApplicationTenancyPathEvaluatorDefault implements ApplicationTenanc

@Override
public boolean handles(final Class<?> cls) {
return WithApplicationTenancy.class.isAssignableFrom(cls);
return WithAtPath.class.isAssignableFrom(cls);
}

public String applicationTenancyPathFor(final Object domainObject) {
// always safe, facet factory only installs facet for classes implementing WithApplicationTenancy
final WithApplicationTenancy tenantedObject = (WithApplicationTenancy) domainObject;
final WithAtPath tenantedObject = (WithAtPath) domainObject;

final ApplicationTenancy objectTenancy = tenantedObject.getApplicationTenancy();
final String objectTenancyPath = objectTenancy == null ? null : objectTenancy.getPath();
return objectTenancyPath;
return tenantedObject.getAtPath();
}
}

Expand Down
Expand Up @@ -29,8 +29,6 @@
import org.isisaddons.module.security.dom.password.PasswordEncryptionService;
import org.isisaddons.module.security.dom.role.ApplicationRole;
import org.isisaddons.module.security.dom.role.ApplicationRoleRepository;
import org.isisaddons.module.security.dom.tenancy.ApplicationTenancy;
import org.isisaddons.module.security.dom.tenancy.ApplicationTenancyRepository;
import org.isisaddons.module.security.dom.user.AccountType;
import org.isisaddons.module.security.dom.user.ApplicationUser;
import org.isisaddons.module.security.dom.user.ApplicationUserRepository;
Expand Down Expand Up @@ -84,8 +82,7 @@ protected void execute(final ExecutionContext executionContext) {
}

// update tenancy (repository checks for null)
final ApplicationTenancy applicationTenancy = applicationTenancyRepository.findByPath(tenancyPath);
applicationUser.setTenancy(applicationTenancy);
applicationUser.setAtPath(tenancyPath);

for (final String roleName : roleNames) {
final ApplicationRole securityRole = applicationRoleRepository.findByName(roleName);
Expand All @@ -108,10 +105,6 @@ public ApplicationUser getApplicationUser() {
ApplicationUserRepository applicationUserRepository;
@Inject
ApplicationRoleRepository applicationRoleRepository;
@Inject
ApplicationTenancyRepository applicationTenancyRepository;
@Inject
PasswordEncryptionService passwordEncryptionService;
//endregion

}

0 comments on commit 69d7e0e

Please sign in to comment.