Secured users created in grails integration test are unauthorized but bootstrapped ones are - spring

I'm using Grails Spring Security Core and the Grails Spring Security REST plugin and I'm just starting to get things set up. I initialized the plugins with a User class and an Authority class (defaults) and went to write an integration test, following a guide I found on the Grails website.
It said to put the following in an integration test:
def "test a user with the role ROLE_BOSS is able to access /api/announcements url"() {
when: 'login with the sherlock'
RestBuilder rest = new RestBuilder()
def resp = rest.post("http://localhost:${serverPort}/api/login") {
accept('application/json')
contentType('application/json')
json {
username = 'sherlock'
password = 'elementary'
}
}
then:
resp.status == 200
resp.json.roles.find { it == 'ROLE_BOSS' }
}
I went ahead and did something similar and it worked with a bootstrapped User, but when I tried to do the exact same test with a User created in the test method itself, it would fail with a 401 HTTP response code.
The code I'm trying to run:
void "check get access token"() {
given:
RestBuilder rest = new RestBuilder()
new User(username: "securitySpecTestUserName", password: "securitySpecTestPassword").save(flush: true)
assert User.count == 2
when:
def resp = rest.post("http://localhost:${serverPort}/api/login") {
accept('application/json')
contentType('application/json')
json {
username = "securitySpecTestUserName"
password = "securitySpecTestPassword"
}
}
then:
resp.status == 200
}
Note that the User.count == 2 assertion passes because there is one User in Bootstrap.groovy and the one create in the test method.
Why does this work and pass with the bootstrapped User without any issues at all but not the one created in the method? Is there a way I can write this integration test so that I can test the /api/login endpoint included in the grails-spring-security-rest plugin in this way?

The User you create in the given section is in a transaction that has not been committed. When you make the REST call, the api/login controller will be run in a new transaction that cannot see your un-committed User.
A few options (there are others)...
Create User in BootStrap.groovy
def init = { servletContext ->
environments {
test {
new User(username: "securitySpecTestUserName", password: "securitySpecTestPassword").save(flush: true)
}
}
}
Make REST calls to create the User - assuming you have such functionality
Create User in setup
#Integration
#Rollback
class UserIntSpec extends Specification {
def setup() {
new User(username: "securitySpecTestUserName", password: "securitySpecTestPassword").save(flush: true)
}
void "check get access token"() {
given:
RestBuilder rest = new RestBuilder()
when:
def response = rest.post("http://localhost:${serverPort}/api/login") {
accept('application/json')
contentType('application/json')
json {
username = "securitySpecTestUserName"
password = "securitySpecTestPassword"
}
}
then:
response.status == HttpServletResponse.SC_OK
when:
def token = response.json.access_token
then:
token
}
}
Note: In Grails >= 3.0, setup() is run in a separate transaction and persisted (why it solves your problem) which is not rolled back. Any data will need to be cleaned up manually.
I suggest you read the grails documentation on testing: Integration Testing

Related

Adding body to Http request with Spock

I'm developing a Spring Boot application and I'm trying to do some authorization/authentication testing using Spock and groovyx.net.http.RESTClient. I'm trying to pass username and password inside body block like this:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class AuthorizationTest extends Specification {
#Shared
def client = new RESTClient("http://localhost:8080")
def "something should happen"() {
when:
def response = client.post(
path: "/login",
body: [ password : "1234", username : "admin"],
requestContentType: ContentType.JSON
)
then:
response.status == 200
}
Sadly, something's not working, and when I'm debugging I don't see the two parameters (username and password) inside the request.
What am I doing wrong?
It turned out I need to use different encoding, requestContentType: ContentType.URLENC, which is of type application/x-www-form-urlencoded.

Spring cloud contract load active profiles

I have a contract like:
Contract.make {
ignoreForDevEnvironment() ? ignored() : ""
description ""
request {
method 'POST'
url '/something'
body($(execute("someMethod()")))
}
response {
status 200
}
}
private static Boolean ignoreForDevEnvironment() {
//read Spring Active profiles
//return true if `dev` profile is listed
}
I want my method ignoreForDevEnvironment to read the active spring profiles, how can I achieve this?

Headers disappear in integration test on REST service

