I am trying to use Apache Shiro for an RMI server with multiple clients connecting.
The architecture I want to have is a few singleton service registered in the register of RMI. Each of them have a login method that return a new exported service by client. So I can in each client's service keep a final reference to a client Object.
With Shiro I will use annotation @RequireRoles etc on services of clients.
My question is how to intercept the Aspect of all annotations @RequireRoles and just set the Subject with the reference in the service?
I could write my own annotations @AllowRoles(String[]) and my own Aspect to get the jointPoint (the service) with the "this" and get the reference to the client and check if the client has these roles. But I would rather use a good framework and not code everything from beginning...
The same apply to @Transactional but I do not use SpringAOP.
How to organize RMI Client-Server architecture
Correct way to use Apache Shiro on distributed system using RMI?
EDIT: I might have found a solution but not sure it is the good one: Without precedence it would not work properly or not work at all if subject is null.
public aspect TestIntercept {
private static final Logger log = LoggerFactory.getLogger(TestIntercept.class);
declare precedence : TestIntercept, org.apache.shiro.aspectj.ShiroAnnotationAuthorizingAspect;
pointcut allow(): execution(@org.apache.shiro.authz.annotation.RequiresPermissions * *(..)) || execution(@org.apache.shiro.authz.annotation.RequiresRoles * *(..));
before(): allow(){
log.info("Before, in log2");
Signature sig = thisJoinPointStaticPart.getSignature();
String line = String.valueOf(thisJoinPointStaticPart.getSourceLocation().getLine());
String sourceName = thisJoinPointStaticPart.getSourceLocation()
.getWithinType().getCanonicalName();
System.out.println("Call2 from " + sourceName + " line " + line + "\n to "
+ sig.getDeclaringTypeName() + "." + sig.getName() + "\n");
log.info("Got subject from service: " + ((Service) thisJoinPoint.getThis()).getSubject().isAuthenticated());
log.info("Got subject from service: " + ((Service) thisJoinPoint.getThis()).getSubject().getPrincipal());
// Subject subject = ((Service) thisJoinPoint.getThis()).getSubject();
/*
Subject subject = new Subject.Builder()
.authenticated(true)
.principals(new SimplePrincipalCollection("fake", "realmm"))
.buildSubject();
//*/
//*
Subject subject = SecurityUtils.getSubject();
subject.logout();
subject.login(new UsernamePasswordToken("fake2", "11"));
//*/
ThreadState threadState = new SubjectThreadState(subject);
threadState.bind();
}
}
I did not unbind the subject from the thread context because any call to a service method will make sure the user of the service is bound to the executing thread.
I could use instead of bind, use: subject.execute(()->{return proceed()}); within an advice "around" to automatically have the threadConext cleared but is it really necessary ?
Thanks for any help