-
Notifications
You must be signed in to change notification settings - Fork 1
Home
- Create a Spring Boot Security Thymeleaf project
- Build a .jar
- Deploy .jar by
SSH
to EC2 AWS
-
Spring Boot
init
Java 11
- IntellIJIdea IDE
- Thymeleaf
- Security starter
- AWS EC2: Linux VM, Ubuntu Server 22.0
- SSH
References
Spring Boot Security:
AWS EC2 & SSH:
Thymeleaf:
Spring Boot Deploy:
- Create and test
Spring Boot App
- Get
app–0.0.1-SNAPSHOT.jar
from target: app.jar - Create AWS EC2 VM
T2.micro Linux
- Login from local to EC2 VM with SSH .pem file
- Install JAVA and upload app.jar
- Run app.jar
Ensure Maven is Installed. Make sure you have Maven installed on your system. You can check this by running:
sh mvn -version
Navigate to the Project Directory open a terminal or command prompt and navigate to the root directory
of your Spring Boot project.
Build the Project. To build the project and package it into a JAR
(Java Archive) file, use the following Maven command:
mvn clean package
For instance, you could create a Linux Amazon machine or a Ubuntu Server 22.0, by creating the VM you should not forget the key pair to connect to the instance from your local.
Note
Please keep the keypair handy in the same folder as a jar file: demosecurity.jar
& securitydeploy.pem
Now, go to the folder where your downloaded .pem
file is and open the terminal to connect to the EC2
instance via SSH
. Get the SSH command from the EC2 AWS visual console following these steps:
Instance ID (securitydeploy): i-014b57b86a116762a
- Open an SSH client.
- Locate your private key file. The key used to launch this instance is
securitydeploy.pem
- Run this command, if necessary, to ensure your key is not publicly viewable.
chmod 400 "securitydeploy.pem"
- Connect to your instance using its Public DNS:
ec2-3-68-82-57.eu-central-1.compute.amazonaws.com
After that, copy the SSH command like it is shown in the SSH tab on Connect to Instance. paste it in the terminal and click enter.
ssh -i "securitydeploy.pem" ubuntu@ec2-3-68-82-57.eu-central-1.compute.amazonaws.com
You could:
- use the
ssh
connection or - (if it fails) excute upload with
scp
right from your local directory:
scp
: security copy
scp -i securitydeploy.pem demosecurity.jar ubuntu@ec2-3-68-82-57.eu-central-1.compute.amazonaws.com:~/
Now, we need ssh
to access Ubuntu 22 server on EC2
to run our .jar
:
And run it:
java -jar demosecurity.jar
Our Spring Boot is configured at port 8088, so we nee to edit the inbound rules
:
The class MvcConfig
that implements WebMvcConfigurer
. The addViewControllers
method configures simple automated controllers for specific URLs. It maps:
- the URL "/home" to the "home" view,
- the root URL "/" to the "home" view,
- the URL "/hello" to the "hello" view,
- and the URL "/login" to the "login" view.
This means when users visit these URLs, they are directed to the corresponding HTML pages without needing a dedicated controller for each view.
MvcConfig v0.3.0
package com.example.demoSecurity;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
}
This code configures web security for an application.
The WebSecurityConfig
class is annotated with @Configuration
and @EnableWebSecurity
, indicating that it is a configuration class for web security.
configure
The configure method sets up HTTP security
.
- It allows unrestricted access to the root URL ("/") and the
home
URL ("/home") - While requiring authentication for any other requests
- Form-based login is enabled with the
login
page set to "/login":login
andlogout
functionalities are allowed for all users.
userDetailsService
The userDetailsService
method creates an in-memory user store.
- It defines a single user with the username "albert", password "1234", and role "USER".
- The
User.withDefaultPasswordEncoder()
method is used to create the user, which is then managed by anInMemoryUserDetailsManager
.
This setup is mainly for development and testing purposes and not recommended for production due to the use of plain text passwords and in-memory storage.
WebSecurityConfig
package com.example.demoSecurity;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
@Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("albert")
.password("1234")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
userDetailsService() with several users
@Bean
@Override
public UserDetailsService userDetailsService() {
UserDetails user1 = User.withDefaultPasswordEncoder()
.username("albert")
.password("1234")
.roles("USER")
.build();
UserDetails user2 = User.withDefaultPasswordEncoder()
.username("brenda")
.password("5678")
.roles("USER")
.build();
UserDetails admin = User.withDefaultPasswordEncoder()
.username("charlie")
.password("adminpass")
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user1, user2, admin);
}
This HTML file generates a "Hello" page personalized for the logged-in user. It uses Thymeleaf
and Spring Security integration
for rendering dynamic content and handling security.
- Thymeleaf: A server-side Java template engine.
-
th:inline="text"
: Enables text inline mode for Thymeleaf. -
[[${#httpServletRequest.remoteUser}]]
: Displays the username of the logged-in user. - Logout Form: A form to sign out the user.
Hello.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Hello World!</title>
</head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
This HTML file creates a home page with a welcome message and a link to the "Hello" page.
- Welcome Message: A simple "Welcome!" heading.
- Link to Hello Page: A link that navigates to the "Hello" page.
Home.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example</title>
</head>
<body>
<h1>Welcome!</h1>
<p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
</body>
</html>
This HTML file provides a login form for users to sign in, with messages for invalid
login attempts and successful
logout.
- Error Message: Displays if login fails.
- Logout Message: Displays if the user has logged out.
-
Login Form: Contains fields for username and password, and a submit button. The form action is set to
/login
.
Login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
- Externalized Configuration
- direnv – unclutter your .profile
- Spring Boot with Docker: Docker Compose Support in Spring Boot 3.1 & Profiles
- Install
direnv
:
sudo apt update
sudo apt install direnv
- Configure
direnv
:
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
source ~/.bashrc
- Create the .envrc file:
cd ~/my-spring-boot-app
echo 'export DB_USERNAME="ReadOnlyUser"' > .envrc
echo 'export DB_PASSWORD="P@ssw0rd1"' >> .envrc
echo 'export API_KEY="sk-proj-oqHcx6hjqPNhRZi7MpfHT"' > .envrc
- Allow
direnv
to load the.envrc
file:
direnv allow
- Verify the Environment Variable
echo $API_KEY
sk-proj-oqHcx6hjqPNhRZi7MpfHT
- Configure Spring Boot to Use Environment Variables:
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
Open the browser at http://localhost:8088/
Spring Boot Security executing at AWS EC2 Ubuntu 22.0 server. It publishes at URL:
http://ec2-3-68-82-57.eu-central-1.compute.amazonaws.com:8088/home
: link
http://ec2-3-79-242-20.eu-central-1.compute.amazonaws.com:8088/home
: link
Note
When an AWS EC2 instance, such as a t2.micro, is stopped and then started again, it receives a new public IP address.
This occurs because public IP addresses are dynamically assigned from a pool of available IPs at the time the instance starts.
Unlike Elastic IPs
, which are static and persist across instance stops and starts, standard public IPs are released when the instance stops and a new one is assigned upon start.
To maintain a consistent IP address, an Elastic IP must be associated with the instance.