Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SEC-2597: Extend the MockMvc DSL to support authentication #2813

Closed
spring-projects-issues opened this issue May 18, 2014 · 4 comments
Closed

SEC-2597: Extend the MockMvc DSL to support authentication #2813

spring-projects-issues opened this issue May 18, 2014 · 4 comments

Comments

@spring-projects-issues
Copy link

@spring-projects-issues spring-projects-issues commented May 18, 2014

Mattias Severson (Migrated from SEC-2597) said:

I suggest that the fluent DSL of the MockMvc should be extended to support different authentication methods. The idea is that it should be possible to validate access rules to different urls if the Spring Security filter chain is added to the MockMvc by using the addFilters(..) method, e.g.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
@WebAppConfiguration
public class AuthenticationTest {

    @Autowired
    WebApplicationContext wac;
    @Autowired
    FilterChainProxy springSecurityFilterChain;

    MockMvc mockMvc;

    @Before
    public void setup() {
        mockMvc = webAppContextSetup(wac).addFilters(springSecurityFilterChain).build();
    }

    @Test
    public void loginUsingBasicAuth() throws Exception {
        mockMvc
                .auth().basic("username", "password")
                .perform(get("/example"))
                .andExpect(status().isOk());
    }

    @Test
    public void loginWithBadCredentials() throws Exception {
        mockMvc
                .auth().basic("unknown", "erroneous")
                .perform(get("/example"))
                .andExpect(status().isUnauthorized());
    }

    @Test
    public void loginUsingFormAuthentication() throws Exception {
        mockMvc
                .auth().form("username", "password")
                .perform(get("/example"))
                .andExpect(status().isOk());
    }

    @Test
    public void loginUsingOAuth2() throws Exception {
        mockMvc
                .auth().oauth2("accessToken")
                .perform(get("/example"))
                .andExpect(status().isOk());
    }
}

The above examples were inspired by Rest Assured that already have these features. Using Rest Assured, the tests would look something like:

public class AuthenticationTest {

    @Test
    public void loginUsingBasicAuth() {
        given()
                .auth().basic("username", "password").
        when()
                .get("/example").
        then()
                .statusCode(HttpStatus.SC_OK);
    }

    @Test
    public void loginWithBadCredentials() {
        given()
                .auth().basic("unknown", "erroneous").
        when()
                .get("/example").
        then()
                .statusCode(HttpStatus.SC_UNAUTHORIZED);
    }

    @Test
    public void loginUsingFormAuthentication() {
        given()
                .auth().form("username", "password").
        when()
                .get("/example").
        then()
                .statusCode(HttpStatus.SC_OK);
    }

    @Test
    public void loginUsingOAuth2() {
        given()
                .auth().oauth2("accessToken").
        when()
                .get("/example").
        then()
                .statusCode(HttpStatus.SC_OK);
    }
}

See also:

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented May 19, 2014

Rob Winch said:

Adding an auth method to the MockMvc API is not really an option for Spring Security since Spring Security doesn't own that code. However, this should not be necessary. Generally MockMvc is open for extension using a RequestPostProcessor.

Spring Security 4.0.0.M1 has added extensions for MockMvc. For example, SecurityRequestsTests shows how you can use something like the following:

mockMvc
                .perform(get("/example").with(user("admin").roles("ADMIN")))

You can also use annotations. See WithUserAuthenticationTests:

  • First ensure you are using WithSecurityContextTestExcecutionListener
  • Second add defaultRequest that is "with testSecurityContext()"
  • Next annotate your tests
@Before
    public void setup() {
        mvc = MockMvcBuilders
                .webAppContextSetup(context)
                .addFilters(springSecurityFilterChain)
                .defaultRequest(get("/").with(testSecurityContext()))
                .build();
    }

    @Test
    @WithMockUser
    public void requestProtectedUrlWithUser() throws Exception {
        mvc
            .perform(get("/"))
            // Ensure we got past Security
            .andExpect(status().isNotFound())
            // Ensure it appears we are authenticated with user
            .andExpect(authenticated().withUsername("user"));
    }

    @Test
    @WithMockUser(roles="ADMIN")
    public void requestProtectedUrlWithAdmin() throws Exception {
        mvc
            .perform(get("/admin"))
            // Ensure we got past Security
            .andExpect(status().isNotFound())
            // Ensure it appears we are authenticated with user
            .andExpect(authenticated().withUsername("user").withRoles("ADMIN"));
    }

Note that the above method are used to emulate already being authenticated with the specified user (the user does not need to exist). If you want to test authentication attempts you can do that is well. For example, to test basic authentication you can do something like this:

mvc
            .perform(get("/secured").with(httpBasic("user","password")))

If you want to perform form based login, you can do something like this:

mvc
            .perform(formLogin().user("user").password("invalid"))

If you have additional feedback on what you would like available, please log specific tickets.

Loading

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented May 19, 2014

Mattias Severson said:

Thanks for your answer. I like the @WithMockUser annotation, but it solves a somewhat different problem than the one I currently have.

The reason for my suggestion is that I have migrated a legacy rest service to Spring Boot. Previously, integration tests were performed by starting a Jetty server by using the jetty-maven-plugin, and then Rest Assured was used to send various web requests and validate both success and error responses. The only difference from the production environment was the database configuration, which during the integration tests points to a local database so that the test data can be seeded with known data before the tests (including encrypted authentication credentials for test users, role mapping, etc).

Now, since I am using Spring Boot, I use the @IntegrationTest annotation instead of jetty-maven-plugin. Consequently, an embedded servlet container is automatically started without the need of the maven plugin. During the migration process, I started thinking that it could be possible to perform the integration tests without any servlet container at all if I could migrate the tests MockMvc. From your last two examples, I understand that the problem has already been solved, at least for basic authentication and form based authentication. I guess that you would like to add support for other authentication methods such as oath, oath2, digest, and certificate in a similar fashion (my apologies if they already exists. I looked briefly in the SecurityMockMvcRequestPostProcessors and SecurityMockMvcRequestBuilders but I did not find them there).

Loading

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented May 19, 2014

Rob Winch said:

I created SEC-2601 and SEC-2602 to address the certificate and digest use cases. Please create any others you feel like are missing. NOTE: Please use the OAuth JIRA for OAuth related tickets. It can be found at https://jira.spring.io/browse/SECOAUTH

Loading

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented May 19, 2014

Rob Winch said:

Marking as invalid since extending the MockMvc is not an option for Spring Security. Please refer to the extensions and the linked JIRAs for additional extensions requested

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants