Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions core/src/main/kotlin/org/evomaster/core/output/auth/AuthWriter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package org.evomaster.core.output.auth

import org.evomaster.core.output.Lines
import org.evomaster.core.output.OutputFormat
import org.evomaster.core.output.service.HttpWsTestCaseWriter
import org.evomaster.core.problem.httpws.auth.CallToEndpoint
import org.evomaster.core.problem.rest.data.ContentType

object AuthWriter {

/**
* Add lines related to make the call (eg setup of body payload), without the opening function (eg, 'given()' for
* RestAssured).
* Python is treated specially, as before the opening function we need to setup some variables.
* The opening function is then added here in this function.
*
* @param lines Current lines buffer
* @param k The endpoint to call
* @param targetVariable Only used for languages like Python. If present, in the generated code the result of call
* is saved to this variable.
*/
fun addBodyOfCallCommand(
lines: Lines,
k: CallToEndpoint,
testCaseWriter: HttpWsTestCaseWriter,
format: OutputFormat,
baseUrlOfSut: String,
targetVariable: String?
) {

if(format.isJavaScript()) {
callEndpoint(lines, k, format, baseUrlOfSut)
}

if(format.isPython()) {
lines.add("headers = {}")
}

val contentType = k.contentType
if(contentType != null) {
when {
format.isJavaOrKotlin() -> lines.add(".contentType(\"${contentType.defaultValue}\")")
format.isJavaScript() -> lines.add(".set(\"content-type\", \"${contentType.defaultValue}\")")
format.isPython() -> {
lines.add("headers[\"content-type\"] = \"${contentType.defaultValue}\"")
}
}

when (contentType) {
ContentType.X_WWW_FORM_URLENCODED -> {
val send = testCaseWriter.sendBodyCommand()
when {
format.isPython() -> lines.add("body = \"${k.payload}\"")
else -> lines.add(".$send(\"${k.payload}\")")
}
}

ContentType.JSON -> {
testCaseWriter.printSendJsonBody(k.payload!!, lines)
}

else -> {
throw IllegalStateException("Currently not supporting yet ${k.contentType} in login")
}
}
}

for(header in k.headers) {
when {
format.isJavaOrKotlin() -> lines.add(".header(\"${header.name}\", \"${header.value}\")")
format.isJavaScript() -> lines.add(".set(\"${header.name}\", \"${header.value}\")")
format.isPython() -> {
lines.add("headers[\"${header.name}\"] = \"${header.value}\"")
}
}
}

if (format.isJavaScript()){
// disable redirections
lines.add(".redirects(0)")
}

/*
For RestAssure, the call to "post" must be last, which is in opposite of what
needed in used libraries for Python and JS
*/
if(format.isJavaOrKotlin()) {
callEndpoint(lines, k, format, baseUrlOfSut)
}

if (format.isPython()) {
if(targetVariable != null){
lines.add("$targetVariable = requests \\")
} else {
lines.add("requests \\")
}
lines.indent(2)
callEndpoint(lines, k, format, baseUrlOfSut)
lines.append(", ")
lines.indented {
lines.add("headers=headers, data=body, allow_redirects=False, verify=False)")
}
lines.deindent(2)
}
}

private fun callEndpoint(
lines: Lines,
k: CallToEndpoint,
format: OutputFormat,
baseUrlOfSut: String
) {
val verb = k.verb.name.lowercase()
lines.add(".$verb(")
if (k.externalEndpointURL != null) {
lines.append("\"${k.externalEndpointURL}\"")
} else {
when {
format.isJava() || format.isJavaScript() -> lines.append("$baseUrlOfSut + \"")
format.isPython() -> lines.append("self.$baseUrlOfSut + \"")
else -> lines.append("\"\${$baseUrlOfSut}")
}
lines.append("${k.endpoint}\"")
}
if (!format.isPython()) {
lines.append(")")
}
}
}
109 changes: 1 addition & 108 deletions core/src/main/kotlin/org/evomaster/core/output/auth/CookieWriter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import org.evomaster.core.output.TestWriterUtils
import org.evomaster.core.output.service.HttpWsTestCaseWriter
import org.evomaster.core.problem.httpws.HttpWsAction
import org.evomaster.core.problem.httpws.auth.EndpointCallLogin
import org.evomaster.core.problem.rest.data.ContentType
import org.evomaster.core.search.EvaluatedIndividual
import org.evomaster.core.search.Individual

