Skip to content
Snippets Groups Projects
Commit e846dafa authored by Jueun Park's avatar Jueun Park
Browse files

Update

parent 51d5ee1a
No related branches found
No related tags found
No related merge requests found
Pipeline #11548 passed with warnings
\section{OpenAPI Specification}
\section{OpenAPI Specification} \label{sec:openapi}
%General
Nowadays, there is a way to document REST APIs which allows both humans and computers to understand the whole structure of a RESTful web service and is globally used. It is called OpenAPI or also known as Swagger (older than 3.0.0 version). \\
An OpenAPI document with its specification is written in a structured JSON or YAML and describes which API operations are available, what kind of details they have, how to reach them using a URI, what parameters and request bodies are required and optional in available operations and what authentication schema is. \\
OpenAPI specification does not hold on strict definitions and has a tree-shaped structure, which facilitates to use and extend in more than 25 programming languages, while JSON schema is available in them. An example of an OpenAPI document is shown in Listing 2.1.
OpenAPI specification does not hold on strict definitions and has a tree-shaped structure, which facilitates to use and extend in more than 25 programming languages, while JSON schema is available in them. An example of an OpenAPI document is shown in Listing~\ref{lst:openapi}.
%Testing OpenAPI (Black-Box)
This specification is relevant to automated testing of REST APIs, because it enables black-box testing. There are already many interesting approaches \cite{atlidakis2019restler}, \cite{ed2018automatic}, \cite{karlsson2020quickrest}, \cite{martin2020restest}, \cite{viglianisi2020resttestgen}, more concrete explanations to separate approaches are in \cref{ch:curr-appr}. \\
Black-box testing needs the specification of the REST API (in our case, OpenAPI specification) and generates test cases automatically. OpenAPI specifications are defined semi-formal, so test generations could generate unrealistic or invalid inputs. Nonetheleoss it is a meaningful way to test APIs automatically, because it does not require access to the source code and is available for every API regardless of in which programming language it is implemented or whether it is locally or remotely deployed \cite{arcuri2019restful}. \\
\begin{lstlisting}[style=unboxed, caption={Example OpenAPI}]
\begin{lstlisting}[style=unboxed, caption={Example OpenAPI}, label={lst:openapi}]
{
"openapi" : "3.0.0",
"info" : {
......
......@@ -16,7 +16,7 @@ This situation leads to problems in terms complexity of analysis and extension.
%RAG
In 2000 Hedin has proposed RAG as an object-oriented extension of AG to solve these problems \cite{hedin2000reference}.
This approach enables the references of attributes as a node in an AST and every property of structured attributes (i.e. sets, dictionaries, lists) can also be references. \\
If there is a reference attribute stored in an AST, it represents a direct connection from an any node that is freely distant (non-local) and to itself. The value of the referred node is directly usable in the referring node without accessing any other nodes in the AST. An example of an AST in RAG compared to a traditional AST without RAG is shown in Figure 2.1. \\
If there is a reference attribute stored in an AST, it represents a direct connection from an any node that is freely distant (non-local) and to itself. The value of the referred node is directly usable in the referring node without accessing any other nodes in the AST. An example of an AST in RAG compared to a traditional AST without RAG is shown in \Cref{fig:ast}. \\
Such features of RAG represent advantages over AG, largely in efficiency. It is not necessary to duplicate a same value of a node to another node and semantic functions in a complex data structure can be split into smaller functions which are completely describable in RAG. Consequently, RAG can extend existing grammars and give them more functionalities.
\begin{figure}
......@@ -27,8 +27,8 @@ Such features of RAG represent advantages over AG, largely in efficiency. It is
%JastAdd
An extensible system producing language-based compilers and tools is called, JastAdd. It enables to generate modules and tools based on RAG, where properties of AST to be programmed declaratively. There are already several tools implemented and extended with JastAdd (e.g. ExtendJ, JModelica.org, abc, Soot, McLab, Palacom, etc.\footnote{\url{https://jastadd.cs.lth.se/web/applications.php}}) \\
Generally, JastAdd needs two input data to generate classes written in Java. One input data is a file in ast file where AST nodes are described. With this input a class for every non-terminal node is generated and constructed using defined attributes. Other input data is one of more declarative definitions of corresponding attributes and methods. A graphical model of JastAdd is described in Figure 2.2\\
Examples are in Listing 2.2 and 2.3 implementing basic arithmetic operations. Listing 2.2 shows how separate AST nodes can be defined in RAG and Listing 2.3 explains a case of how attributes can be implemented, especially synthesized attributes by eq (equation). \\ \\
Generally, JastAdd needs two input data to generate classes written in Java. One input data is a file in ast file where AST nodes are described. With this input a class for every non-terminal node is generated and constructed using defined attributes. Other input data is one of more declarative definitions of corresponding attributes and methods. A graphical model of JastAdd is described in \Cref{fig:jastadd}.\\
Examples are in Listing~\ref{lst:example-ast} and Listing~\ref{lst:example-attributes} implementing basic arithmetic operations. Listing~\ref{lst:example-ast} shows how separate AST nodes can be defined in RAG and Listing~\ref{lst:example-attributes} explains a case of how attributes can be implemented, especially synthesized attributes by eq (equation). \\ \\
\begin{lstlisting}[language=AST,label={lst:example-ast},caption={Example of an AST}]
Root ::= Def* Exp ;
......
\chapter{RAGO API}\label{ch:rago}
In this section, we propose RAGO API (temporary name, Test with Reference Attribute Grammar in OpenAPI), the first REST API fuzzing framework modeled by RAG (JastAdd). RAGO API parses the OpenAPI specification in Java to transfer it into a RAG and generates test cases (requests) that automatically send requests to test the target API.
In this section, we propose RAGO API, the first REST API fuzzing framework modeled in RAG (JastAdd). RAGO API parses the OpenAPI specification in Java to transfer it into a RAG and generates test cases (requests) that automatically send requests to test the target API.
% Generation
Requests in RAGO API are generated in two basic fuzzing methods. Firstly, generating requests with random values. Secondly, inferring dependencies between two operations by schemas (i.e. a value of an object returned by a response could be usable as a value in an input parameter).
Requests of RAGO API are generated in two basic fuzzing methods. Firstly, generating requests with random values. Secondly, inferring parameters available in responses (i.e. an object returned by a response could be usable as a value in an input parameter).
\input{sections/ragoGram}
\input{sections/ragoProcess}
......
\section{Grammar}
As mentioned in section 2.3, OpenAPI specifications are written in structured JSON or YAML and do not hold on strict definitions (i.e. programming language-agnostic). It means that specifications can be described and implemented in any programming language or grammar, which also applies to RAG.
As mentioned in \Cref{sec:openapi}, OpenAPI specifications are written in structured JSON or YAML and do not hold on strict definitions (i.e. programming language-agnostic). It means that specifications can be described and implemented in any programming language or grammar, which also applies to RAG.
% AST
To use OpenAPI in RAG, it is firstly necessary to rewrite the OpenAPI structure in an AST. We have constructed this AST in 95 AST-nodes to define 30 objects. The version of OpenAPI considered in this framework is 3.0.1. To have a better overview, the definition of Parameter Object in our AST is shown in Listing 4.1 and can be compared with the definition in the OpenAPI official GitHub$^{1}$.
To use OpenAPI in RAG, it is firstly necessary to rewrite the OpenAPI structure in an AST. We have constructed this AST in 95 AST-nodes to define 30 objects. The version of OpenAPI considered in this framework is 3.0.0. To have a better overview, the definition of Parameter Object in our AST is shown in Listing~\ref{lst:rago-ast} and can be compared with the definition in the OpenAPI official GitHub\footnote{\url{https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md}}.
\begin{lstlisting}[language=AST,label={lst:rago-ast},caption={Parameter Object}]
abstract ParameterOb;
......@@ -12,11 +12,8 @@ ParameterObject : ParameterOb ::= <Name> <In> <Description> <Required:Boolean> <
\end{lstlisting} \label{lst:rago-one}
During transferring the structure from OpenAPI to RAG, several properties of JastAdd could be clearly noticed:
\begin{enumerate}
\begin{description}
\item JastAdd does not support any map structure. So, nodes derived from maps in OpenAPI must be configured in tuples (List of a named tuple containing a key and a value).
\item Extensions which are properties of an object class in OpenAPI are also defined in nodes.
\item If a separate object is a reference object, it calls the corresponding object and saves in itself (Listing 4.1).
\end{enumerate}
% ^{1} : https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.1.md
\ No newline at end of file
\item If a separate object is a reference object, it saves only a String token and calls the corresponding object, if needed. (Listing~\ref{lst:rago-ast}).
\end{description}
\ No newline at end of file
......@@ -3,18 +3,18 @@
\begin{figure}
\centering
\includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{diagram}
\caption{Process of RAG (Parse, Backtransformation)}\label{fig:diagram}
\caption{Process of RAGO (Parse, Backtransformation)}\label{fig:ragoprocess}
\end{figure}
After the completion of the syntactic AST structure, declarative definitions are expected to concrete what individual attributes mean semantically. It was a biggest effort to this work. A diagram in Figure 4.1 represents a graphic overview of the process.
After the completion of the syntactic AST structure, declarative definitions are expected to concrete what individual attributes mean semantically. It was a biggest effort to this work. A diagram in \Cref{fig:ragoprocess} represents a graphic overview of the process.
%Parse OpenAPI -> Java
Before working with attribute definitions, an input specification in JSON or YAML file needs to be parsed in Java to process it in RAG. A simple JSON or YAML parser does not hold on the schema of an OpenAPI specification. So, we used an additional library, openapi4j$^{2}$. It enables to parse and to validate an OpenAPI document in Java and performs well. It has small limitations (e.g. no support for type 'any' and mapping with schema name outside of 'components/schemas' not supported). But, they are not critical to this work.
Before working with attribute definitions, an input specification in JSON or YAML file needs to be parsed in Java to process it in RAG. A simple JSON or YAML parser does not hold on the schema of an OpenAPI specification. So, we used an additional library, openapi4j\footnote{\url{https://www.openapi4j.org/parser.html}}. It enables to parse and to validate an OpenAPI document in Java and performs well. It has small limitations (e.g. no support for type 'any' and mapping with schema name outside of 'components/schemas' not supported). But, they are not critical to this work.
%Parse Java -> RAG
The next step of processing this framework is transferring parsed objects in java into AST nodes. This step is done with attribute definitions in jrag file. A small definition example of Parameter Object is in Listing 4.2.
The next step of processing this framework is transferring parsed objects in java into AST nodes. This step is done with attribute definitions in jrag file. A small definition example of Parameter Object is in Listing~\ref{lst:parser}.
\begin{lstlisting}[language=JRAG,label={lst:attribute-parameterobject},caption={Parser for Parameter Object}]
\begin{lstlisting}[language=JRAG,label={lst:parser},caption={Parser for Parameter Object}]
{ ...
if( parameter.getName() != null )
parameterObject.setName(parameter.getName());
......@@ -32,9 +32,9 @@ The next step of processing this framework is transferring parsed objects in jav
First, "parameter" is an object parsed with openapi4j and "parameterObject" is a node which should describe the structure of Parameter Object in RAG. It checks whether values in "parameter" exist and are set into the matching node in the AST (in this case "parameterObject"). At the end of the attribute, it returns the node.
%Transfer back RAG -> Java for validation
To see if the parser implemented with JastAdd works correctly, parsed nodes in an AST that describes OpenAPI structure must be transferred back into the structure of openapi4j and validated. The validation of objects after processing is explained in section 4.3. The way of definitions to transfer RAG into openapi4j is similar to the parser, it only provides the opposite direction of implementation. Listing 4.3 allows to compare itself with Listing 4.2.
To see if the parser implemented with JastAdd works correctly, parsed nodes in an AST that describes OpenAPI structure must be transferred back into the structure of openapi4j and validated. The validation of objects after processing is explained in \Cref{sec:ragotest}. The way of definitions to transfer RAG into openapi4j is similar to the parser, it only provides the opposite direction of implementation. Listing~\ref{lst:backtransf} allows to compare itself with Listing 4.2.
\begin{lstlisting}[language=JRAG,label={lst:attribute-parameterobject},caption={Back Transformation for Parameter Object}]
\begin{lstlisting}[language=JRAG,label={lst:backtransf},caption={Back-Transformation for Parameter Object}]
{ ...
if( !p.getName().isEmpty() )
parameter.setName(p.getName());
......
\section{Validation}
\section{Validation} \label{sec:ragotest}
% General
For correct (re-)constructions, objects after the processing phase must be the same before. In that sense, a generated JSON or YAML must be equivalent to the given OpenAPI document. Thankfully, there are several practical libraries to compare two JSONs (JsonNode, JsonDiff, JsonPath) and conditions for the assertion were uncomplicated. As a result, we have validated the functionality of the structure transfer, while 100 APIs from api.guru$^{3}$ are constructed in RAG and reconstructed in openapi4j.
......
......@@ -3,19 +3,17 @@ Random testing is a one of easiest way to test API and can be useful in some sit
% General
To solve this problem, most of REST API testing approaches use a stateful process, because it enables to analyze properties of APIs and infer inputs which are more appropriate than random inputs. There are several suggestions in \Cref{ch:curr-appr}, this framework investigates a inference of parameters with operation dependency motivated by Specification-based Approach \cite{ed2018automatic} and RESTTESTGEN \cite{viglianisi2020resttestgen}. Generally, it collects all responses and inferences parameters contributing the same schema of a succesful response. \\
If there is a schema set in a request and a response, parameters of them are inferred by three strategies:
If there is a schema set in a request and a response, parameters of them are inferred by three strategies.
\begin{description}
\begin{itemize}
\item Case insensitive
\item Id completion in a field name (e.g. if a property is named with "id", it gets an additional field name available in the specification)
\item Stemming algorithm (e.g. pet and pets are considered as a same value.)
\end{description}
\end{itemize}
% Process
In the implementation of this work, case insensitive comparison and id completion are utilized to create the basic functionality. Stemming algorithm can be also extended in the future. \\
The follwing code in \Cref{lst:parameter-inference} shows how the parameter inference is compiled with predefined attributes:
The follwing code in Listng~\ref{lst:parameter-inference} shows how the parameter inference is compiled with predefined attributes:
\begin{lstlisting}[language=JRAG,label={lst:parameter-inference},caption={Parameter Inference}]
generateRequests();
......@@ -42,7 +40,7 @@ for (String path : paths)
connect(path);
\end{lstlisting}
Before it starts with the parameter inference, the random testing generator of Section 5.1 is executed first (Line 1). During this execution, the status code of a response is checked if it is a successful response with 200 status code (Line 4). Afterwards, the response schema of returned values is also checked. If it is in type array, the function "writeDictionary" is iterated, otherwise it only executed once (Line 6-9). "writeDictionary" is not attributed, because it would be critical for the rule of RAG that an AST structure must not be edited, while attributes are computed. However, the function "writeDictionary" saves the returend values of a successful response in seperate properties and write them in a dictionary (e.g. properties "id" and "name" are seperately stored with their value in the dictionary). If the schema of a response provides a reference of a schema object, the field name gets a name of a reference as prefix. Subsequently, this implementation does the similar way of execution in random testing at the generation phase. Firstly, it iterates all parameter objects (Line 14) and examines whether the parameter type is Path or Query (Line 15-18). Both attributes return URIs with parameter values inferred by the dictionary and case insensitive comparison. Generated URIs are put in a list. Lastly, the generator attribute sends requests with the URIs and starts with observation (Line 20-21).
Before it starts with the parameter inference, the random testing generator of \Cref{sec:stm1} is executed first (Line 1). During this execution, the status code of a response is checked if it is a successful response with 200 status code (Line 4). Afterwards, the response schema of returned values is also checked. If it is in type array, the function "writeDictionary" is iterated, otherwise it only executed once (Line 6-9). "writeDictionary" is not attributed, because it would be critical for the rule of RAG that an AST structure must not be edited, while attributes are computed. However, the function "writeDictionary" saves the returend values of a successful response in seperate properties and write them in a dictionary (e.g. properties "id" and "name" are seperately stored with their value in the dictionary). If the schema of a response provides a reference of a schema object, the field name gets a name of a reference as prefix. Subsequently, this implementation does the similar way of execution in random testing at the generation phase. Firstly, it iterates all parameter objects (Line 14) and examines whether the parameter type is Path or Query (Line 15-18). Both attributes return URIs with parameter values inferred by the dictionary and case insensitive comparison. Generated URIs are put in a list. Lastly, the generator attribute sends requests with the URIs and starts with observation (Line 20-21).
% Result
As results, the test case generator with parameter inference implemented in this framework could create maximum over 300 acceptable URIs for the parameter petId in the selected API, pet store, at the operation getPetById. It generated also numerous requests denied by the server. After the observation of several execution iterations, it can be assumed that the API with this operation sends 200 or 404 status codes randomly or according to some rules, because a same URI provided status codes in that way.
......@@ -51,9 +49,9 @@ As results, the test case generator with parameter inference implemented in this
During the implementation phase of parameter inference, RAG was beneficial at writing codes. At writing codes for parser and back-transformation, attributes could not be applied, because the functional parts change the structure of AST, which conflicts to the definition of attribute and also in JastAdd. So, it could not be realized that attributes can be practical. But, following attributes and features of JastAdd were helpful to construct the generators and implement them:
\begin{itemize}
\item As long as a returning value can be called or storable by an AST node, the syntax in RAG is reduced with an equals sign and simpler than in common programming language. Therefore, the source codes are compact. To compare how RAG could be implemented effectively, see the implementation of an attribute in this work in \Cref{lst:attribute-infParam} and how this attribute is defined in common Java description in \Cref{lst:java-infParam}.
\item To iterate all paths available in OpenAPI, an inherited attribute facilitated the writing effort. Paths Objects are child nodes of OpenAPI Object, so, all that should have been done was only two lines of code instead of writing an extra for loop. See \Cref{lst:inherited}.
\item As its name, Reference Attribute Grammar, every AST node can be referenced by an attribute. For instance, with a collection attribute. A reference defined in \Cref{lst:rago-ast} contains only a String variable named Ref, it still could provide its Object like in \Cref{lst:coll-param}.
\item As long as a returning value can be called or storable by an AST node, the syntax in RAG is reduced with an equals sign and simpler than in common programming language. Therefore, the source codes are compact. To compare how RAG could be implemented effectively, see the implementation of an attribute in this work in Listing~\ref{lst:attribute-infParam} and how this attribute is defined in common Java description in Listing~\ref{lst:java-infParam}.
\item To iterate all paths available in OpenAPI, an inherited attribute facilitated the writing effort. Paths Objects are child nodes of OpenAPI Object, so, all that should have been done was only two lines of code instead of writing an extra for loop. See Listing~\ref{lst:inherited}.
\item As its name, Reference Attribute Grammar, every AST node can be referenced by an attribute. For instance, with a collection attribute. A reference defined in Listing~\ref{lst:rago-ast} contains only a String variable named Ref, it still could provide its Object like in Listing~\ref{lst:coll-param}.
\end{itemize}
\begin{lstlisting}[language=JRAG,label={lst:attribute-infParam},caption={Attribute InferredParameter.value()}]
......@@ -92,16 +90,3 @@ eq ParameterReference.parameterObject() {
return new ParameterObject();
}
\end{lstlisting}
\begin{comment}
- Process \\
- writeDictionary, writeDictionaryWithArray
- Collection (Listing) \\
- Algorithms \\
- Case insensitive \\
- Results
maximal over 300 akzeptierte paths fuer petid generierbar
in pet store api werden pets zufaellig dauernd erstellt und geloescht vermutlich. nach mehreren iterationen ist es beobachtbar dass diese operation zufaellig oder nach regeln 200 und 404 erzeugen.
\end{comment}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment