Guice: Injecting Interceptors in ServletModule - java

I am trying to inject an Interceptor with a Vaadin Application instance created by Guice.
I've followed the documentation for Vaadin-Guice integration in the Vaadin Wiki and
the documenation on Interceptor DI in the Guice Wiki:
public class RecruitmentServletConfig extends GuiceServletContextListener {
#Override
protected Injector getInjector() {
ServletModule servletModule = new ServletModule() {
#Override
protected void configureServlets() {
...
bind(Application.class).to(RecruitmentApplication.class).in(ServletScopes.SESSION);
SecurityGuard securityGuard = new SecurityGuard();
requestInjection(securityGuard);
bindInterceptor(Matchers.subclassesOf(CustomComponent.class), Matchers.annotatedWith(AllowedRoles.class), securityGuard);
}
};
return Guice.createInjector(servletModule);
}
}
The SecurityGuard interceptor:
public class SecurityGuard implements MethodInterceptor {
#Inject private Application application;
public Object invoke(MethodInvocation invocation) throws Throwable {
AllowedRoles allowedRoles = invocation.getMethod().getAnnotation(AllowedRoles.class);
if (((User) application.getUser()).hasRole(allowedRoles.value())) {
return invocation.proceed();
} else {
return null;
}
}
However, I get an OutOfScopeException on server startup:
SEVERE: Exception sending context initialized event to listener instance of class de.embl.eicat.recruit.ioc.RecruitmentServletConfig
com.google.inject.CreationException: Guice creation errors:
1) Error in custom provider, com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
at recruit.ioc.RecruitmentServletConfig$1.configureServlets(RecruitmentServletConfig.java:86)

Does it work if you wrap your Application in a Provider?
public class SecurityGuard implements MethodInterceptor {
#Inject private Provider<Application> application;
public Object invoke(MethodInvocation invocation) throws Throwable {
AllowedRoles allowedRoles = invocation.getMethod().getAnnotation(AllowedRoles.class);
if (((User) application.get().getUser()).hasRole(allowedRoles.value())) {
return invocation.proceed();
} else {
return null;
}
}

Related

Custom Security Expression

I'm studying tutorial how to create custom security expression and I created threes classes but I got error, I tried google everything, may be I am not updated or some. Can you explain what's going on?
Error:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Failed to evaluate expression 'isComprador()'] with root cause
Method call: Method isComprador() cannot be found on type org.springframework.security.access.expression.method.MethodSecurityExpressionRoot
MethodSecurityConfig:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new CustomMethodSecurityExpressionHandler();
}
}
CustomMethodSecurityExpressionHandler:
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
#Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}
CustomMethodSecurityExpressionRoot:
public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
private Object filterObject;
private Object returnObject;
private Object target;
public CustomMethodSecurityExpressionRoot(Authentication authentication) {
super(authentication);
}
#Override
public void setFilterObject(Object filterObject) {
this.filterObject = filterObject;
}
#Override
public Object getFilterObject() {
return filterObject;
}
#Override
public void setReturnObject(Object returnObject) {
this.returnObject = returnObject;
}
#Override
public Object getReturnObject() {
return returnObject;
}
void setThis(Object target) {
this.target = target;
}
#Override
public Object getThis() {
return target;
}
//
public boolean isComprador() {
final Usuario usuario = ((UserDetailsImpl) this.getPrincipal()).getUsuario();
return usuario.getPerfil() == Perfil.COMPRADOR;
}
public boolean isVendedor() {
final Usuario usuario = ((UserDetailsImpl) this.getPrincipal()).getUsuario();
return usuario.getPerfil() == Perfil.VENDEDOR;
}
}
Thanks!
Att,
Carlos Oliveira
I'd really recommend using a custom bean rather than trying to integrate into the expression root. This is much easier to configure, decouples your code from Spring Security you just create a simple pojo, and allows your code to be more focused.
To use this approach start by creating a Spring Bean:
#Component
public class Authz {
public boolean isComprador() {
// Authentication is the currently logged in user
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication != null && "comprador".equals(authentication.getName());
}
}
Then you can refer to methods in the Bean using #beanName.methodName. In our case, the Bean name is authz and our method is isComprador so the following would work:
#Service
public class MessageService {
// we pass in the name argument into our custom expression Authz.isComprador
#PreAuthorize("#authz.isComprador()")
String greetForName(String name) {
return "Hello " + name;
}
}
Finally we just enable method security like normal:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {
}
You can then write a few unit tests to prove that it works:
#SpringBootTest
class DemoApplicationTests {
#Autowired
MessageService service;
#Test
#WithMockUser // run the test as a user with the default username of user
void secureWhenForbidden() {
assertThatCode(() -> service.greetForName("Rob")).isInstanceOf(AccessDeniedException.class);
}
#Test
#WithMockUser("comprador") // run the test as a user with the username of comprador
void secureWhenGranted() {
assertThatCode(() -> service.greetForName("Rob")).doesNotThrowAnyException();;
}
}
You can find a complete sample at https://github.com/rwinch/spring-security-sample/tree/method-security-bean-expression