Expand Down Expand Up @@ -69,7 +68,7 @@ object CookieWriter {
else -> cookiesName(k)
}

addCallCommand(lines, k, testCaseWriter, format, baseUrlOfSut, targetCookieVariable)
AuthWriter.addBodyOfCallCommand(lines, k.call, testCaseWriter, format, baseUrlOfSut, targetCookieVariable)

when {
format.isJavaOrKotlin() -> lines.add(".then().extract().cookies()")
Expand Down Expand Up @@ -98,110 +97,4 @@ object CookieWriter {
}
}
}



fun addCallCommand(
lines: Lines,
k: EndpointCallLogin,
testCaseWriter: HttpWsTestCaseWriter,
format: OutputFormat,
baseUrlOfSut: String,
targetVariable: String
) {

if(format.isJavaScript()) {
callEndpoint(lines, k, format, baseUrlOfSut)
}

if(format.isPython()) {
lines.add("headers = {}")
}

val contentType = k.contentType
if(contentType != null) {
when {
format.isJavaOrKotlin() -> lines.add(".contentType(\"${contentType.defaultValue}\")")
format.isJavaScript() -> lines.add(".set(\"content-type\", \"${contentType.defaultValue}\")")
format.isPython() -> {
lines.add("headers[\"content-type\"] = \"${contentType.defaultValue}\"")
}
}

when (contentType) {
ContentType.X_WWW_FORM_URLENCODED -> {
val send = testCaseWriter.sendBodyCommand()
when {
format.isPython() -> lines.add("body = \"${k.payload}\"")
else -> lines.add(".$send(\"${k.payload}\")")
}
}

ContentType.JSON -> {
testCaseWriter.printSendJsonBody(k.payload!!, lines)
}

else -> {
throw IllegalStateException("Currently not supporting yet ${k.contentType} in login")
}
}
}

for(header in k.headers) {
when {
format.isJavaOrKotlin() -> lines.add(".header(\"${header.name}\", \"${header.value}\")")
format.isJavaScript() -> lines.add(".set(\"${header.name}\", \"${header.value}\")")
format.isPython() -> {
lines.add("headers[\"${header.name}\"] = \"${header.value}\"")
}
}
}

if (format.isJavaScript()){
// disable redirections
lines.add(".redirects(0)")
}

/*
For RestAssure, the call to "post" must be last, which is in opposite of what
needed in used libraries for Python and JS
*/
if(format.isJavaOrKotlin()) {
callEndpoint(lines, k, format, baseUrlOfSut)
}

if (format.isPython()) {
lines.add("$targetVariable = requests \\")
lines.indent(2)
callEndpoint(lines, k, format, baseUrlOfSut)
lines.append(", ")
lines.indented {
lines.add("headers=headers, data=body, allow_redirects=False, verify=False)")
}
lines.deindent(2)
}
}

