Spring Security: Integrate In-Memory Authentication for Test Automation


Use Case
To automate test of our web services apis, we need add test users in test environments.

The Solution
We configure Spring Security AuthenticationManager: first add  in-memory DaoAuthenticationProvider in test environments then add other authentication providers.

The legacy code uses xml to configure authenticationManager and intercept-url rules, so I create org.springframework.security.authenticationManager bean. If you are using pure java config, please check Spring Security Java Config.
@Configuration
public class WebSecurityConfiguration {
    private static final String[] ENV_SUPPORT_TEST_USER = {PROFILE_LOCAL, PROFILE_XX};

    @Autowired
    private Environment environment;

    @Bean(name = "org.springframework.security.authenticationManager")
    public AuthenticationManager authenticationManager() {
        final List providers = new ArrayList<>();

        final String env = System.getProperty("env");
        if (StringUtils.isBlank(env)) {
            throw new BusinessException(ErrorCode.INTERNAL_ERROR, "env is empty");
        }
        // The order matters: don't change the order - it will first try to use the test user
        // if not succeed then use ldap
        // add test user for local, q1, e1 only
        if (ArrayUtils.contains(ENV_SUPPORT_TEST_USER, env)) {
            addTestUserAuthProvider(providers);
        }

        if (PROFILE_LOCAL.equals(env) || PROFILE_DOCKER.equals(env)) {
            addLdapProviderForLocal(providers);
        } else {
            // application is deployed to aws, use different LdapAuthenticationProvider
            addLdapProviderForAwsEnv(providers);
        }

        final AuthenticationManager authenticationManager = new ProviderManager(providers);
        return authenticationManager;
    }

    protected void addTestUserAuthProvider(final List providers) {
        final DaoAuthenticationProvider testUserAuthProvider = new DaoAuthenticationProvider();
        final Collection users = new ArrayList<>();
        // add admin user
        UserDetails user = new User(environment.getProperty("spring.security.test.user.adminOnly.name"),
                environment.getProperty("spring.security.test.user.adminOnly.password"),
                Lists.newArrayList(new SimpleGrantedAuthority(environment.getProperty("spring.security.adminGroup"))));
        users.add(user);
        // add provisioner
        user = new User(environment.getProperty("spring.security.test.user.provisionerOnly.name"),
                environment.getProperty("spring.security.test.user.provisionerOnly.password"), Lists.newArrayList(
                        new SimpleGrantedAuthority(environment.getProperty("spring.security.provisionGroup"))));
        users.add(user);

        // add user with admin and provisioner
        user = new User(environment.getProperty("spring.security.test.user.adminProvisioner.name"),
                environment.getProperty("spring.security.test.user.adminProvisioner.password"),
                Lists.newArrayList(new SimpleGrantedAuthority(environment.getProperty("spring.security.adminGroup")),
                        new SimpleGrantedAuthority(environment.getProperty("spring.security.provisionGroup"))));
        users.add(user);

        final UserDetailsService userDetailsService = new InMemoryUserDetailsManager(users);
        testUserAuthProvider.setUserDetailsService(userDetailsService);

        providers.add(testUserAuthProvider);
    }
}

Testing with Rest-Assured
Now we can use Rest-Assured to login and capture the session and reuse it in subsequent requests.
RestAssured.reset();
RestAssured.baseURI = baseURI;
RestAssured.basePath = basePath;
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
RestAssured.config = config().logConfig(new LogConfig());
RestAssured.useRelaxedHTTPSValidation();

final SessionFilter sessionFilter = new SessionFilter();
given().auth()
.form(user, passwd,
        new FormAuthConfig("/j_spring_security_check", "j_username", "j_password"))
.filter(sessionFilter).expect().statusCode(200).when().get("/api");

// later...
given().filter(sessionFilter).contentType(ContentType.JSON).when().delete(productUrl).then()
        .statusCode(200);

Labels

adsense (5) Algorithm (69) Algorithm Series (35) Android (7) ANT (6) bat (8) Big Data (7) Blogger (14) Bugs (6) Cache (5) Chrome (19) Code Example (29) Code Quality (7) Coding Skills (5) Database (7) Debug (16) Design (5) Dev Tips (63) Eclipse (32) Git (5) Google (33) Guava (7) How to (9) Http Client (8) IDE (7) Interview (88) J2EE (13) J2SE (49) Java (186) JavaScript (27) JSON (7) Learning code (9) Lesson Learned (6) Linux (26) Lucene-Solr (112) Mac (10) Maven (8) Network (9) Nutch2 (18) Performance (9) PowerShell (11) Problem Solving (11) Programmer Skills (6) regex (5) Scala (6) Security (9) Soft Skills (38) Spring (22) System Design (11) Testing (7) Text Mining (14) Tips (17) Tools (24) Troubleshooting (29) UIMA (9) Web Development (19) Windows (21) xml (5)