Sidebar LogoHomeIndexIndexGitHub </> Back Next Groovy console

Groovy console


About this section

In this section we are going to implement Groovy console that allows:

Warning

This solution may be convenient for a running web application diagnostic and manipulation. Still this makes the application unstable and vulnerable as the actions performed via the console are not properly controlled. The safer solution would be certain manipulation actions defined via corresponding endpoints with appropriate restrictions and checks. But the certain endpoints approach is harder to implement and it doesn't provide so much flexibility.


Materials

A more extensive variation may be found at [groovy_wc_github].


Spring project setup

Go to Spring Initializr site and define the following configuration:

Alternatively the following link may be used: https://start.spring.io/#!type=maven-project&language=java&platformVersion=3.3.2&packaging=jar&jvmVersion=17&groupId=groovy.study&artifactId=groovy-console&name=&description=&packageName=groovyconsole&dependencies=web

Delete some unnecessary files (like mvnw and mvnw.cmd), do some other code cleaning and reformatting.

The generated artifact is going to be a JAR file with dependencies. It is massive enough, so we are going to bring the target location out of the working project directory. To do that, the build/directory element is added into the pom.xml. The environment variable TMP_MAVEN_BUILDS_DIR must be defined in the system.

Building (as Java 17 is not set by default we need to set the corresponding environment variables):

>set JAVA_HOME=%JAVA_17_HOME%

>set PATH=%JAVA_17_HOME%\bin;%PATH%

>mvn clean package
...
[INFO] --------------------< groovy.study:groovy-console >---------------------
[INFO] Building groovy-console 0.0.1-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
...
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
...
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  7.698 s
[INFO] Finished at: 2024-08-14T09:04:21+02:00
[INFO] ------------------------------------------------------------------------

Running:

>cd /d %TMP_MAVEN_BUILDS_DIR%\groovy-console\

>set PATH=%JAVA_17_HOME%\bin;%PATH%

>java -jar groovy-console-0.0.1-SNAPSHOT.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.2)
...
... : Tomcat started on port 8080 (http) with context path '/'
... : Started Application in 1.584 seconds (process running for 1.913)

To stop press Ctrl+C (but not now please).

Alternatively the project may be run in an IDE by executing the class Application.java.

Testing the result in a browser: http://localhost:8080/. The result must look like this:

The following commit represents the newly automatically generated project with the above cleanup and customization:

Git commit: 66bfc6ce328ff55b7af8ccacf3d6a8a4f71848c9 Groovy console Spring Boot project initialized

Dependency tree report:

>mvn dependency:tree > dependency_tree.txt

Git commit: 5023a8176c11a98a7d4aecfe8c726aaa121c1269 dependency tree added

The result is in the file dependency_tree.txt (note that this is the latest version, not what it was at the current step, see the commit above to see the the actual version at this point of time).


Adding UI and REST

Git commit: 3c58c015b4e9378126ec86c2d0ce3a81f42f61a4 UI and REST added

Git commit: 28ec2b720ddb6405c25600b85a8a0230fcc5ee9c dependency tree updated

The full dependency tree file is dependency_tree.txt.

Note

This is a very simple implementation that lacks a lot of important features (like security) required in production.

Here are some explanations. The UI is created as simple as possible so no template engine is used. A single static HTML page is used for demonstration. Ajax is used to execute the scripts and to update the displayed application state (see the src/main/resources/static/console.html file).

The actual script execution is not implemented by now so the returned result is fake.

Here's the UI snapshot:

The following configuration adds a logic-less controller to serve the static page:

src/main/java/groovyconsole/MvcConfig.java
@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("console.html");
    }
}

The groovyconsole/State.java Spring bean is used for holding the application state that we are going to manipulate later.

There are two REST endpoints created:

>curl -s -X POST -H "Content-Type:application/text" -d "2+2" http://localhost:8080/console | python -m json.tool
{
    "error": null,
    "result": "The script is: 2+2",
    "output": "Fake output"
}

>curl -s http://localhost:8080/state | python -m json.tool
{
    "consoleRequestCount": 5,
    "someProperty": null
}

The Python json.tool module is used just for pretty-printing the output.


Implementing Groovy console

Git commit: 50c798b76895787c41f67b56b2f44b65d9e49ddd Groovy console implemented

Git commit: 6b0681171308eb83fa17ae42a7ffd9fd75f7f75d dependency tree updated

The full dependency tree file is dependency_tree.txt.

The following library is used for the actual Groovy scripts execution:

<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy</artifactId>
    <version>3.0.22</version>
</dependency>

The src/main/java/groovyconsole/SpringBinding.java class makes the web application Spring context available inside the Groovy scripts.

The groovyconsole.Controller#console endpoint method was rewritten to perform real Groovy scripts execution.

The groovyconsole.Greeter class was created to demonstrate usage of arbitrary Java code artifacts inside the Groovy scripts.

Some properties were added to the src/main/resources/application.properties file to check access to them from the Groovy scripts.


Demo

Here the UI snapshot is repeated for convenience:

ScriptResultComments
println "Hello world!"
RESULT: null
OUTPUT: Hello world!
The consoleRequestCount property value incremented.
System.out.println("Hello " + 
    "from Groovy script!")
RESULT: null
The specified message printed to the web application's standard output.
state.someProperty = "LALALA"
RESULT: LALALA
The someProperty property value updated. Here a bean from the Spring context is manipulated.
import groovyconsole.Greeter
var greeter = new Greeter("Bob")
greeter.greet()
RESULT: Hello, Bob!
Arbitrary Java code artifact is manipulated.
environment
    .getProperty("some.property")
RESULT: This is Groovy console
Spring environment property is accessed.
println "Some message"
1 / 0
ERROR: Division by zero
OUTPUT: Some message
Errors are processed correctly.

 


Back Next