private fun callEndpoint(
lines: Lines,
k: EndpointCallLogin,
format: OutputFormat,
baseUrlOfSut: String
) {
val verb = k.verb.name.lowercase()
lines.add(".$verb(")
if (k.externalEndpointURL != null) {
lines.append("\"${k.externalEndpointURL}\"")
} else {
when {
format.isJava() || format.isJavaScript() -> lines.append("$baseUrlOfSut + \"")
format.isPython() -> lines.append("self.$baseUrlOfSut + \"")
else -> lines.append("\"\${$baseUrlOfSut}")
}
lines.append("${k.endpoint}\"")
}
if (!format.isPython()) {
lines.append(")")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ object TokenWriter {
lines.indent(2)
}

CookieWriter.addCallCommand(lines,k,testCaseWriter,format,baseUrlOfSut, responseName(k))
AuthWriter.addBodyOfCallCommand(lines,k.call,testCaseWriter,format,baseUrlOfSut, responseName(k))

var path = token.extractSelector.substring(1).replace("/",".")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ object AuthUtils {
}
val data = tl.token ?: throw IllegalArgumentException("Token based login requires token definition")

val response = makeCall(client, tl, baseUrl)
val response = makeCall(client, tl.name, tl.call, baseUrl)
?: continue

var token = when(data.extractFrom){
Expand Down Expand Up @@ -113,7 +113,7 @@ object AuthUtils {
}


val response = makeCall(client, cl, baseUrl)
val response = makeCall(client, cl.name, cl.call, baseUrl)
?: continue
response.close()

Expand All @@ -130,7 +130,7 @@ object AuthUtils {



private fun makeCall(client: Client, x: EndpointCallLogin, baseUrl: String) : Response?{
private fun makeCall(client: Client, name: String, x: CallToEndpoint, baseUrl: String) : Response?{

val mediaType = when (x.contentType) {
ContentType.X_WWW_FORM_URLENCODED -> MediaType.APPLICATION_FORM_URLENCODED_TYPE
Expand Down Expand Up @@ -171,7 +171,7 @@ object AuthUtils {
val response = try {
invocation.invoke()
} catch (e: Exception) {
log.warn("Failed to login for ${x.name}: $e")
log.warn("Failed to login for ${name}: $e")
return null
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.evomaster.core.problem.httpws.auth

import org.evomaster.core.Lazy
import org.evomaster.core.problem.rest.data.ContentType
import org.evomaster.core.problem.rest.data.HttpVerb
import java.net.MalformedURLException
import java.net.URL

class CallToEndpoint(
/**
* The endpoint path (eg "/v1/api/data") where to execute the call.
* It assumes it is on same server of API.
* If not, rather use externalEndpointURL
*/
val endpoint: String?,

/**
* If the endpoint is on a different server, here can rather specify the full URL for it.
*/
val externalEndpointURL: String?,

/**
* The raw payload to send, as a string, if any
*/
val payload: String?,


val headers: List<AuthenticationHeader>,

/**
* The verb used to make the call to the endpoint.
* Most of the time, for auth this will be a POST.
*/
val verb: HttpVerb,

/**
* Specify the format in which the payload is sent to the endpoint.
* A common example is "application/json"
*/
val contentType: ContentType?,
) {

init{
if (endpoint == null && externalEndpointURL == null) {
throw IllegalArgumentException("Either 'endpoint' or 'externalEndpointURL' should be specified")
}
if (endpoint != null && externalEndpointURL != null) {
throw IllegalArgumentException("Cannot have both 'endpoint' and 'externalEndpointURL' specified. It is ambiguous.")
}
if (endpoint != null && !endpoint.startsWith("/")) {
throw IllegalArgumentException(
"Endpoint definition must start with a /. It is not a full URL." +
" For example: '/login'"
)
}
if (externalEndpointURL != null) {
try {
//FIXME should not use URL for validation, as Java URL is not standard compliant
URL(externalEndpointURL)
} catch (e: MalformedURLException) {
throw IllegalArgumentException("'externalEndpointURL' is not a valid URL: ${e.message}")
}
}
if( (payload != null && contentType==null) || (payload==null && contentType!=null)) {
throw IllegalArgumentException("Payload and contentType must be both specified, or none specified")
}
}


fun getUrl(baseUrl: String): String {
val s = baseUrl.trim()
if (externalEndpointURL != null) return externalEndpointURL

if (!s.startsWith("http://", true) && !s.startsWith("https://")) {
throw IllegalArgumentException("baseUrl should use HTTP(S): $baseUrl")
}
Lazy.assert { endpoint != null && endpoint.startsWith("/") }
return if (s.endsWith("/")) {
s.substring(0, s.length - 1) + endpoint
} else {
s + endpoint
}
}
}
Loading
Loading