-
-
Save mrbusche/6854a48889eee034331c08dfe6772459 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment