Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,16 @@
import javax.annotation.Priority;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import org.apache.isis.applib.annotation.PriorityPrecedence;
import org.apache.isis.applib.services.iactnlayer.InteractionContext;
import org.apache.isis.applib.services.iactnlayer.InteractionLayerTracker;
import org.apache.isis.applib.services.sudo.SudoService;
import org.apache.isis.commons.internal.exceptions._Exceptions;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
import lombok.val;
Expand Down Expand Up @@ -75,7 +77,7 @@ public class UserService {
*/
public static final String NOBODY = "__isis_nobody";

private final InteractionLayerTracker iInteractionLayerTracker;
private final Provider<InteractionLayerTracker> iInteractionLayerTrackerProvider;
private final List<ImpersonatedUserHolder> impersonatedUserHolders;


Expand All @@ -88,7 +90,7 @@ public Optional<UserMemento> currentUser() {
val impersonatedUserIfAny = impersonatedUserIfAny();
return impersonatedUserIfAny.isPresent()
? impersonatedUserIfAny
: iInteractionLayerTracker.currentInteractionContext().map(InteractionContext::getUser);
: iInteractionLayerTrackerProvider.get().currentInteractionContext().map(InteractionContext::getUser);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ public class Password implements Serializable {

private final String password;

public static Password of(final String password) {
return new Password(password);
}

// in support of XML un-marshaling
@SuppressWarnings("unused")
private Password() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@

import org.apache.isis.core.config.presets.IsisPresets;
import org.apache.isis.extensions.commandlog.jdo.IsisModuleExtCommandLogJdo;
import org.apache.isis.persistence.jdo.datanucleus.IsisModuleJdoDatanucleus;
import org.apache.isis.persistence.jdo.datanucleus.IsisModulePersistenceJdoDatanucleus;

@Configuration
@Profile("demo-jdo")
@Import({
DemoModuleCommon.class,
IsisModuleJdoDatanucleus.class,
IsisModulePersistenceJdoDatanucleus.class,
IsisModuleExtCommandLogJdo.class,
})
@PropertySources({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import org.springframework.context.annotation.Profile;

import org.apache.isis.extensions.commandlog.jpa.IsisModuleExtCommandLogJpa;
import org.apache.isis.persistence.jpa.eclipselink.IsisModuleJpaEclipselink;
import org.apache.isis.persistence.jpa.eclipselink.IsisModulePersistenceJpaEclipselink;

import demoapp.dom.domain.actions.Action.commandPublishing.jpa.ActionCommandPublishingJpa;
import demoapp.dom.domain.actions.Action.executionPublishing.jpa.ActionExecutionPublishingJpa;
Expand Down Expand Up @@ -81,7 +81,7 @@
@Profile("demo-jpa")
@Import({
DemoModuleCommon.class,
IsisModuleJpaEclipselink.class,
IsisModulePersistenceJpaEclipselink.class,
IsisModuleExtCommandLogJpa.class,
})
@EntityScan(basePackageClasses = {
Expand Down
7 changes: 7 additions & 0 deletions extensions/security/secman/applib/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@
</exclusions>
</dependency>

<dependency>
<groupId>org.apache.isis.mavendeps</groupId>
<artifactId>isis-mavendeps-integtests</artifactId>
<type>pom</type>
<scope>test</scope>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,16 @@
import org.apache.isis.extensions.secman.applib.user.dom.mixins.perms.UserPermissionViewModel;
import org.apache.isis.extensions.secman.applib.user.menu.ApplicationUserMenu;
import org.apache.isis.extensions.secman.applib.user.menu.MeService;
import org.apache.isis.testing.fixtures.applib.IsisModuleTestingFixturesApplib;

/**
* @since 2.0 {@index}
*/
@Configuration
@Import({
// modules
IsisModuleTestingFixturesApplib.class,

ApplicationFeatureChoices.class,

// @DomainService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public abstract class ApplicationPermission implements Comparable<ApplicationPer
public static final String NAMED_QUERY_FIND_BY_ROLE_RULE_FEATURE = "ApplicationPermission.findByRoleAndRuleAndFeature";
public static final String NAMED_QUERY_FIND_BY_ROLE_RULE_FEATURE_FQN = "ApplicationPermission.findByRoleAndRuleAndFeatureAndFqn";
public static final String NAMED_QUERY_FIND_BY_USER = "ApplicationPermission.findByUser";
public static final String NAMED_QUERY_FIND_BY_ROLE_NAMES = "ApplicationPermission.findByRoleNames";


@Inject transient ApplicationFeatureRepository featureRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,30 @@ ApplicationPermission newPermissionNoCheck(
ApplicationFeatureSort sort,
String featureFqn);

/**
* Uses the {@link ApplicationRole}s associated with the {@link ApplicationUser}.
*/
List<ApplicationPermission> findByUser(ApplicationUser applicationUser);

List<ApplicationPermission> findByRole(ApplicationRole applicationRole);

/**
* To support impersonation by role
* @param user
* @return
* Uses the {@link UserMemento#getRoles() roles} held within the provided {@link UserMemento}.
*
* <p>
* Added to support {@link org.apache.isis.applib.services.user.ImpersonateMenu#impersonateWithRoles(String, List) impersonation by role}.
* </p>
*
* @see #findByRoleNames(List)
*/
List<ApplicationPermission> findByUserMemento(UserMemento user);

/**
* Returns the set of permissions associated with the provided list of roles (identified by
* their role name).
*
* @see #findByUserMemento(UserMemento).
*/
List<ApplicationPermission> findByRoleNames(List<String> roleNames);

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
*/
package org.apache.isis.extensions.secman.applib.permission.dom;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.inject.Inject;

Expand Down Expand Up @@ -97,19 +97,18 @@ public List<ApplicationPermission> findByUser(@NonNull final ApplicationUser use
}

public List<ApplicationPermission> findByUserMemento(@NonNull final UserMemento userMemento) {
val permissions = new ArrayList<ApplicationPermission>();

// TODO: this is naive in the extreme...
userMemento.getRoles().stream()
val roleNames = userMemento.getRoles().stream()
.map(RoleMemento::getName)
.map(roleRepository::findByName)
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(role -> {
final List<ApplicationPermission> byRole = findByRole(role);
permissions.addAll(byRole);
});
return permissions;
.collect(Collectors.toList());
return findByRoleNames(roleNames);
}

public List<ApplicationPermission> findByRoleNames(@NonNull final List<String> roleNames) {
return _Casts.uncheckedCast(
repository.allMatches(
Query.named(this.applicationPermissionClass, ApplicationPermission.NAMED_QUERY_FIND_BY_ROLE_NAMES)
.withParameter("roleNames", roleNames))
);
}

private List<ApplicationPermission> findByUser(final String username) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class ApplicationPermission_updateRole {
public static class DomainEvent
extends IsisModuleExtSecmanApplib.ActionDomainEvent<ApplicationPermission_updateRole> {}

@Inject private ApplicationRoleRepository applicationRoleRepository;
@Inject ApplicationRoleRepository applicationRoleRepository;

private final ApplicationPermission target;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,4 @@ default ApplicationRole upsert(final String name, final String roleDescription)

void deleteRole(ApplicationRole holder);



}
Original file line number Diff line number Diff line change
Expand Up @@ -178,4 +178,5 @@ public Collection<ApplicationRole> getRoles(
return user.getRoles();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
import org.springframework.stereotype.Service;

import org.apache.isis.applib.annotation.PriorityPrecedence;
import org.apache.isis.applib.services.iactnlayer.InteractionService;
import org.apache.isis.core.metamodel.events.MetamodelEvent;
import org.apache.isis.extensions.secman.applib.seed.scripts.SeedUsersAndRolesFixtureScript;
import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScripts;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;

/**
Expand All @@ -49,15 +51,12 @@
@Service
@Named("isis.ext.secman.SeedSecurityModuleService")
@Qualifier("Default")
@RequiredArgsConstructor(onConstructor_ = {@Inject })
@Log4j2
public class SeedSecurityModuleService {

private final FixtureScripts fixtureScripts;

@Inject
public SeedSecurityModuleService(final FixtureScripts fixtureScripts) {
this.fixtureScripts = fixtureScripts;
}
private final InteractionService interactionService;

@EventListener(MetamodelEvent.class)
@Order(PriorityPrecedence.MIDPOINT - 100)
Expand All @@ -68,7 +67,7 @@ public void onMetamodelEvent(final MetamodelEvent event) {
if (event.isPostMetamodel()) {
log.info("SEED security fixtures (Users and Roles)");

fixtureScripts.run(new SeedUsersAndRolesFixtureScript());
interactionService.runAnonymous(() -> fixtureScripts.run(new SeedUsersAndRolesFixtureScript()));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.apache.isis.extensions.secman.applib;

import java.util.Arrays;
import java.util.List;

import javax.inject.Inject;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import org.apache.isis.applib.services.appfeat.ApplicationFeatureId;
import org.apache.isis.applib.value.Password;
import org.apache.isis.extensions.secman.applib.permission.dom.ApplicationPermission;
import org.apache.isis.extensions.secman.applib.permission.dom.ApplicationPermissionRepository;
import org.apache.isis.extensions.secman.applib.role.dom.ApplicationRole;
import org.apache.isis.extensions.secman.applib.role.dom.ApplicationRoleRepository;
import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUser;
import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUserRepository;
import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUserStatus;
import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstract;

import static org.apache.isis.applib.services.appfeat.ApplicationFeatureId.newType;
import static org.apache.isis.extensions.secman.applib.permission.dom.ApplicationPermissionMode.CHANGING;
import static org.apache.isis.extensions.secman.applib.permission.dom.ApplicationPermissionRule.ALLOW;

import lombok.val;

public abstract class ApplicationPermissionRepositoryIntegTestAbstract extends IsisIntegrationTestAbstract {

protected ApplicationUser maryUser, mungoUser, midgeUser;
protected ApplicationRole girlRole, dogRole, mouseRole, littleRole, flatDwellerRole;
protected ApplicationPermission rideLiftForGirlRolePerm, rideLiftForDogRolePerm, rideLiftForMouseRolePerm;
protected ApplicationPermission liftButtonForGirlRolePerm;
protected ApplicationPermission chaseCatsForDogRolePerm;
protected ApplicationPermission eatCheeseForMouseRolePerm;

@BeforeEach
void setUp() {
maryUser = userRepository
.upsertLocal("mary", Password.of("marypass"), ApplicationUserStatus.UNLOCKED);
mungoUser = userRepository
.upsertLocal("mungo", Password.of("mungopass"), ApplicationUserStatus.UNLOCKED);
midgeUser = userRepository.upsertLocal("midge", Password.of("midgepass"), ApplicationUserStatus.UNLOCKED);

girlRole = roleRepository.upsert("girl", "Girl");
dogRole = roleRepository.upsert("dog", "Dog");
mouseRole = roleRepository.upsert("mouse", "Mouse");

littleRole = roleRepository.upsert("little", "Little");
flatDwellerRole = roleRepository.upsert("flat-dweller", "Flat Dweller");

roleRepository.addRoleToUser(girlRole, maryUser);
roleRepository.addRoleToUser(littleRole, maryUser);
roleRepository.addRoleToUser(flatDwellerRole, maryUser);

roleRepository.addRoleToUser(dogRole, mungoUser);
roleRepository.addRoleToUser(flatDwellerRole, mungoUser);

roleRepository.addRoleToUser(mouseRole, midgeUser);
roleRepository.addRoleToUser(littleRole, midgeUser);
roleRepository.addRoleToUser(flatDwellerRole, midgeUser);

ApplicationFeatureId rideLiftFeature = newType("mmm.RideLiftService");

liftButtonForGirlRolePerm = permissionRepository.newPermission(girlRole, ALLOW, CHANGING, newType("mmm.PressLiftButtonService"));
rideLiftForGirlRolePerm = permissionRepository.newPermission(girlRole, ALLOW, CHANGING, rideLiftFeature);
rideLiftForDogRolePerm = permissionRepository.newPermission(dogRole, ALLOW, CHANGING, rideLiftFeature);
chaseCatsForDogRolePerm = permissionRepository.newPermission(dogRole, ALLOW, CHANGING, newType("mmm.ChaseCatsService"));
rideLiftForMouseRolePerm = permissionRepository.newPermission(mouseRole, ALLOW, CHANGING, rideLiftFeature);
eatCheeseForMouseRolePerm = permissionRepository.newPermission(mouseRole, ALLOW, CHANGING, newType("mmm.EatsCheeseService"));
}

@Test
void end_to_end() {

// when
val maryPermissions = permissionRepository.findByUser(maryUser);

// then
Assertions.assertThat(maryPermissions).containsExactlyInAnyOrder(liftButtonForGirlRolePerm, rideLiftForGirlRolePerm);

// when
final List<ApplicationPermission> adhocPermissions = permissionRepository.findByRoleNames(Arrays.asList(girlRole.getName(), mouseRole.getName()));

// then
Assertions.assertThat(adhocPermissions).containsExactlyInAnyOrder(liftButtonForGirlRolePerm, rideLiftForGirlRolePerm, rideLiftForMouseRolePerm, eatCheeseForMouseRolePerm);

}

@Inject ApplicationPermissionRepository permissionRepository;
@Inject ApplicationRoleRepository roleRepository;
@Inject ApplicationUserRepository userRepository;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.apache.isis.extensions.secman.applib.mmm;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import org.apache.isis.extensions.secman.applib.mmm.dom.ChaseCatsService;
import org.apache.isis.extensions.secman.applib.mmm.dom.EatCheeseService;
import org.apache.isis.extensions.secman.applib.mmm.dom.PressLiftButtonService;
import org.apache.isis.extensions.secman.applib.mmm.dom.RideLiftService;

@Configuration
@Import({
PressLiftButtonService.class,
RideLiftService.class,
ChaseCatsService.class,
EatCheeseService.class,
})
public class MmmModule {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.apache.isis.extensions.secman.applib.mmm.dom;

import org.apache.isis.applib.annotation.Action;
import org.apache.isis.applib.annotation.DomainService;

@DomainService(logicalTypeName = "mmm.ChaseCatsService")
public class ChaseCatsService {
@Action
public void chaseCats() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.apache.isis.extensions.secman.applib.mmm.dom;

import org.apache.isis.applib.annotation.Action;
import org.apache.isis.applib.annotation.DomainService;

@DomainService(logicalTypeName = "mmm.EatsCheeseService")
public class EatCheeseService {
@Action
public void eatCheese() {}
}
Loading