Can't override onAuthenticationSuccess method of AuthenticationSuccessHandler - grails

Following some other posts, I tried to override the authentication success method of the spring-security handler, but it's never being called. My code looks like:
src/groovy/mypackage/MyAuthenticationSuccessHandler.groovy:
package mypackage
import org.springframework.security.core.Authentication
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
public class MyAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
public MyAuthenticationSuccessHandler() {
println("constructed!")
}
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
println("override called")
super.onAuthenticationSuccess(request, response, authentication);
}
}
resources.groovy:
authenticationSuccessHandler(MyAuthenticationSuccessHandler) {
def conf = SpringSecurityUtils.securityConfig
requestCache = ref('requestCache')
defaultTargetUrl = conf.successHandler.defaultTargetUrl
alwaysUseDefaultTargetUrl = conf.successHandler.alwaysUseDefault
targetUrlParameter = conf.successHandler.targetUrlParameter
useReferer = conf.successHandler.useReferer
redirectStrategy = ref('redirectStrategy')
}
There are no errors, the constructor is definitely called and MyAuthenticationSuccessHandler is injected into a test controller, but onAuthenticationSuccess is never called. I dropped a breakpoint into the superclass version and that worked. I also tried rewriting my custom class in java but that didn't work.
What am I doing wrong?

Turns out another login filter was already active and it was preventing the normal method from working. The filter in question is org.mitre.openid.connect.client.OIDCAuthenticationFilter and the workaround is to inject your success handler through that one e.g.:
authenticationSuccessHandler(apipulse.MyAuthenticationSuccessHandler) {
clientRegistrationTemplate = ref(clientRegistrationTemplate)
}
...
openIdConnectAuthenticationFilter(OIDCAuthenticationFilter) {
...
authenticationSuccessHandler = ref('authenticationSuccessHandler')
}
Just wasted a day looking at this - thanks a bunch, spring.

Related

Can't inject the guice dependency in the jersey filter

In the process of setup a bridge between guice and jersey, I ran into one problem.
When trying to create a jersey filter, I was unable to inject guice dependencies into it.
I found a duplicate, however there is no solution to the problem there.
Everything is exactly the same.
The only difference is that I don't get a startup error. The filter works, but my dependencies are null.
Interestingly, Filter and HttpFilter work fine. But it doesn't really work for me.
There's another thing that's interesting. In the resource, which I understand is an HK2 dependency, I can inject guice bean.
#ApplicationPath("/test")
private static class TestApplicationConfig extends ResourceConfig
{
public TestApplicationConfig()
{
register(JacksonFeature.class);
register(AuthFilter.class);
register(new ContainerLifecycleListener()
{
public void onStartup(Container container)
{
ServletContainer servletContainer = (ServletContainer) container;
ServiceLocator serviceLocator = container.getApplicationHandler().getServiceLocator();
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
Injector injector = (Injector) servletContainer
.getServletContext()
.getAttribute(Injector.class.getName());
guiceBridge.bridgeGuiceInjector(injector);
}
public void onReload(Container container)
{
}
public void onShutdown(Container container)
{
}
});
}
}
In ServletModule child.
serve(path).with(ServletContainer.class, ImmutableMap.of(
"javax.ws.rs.Application", TestApplicationConfig.class.getName(),
"jersey.config.server.provider.packages", sb.toString()));
I trying with register(AuthFilter.class) and #Provider
#Singleton
#Provider
public class AuthFilter implements ContainerRequestFilter
{
#Inject
private SomeInjectedService someInjectedService; **// null here**
#Context
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
// some code
}
}
SomeInjectedService I register by guice
bind(SomeInjectedService.class).asEagerSingleton();
Where can I start diagnosing and what can I do?
UPD:
I noticed different behavior when using different annotations.
If I use javax.inject.Inject, I get the following error message.
org.glassfish.hk2.api.MultiException: A MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=SomeInjectedService,parent=AuthFilter,qualifiers={},position=-1,optional=false,self=false,unqualified=null,1496814489)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of some.package.AuthFilter errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on some.package.AuthFilter
If com.google.inject.Inject, just null. As I understand this method is not correct.
Considering that javax Inject is trying to inject the service but can't find it. Can we conclude that the bridge is not working correctly? But if it's not working correctly, why can I inject this service into my resource?
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class SomeResource
{
private final SomeInjectedService someInjectedResource;
#Inject // here I use javax annotation and this code working correctry
public SomeResource(SomeInjectedService someInjectedResource)
{
this.someInjectedResource = someInjectedResource;
}
#GET
#Path("/{user}")
public Response returnSomeResponse(#PathParam("user") String user) throws Exception
{
// some code
}
}

Which class to Mock for to bypass Springboot security in integration tests

#SpringBootTest(webEnvironment = RANDOM_PORT)
#ActiveProfiles("test")
class ContextLoadingSpec extends Specification {
#Autowired
TestRestTemplate testRestTemplate
def '/ should load the context'() {
when:
ResponseEntity<Object> entity = testRestTemplate.getForEntity('/', Object.class)
then:
entity.statusCode == HttpStatus.OK
}
#TestConfiguration
static class Config {
#Bean
RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder()
.basicAuthorization('user', 'xxxxxxxx')
}
}
}
Creating a TestConfiguration doesn't seem correct to me here. The credentials should be in 'application.yml' and the authentication call should have been mocked. Please suggest a better way of writing this test.

Spring Security Test : Testing the annotation #Secured (or #PreAuthorize)

I've got a problem (of course :)). I have a spring 4.2 application with Spring Security and Spring MVC (with Rest API) and I want to test the effectiveness of the annotation #Secured(ROLE_FOO) present on a REST method.
So I need to install spring-security-test library for this. OK.
Then I follow up some tutorials (or doc) like the official one : http://docs.spring.io/autorepo/docs/spring-security/4.1.0.RC1/reference/htmlsingle/
Here my test code (I'am trying to remove all "uneccessary" code.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest
public class UserResourceIntTest {
private MockMvc restUserMockMvc2;
#Autowired
private WebApplicationContext context;
....//Injection, Mocks declarations here
#Before
public void setup() {
this.restUserMockMvc2 = MockMvcBuilders.webAppContextSetup(context).apply(SecurityMockMvcConfigurers.springSecurity()).build();
}
#Test
#WithMockUser(roles="ROLE_VIEWER")
public void testGetUserListe() throws Exception {
//here getAuthentication() returns null !!! why ???
SecurityContextHolder.getContext().getAuthentication().getPrincipal();
// restUserMockMvc2.perform(get("/api/users/liste")
// .principal(SecurityContextHolder.getContext().getAuthentication()))
// .accept(MediaType.APPLICATION_JSON))
// .andExpect(status().isForbidden());
// .andExpect(content().contentType("application/json"));
}
Here the method I want to test :
#RestController
#RequestMapping("/api")
public class UserResource {
#RequestMapping(value = "/users/liste", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
#Transactional(readOnly = true)
#Secured({ AuthoritiesConstants.TC_ADMIN })
public ResponseEntity<List<ManagedUserDTO>> getUserListe(Pageable pageable, Principal principal) throws URISyntaxException {
//doSomething...
}
Can you tell me WHY in my test,
SecurityContextHolder.getContext().getAuthentication()
returns null ??
#WithMockUser should authenticate a user automatically (the principal hence)
Thanks
EDIT1 : the setup part of the test (concerning only the security instruction) :
#Inject
private FilterChainProxy springSecurityFilterChain;
#Inject
private PageableHandlerMethodArgumentResolver pageableArgumentResolver;
#Before
public void setup() {
....
this.restUserMockMvc2 = MockMvcBuilders
.standaloneSetup(userResource2)
.alwaysDo(print()) .apply(SecurityMockMvcConfigurers.springSecurity(springSecurityFilterChain))
.setCustomArgumentResolvers(pageableArgumentResolver)
.build();
...
}
EDIT2 : just to be clear on the class definition :
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#TestExecutionListeners(listeners={ServletTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
WithSecurityContextTestExecutionListener.class})
public class UserResourceIntTest {
}
The problem is that Spring Security's WithSecurityContextTestExecutionListener is not being executed because #IntegrationTest is overriding the default TestExecutionListeners.
Most likely you don't need #IntegrationTest with MockMvc, so you should be able to remove it entirely and resolve your issue.
Alternatively you can resolve this by explicitly adding WithSecurityContextTestExecutionListener to your class like:
#TestExecutionListeners(listeners = { WithSecurityContextTestExecutionListener.class, IntegrationTestPropertiesListener.class,
DirtiesContextBeforeModesTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class })
#IntegrationTest
public class UserResourceIntTest {

Custom Logout Handler Not Working Grails

I have implemented custom Logout handler in grails. For some reasons, it is not working. I have checked a similar question on stackoverflow
spring security logout handler not working ,but it did not work for me. The problem is my custom method is not being called.
My code is as follows:
Config.groovy
grails.plugin.springsecurity.filterChain.chainMap = [
'/api/v1/login/**': 'authenticationProcessingFilter,restAuthenticationFilter,restTokenValidationFilter,filterInvocationInterceptor,restExceptionTranslationFilter',
'/api/v1/logout/**': 'authenticationProcessingFilter,restAuthenticationFilter,restExceptionTranslationFilter,restLogoutFilter',
'/**': 'securityContextPersistenceFilter,anonymousAuthenticationFilter,restAuthenticationFilter,restTokenValidationFilter,restExceptionTranslationFilter,filterInvocationInterceptor']
grails.plugin.springsecurity.useSecurityEventListener = true
grails.plugin.springsecurity.logout.handlerNames =
['rememberMeServices', 'myHandler' ,
'securityEventListener',
'securityContextLogoutHandler']
resources.groovy
beans = {
myHandler(com.as.rest.handlers.CustomSecurityContextLogoutHandler) }
CustomSecurityContextLogoutHandler.groovy
package com.as.rest.handlers
import org.springframework.security.core.Authentication
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class CustomSecurityContextLogoutHandler extends SecurityContextLogoutHandler {
#Override
void logout(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) {
println("#############################################")
println("#############################################")
println("#############################################")
println("logout")
}
}

ViewMapListener JSF not being called

I'm trying to port the JSF #ViewScoped annotation to CDI. The reason is more educational rather than based on need. I chose this particular scope mainly due to the lack of a better concrete example of a custom scope one might want to implement in CDI.
That said, my starting point was Porting the #ViewScoped JSF annotation to CDI. But, this implementation does not take into account a seemingly very important responsibility of Context (i.e. destroying) mentioned in the API:
The context object is responsible for creating and destroying contextual instances by calling operations of Contextual. In particular, the context object is responsible for destroying any contextual instance it creates by passing the instance to Contextual.destroy(Object, CreationalContext). A destroyed instance must not subsequently be returned by get(). The context object must pass the same instance of CreationalContext to Contextual.destroy() that it passed to Contextual.create() when it created the instance.
I decided to add this functionality by having my Context object:
keep track of what Contextual objects it creates for which UIViewRoots;
implement the ViewMapListener interface and register itself as listener for each UIViewRoot by calling UIViewRoot.subscribeToViewEvent(PreDestroyViewMapEvent.class, this);
destroy any created Contextuals when the ViewMapListener.processEvent(SystemEvent event) is called and unregister itself from that UIViewRoot.
Here's my Context implementation:
package com.example;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import javax.enterprise.context.spi.Context;
import javax.enterprise.context.spi.Contextual;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.PreDestroyViewMapEvent;
import javax.faces.event.SystemEvent;
import javax.faces.event.ViewMapListener;
public class ViewContext implements Context, ViewMapListener {
private Map<UIViewRoot, Set<Disposable>> state;
public ViewContext() {
this.state = new HashMap<UIViewRoot, Set<Disposable>>();
}
// mimics a multimap put()
private void put(UIViewRoot key, Disposable value) {
if (this.state.containsKey(key)) {
this.state.get(key).add(value);
} else {
HashSet<Disposable> valueSet = new HashSet<Disposable>(1);
valueSet.add(value);
this.state.put(key, valueSet);
}
}
#Override
public Class<? extends Annotation> getScope() {
return ViewScoped.class;
}
#Override
public <T> T get(final Contextual<T> contextual,
final CreationalContext<T> creationalContext) {
if (contextual instanceof Bean) {
Bean bean = (Bean) contextual;
String name = bean.getName();
FacesContext ctx = FacesContext.getCurrentInstance();
UIViewRoot viewRoot = ctx.getViewRoot();
Map<String, Object> viewMap = viewRoot.getViewMap();
if (viewMap.containsKey(name)) {
return (T) viewMap.get(name);
} else {
final T instance = contextual.create(creationalContext);
viewMap.put(name, instance);
// register for events
viewRoot.subscribeToViewEvent(
PreDestroyViewMapEvent.class, this);
// allows us to properly couple the right contaxtual, instance, and creational context
this.put(viewRoot, new Disposable() {
#Override
public void dispose() {
contextual.destroy(instance, creationalContext);
}
});
return instance;
}
} else {
return null;
}
}
#Override
public <T> T get(Contextual<T> contextual) {
if (contextual instanceof Bean) {
Bean bean = (Bean) contextual;
String name = bean.getName();
FacesContext ctx = FacesContext.getCurrentInstance();
UIViewRoot viewRoot = ctx.getViewRoot();
Map<String, Object> viewMap = viewRoot.getViewMap();
if (viewMap.containsKey(name)) {
return (T) viewMap.get(name);
} else {
return null;
}
} else {
return null;
}
}
// this scope is only active when a FacesContext with a UIViewRoot exists
#Override
public boolean isActive() {
FacesContext ctx = FacesContext.getCurrentInstance();
if (ctx == null) {
return false;
} else {
UIViewRoot viewRoot = ctx.getViewRoot();
return viewRoot != null;
}
}
// dispose all of the beans associated with the UIViewRoot that fired this event
#Override
public void processEvent(SystemEvent event)
throws AbortProcessingException {
if (event instanceof PreDestroyViewMapEvent) {
UIViewRoot viewRoot = (UIViewRoot) event.getSource();
if (this.state.containsKey(viewRoot)) {
Set<Disposable> valueSet = this.state.remove(viewRoot);
for (Disposable disposable : valueSet) {
disposable.dispose();
}
viewRoot.unsubscribeFromViewEvent(
PreDestroyViewMapEvent.class, this);
}
}
}
#Override
public boolean isListenerForSource(Object source) {
return source instanceof UIViewRoot;
}
}
Here's the Disposable interface:
package com.example;
public interface Disposable {
public void dispose();
}
Here's the scope annotation:
package com.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.enterprise.context.NormalScope;
#Inherited
#NormalScope
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD,
ElementType.FIELD, ElementType.PARAMETER})
public #interface ViewScoped {
}
Here's the CDI extension declaration:
package com.example;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.Extension;
public class CustomContextsExtension implements Extension {
public void afterBeanDiscovery(#Observes AfterBeanDiscovery event) {
event.addContext(new ViewContext());
}
}
I added the javax.enterprise.inject.spi.Extension file under META-INF/services containing com.example.CustomContextsExtension to properly register the above with CDI.
I can now make beans like (notice the use of the custom #ViewScoped implementation.):
package com.example;
import com.concensus.athena.framework.cdi.extension.ViewScoped;
import java.io.Serializable;
import javax.inject.Named;
#Named
#ViewScoped
public class User implements Serializable {
...
}
The beans are created properly and properly injected into JSF pages (i.e. the same instance is returned per view, new ones are created only when the view is created, the same instances are injected over multiple requests to the same view). How do I know? Imagine the above code littered with debugging code which I purposefully stripped out for clarity and since this is already a huge post.
The problem is that my ViewContext.isListenerForSource(Object source) and ViewContext.processEvent(SystemEvent event) are never called. I was expecting that at least upon session expiration those events would be called, since the view map is stored in the session map (correct?). I set the session timeout to 1 minute, waited, saw the timeout happen, but my listener was still not called.
I also tried adding the following to my faces-config.xml (mostly out of the lack of ideas):
<system-event-listener>
<system-event-listener-class>com.example.ViewContext</system-event-listener-class>
<system-event-class>javax.faces.event.PreDestroyViewMapEvent</system-event-class>
<source-class>javax.faces.component.UIViewRoot</source-class>
</system-event-listener>
Finally, my environment is JBoss AS 7.1.1 with Mojarra 2.1.7.
Any clues would be greatly appreciated.
EDIT: Further Investigation.
PreDestroyViewMapEvent doesn't seem to be fired at all while PostConstructViewMapEvent is fired as expected - every time a new view map is created, specifically during UIViewRoot.getViewMap(true). The documentation states that PreDestroyViewMapEvent should be fired every time clear() is called on the view map. That leaves to wonder - is clear() required to be called at all? If so, when?
The only place in the documentation that I was able to find such a requirement is in FacesContext.setViewRoot():
If the current UIViewRoot is non-null, and calling equals() on the
argument root, passing the current UIViewRoot returns false, the clear
method must be called on the Map returned from UIViewRoot#getViewMap.
Does this ever happen in the normal JSF lifecycle, i.e. without programmatically calling UIViewRoot.setViewMap()? I can't seem to find any indication.
This is related to an issue with the JSF spec that is being fixed in the JSF2.2 spec, see here. Also, I created an issue with Apache DeltaSpike so they may try to fix it, see here. If it's fixed in DeltaSpike, then it may end up being merged into CODI and / or Seam as well.
The view map is stored in a LRU map, because you never know which view will be post back. Unfortunately, the PreDestroyViewMapEvent is not called before removing from this map.
A workaround is to reference your object from within a WeakReference. You can use ReferenceQueue or check the reference when to call your destruction code.

Resources