Jersey Test + HK2 + Inject Factory service

I am trying to inject a object provided by HK2 Factory service in a Jersey Test Class but getting unsatisfied dependencies exception.
I have a factory service as below
public class TestFactory implements Factory<TestObject>{
private final CloseableService closeService;
#Inject
public TestFactory(CloseableService closeService) {
this.closeService = closeService;
}
#Override
public TestObject provide() {
TestObject casualObject = new TestObject();
this.closeService.add(() -> dispose(casualObject));
return casualObject;
}
#Override
public void dispose(TestObject instance) {
instance.destroy();
}
}
And a Jersey Test class
public class SampleTestCass extends JerseyTestNg.ContainerPerClassTest
{
//#Inject
private TestObject myTestObject;
private ServiceLocator locator;
#Override
protected Application configure()
{
ResourceConfig resConfig = new ResourceConfig(MyApi.class);
resConfig.register(getBinder());
locator = setupHK2(getBinder());
return resConfig;
}
// setup local hk2
public setupHK2(AbstractBinder binder)
{
ServiceLocatorFactory factory = ServiceLocatorFactory.getInstance();
ServiceLocator locator = factory.create("test-locator");
DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
DynamicConfiguration dc = dcs.createDynamicConfiguration();
locator.inject(binder);
binder.bind(dc);
dc.commit();
return locator;
}
// get the binder
public AbstractBinder getBinder()
{
return new AbstractBinder() {
#Override
protected void configure() {
bindFactory(TestFactory.class, Singleton.class).to(TestObject.class).in(PerLookup.class);
}
}
}
#BeforeClass
public void beforeClass()
{
myTestObject = locator.getService(TestObject.class);
// use myTestObject
}
#AfterClass
public void afterClass()
{
if (locator != null) {
locator.shutdown();
}
}
#Test()
public void someTest()
{
// some test code...
}
}
And getting below exceptions
A MultiException has 3 exceptions. They are:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=CloseableService,parent=TestFactory,qualifiers={},position=0,optional=false,self=false,unqualified=null,2053349061)
java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.test.factories.TestFactory errors were found
java.lang.IllegalStateException: Unable to perform operation: resolve on com.test.factories.TestFactory
CloseableService is a service available within a Jersey application. The ServiceLocator you created is not tied to the Jersey application. It is just a standalone locator. So trying to register the TestFactory with this locator will cause it to fail, as there is no CloseableService. The one that you registered with the ResourceConfig will work just fine.
Not sure what exactly you're trying to do, but if you want access to the service inside the test, one thing you can do is just bind the service as an instance, something like
class MyTest {
private Service service;
#Override
public ResourceConfig configure() {
service = new Service();
return new ResourceConfig()
.register(new AbstractBinder() {
#Override
public void configure() {
bind(service).to(Service.class);
}
})
}
}

Create #UnitOfWork-aware proxies of existing objects

I have the following classes:
public FooDAO extends AbstractDAO<Foo> { // Dropwizard DAO
#Inject FooDAO(SessionFactory sf) { super(sf); }
public void foo() { /* use SessionFactory */ }
}
public class FooService {
private final FooDAO fooDAO; // Constructor-injected dependency
#Inject FooService (FooDAO fooDAO) { this.fooDAO = fooDAO; }
#UnitOfWork
public void foo() {
this.fooDAO.foo();
System.out.println("I went through FooService.foo()");
}
}
Now, FooService is not a resource, so Dropwizard doesn't know about it and doesn't automagically proxy it. However the smart guys at Dropwizard made it so I can get a proxy through UnitOfWorkAwareProxyFactory.
I tried doing feeding these proxies to Guice with an interceptor, but I faced an issue because UnitOfWorkAwareProxyFactory only ever creates new instances and never lets me pass existing objects. The thing with new instances is that I don't know the parameters to give it since they're injected by Guice.
How do I create #UnitOfWork-aware proxies of existing objects?
Here's the interceptor I've made so far:
public class UnitOfWorkModule extends AbstractModule {
#Override protected void configure() {
UnitOfWorkInterceptor interceptor = new UnitOfWorkInterceptor();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(UnitOfWork.class), interceptor);
requestInjection(interceptor);
}
private static class UnitOfWorkInterceptor implements MethodInterceptor {
#Inject UnitOfWorkAwareProxyFactory proxyFactory;
Map<Object, Object> proxies = new IdentityHashMap<>();
#Override public Object invoke(MethodInvocation mi) throws Throwable {
Object target = proxies.computeIfAbsent(mi.getThis(), x -> createProxy(mi));
Method method = mi.getMethod();
Object[] arguments = mi.getArguments();
return method.invoke(target, arguments);
}
Object createProxy(MethodInvocation mi) {
// here, what to do? proxyFactory will only provide objects where I pass constructor arguments, but... I don't have those!
}
}
}
Of course, if Dropwizard (or Guice) offers me a simpler way to do so, which is it?
As from Dropwizard 1.1: (not yet released, as of August 10, 2016)
public class UnitOfWorkModule extends AbstractModule {
#Override
protected void configure() {
UnitOfWorkInterceptor interceptor = new UnitOfWorkInterceptor();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(UnitOfWork.class), interceptor);
requestInjection(interceptor);
}
#Provides
#Singleton
UnitOfWorkAwareProxyFactory provideUnitOfWorkAwareProxyFactory(HibernateBundle<AlexandriaConfiguration> hibernateBundle) {
return new UnitOfWorkAwareProxyFactory(hibernateBundle);
}
private static class UnitOfWorkInterceptor implements MethodInterceptor {
#Inject
UnitOfWorkAwareProxyFactory proxyFactory;
#Override
public Object invoke(MethodInvocation mi) throws Throwable {
UnitOfWorkAspect aspect = proxyFactory.newAspect();
try {
aspect.beforeStart(mi.getMethod().getAnnotation(UnitOfWork.class));
Object result = mi.proceed();
aspect.afterEnd();
return result;
} catch (InvocationTargetException e) {
aspect.onError();
throw e.getCause();
} catch (Exception e) {
aspect.onError();
throw e;
} finally {
aspect.onFinish();
}
}
}
}

Java Deep Injection with custom annotations preferably with hk2 [duplicate]

I have a Jersey resource with a facade object injected. This is configured in my ResourceConfig and the facade gets injected fine. The facade contains a DAO class which also should be injected and is configured in the same ResourceConfig. Now to my problem; the DAO class is null. Thus, not injected.
#ApplicationPath("/service")
public class SystemSetup extends ResourceConfig {
public SystemSetup() {
packages(false, "com.foo.bar");
packages("org.glassfish.jersey.jackson");
register(JacksonFeature.class);
final LockManager manager = getLockManager();
final SessionFactory sessionFactory = getSessionFactory();
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(InjectFactory.getDaoFactory(sessionFactory)).to(Dao.class).in(Singleton.class);
bindFactory(InjectFactory.getFacadeFactory(manager)).to(Facade.class).in(Singleton.class);
}
});
}
#Path("/")
#Produces("text/json")
public class ViewResource {
#Inject
private Facade logic;
public class Facade {
#Inject
private Dao dao; //Not injected
The factory instances are rather simple. They simply call the constructor and pass the argument to it.
The strange thing is that this worked absolut fine when I used bind(Class object) rather than bindFactory.
EDIT
Factories
class InjectFactory {
static Factory<Dao> getDaoFactory() {
return new Factory<Dao>() {
#Override
public Dao provide() {
return new Dao(new Object());
}
#Override
public void dispose(Dao dao) {}
};
}
static Factory<Facade> getFacadeFactory() {
return new Factory<Facade>() {
#Override
public Facade provide() {
return new Facade();
}
#Override
public void dispose(Facade facade) {}
};
}
}
As is the case with most Di frameworks, when you start instantiating things yourself, it's often the case that you are kicking the framework out of the equation. This holds true for the Factory instances, as well as the objects the factory creates. So the Facade instance never gets touch by the framework, except to inject it into the resource class.
You can can a hold of the ServiceLocator, and explicitly inject objects yourself if you want to create them yourself. Here are a couple options.
1) Inject the ServiceLocator into the Factory instance, then inject the Facade instance.
static Factory<Facade> getFacadeFactory() {
return new Factory<Facade>() {
#Context
ServiceLocator locator;
#Override
public Facade provide() {
Facade facade = new Facade();
locator.inject(facade);
return facade;
}
#Override
public void dispose(Facade facade) {}
};
}
#Inject
public SystemSetup(ServiceLocator locator) {
packages("foo.bar.rest");
packages("org.glassfish.jersey.jackson");
register(JacksonFeature.class);
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(InjectFactory.getDaoFactory()).to(Dao.class);
Factory<Facade> factory = InjectFactory.getFacadeFactory();
locator.inject(factory);
bindFactory(factory).to(Facade.class);
}
});
}
2) Or bind a Factory class, and let the framework inject the ServiceLocator
public static class FacadeFactory implements Factory<Facade> {
#Context
ServiceLocator locator;
#Override
public Facade provide() {
Facade facade = new Facade();
locator.inject(facade);
return facade;
}
#Override
public void dispose(Facade facade) {}
}
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(InjectFactory.getDaoFactory()).to(Dao.class);
bindFactory(InjectFactory.FacadeFactory.class).to(Facade.class);
}
});