I have an integration test in my Grails 3.2.2 application that is supposed to check that CORS support is operational. When I start the application and use something like Paw or Postman to do a request, the breakpoint I have set in CorsFilter shows that my headers are set properly. But when I do the same request from an integration test using RestBuilder with the following code:
void "Test request http OPTIONS"() {
given: "JSON content request"
when: "OPTIONS are requested"
def rest = new RestBuilder()
def optionsUrl = url(path)
def resp = rest.options(optionsUrl) {
header 'Origin', 'http://localhost:4200'
header 'Access-Control-Request-Method', 'GET'
}
then: "they are returned"
resp.status == HttpStatus.SC_OK
!resp.json
}
The breakpoint in CorsFilter shows that both headers are null:
And the weird thing is that when I put a breakpoint in RestTemplate, right before the request is executed, the headers are there:
I don't get how those headers can disappear. Any idea?
I was working on this problem problem recently, and while I don't know where RestBuilder is suppressing the Origin header, I did come up with a workaround for testing that grails' CORS support is operating as configured: using HTTPBuilder instead of RestBuilder to invoke the service.
After adding org.codehaus.groovy.modules.http-builder:http-builder:0.7.1 as a testCompile dependency in build.gradle, and with grails.cors.allowedOrigins set to http://localhost, the following tests both worked as desired:
import geb.spock.GebSpec
import grails.test.mixin.integration.Integration
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.HttpResponseException
import groovyx.net.http.Method
#Integration
class ExampleSpec extends GebSpec {
def 'verify that explicit, allowed origin works'() {
when:
def http = new HTTPBuilder("http://localhost:${serverPort}/todo/1")
def result = http.request(Method.GET, "application/json") { req ->
headers.'Origin' = "http://localhost"
}
then:
result.id == 1
result.name == "task 1.1"
}
def 'verify that explicit, disallowed origin is disallowed'() {
when:
def http = new HTTPBuilder("http://localhost:${serverPort}/todo/1")
http.request(Method.GET, "application/json") { req ->
headers.'Origin' = "http://foobar.com"
}
then:
HttpResponseException e = thrown()
e.statusCode == 403
}
}
Had same problem. After some research I found out: http://hc.apache.org/, it supports sending 'Origin' and options requests.
import grails.test.mixin.integration.Integration
import grails.transaction.Rollback
import groovy.util.logging.Slf4j
import org.apache.http.client.HttpClient
import org.apache.http.client.methods.HttpOptions
import org.apache.http.impl.client.MinimalHttpClient
import org.apache.http.impl.conn.BasicHttpClientConnectionManager
import spock.lang.Specification
#Integration
#Rollback
#Slf4j
class CorsIntegrationSpec extends Specification {
def 'call with origin'() {
when:
def response = call(["Origin":"test","Content-Type":"application/json"])
then:
response != null
response.getStatusLine().getStatusCode() == 200
response.containsHeader("Access-Control-Allow-Origin")
response.containsHeader("Access-Control-Allow-Credentials")
response.containsHeader("Access-Control-Allow-Headers")
response.containsHeader("Access-Control-Allow-Methods")
response.containsHeader("Access-Control-Max-Age")
}
private call (Map<String, String> headers) {
HttpOptions httpOptions = new HttpOptions("http://localhost:${serverPort}/authz/token")
headers.each { k,v ->
httpOptions.setHeader(k,v)
}
BasicHttpClientConnectionManager manager = new BasicHttpClientConnectionManager()
HttpClient client = new MinimalHttpClient(manager)
return client.execute(httpOptions)
}
}

Grails Spring Security Rest - 403 Forbidden

So I just started learning Grails, and I am trying incorporate the Spring Security REST plugin into my app, the plugin is installed in addition to spring security core which is working. In my REST client, when I hit "api/login" I am able to get an access token and it says I have the role of "ROLE_ADMIN", but then when I try to hit something using that, I keep getting a 403 Forbidden. In Postman, the REST client I am using, I have my Authorization header with "Bearer {key}", with my url of "http://localhost:8080/test/api/secret" and it gives the 403 error. I am trying to setup the log4j logging to see any other issues, but does anyone know what I should look into, any help would be appreciated. I provided my classes below if that helps, I generally used default values for everything such as the UrlMappings.
RandomController.groovy
package test
import grails.plugin.springsecurity.annotation.Secured
#Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
class MyController {
#Secured(['ROLE_ADMIN'])
def secret() {
render "You have ACCESS!!!"
}
}
Bootstrap.groovy
class BootStrap {
def init = { servletContext ->
def adminRole = new SecRole(authority: 'ROLE_ADMIN').save(flush: true)
def testUser = new SecUser(username: 'bob', password: 'test')
testUser.save(flush: true)
SecUserSecRole.create testUser, adminRole, true
}
def destroy = {
}
}
UrlMappings.groovy
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?(.$format)?"{
constraints {
// apply constraints here
}
}
"/api/$controller/$action?/$id?(.$format)?"{ constraints { // apply constraints here
} }
"/"(view:"/index")
"500"(view:'/error')
}
}
For what I can see from the code you posted, if you invoke url http://localhost:8080/test/api/secret, it should execute default action (maybe index) in SecretController but the controller you posted is called MyController.
To investigate further, you should enable more verbose logging using log4j configuration as suggested in the doc http://alvarosanchez.github.io/grails-spring-security-rest/1.5.1/docs/guide/debugging.html

Grails session attributes are not flushed between two applications

I have two separate Grails applications that use the JASIG CAS Client Plugin. When my applications run, different users can authenticate against my CAS server (using the client plugin).
Authentication aside, I use a Grails Filter for authorization in both applications. A user may be authenticated, but I want to make sure that only certain users can only access the appropriate application.
Everything works, except for the below scenario:
I successfully authenticate against the CAS server with username "jack" and I am authorized to use Application A.
I close Application A and sign out of CAS.
I successfully authenticate against the CAS server with username "jill", but I am not authorized to use the Application B because the username from the session is still "jack"
Do I need to flush the session at any point when my applications initiate? If so, how can I do that? Here is the code for my Filter:
import edu.yale.its.tp.cas.client.filter.CASFilter
class SecurityFilters {
def filters = {
loginCheck(controller: '*', action: '*') {
before = {
def username = session?.getAttribute(CASFilter.CAS_FILTER_USER)?.toLowerCase()
if (username in grailsApplication.config.users) {
return true
} else {
render view: '/invalid_user', model: [username: username]
return false
}
}
}
}
}

Resources