Created
September 6, 2017 16:33
-
-
Save jeffsheets/44a60c5956648323b97064ffe15fa8ff to your computer and use it in GitHub Desktop.
Spock Test for Spring Boot Security configuration - showing basic simple examples for unauthenticated users, role based access, and httpBasic logins
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@EnableWebSecurity | |
class ApiSecurityConfig extends WebSecurityConfigurerAdapter { | |
@Inject | |
void configureGlobal(AuthenticationManagerBuilder auth) { | |
auth.inMemoryAuthentication() | |
.withUser('svc_acct').password('somePassword').roles('FULL_ACCESS') | |
} | |
@Override | |
protected void configure(HttpSecurity http) { | |
//Enable Basic authentication via http headers | |
http.httpBasic() | |
//Allow unauthenticated GET requests | |
http.authorizeRequests() | |
.antMatchers(HttpMethod.GET).permitAll() | |
//Everything else is secured with a login | |
.and().authorizeRequests() | |
.antMatchers('/**').hasRole('FULL_ACCESS') | |
http.csrf().disable() | |
} | |
} | |
import org.springframework.context.annotation.Profile | |
import org.springframework.http.HttpMethod | |
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder | |
import org.springframework.security.config.annotation.web.builders.HttpSecurity | |
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity | |
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter | |
import javax.inject.Inject |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@ContextConfiguration(classes = [SecurityTestController, ApiSecurityConfig]) | |
@WebAppConfiguration | |
class ApiSecurityConfigSpec extends Specification { | |
@Autowired | |
WebApplicationContext context | |
MockMvc mvc | |
void setup() { | |
mvc = webAppContextSetup(context).apply(springSecurity()).build() | |
} | |
def 'GET is accessible without login'() { | |
when: | |
def response = mvc.perform(get('/securityTest/')).andReturn().response | |
then: | |
response.status == OK.value() | |
} | |
@Unroll | |
def '#method throws error without login'(HttpMethod method) { | |
when: 'request tried without login' | |
def response = mvc.perform(request(method, '/securityTest/')).andReturn().response | |
then: 'it fails' | |
response.status == UNAUTHORIZED.value() | |
where: | |
method << [POST, PUT, PATCH, DELETE] | |
} | |
@WithMockUser(roles = ['FULL_ACCESS']) | |
@Unroll | |
def '#method works when logged in for user with FULL_ACCESS'(HttpMethod method) { | |
when: | |
def response = mvc.perform(request(method, '/securityTest/')).andReturn().response | |
then: | |
response.status == OK.value() | |
where: | |
method << [POST, PUT, PATCH, DELETE] | |
} | |
def 'Login works with the system account'() { | |
given: | |
String user = 'svc_acct' | |
String pass = 'somePassword' | |
when: | |
def response = mvc.perform(post('/securityTest/').with(httpBasic(user, pass))).andReturn().response | |
then: | |
response.status == OK.value() | |
} | |
def 'Login fails with bad account info'() { | |
given: | |
String user = 'svc_acct' | |
String pass = 'ThisIsNotCorrect' | |
when: | |
def response = mvc.perform(post('/securityTest/').with(httpBasic(user, pass))).andReturn().response | |
then: | |
response.status == UNAUTHORIZED.value() | |
} | |
@RestController | |
@RequestMapping(value = '/securityTest', produces = MediaType.APPLICATION_JSON_VALUE) | |
static class SecurityTestController { | |
@GetMapping('/') | |
ResponseEntity<String> get() { | |
ok('Saul Goodman') | |
} | |
@PostMapping('/') | |
ResponseEntity post() { | |
ok('Saul Goodman') | |
} | |
@PutMapping('/') | |
ResponseEntity put() { | |
ok('Saul Goodman') | |
} | |
@PatchMapping('/') | |
ResponseEntity patch() { | |
ok('Saul Goodman') | |
} | |
@DeleteMapping('/') | |
ResponseEntity delete() { | |
ok('Saul Goodman') | |
} | |
} | |
} | |
//Yeah, imports at the bottom look weird but they work and make the gist look cleaner... | |
import org.springframework.beans.factory.annotation.Autowired | |
import org.springframework.http.HttpMethod | |
import org.springframework.http.MediaType | |
import org.springframework.http.ResponseEntity | |
import org.springframework.security.test.context.support.WithMockUser | |
import org.springframework.test.context.ContextConfiguration | |
import org.springframework.test.context.web.WebAppConfiguration | |
import org.springframework.test.web.servlet.MockMvc | |
import org.springframework.web.bind.annotation.* | |
import org.springframework.web.context.WebApplicationContext | |
import spock.lang.Specification | |
import spock.lang.Unroll | |
import static org.springframework.http.HttpMethod.* | |
import static org.springframework.http.HttpStatus.OK | |
import static org.springframework.http.HttpStatus.UNAUTHORIZED | |
import static org.springframework.http.ResponseEntity.ok | |
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic | |
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity | |
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.* | |
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup |
@thanhphamduy I'm not sure exactly, but I'm guessing that the WebApplicationContext context
did not autowire correctly. I just ran these tests again locally and they appear fine for me. Can you provide a full stacktrace? (also, sorry but github doesn't give notifications on gist comments, so I didn't see this until now. ping me on twitter @Sheetsj if you are still stuck too)
hi everyone, the same problem on my side. Have you investigated any solution?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi Jeff, thank you for your helpful example,
I followed it but got an issue java.lang.IllegalArgumentException: WebApplicationContext is required
Could you please share with me some ideas about that?
Regards