11

I've defined this method in my Spring MVC Controller :

@RequestMapping(value = "{id}/content", method=RequestMethod.POST)
@PreAuthorize("principal.user.userAccount instanceof T(com.anonym.model.identity.PedagoAccount) AND principal.user.userAccount.userId == #object.pedago.userId AND #form.id == #object.id")
public String modifyContent(@PathVariable("id") Project object, @Valid  @ModelAttribute("form") ProjectContentForm form) {
    ....
}

Then in my JUnit test I'd like to call this method and ensure that the PreAuthorize condition is verified. But when I set the user principal in my JUnit test with a bad account there is no error and the method completes. It seems the annotation is bypassed.
But when I call this method in a normal way (not testing), the PreAuthorize is verified.

If it's possible, how to test this annotation in a junit test and how to catch the exception if it throws one ?

Thanks,
Nicolas

Nico
  • 3,430
  • 4
  • 20
  • 27
  • Just a note for others using "principal" in PreAuthorize, this will fail with a nullpointerexcpetion, and not trigger a reauthorization unless you either include something to the effect of isAuthenticated() either in the PreAuthorize annotation or in the security.xml – chrismarx Feb 28 '14 at 15:34

1 Answers1

15

Since you want to test features implemented via Spring AOP, you need to use Spring TestContext framework to run tests against application context.

Then you create a base test with minimal security configuration:

abstract-security-test.xml:

<security:authentication-manager alias="authenticationManager">
    <security:authentication-provider user-service-ref = "userService" />
</security:authentication-manager>

<security:global-method-security pre-post-annotations="enabled" />

<bean id = "userService" class = "..." />

AbstractSecurityTest.java:

@ContextConfiguration("abstract-security-test.xml")
abstract public class AbstractSecurityTest {
    @Autowired
    private AuthenticationManager am;

    @After
    public void clear() {
        SecurityContextHolder.clearContext();
    }

    protected void login(String name, String password) {
        Authentication auth = new UsernamePasswordAuthenticationToken(name, password);
        SecurityContextHolder.getContext().setAuthentication(am.authenticate(auth));
    }
}

Now you can use it in your tests:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(...)
public class CreatePostControllerSecurityTest extends AbstractSecurityTest {
    ...

    @Test
    @ExpectedException(AuthenticationCredentialsNotFoundException.class)
    public void testNoAuth() {
        controller.modifyContent(...);
    }

    @Test
    @ExpectedException(AccessDeniedException.class)
    public void testAccessDenied() {
        login("userWithoutAccessRight", "...");
        controller.modifyContent(...);
    }

    @Test
    public void testAuthOK() {
        login("userWithAccessRight", "...");
        controller.modifyContent(...);
    }
}
axtavt
  • 239,438
  • 41
  • 511
  • 482
  • Thank you, it works fine for authentication, but if want to test the whole Spring EL defined in the PreAuthorize annotation, how do I do ?
    – Nico Mar 23 '11 at 12:49
  • Thank you, it works fine for authentication, but if I want to test the whole Spring EL defined in the PreAuthorize annotation, how do I do ? I mean how to verify principal.user.userAccount.userId == #object.pedago.userId AND #form.id == #object.id where #object and #form designate variables of the modifyContent method. Is there any exception to catch for an unverified security Spring EL ? – Nico Mar 23 '11 at 12:55
  • 5
    The @ExpectedException annotation is deprecated; use JUnit4's @Test(expected=…) instead. – praseodym Feb 28 '12 at 14:59
  • 1
    Terrific advice. This works very well for me. One thing I did a bit different is that I separated out my existing `security-context.xml` from my `webapp-context.xml` so that I can use the security context configuration in my tests without including the web app stuff. That way I can reuse the existing security config in my tests. – Matt Friedman Oct 07 '12 at 00:08