From 89aa262830dd1db6c3888ba5a05de6c0928b1f63 Mon Sep 17 00:00:00 2001 From: Snoweuph Date: Tue, 11 Feb 2025 13:32:36 +0100 Subject: [PATCH 1/2] TD-3: Player Test Data and CSRF Fix --- .../towerdefence/server/auth/AuthConfig.java | 4 +-- .../de/towerdefence/server/player/Player.java | 1 + .../server/player/PlayerTestData.java | 32 +++++++++++++++++++ src/main/resources/application.properties | 1 + 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 src/main/java/de/towerdefence/server/player/PlayerTestData.java diff --git a/src/main/java/de/towerdefence/server/auth/AuthConfig.java b/src/main/java/de/towerdefence/server/auth/AuthConfig.java index 8bf7f7f..a3c920f 100644 --- a/src/main/java/de/towerdefence/server/auth/AuthConfig.java +++ b/src/main/java/de/towerdefence/server/auth/AuthConfig.java @@ -2,10 +2,10 @@ package de.towerdefence.server.auth; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; 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.configurers.AbstractHttpConfigurer; import org.springframework.security.core.session.SessionRegistry; import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.web.SecurityFilterChain; @@ -45,7 +45,7 @@ public class AuthConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http - .csrf(Customizer.withDefaults()) + .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/" + API_VERSION + "/admin/**") .authenticated() diff --git a/src/main/java/de/towerdefence/server/player/Player.java b/src/main/java/de/towerdefence/server/player/Player.java index 79a7fd3..1d84ec9 100644 --- a/src/main/java/de/towerdefence/server/player/Player.java +++ b/src/main/java/de/towerdefence/server/player/Player.java @@ -19,6 +19,7 @@ public class Player { public static final int PASSWORD_HASH_BYTE_LENGTH = 64; @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @NotNull diff --git a/src/main/java/de/towerdefence/server/player/PlayerTestData.java b/src/main/java/de/towerdefence/server/player/PlayerTestData.java new file mode 100644 index 0000000..b7db6ac --- /dev/null +++ b/src/main/java/de/towerdefence/server/player/PlayerTestData.java @@ -0,0 +1,32 @@ +package de.towerdefence.server.player; + +import jakarta.annotation.PostConstruct; +import lombok.AllArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import java.security.NoSuchAlgorithmException; + +@AllArgsConstructor +@Configuration +@Profile("dev") +public class PlayerTestData { + @Autowired + private PlayerRepository playerRepository; + @Autowired + private PlayerService playerService; + + @PostConstruct + public void loadFixtures() throws NoSuchAlgorithmException { + Player player1 = new Player(); + player1.setUsername("Player1"); + playerService.setPassword(player1, "1234"); + this.playerRepository.save(player1); + + Player player2 = new Player(); + player2.setUsername("Player2"); + playerService.setPassword(player2, "1234"); + this.playerRepository.save(player2); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 88e9b20..eb3a310 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,4 +1,5 @@ # General +spring.profiles.active=dev spring.application.name=Tower Defence Server server.port=8080 From 721ad39cb97e5dc090dce6a401e2081072c14091 Mon Sep 17 00:00:00 2001 From: Snoweuph Date: Tue, 11 Feb 2025 13:34:36 +0100 Subject: [PATCH 2/2] TD-3: Add Player Registration Endpoint --- api/api.yml | 40 +++++++++++++++++++ .../server/player/PlayerRepository.java | 1 + .../server/server/ServerApiController.java | 29 ++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/api/api.yml b/api/api.yml index b0cc553..17a79e2 100644 --- a/api/api.yml +++ b/api/api.yml @@ -25,6 +25,20 @@ components: format: uuid example: f0981749-f550-46cd-b9ce-b6ca7cd0251f ############################################# + # PlayerRegistrationData # + ############################################# + PlayerRegistrationData: + description: Data needed to create a new player + type: object + properties: + username: + type: string + password: + type: string + required: + - username + - password + ############################################# # AdminAuthInfo # ############################################# ServerHealth: @@ -45,6 +59,8 @@ components: required: - username responses: + 201PlayerCreated: + description: "201 - Player Created" 401Unauthorized: description: "401 - Unauthorized" 404NotFound: @@ -53,6 +69,12 @@ components: text/plain: schema: type: string + 409UsernameTaken: + description: "409 - Username Taken" + content: + text/plain: + schema: + type: string 409Conflict: description: "409 - Conflict" content: @@ -72,6 +94,24 @@ components: schema: type: string paths: + /player/register: + post: + operationId: "PlayerRegister" + tags: + - server + description: "Endpoint for registering a new Player" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/PlayerRegistrationData" + responses: + 201: + $ref: "#/components/responses/201PlayerCreated" + 409: + $ref: "#/components/responses/409UsernameTaken" + 500: + $ref: "#/components/responses/500InternalError" /server/health: get: operationId: "ServerGetHealthcheck" diff --git a/src/main/java/de/towerdefence/server/player/PlayerRepository.java b/src/main/java/de/towerdefence/server/player/PlayerRepository.java index 39b7d04..5ca4c19 100644 --- a/src/main/java/de/towerdefence/server/player/PlayerRepository.java +++ b/src/main/java/de/towerdefence/server/player/PlayerRepository.java @@ -4,4 +4,5 @@ import org.springframework.data.jpa.repository.JpaRepository; public interface PlayerRepository extends JpaRepository { Player findByUsername(String username); + boolean existsByUsername(String username); } diff --git a/src/main/java/de/towerdefence/server/server/ServerApiController.java b/src/main/java/de/towerdefence/server/server/ServerApiController.java index 01f966e..447660f 100644 --- a/src/main/java/de/towerdefence/server/server/ServerApiController.java +++ b/src/main/java/de/towerdefence/server/server/ServerApiController.java @@ -2,17 +2,30 @@ package de.towerdefence.server.server; import com.fasterxml.jackson.databind.ObjectMapper; import de.towerdefence.server.oas.ServerApi; +import de.towerdefence.server.oas.models.PlayerRegistrationData; import de.towerdefence.server.oas.models.ServerHealth; +import de.towerdefence.server.player.Player; +import de.towerdefence.server.player.PlayerRepository; +import de.towerdefence.server.player.PlayerService; import jakarta.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; +import java.security.NoSuchAlgorithmException; import java.util.Optional; @Controller @RequestMapping("${openapi.api.base-path:/api/v1}") public class ServerApiController implements ServerApi { + + @Autowired + private PlayerRepository playerRepository; + @Autowired + private PlayerService playerService; + @Override public Optional getObjectMapper() { return Optional.empty(); @@ -23,6 +36,22 @@ public class ServerApiController implements ServerApi { return Optional.empty(); } + @Override + public ResponseEntity playerRegister(PlayerRegistrationData body) { + if(playerRepository.existsByUsername(body.getUsername())){ + return new ResponseEntity<>(HttpStatus.CONFLICT); + } + Player newPlayer = new Player(); + newPlayer.setUsername(body.getUsername()); + try{ + playerService.setPassword(newPlayer, body.getPassword()); + } catch (NoSuchAlgorithmException exception){ + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + playerRepository.save(newPlayer); + return new ResponseEntity<>(HttpStatus.CREATED); + } + @Override public ResponseEntity serverGetHealthcheck() { ServerHealth health = new ServerHealth();