A sample web app to play Tic Tac Toe against the computer. The application requires minimum JDK 21 to run locally.
This application has several components:
- Running on JDK 21+ and built with Maven.
- Setup built with Spring Boot (v3.2.2), persistency layer with JPA and H2 database, UI with Thymeleaf with Bootstrap
- Containerized with Dockerfile and deployed with Docker Compose.
UI Component | Link |
---|---|
Header | https://getbootstrap.com/docs/5.3/examples/headers/ |
Footer | https://getbootstrap.com/docs/5.3/examples/footers/ |
Sign In and Register | https://getbootstrap.com/docs/5.3/examples/sign-in/ |
In order to build an example keystore, you can use the following series of commands:
- Create a CA certificate, by running
openssl req -x509 -sha256 -days 3650 -newkey rsa:4096 -keyout localCA.key -out localCA.crt
- Create a certificate signing request, by running
openssl req -new -newkey rsa:4096 -keyout localhost.key -out localhost.csr
- Make an extension file (
local.ext
) containing additional hosts and IPs that your certificate should authorize:
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = springboot
IP.1 = 127.0.0.1
- Sign the request with our localCA.crt certificate and its private key:
openssl x509 -req -CA localCA.crt -CAkey localCA.key -in localhost.csr \
-out localhost.crt -days 365 -CAcreateserial -extfile local.ext
- Create the keystore by importing the certificate created at previous step:
openssl pkcs12 -export -out keystore.p12 -name "localhost" -inkey localhost.key -in localhost.crt
To enable mutual authentication, you need to generate a truststore and generate client certificates:
- Create a truststore by running:
keytool -import -trustcacerts -noprompt -alias ca -ext san=dns:localhost,ip:127.0.0.1 -file localCA.crt -keystore truststore.p12
- Generate a client-side certificate signing request with common name (CN) Ana:
openssl req -new -newkey rsa:4096 -nodes -keyout ana.key -out ana.csr -subj '/CN=ana'
- Sign the request with the existing CA:
openssl x509 -req -CA localCA.crt -CAkey localCA.key -in ana.csr -out ana.crt -days 365 -CAcreateserial
- Package the signed certificate and the private key into the PKCS file:
openssl pkcs12 -export -out ana.p12 -name "ana" -inkey ana.key -in ana.crt
- Import the generated certificate (
ana.p12
) in your browser.
Do not forget to reference the location of your keystore/truststore in the application.properties
file:
server.ssl.bundle=mybundle
spring.ssl.bundle.jks.mybundle.keystore.location=stores/keystore.p12
spring.ssl.bundle.jks.mybundle.truststore.location=stores/truststore.p12
IMPORTANT For demo purposes, application.properties
contains the passwords in clear.
For production environments you must consider encrypting your passwords.
You can start the application locally from your IDE or by running the following command in a terminal window:
./mvnw spring-boot:run
When accessing the application on https://localhost:8443, you will be asked to sign in to play. If you didn't register, you can do so by clicking the register link. If there is an user already registered with a chosen username, please select a different one.
Once you register, login with your chosen username and password to play. Have fun!
You can deploy the application locally via Docker Compose. First build the application using:
./mvnw clean verify
By default, the provided docker compose file has enabled remote JMX connection via JDK_JAVA_OPTIONS
environment variable:
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=true
-Dcom.sun.management.jmxremote.rmi.port=1099
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.access.file=/etc/jmxremote/jmxremote.access
-Dcom.sun.management.jmxremote.password.file=/etc/jmxremote/jmxremote.password
and mounts the jmxremote.access
and jmxremote.password
files as volumes from stores folder:
volumes:
- ./stores/jmxremote.access:/etc/jmxremote/jmxremote.access
- ./stores/jmxremote.password:/etc/jmxremote/jmxremote.password
If you wish to keep that configuration, make sure that you can read and write the /etc/jmxremote/jmxremote.password
and other users have no access to it.
An example on how to do that on Mac/Linux is by running the following command over :
chmod 0600 stores/jmxremote.password
Now you can invoke docker-compose up
command:
docker-compose up --build
This will build a local containerize environment for you to inspect the application.
If you wish to deploy in other environments, you can always build and push a docker image using:
docker buildx build --platform=linux/amd64 --tag <registry>/<username>/tictactoe:1.0 . --no-cache