Inject not working for nested objects[Jersey 2.22.1]

I have a Jersey resource with a facade object injected. This is configured in my ResourceConfig and the facade gets injected fine. The facade contains a DAO class which also should be injected and is configured in the same ResourceConfig. Now to my problem; the DAO class is null. Thus, not injected.
#ApplicationPath("/service")
public class SystemSetup extends ResourceConfig {
public SystemSetup() {
packages(false, "com.foo.bar");
packages("org.glassfish.jersey.jackson");
register(JacksonFeature.class);
final LockManager manager = getLockManager();
final SessionFactory sessionFactory = getSessionFactory();
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(InjectFactory.getDaoFactory(sessionFactory)).to(Dao.class).in(Singleton.class);
bindFactory(InjectFactory.getFacadeFactory(manager)).to(Facade.class).in(Singleton.class);
}
});
}
#Path("/")
#Produces("text/json")
public class ViewResource {
#Inject
private Facade logic;
public class Facade {
#Inject
private Dao dao; //Not injected
The factory instances are rather simple. They simply call the constructor and pass the argument to it.
The strange thing is that this worked absolut fine when I used bind(Class object) rather than bindFactory.
EDIT
Factories
class InjectFactory {
static Factory<Dao> getDaoFactory() {
return new Factory<Dao>() {
#Override
public Dao provide() {
return new Dao(new Object());
}
#Override
public void dispose(Dao dao) {}
};
}
static Factory<Facade> getFacadeFactory() {
return new Factory<Facade>() {
#Override
public Facade provide() {
return new Facade();
}
#Override
public void dispose(Facade facade) {}
};
}
}
As is the case with most Di frameworks, when you start instantiating things yourself, it's often the case that you are kicking the framework out of the equation. This holds true for the Factory instances, as well as the objects the factory creates. So the Facade instance never gets touch by the framework, except to inject it into the resource class.
You can can a hold of the ServiceLocator, and explicitly inject objects yourself if you want to create them yourself. Here are a couple options.
1) Inject the ServiceLocator into the Factory instance, then inject the Facade instance.
static Factory<Facade> getFacadeFactory() {
return new Factory<Facade>() {
#Context
ServiceLocator locator;
#Override
public Facade provide() {
Facade facade = new Facade();
locator.inject(facade);
return facade;
}
#Override
public void dispose(Facade facade) {}
};
}
#Inject
public SystemSetup(ServiceLocator locator) {
packages("foo.bar.rest");
packages("org.glassfish.jersey.jackson");
register(JacksonFeature.class);
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(InjectFactory.getDaoFactory()).to(Dao.class);
Factory<Facade> factory = InjectFactory.getFacadeFactory();
locator.inject(factory);
bindFactory(factory).to(Facade.class);
}
});
}
2) Or bind a Factory class, and let the framework inject the ServiceLocator
public static class FacadeFactory implements Factory<Facade> {
#Context
ServiceLocator locator;
#Override
public Facade provide() {
Facade facade = new Facade();
locator.inject(facade);
return facade;
}
#Override
public void dispose(Facade facade) {}
}
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(InjectFactory.getDaoFactory()).to(Dao.class);
bindFactory(InjectFactory.FacadeFactory.class).to(Facade.class);
}
});

Categories

Resources