Skip to content

Commit 8e87ff6

Browse files
Theo-lbgCopilot
andcommitted
feat(security): enhance security configuration with multiple user roles and credentials
Co-authored-by: Copilot <copilot@github.com>
1 parent cf98b08 commit 8e87ff6

7 files changed

Lines changed: 104 additions & 14 deletions

File tree

.env.template

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ POSTGRES_DB=your_postgres_db
44
POSTGRES_PORT=5432
55

66
# Spring Security
7+
APP_SECURITY_ADMIN_USER=your_admin_username
8+
APP_SECURITY_ADMIN_PASSWORD=your_admin_password
79
APP_SECURITY_USER=your_api_username
810
APP_SECURITY_PASSWORD=your_api_password
11+
APP_SECURITY_TEST_USER=your_test_username
12+
APP_SECURITY_TEST_PASSWORD=your_test_password
913

1014
# Liquibase configuration
1115
LB_CHANGELOG=your_changelog_file.yaml

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,36 @@ POSTGRES_PASSWORD=your_password
120120
POSTGRES_DB=your_database
121121
POSTGRES_PORT=5432
122122
123+
# Spring Security
124+
APP_SECURITY_ADMIN_USER=admin
125+
APP_SECURITY_ADMIN_PASSWORD=admin123
126+
APP_SECURITY_USER=apiuser
127+
APP_SECURITY_PASSWORD=changeit
128+
APP_SECURITY_TEST_USER=testuser
129+
APP_SECURITY_TEST_PASSWORD=testpass
130+
123131
# Liquibase (optional, defaults provided)
124132
LB_CHANGELOG=db/changelog/db.changelog-master.yaml
125133
LB_SCHEMA=public
126134
SPRING_LIQUIBASE_ENABLED=true
127135
```
128136

137+
### Spring Security
138+
139+
The API uses HTTP Basic authentication with three in-memory roles:
140+
141+
- `ADMIN`: can read, create, update and delete users
142+
- `USER`: can read users
143+
- `TEST`: can read users and is used by automated tests
144+
145+
Protected endpoints require credentials. Example:
146+
147+
```bash
148+
curl -u apiuser:changeit "http://localhost:8080/random-users"
149+
```
150+
151+
Swagger UI remains publicly accessible, while API endpoints are protected according to the role rules above.
152+
129153
### External API Configuration
130154

131155
`application.properties` uses:

src/main/java/com/xpeho/spring_boot_java_random_user/config/SecurityConfig.java

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,46 @@
22

33
import org.springframework.context.annotation.Bean;
44
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.beans.factory.annotation.Value;
56
import org.springframework.http.HttpMethod;
7+
import org.springframework.security.core.userdetails.User;
8+
import org.springframework.security.core.userdetails.UserDetails;
9+
import org.springframework.security.core.userdetails.UserDetailsService;
10+
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
11+
import org.springframework.security.crypto.password.PasswordEncoder;
612
import org.springframework.security.config.Customizer;
713
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
814
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
9-
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
1015
import org.springframework.security.config.http.SessionCreationPolicy;
16+
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
1117
import org.springframework.security.web.SecurityFilterChain;
1218

1319
@Configuration
1420
@EnableWebSecurity
1521
public class SecurityConfig {
1622

23+
@Value("${app.security.admin.username}")
24+
private String adminUsername;
25+
26+
@Value("${app.security.admin.password}")
27+
private String adminPassword;
28+
29+
@Value("${app.security.user.username}")
30+
private String userUsername;
31+
32+
@Value("${app.security.user.password}")
33+
private String userPassword;
34+
35+
@Value("${app.security.test.username}")
36+
private String testUsername;
37+
38+
@Value("${app.security.test.password}")
39+
private String testPassword;
40+
1741
@Bean
1842
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
1943
http
20-
.csrf(AbstractHttpConfigurer::disable)
44+
.csrf(csrf -> csrf.ignoringRequestMatchers("/random-users/**"))
2145
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
2246
.httpBasic(Customizer.withDefaults())
2347
.authorizeHttpRequests(auth -> auth
@@ -29,9 +53,38 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
2953
"/actuator/health"
3054
).permitAll()
3155
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
56+
.requestMatchers(HttpMethod.GET, "/random-users/**").hasAnyRole("ADMIN", "USER", "TEST")
57+
.requestMatchers(HttpMethod.POST, "/random-users/**").hasRole("ADMIN")
58+
.requestMatchers(HttpMethod.PUT, "/random-users/**").hasRole("ADMIN")
59+
.requestMatchers(HttpMethod.DELETE, "/random-users/**").hasRole("ADMIN")
3260
.anyRequest().authenticated()
3361
);
3462

3563
return http.build();
3664
}
65+
66+
@Bean
67+
UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
68+
UserDetails admin = User.withUsername(adminUsername)
69+
.password(passwordEncoder.encode(adminPassword))
70+
.roles("ADMIN")
71+
.build();
72+
73+
UserDetails user = User.withUsername(userUsername)
74+
.password(passwordEncoder.encode(userPassword))
75+
.roles("USER")
76+
.build();
77+
78+
UserDetails test = User.withUsername(testUsername)
79+
.password(passwordEncoder.encode(testPassword))
80+
.roles("TEST")
81+
.build();
82+
83+
return new InMemoryUserDetailsManager(admin, user, test);
84+
}
85+
86+
@Bean
87+
PasswordEncoder passwordEncoder() {
88+
return new BCryptPasswordEncoder();
89+
}
3790
}

src/main/resources/application.properties

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
spring.application.name=spring_boot_java_random_user
22

33
# Security
4-
spring.security.user.name=${APP_SECURITY_USER}
5-
spring.security.user.password=${APP_SECURITY_PASSWORD}
6-
spring.security.user.roles=USER
4+
app.security.admin.username=${APP_SECURITY_ADMIN_USER}
5+
app.security.admin.password=${APP_SECURITY_ADMIN_PASSWORD}
6+
app.security.user.username=${APP_SECURITY_USER}
7+
app.security.user.password=${APP_SECURITY_PASSWORD}
8+
app.security.test.username=${APP_SECURITY_TEST_USER}
9+
app.security.test.password=${APP_SECURITY_TEST_PASSWORD}
710

811
# Swagger UI custom path
912
springdoc.swagger-ui.path=/api

src/test/java/com/xpeho/spring_boot_java_random_user/presentation/UserGetByIdContainerTest.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@
2626
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
2727
properties = {
2828
"spring.sql.init.mode=never",
29-
"spring.jpa.hibernate.ddl-auto=create-drop",
30-
"spring.security.user.name=testuser",
31-
"spring.security.user.password=testpass",
32-
"spring.security.user.roles=USER"
29+
"spring.jpa.hibernate.ddl-auto=create-drop",
30+
"app.security.admin.username=testadmin",
31+
"app.security.admin.password=testadminpass",
32+
"app.security.user.username=testuser",
33+
"app.security.user.password=testpass",
34+
"app.security.test.username=testviewer",
35+
"app.security.test.password=testviewerpass"
3336
}
3437
)
3538
class UserGetByIdContainerTest {

src/test/java/feature/SpringIntegrationTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
)
2828
public class SpringIntegrationTest {
2929

30-
private static final String TEST_USERNAME = "testuser";
31-
private static final String TEST_PASSWORD = "testpass";
30+
private static final String TEST_USERNAME = "testadmin";
31+
private static final String TEST_PASSWORD = "testadminpass";
3232

3333
@Autowired
3434
protected TestRestTemplate restTemplate;

src/test/resources/application-test.properties

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ spring.datasource.url=${H2_URL:jdbc:h2:mem:mydb};MODE=PostgreSQL;DATABASE_TO_UPP
22
spring.datasource.driver-class-name=org.h2.Driver
33
spring.datasource.username=${H2_USERNAME:myusername}
44
spring.datasource.password=${H2_PASSWORD:mypassword}
5-
spring.security.user.name=testuser
6-
spring.security.user.password=testpass
7-
spring.security.user.roles=USER
5+
app.security.admin.username=testadmin
6+
app.security.admin.password=testadminpass
7+
app.security.user.username=testuser
8+
app.security.user.password=testpass
9+
app.security.test.username=testviewer
10+
app.security.test.password=testviewerpass
811
spring.sql.init.mode=never
912
spring.docker.compose.enabled=false

0 commit comments

Comments
 (0)