better secret handling docker api upgrade

This commit is contained in:
2025-01-07 23:40:00 +01:00
parent 53a262ddb9
commit 5546b0ba3b
14 changed files with 168 additions and 38 deletions

View File

@@ -4,11 +4,20 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import io.github.cdimascio.dotenv.Dotenv;
@SpringBootApplication
@EnableScheduling
public class XpenselyServerApplication {
public static void main(String[] args) {
Dotenv dotenv = Dotenv.load(); // Loads the .env file
System.setProperty("GOOGLE_CLIENT_ID", dotenv.get("GOOGLE_CLIENT_ID"));
System.setProperty("GOOGLE_CLIENT_SECRET", dotenv.get("GOOGLE_CLIENT_SECRET"));
System.setProperty("DB_USERNAME", dotenv.get("DB_USERNAME"));
System.setProperty("DB_PASSWORD", dotenv.get("DB_PASSWORD"));
System.setProperty("DB_DEV_CONTAINER", dotenv.get("DB_DEV_CONTAINER"));
System.setProperty("DB_DEV_NAME", dotenv.get("DB_DEV_NAME"));
SpringApplication.run(XpenselyServerApplication.class, args);
}

View File

@@ -3,7 +3,6 @@ package de.zendric.app.xpensely_server.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@@ -13,6 +12,8 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import de.zendric.app.xpensely_server.model.AppUser;
import de.zendric.app.xpensely_server.model.AppUserCreateRequest;
import de.zendric.app.xpensely_server.model.UsernameAlreadyExistsException;
import de.zendric.app.xpensely_server.services.UserService;
@RestController
@@ -36,18 +37,32 @@ public class AppUserController {
return userService.getUserByName(username);
}
@PostMapping
public ResponseEntity<AppUser> createUser(@RequestBody AppUser user) {
AppUser appUser = userService.createUser(user);
return ResponseEntity.status(HttpStatus.CREATED).body(appUser);
@GetMapping("/byGoogleId")
public ResponseEntity<AppUser> getUserByGoogleId(@RequestParam String id) {
try {
AppUser userByGoogleId = userService.getUserByGoogleId(id);
return new ResponseEntity<>(userByGoogleId, HttpStatus.OK);
} catch (IllegalArgumentException e) {
return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
} catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@PostMapping("/createUser")
public ResponseEntity<?> createUsername(@RequestBody AppUser user, Authentication authentication) {
String googleUserId = authentication.getName();
// Validate and store the username with googleUserId
public ResponseEntity<AppUser> createUser(@RequestBody AppUserCreateRequest userRequest) {
try {
AppUser convertedUser = userRequest.convertToAppUser();
AppUser nUser = userService.createUser(convertedUser);
return new ResponseEntity<>(nUser, HttpStatus.CREATED);
} catch (UsernameAlreadyExistsException e) {
return new ResponseEntity<>(null, HttpStatus.CONFLICT);
} catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
}
return ResponseEntity.ok("Username created successfully");
}
@DeleteMapping

View File

@@ -95,7 +95,7 @@ class ExpenseListController {
}
}
@PostMapping
@PostMapping("/create")
public ResponseEntity<ExpenseList> create(@RequestBody ExpenseList expenseList) {
try {
if (expenseList.getOwner() != null) {

View File

@@ -1,10 +1,17 @@
package de.zendric.app.xpensely_server.model;
import java.time.LocalDateTime;
import org.hibernate.annotations.CreationTimestamp;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@@ -13,6 +20,7 @@ import lombok.Setter;
@Setter
@NoArgsConstructor
@Entity
@EqualsAndHashCode
public class AppUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -21,4 +29,12 @@ public class AppUser {
@Column(name = "username", nullable = false, unique = true)
private String username;
@JsonIgnore
private String googleId;
@Column(updatable = false)
@CreationTimestamp
@JsonIgnore
private LocalDateTime createdAt;
}

View File

@@ -0,0 +1,21 @@
package de.zendric.app.xpensely_server.model;
import jakarta.persistence.Column;
import lombok.Data;
@Data
public class AppUserCreateRequest {
@Column(name = "username", nullable = false, unique = true)
private String username;
private String googleId;
public AppUser convertToAppUser() {
AppUser appUser = new AppUser();
appUser.setGoogleId(googleId);
appUser.setUsername(username);
return appUser;
}
}

View File

@@ -0,0 +1,11 @@
package de.zendric.app.xpensely_server.model;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.CONFLICT)
public class UsernameAlreadyExistsException extends RuntimeException {
public UsernameAlreadyExistsException(String message) {
super(message);
}
}

View File

@@ -10,4 +10,8 @@ import de.zendric.app.xpensely_server.model.AppUser;
@Repository
public interface UserRepository extends JpaRepository<AppUser, Long> {
Optional<AppUser> findByUsername(String username);
Optional<AppUser> findByGoogleId(String id);
Boolean existsByUsername(String username);
}

View File

@@ -10,28 +10,26 @@ import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// @Bean
// public SecurityFilterChain securityFilterChain(HttpSecurity http) throws
// Exception {
// http.authorizeHttpRequests(auth -> auth
// .anyRequest().permitAll()).csrf().disable();
// ;
// @Bean
// public SecurityFilterChain securityFilterChain(HttpSecurity http) throws
// Exception {
// http.authorizeHttpRequests(auth -> auth
// .anyRequest().permitAll()).csrf().disable();
// ;
// return http.build();
// }
// return http.build();
// }
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated() // Require authentication for all requests
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(Customizer.withDefaults()) // Enable JWT validation
)
.oauth2Login(Customizer.withDefaults()) // Optional if you want OAuth2 login
.csrf().disable(); // Disable CSRF for simplicity in APIs (consider enabling it for forms)
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(Customizer.withDefaults()))
.oauth2Login(Customizer.withDefaults())
.csrf().disable();
return http.build();
}
return http.build();
}
}

View File

@@ -6,6 +6,7 @@ import java.util.Optional;
import org.springframework.stereotype.Service;
import de.zendric.app.xpensely_server.model.AppUser;
import de.zendric.app.xpensely_server.model.UsernameAlreadyExistsException;
import de.zendric.app.xpensely_server.repo.UserRepository;
@Service
@@ -21,6 +22,9 @@ public class UserService {
}
public AppUser createUser(AppUser user) {
if (Boolean.TRUE.equals(userRepository.existsByUsername(user.getUsername()))) {
throw new UsernameAlreadyExistsException("Username already exists");
}
return userRepository.save(user);
}
@@ -49,4 +53,12 @@ public class UserService {
return null;
}
public AppUser getUserByGoogleId(String id) {
Optional<AppUser> optUser = userRepository.findByGoogleId(id);
if (optUser.isPresent()) {
return optUser.get();
} else
return null;
}
}

View File

@@ -3,12 +3,14 @@ spring.application.name=XpenselyServer
#Security
spring.security.enabled=false
#logging.level.org.springframework.security=TRACE
spring.security.oauth2.client.registration.google.client-id=${GOOGLE_CLIENT_ID}
spring.security.oauth2.client.registration.google.client-secret=${GOOGLE_CLIENT_SECRET}
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://accounts.google.com
# PostgreSQL Configuration
spring.datasource.url=jdbc:postgresql://localhost:5432/Xpensely
spring.datasource.username=${XpenselyDBUser}
spring.datasource.password=${XpenselyDBPW}
spring.datasource.url=jdbc:postgresql://${DB_DEV_CONTAINER}:5432/${DB_DEV_NAME}
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
spring.datasource.driver-class-name=org.postgresql.Driver
# Hibernate configuration