SudoService
Allows a block of code to be executed within an arbitrary InteractionContext , allowing the who, when and where to be temporarily switched.
Most typically this service is used to temporarily change the "who", that is the user reported by the UserService 's UserService#currentUser() getUser() - hence the name SudoService. But the user’s locale and timezome can also be changed, as well as the time reported by org.apache.isis.applib.services.clock.ClockService .
The primary use case for this service is for fixture scripts and integration tests.
API
class SudoService {
public static RoleMemento ACCESS_ALL_ROLE; (1)
T call(UnaryOperator<InteractionContext> sudoMapper, Callable<T> callable) (2)
void run(UnaryOperator<InteractionContext> sudoMapper, ThrowingRunnable runnable) (3)
}
1 | ACCESS_ALL_ROLE
If included in the list of roles, then will disable security checks (can view and use all object members). |
2 | call(UnaryOperator, Callable)
Executes the supplied Callable block, within the provided InteractionContext . |
3 | run(UnaryOperator, ThrowingRunnable)
Executes the supplied Callable block, within the provided InteractionContext . |
Members
ACCESS_ALL_ROLE
If included in the list of roles, then will disable security checks (can view and use all object members).
call(UnaryOperator, Callable)
Executes the supplied Callable block, within the provided InteractionContext .
run(UnaryOperator, ThrowingRunnable)
Executes the supplied Callable block, within the provided InteractionContext .
Implementation
The core framework provides a default implementation of this service (o.a.i.core.runtimeservices.sudo.SudoServiceDefault
).
Usage
This domain service is useful both for integration testing and while running fixture scripts.
For example, to integration test a workflow system, whereby objects are moved from one user to another, it is helpful to switch the effective user to verify that the task was assigned correctly.
Or, this fixture script uses the SudoService
to set up ToDoItem
objects:
protected void execute(final ExecutionContext ec) {
...
sudoService.sudo(
InteractionContext.switchUser(UserMemento.ofName("joe")),
() -> wrap(toDoItem).completed()
);
...
}
Interaction with Shiro
When sudo(…)
is called the "effective user" is reported by UserService.
However, it does not propagate through to the Shiro security mechanism, which continue to be evaluated according to the permissions of the current user.
This can be a problem in certain use cases.
For example if running a fixture script (which uses the WrapperFactory) from within an implementation of UserRegistrationService, this is likely to result in HiddenException
s being thrown because there is no effective user.
In such cases, permission checking can simply be disabled by specifying SudoService.ACCESS_ALL_ROLE
as one of the roles.
For example:
protected void execute(final ExecutionContext ec) {
...
ExecutionContext ec =
ExecutionContext.ofUserWithSystemDefaults(
UserMemento.ofNameAndRoleNames("joe", SudoService.ACCESS_ALL_ROLE)));
sudoService.sudo(ec, () -> wrap(toDoItem).completed());
...
}
In the future this service may be used more deeply, eg to propagate permissions through to the Shiro security mechanism also. |