better secret handling docker api upgrade
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@ target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
.env
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
|
||||
30
docker-compose.yml
Normal file
30
docker-compose.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: XpenselyServer
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
|
||||
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET}
|
||||
DB_PORT: 5432
|
||||
DB_CONTAINER: ${DB_P_CONTAINER}
|
||||
DB_NAME: ${DB_P_NAME}
|
||||
DB_USERNAME: ${DB_USERNAME}
|
||||
DB_PASSWORD: ${DB_PASSWORD}
|
||||
depends_on:
|
||||
- postgresdb
|
||||
|
||||
postgresdb:
|
||||
image: postgres:14
|
||||
container_name: postgresdb
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
POSTGRES_DB: ${DB_P_NAME}
|
||||
POSTGRES_USER: ${DB_USERNAME}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
7
dockerfile
Normal file
7
dockerfile
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM openjdk:17-jdk-slim
|
||||
|
||||
COPY ./target/*.jar app.jar
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||
10
pom.xml
10
pom.xml
@@ -10,9 +10,9 @@
|
||||
</parent>
|
||||
<groupId>de.zendric.app</groupId>
|
||||
<artifactId>XpenselyServer</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<version>1.0.0</version>
|
||||
<name>XpenselyServer</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
<description>XpenselyServer used to handle the Xpensely App</description>
|
||||
<url/>
|
||||
<licenses>
|
||||
<license/>
|
||||
@@ -50,7 +50,11 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.cdimascio</groupId>
|
||||
<artifactId>dotenv-java</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -95,7 +95,7 @@ class ExpenseListController {
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@PostMapping("/create")
|
||||
public ResponseEntity<ExpenseList> create(@RequestBody ExpenseList expenseList) {
|
||||
try {
|
||||
if (expenseList.getOwner() != null) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -24,13 +24,11 @@ public class SecurityConfig {
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.anyRequest().authenticated() // Require authentication for all requests
|
||||
)
|
||||
.anyRequest().authenticated())
|
||||
.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)
|
||||
.jwt(Customizer.withDefaults()))
|
||||
.oauth2Login(Customizer.withDefaults())
|
||||
.csrf().disable();
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user