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)
}
}
Related
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.
After upgrading grails 2.5.2 to 3.3.11, I am getting Method Not Allowed response while hitting POST request. The GET method works fine.
Controller:
package omapi
import grails.rest.RestfulController
import org.springframework.http.HttpStatus
import static org.springframework.http.HttpStatus.NOT_FOUND
import static org.springframework.http.HttpStatus.NO_CONTENT
class PhaseController extends RestfulController {
PhaseController(){
super(Phase)
}
static responseFormats = ['json', 'xml']
static allowedMethods = [show: 'GET', index:'GET',productAcronym:'GET', phaseByName: 'GET',save:'POST',update:'PUT',delete:'DELETE', deleteGroup: 'DELETE', deletePhase: 'DELETE']
def phaseService
def index(){
def phases = phaseService.getAllPhases()
respond phases
}
def show(){
def phase = phaseService.getPhaseById(params.id)
respond phase
}
def phaseByName(){
def phase = phaseService.getPhaseByName(params?.name)
respond phase
}
def productAcronym() {
def phase = phaseService.getPhaseByProductAcronym(params?.acronym)
log.info("==== phase by product Acronym =====$params.acronym==");
respond phase;
}
}
URL Mapping:
package omapi
import grails.core.GrailsApplication
import java.nio.file.AccessDeniedException
class UrlMappings {
static mappings = {
"/applications/$id/processingGroup"(controller: "application",action: "processingGroup")
"/accounts/$id/applications/"(controller: "accounts", action: "applications")
"/accounts/$aId/application/$id/products/"(controller: "application", action: "products")
"/ftpServer/connection"(controller: 'ftpServer', action: 'testConnection')
"/application/$id/jobs/"(controller: "job",action: "jobByApplication")
"/application/cycleDates"(controller: "cycleDates",action: "getCycleDatesByApplication")
"/ProcessingBranch/branch/"(controller: "processingTicketBranch",action: "branch")
"/application/$appCode/Offset"(controller: "ReportClientOffset",action: "offsetValue")
"/$controller/$action?/$id?(.$format)?"{
constraints {
// apply constraints here
}
}
"/$controller/$id"(parseRequest: true){
action = [GET:"show",PUT:"update",POST:"404",DELETE:"delete"]
constraints {
id matches: /\d+/
}
}
"/$controller"{
action = [GET:"index",POST: "save",PUT:"update",DELETE:"delete"]
constraints {
}
}
"/"(view:"/index")
"403"(controller: "error", action: "error403")
"404"(controller: "error", action: "error404")
"409"(controller: "error", action: "error409")
"500"(controller: "error", action: "error500")
"500"(controller: "error", action: "error403", exception: AccessDeniedException)
}
}
Request: [POST] localhost:5555/OMApi/phase
Response:
{
"timestamp": 1594295030496,
"status": 405,
"error": "Method Not Allowed",
"message": "No message available",
"path": "/OMApi/phase"
}
For grails 2.5.2, everything works fine. It looks like a Spring related issue. All the searches on this matter provided no results. Any idea? Is it due to some error in UrlMapping or other problems like CORS Interceptor not working?
After upgrading grails 2.5.2 to 3.3.11, I am getting Method Not
Allowed response while hitting POST request. The GET method works
fine.
It looks like you have /OMApi/phase mapped to the index action in PhaseController which is configured with index: 'GET' in allowedMethods which means the index action is only accessible via a 'GET' request. Any other verb should result in a 405 for that action. If you want to allow both GET and POST for the index action (unclear why you want to do that) then change your allowedMethods to include index: ['GET', 'POST'] instead of index: 'GET'.
I hope that helps.
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
I am new to spark and scala. I am trying to run an example given in google. I am encounting following exception when running this program.
Exception is:
17/05/25 11:13:42 ERROR ReceiverTracker: Deregistered receiver for stream 0: Restarting receiver with delay 2000ms: Error starting Twitter stream - java.lang.IllegalStateException: Authentication credentials are missing.
Code that I am executing is as follows:
PrintTweets.scala
package example
import org.apache.spark._
import org.apache.spark.SparkContext._
import org.apache.spark.streaming._
import org.apache.spark.streaming.twitter._
import org.apache.spark.streaming.StreamingContext._
import org.apache.log4j.Level
import Utilities._
object PrintTweets {
def main(args: Array[String]) {
// Configure Twitter credentials using twitter.txt
setupTwitter()
val appName = "TwitterData"
val conf = new SparkConf()
conf.setAppName(appName).setMaster("local[3]")
val ssc = new StreamingContext(conf, Seconds(5))
//val ssc = new StreamingContext("local[*]", "PrintTweets", Seconds(10))
setupLogging()
// Create a DStream from Twitter using our streaming context
val tweets = TwitterUtils.createStream(ssc, None)
// Now extract the text of each status update into RDD's using map()
val statuses = tweets.map(status => status.getText())
statuses.print()
ssc.start()
ssc.awaitTermination()
}
}
Utilities.scala
package example
import org.apache.log4j.Level
import java.util.regex.Pattern
import java.util.regex.Matcher
object Utilities {
/** Makes sure only ERROR messages get logged to avoid log spam. */
def setupLogging() = {
import org.apache.log4j.{Level, Logger}
val rootLogger = Logger.getRootLogger()
rootLogger.setLevel(Level.ERROR)
}
/** Configures Twitter service credentials using twiter.txt in the main workspace directory */
def setupTwitter() = {
import scala.io.Source
for (line <- Source.fromFile("../twitter.txt").getLines) {
val fields = line.split(" ")
if (fields.length == 2) {
System.setProperty("twitter4j.oauth." + fields(0), fields(1))
}
}
}
/** Retrieves a regex Pattern for parsing Apache access logs. */
def apacheLogPattern():Pattern = {
val ddd = "\\d{1,3}"
val ip = s"($ddd\\.$ddd\\.$ddd\\.$ddd)?"
val client = "(\\S+)"
val user = "(\\S+)"
val dateTime = "(\\[.+?\\])"
val request = "\"(.*?)\""
val status = "(\\d{3})"
val bytes = "(\\S+)"
val referer = "\"(.*?)\""
val agent = "\"(.*?)\""
val regex = s"$ip $client $user $dateTime $request $status $bytes $referer $agent"
Pattern.compile(regex)
}
}
When I check using print statments I find the exception is happening at line
val tweets = TwitterUtils.createStream(ssc, None)
I am giving credentials in twitter.txt file which is read properly by program. When I don't place twitter.txt in appropriate directory it shows explicit error, It shows explicit error unauthorized access when I give blank keys for customer key and secret etc in twitter.txt
If you need more details about error related information or versions of software let me know.
Thanks,
Madhu.
I could reproduce the issue with your code. I believe its your problem.
You might have not configured twitter.txt properly. Your twitter.txt file should be like this ->
consumerKey your_consumerKey
consumerSecret your_consumerSecret
accessToken your_accessToken
accessTokenSecret your_accessTokenSecret
I hope it helps.
After changing twitter.txt file syntax to following , single space between key and value it worked
consumerKey your_consumerKey
consumerSecret your_consumerSecret
accessToken your_accessToken
accessTokenSecret your_accessTokenSecret
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