From f7630b6754376be03937b8fc4933ed20a1eaff32 Mon Sep 17 00:00:00 2001 From: Laurent Date: Sun, 28 Dec 2025 22:10:13 +0100 Subject: [PATCH] Revert "????????" This reverts commit bc1e598987c13f91df1976f7adea79bfbcd8fa3b. --- api/build.gradle.kts | 4 + api/compose-dev.yaml | 65 --------------- api/compose.yaml | 4 + .../boardmateapi/BoardmateApiApplication.java | 1 + .../boardmateapi/common/models/Client.java | 44 ++++++++++ .../configurations/AppSecurityConfig.java | 33 +++++++- .../configurations/JWTConfig.java | 49 ++++++++++++ .../configurations/SwaggerConfig.java | 21 +++++ .../properties/AppProperties.java | 2 + .../controllers/AuthController.java | 80 +++++++++++++++++++ .../controllers/ClientController.java | 42 ++++++++++ .../controllers/dtos/AuthRequestDto.java | 22 +++++ .../controllers/dtos/AuthResponseDto.java | 40 ++++++++++ .../controllers/dtos/ClientDto.java | 32 ++++++++ .../boardmateapi/repository/ClientRepo.java | 11 +++ .../repository/dtos/ClientDto.java | 59 ++++++++++++++ .../boardmateapi/services/ClientService.java | 56 +++++++++++++ api/src/main/resources/application.properties | 9 ++- 18 files changed, 507 insertions(+), 67 deletions(-) delete mode 100644 api/compose-dev.yaml create mode 100644 api/src/main/java/be/naaturel/boardmateapi/common/models/Client.java create mode 100644 api/src/main/java/be/naaturel/boardmateapi/configurations/configurations/JWTConfig.java create mode 100644 api/src/main/java/be/naaturel/boardmateapi/controllers/AuthController.java create mode 100644 api/src/main/java/be/naaturel/boardmateapi/controllers/ClientController.java create mode 100644 api/src/main/java/be/naaturel/boardmateapi/controllers/dtos/AuthRequestDto.java create mode 100644 api/src/main/java/be/naaturel/boardmateapi/controllers/dtos/AuthResponseDto.java create mode 100644 api/src/main/java/be/naaturel/boardmateapi/controllers/dtos/ClientDto.java create mode 100644 api/src/main/java/be/naaturel/boardmateapi/repository/ClientRepo.java create mode 100644 api/src/main/java/be/naaturel/boardmateapi/repository/dtos/ClientDto.java create mode 100644 api/src/main/java/be/naaturel/boardmateapi/services/ClientService.java diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 465d08c0..4bbce8f3 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -54,6 +54,10 @@ dependencies { //======================PROMETHEUS====================== runtimeOnly("io.micrometer:micrometer-registry-prometheus") + //======================JWT====================== + implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server") + implementation("org.springframework.security:spring-security-oauth2-jose") + //======================OTHER====================== developmentOnly("org.springframework.boot:spring-boot-devtools") developmentOnly("org.springframework.boot:spring-boot-docker-compose") diff --git a/api/compose-dev.yaml b/api/compose-dev.yaml deleted file mode 100644 index 7854f017..00000000 --- a/api/compose-dev.yaml +++ /dev/null @@ -1,65 +0,0 @@ -services: - boardmate-api: - build: - context: . - dockerfile: Dockerfile - container_name: boardmate-api - ports: - - "8000:8080" - - "5005:5005" - environment: - SPRING_DATA_MONGODB_URI: "mongodb://board-mate-user:apx820kcng@mongodb:27017/board-mate-db" - JAVA_TOOL_OPTIONS: "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" - depends_on: - - mongodb - - elasticsearch - volumes: - - ./.gradle:/home/gradle/.gradle # Use your existing local Gradle and build directories - - ./build:/app/.gradle # optional, only if you want project cache mapped too - - elasticsearch: - image: 'docker.elastic.co/elasticsearch/elasticsearch:7.17.10' - environment: - - 'ELASTIC_PASSWORD=secret' - - 'discovery.type=single-node' - - 'xpack.security.enabled=false' - ports: - - '8100:9200' - - '8101:9300' - grafana-lgtm: - image: 'grafana/otel-lgtm:latest' - ports: - - '8200:3000' - - '8201:4317' - - '8202:4318' - prometheus: - image: 'prom/prometheus:latest' - container_name: prometheus - ports: - - "8300:9090" - volumes: - - ./prometheus.yaml:/etc/prometheus/prometheus.yml - - mongodb: - image: mongo:latest - environment: - - MONGO_INITDB_DATABASE=board-mate-db - - MONGO_INITDB_ROOT_PASSWORD=secret - - MONGO_INITDB_ROOT_USERNAME=root - ports: - - "8400:27017" - volumes: - - ./mongo-data:/data/db - - ./mongo-init:/docker-entrypoint-initdb.d - #mongo-express: - # image: mongo-express:latest - # depends_on: - # - mongodb - # ports: - # - "8401:8081" - # environment: - # - ME_CONFIG_MONGODB_SERVER=mongodb - # - ME_CONFIG_MONGODB_PORT=27017 - # - ME_CONFIG_MONGODB_ADMINUSERNAME=root - # - ME_CONFIG_MONGODB_ADMINPASSWORD=secret - # - ME_CONFIG_MONGODB_AUTH_DATABASE=admin \ No newline at end of file diff --git a/api/compose.yaml b/api/compose.yaml index 9dc0bbcc..fdb279c7 100644 --- a/api/compose.yaml +++ b/api/compose.yaml @@ -6,7 +6,10 @@ services: container_name: boardmate-api ports: - "8000:8080" + - "5005:5005" environment: + JWT_SECRET: "enY3OWU4djFyMTByNTZhcG9uY3Z0djQ5cnY0eDhhNWM0bjg5OTRjNDhidA==" + SSL_KEYSTORE_PATH: "/certs/keystore.p12" SPRING_DATA_MONGODB_URI: "mongodb://board-mate-user:apx820kcng@mongodb:27017/board-mate-db" JAVA_TOOL_OPTIONS: "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" depends_on: @@ -16,6 +19,7 @@ services: volumes: - ./.gradle:/home/gradle/.gradle - ./build:/app/.gradle + - ./certs:/certs elasticsearch: image: 'docker.elastic.co/elasticsearch/elasticsearch:7.17.10' diff --git a/api/src/main/java/be/naaturel/boardmateapi/BoardmateApiApplication.java b/api/src/main/java/be/naaturel/boardmateapi/BoardmateApiApplication.java index 23ece7f0..cff862fa 100644 --- a/api/src/main/java/be/naaturel/boardmateapi/BoardmateApiApplication.java +++ b/api/src/main/java/be/naaturel/boardmateapi/BoardmateApiApplication.java @@ -3,6 +3,7 @@ package be.naaturel.boardmateapi; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; + @SpringBootApplication public class BoardmateApiApplication { diff --git a/api/src/main/java/be/naaturel/boardmateapi/common/models/Client.java b/api/src/main/java/be/naaturel/boardmateapi/common/models/Client.java new file mode 100644 index 00000000..ab8fdb95 --- /dev/null +++ b/api/src/main/java/be/naaturel/boardmateapi/common/models/Client.java @@ -0,0 +1,44 @@ +package be.naaturel.boardmateapi.common.models; + +public class Client { + + private String id; + private String name; + private String username; + private String key; + + public Client(String id, String name, String username, String key){ + this.id = id; + this.name = name; + this.username = username; + this.key = key; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getUsername() { + return username; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } +} diff --git a/api/src/main/java/be/naaturel/boardmateapi/configurations/configurations/AppSecurityConfig.java b/api/src/main/java/be/naaturel/boardmateapi/configurations/configurations/AppSecurityConfig.java index 23ca6582..bdb92f81 100644 --- a/api/src/main/java/be/naaturel/boardmateapi/configurations/configurations/AppSecurityConfig.java +++ b/api/src/main/java/be/naaturel/boardmateapi/configurations/configurations/AppSecurityConfig.java @@ -1,18 +1,30 @@ package be.naaturel.boardmateapi.configurations.configurations; import be.naaturel.boardmateapi.configurations.properties.AppProperties; +import com.nimbusds.jose.jwk.source.ImmutableSecret; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; 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.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.jwt.JwtEncoder; +import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; +import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; import java.util.Arrays; @Configuration @@ -28,10 +40,29 @@ public class AppSecurityConfig { } @Bean - public SecurityFilterChain filterChain(HttpSecurity http) { + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + @Bean + SecurityFilterChain filterChain(HttpSecurity http, @Autowired JwtDecoder jwtDecoder) throws Exception { return http .csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(auth -> auth + .requestMatchers( + "/health", + "/actuator/**", + "/v3/api-docs/**", + "/v3/api-docs/swagger-config", + "/webjars/**", + "/swagger-ui/**", + "/docs/**", + "/v1/docs/**", + "/swagger-ui.html", + "/authenticate", + "/client/create").permitAll() + .anyRequest().authenticated() + ).oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())) .build(); } diff --git a/api/src/main/java/be/naaturel/boardmateapi/configurations/configurations/JWTConfig.java b/api/src/main/java/be/naaturel/boardmateapi/configurations/configurations/JWTConfig.java new file mode 100644 index 00000000..733cd846 --- /dev/null +++ b/api/src/main/java/be/naaturel/boardmateapi/configurations/configurations/JWTConfig.java @@ -0,0 +1,49 @@ +package be.naaturel.boardmateapi.configurations.configurations; + +import be.naaturel.boardmateapi.configurations.properties.AppProperties; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.jwk.JWKSet; +import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.OctetSequenceKey; +import com.nimbusds.jose.jwk.source.ImmutableSecret; +import com.nimbusds.jose.jwk.source.JWKSource; +import com.nimbusds.jose.proc.SecurityContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.jwt.JwtEncoder; +import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; +import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +@Configuration +public class JWTConfig { + + private final AppProperties conf; + + @Autowired + public JWTConfig(AppProperties appConf) { + this.conf = appConf; + } + + @Bean + public JwtEncoder jwtEncoder() { + byte[] keyBytes = Base64.getDecoder().decode(conf.jwtSecret); + SecretKey key = new SecretKeySpec(keyBytes, "HmacSHA256"); + return new NimbusJwtEncoder(new ImmutableSecret<>(key)); + } + + @Bean + public JwtDecoder jwtDecoder() { + byte[] keyBytes = Base64.getDecoder().decode(conf.jwtSecret); + SecretKey key = new SecretKeySpec(keyBytes, "HmacSHA256"); + return NimbusJwtDecoder.withSecretKey(key).build(); + } +} diff --git a/api/src/main/java/be/naaturel/boardmateapi/configurations/configurations/SwaggerConfig.java b/api/src/main/java/be/naaturel/boardmateapi/configurations/configurations/SwaggerConfig.java index 75afbf68..4df5a16f 100644 --- a/api/src/main/java/be/naaturel/boardmateapi/configurations/configurations/SwaggerConfig.java +++ b/api/src/main/java/be/naaturel/boardmateapi/configurations/configurations/SwaggerConfig.java @@ -1,8 +1,29 @@ package be.naaturel.boardmateapi.configurations.configurations; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SwaggerConfig { + @Bean + public OpenAPI customOpenAPI() { + final String securitySchemeName = "bearerAuth"; + return new OpenAPI() + .addSecurityItem(new SecurityRequirement().addList(securitySchemeName)) + .components( + new Components() + .addSecuritySchemes(securitySchemeName, + new SecurityScheme() + .name(securitySchemeName) + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + ) + ); + } } \ No newline at end of file diff --git a/api/src/main/java/be/naaturel/boardmateapi/configurations/properties/AppProperties.java b/api/src/main/java/be/naaturel/boardmateapi/configurations/properties/AppProperties.java index 5de097a0..dbae13e4 100644 --- a/api/src/main/java/be/naaturel/boardmateapi/configurations/properties/AppProperties.java +++ b/api/src/main/java/be/naaturel/boardmateapi/configurations/properties/AppProperties.java @@ -21,4 +21,6 @@ public class AppProperties { @Value("${spring.mongodb.database}") public String database; + @Value("${jwt.secret}") + public String jwtSecret; } diff --git a/api/src/main/java/be/naaturel/boardmateapi/controllers/AuthController.java b/api/src/main/java/be/naaturel/boardmateapi/controllers/AuthController.java new file mode 100644 index 00000000..2b58bab9 --- /dev/null +++ b/api/src/main/java/be/naaturel/boardmateapi/controllers/AuthController.java @@ -0,0 +1,80 @@ +package be.naaturel.boardmateapi.controllers; + +import be.naaturel.boardmateapi.common.models.Client; +import be.naaturel.boardmateapi.controllers.dtos.*; +import be.naaturel.boardmateapi.services.ClientService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.oauth2.jose.jws.MacAlgorithm; +import org.springframework.security.oauth2.jwt.JwsHeader; +import org.springframework.security.oauth2.jwt.JwtClaimsSet; +import org.springframework.security.oauth2.jwt.JwtEncoder; +import org.springframework.security.oauth2.jwt.JwtEncoderParameters; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.time.Instant; + +@RestController +public class AuthController { + + private final ClientService service; + private final JwtEncoder jwtEncoder; + + @Autowired + public AuthController(ClientService service, JwtEncoder jwtEncoder) { + this.service = service; + this.jwtEncoder = jwtEncoder; + } + + @PostMapping("/authenticate") + public ResponseEntity> login(@RequestBody AuthRequestDto request) { + ResponseBody result = ResponseBody.createEmpty(); + try { + Client user = service.authenticate( + request.getUsername(), + request.getKey() + ); + + Instant now = Instant.now(); + + JwtClaimsSet claims = JwtClaimsSet.builder() + .subject(user.getId()) + .claim("name", user.getName()) + .claim("username", user.getUsername()) + .issuedAt(now) + .expiresAt(now.plusSeconds(3600*12)) + .build(); + + JwtEncoderParameters params = + JwtEncoderParameters.from( + JwsHeader.with(MacAlgorithm.HS256).build(), + claims + ); + + String token = jwtEncoder.encode(params).getTokenValue(); + + AuthResponseDto response = new AuthResponseDto(); + response.setName(user.getName()); + response.setUsername(user.getUsername()); + response.setClientId(user.getId()); + response.setAuthToken(token); + + result.setSuccess(true); + result.setData(response); + return ResponseEntity + .status(HttpStatus.OK) + .body(result); + + } catch (Exception e){ + e.printStackTrace(); + result.setMessage(e.getMessage()); + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(result); + } + } + +} diff --git a/api/src/main/java/be/naaturel/boardmateapi/controllers/ClientController.java b/api/src/main/java/be/naaturel/boardmateapi/controllers/ClientController.java new file mode 100644 index 00000000..dcf9d99f --- /dev/null +++ b/api/src/main/java/be/naaturel/boardmateapi/controllers/ClientController.java @@ -0,0 +1,42 @@ +package be.naaturel.boardmateapi.controllers; + +import be.naaturel.boardmateapi.controllers.dtos.AuthRequestDto; +import be.naaturel.boardmateapi.controllers.dtos.AuthResponseDto; +import be.naaturel.boardmateapi.controllers.dtos.ClientDto; +import be.naaturel.boardmateapi.controllers.dtos.ResponseBody; +import be.naaturel.boardmateapi.services.ClientService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ClientController { + + private final ClientService service; + + @Autowired + public ClientController(ClientService service){ + this.service = service; + } + + + @PostMapping("/client/create") + public ResponseEntity> create(@RequestBody ClientDto dto) { + ResponseBody result = ResponseBody.createEmpty(); + try{ + String clientId = service.create(dto.getName(), dto.getUsername(), dto.getKey()); + result.setData(clientId); + return ResponseEntity. + status(HttpStatus.OK) + .body(result); + } catch (Exception e){ + result.setMessage(e.getMessage()); + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(result); + } + } +} diff --git a/api/src/main/java/be/naaturel/boardmateapi/controllers/dtos/AuthRequestDto.java b/api/src/main/java/be/naaturel/boardmateapi/controllers/dtos/AuthRequestDto.java new file mode 100644 index 00000000..57c55a4e --- /dev/null +++ b/api/src/main/java/be/naaturel/boardmateapi/controllers/dtos/AuthRequestDto.java @@ -0,0 +1,22 @@ +package be.naaturel.boardmateapi.controllers.dtos; + +public class AuthRequestDto { + private String username; + private String key; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } +} diff --git a/api/src/main/java/be/naaturel/boardmateapi/controllers/dtos/AuthResponseDto.java b/api/src/main/java/be/naaturel/boardmateapi/controllers/dtos/AuthResponseDto.java new file mode 100644 index 00000000..9b8628db --- /dev/null +++ b/api/src/main/java/be/naaturel/boardmateapi/controllers/dtos/AuthResponseDto.java @@ -0,0 +1,40 @@ +package be.naaturel.boardmateapi.controllers.dtos; + +public class AuthResponseDto { + private String clientId; + private String name; + private String username; + private String authToken; + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAuthToken() { + return authToken; + } + + public void setAuthToken(String authToken) { + this.authToken = authToken; + } +} diff --git a/api/src/main/java/be/naaturel/boardmateapi/controllers/dtos/ClientDto.java b/api/src/main/java/be/naaturel/boardmateapi/controllers/dtos/ClientDto.java new file mode 100644 index 00000000..66cdc40f --- /dev/null +++ b/api/src/main/java/be/naaturel/boardmateapi/controllers/dtos/ClientDto.java @@ -0,0 +1,32 @@ +package be.naaturel.boardmateapi.controllers.dtos; + +public class ClientDto { + + private String name; + private String username; + private String key; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } +} diff --git a/api/src/main/java/be/naaturel/boardmateapi/repository/ClientRepo.java b/api/src/main/java/be/naaturel/boardmateapi/repository/ClientRepo.java new file mode 100644 index 00000000..c860655c --- /dev/null +++ b/api/src/main/java/be/naaturel/boardmateapi/repository/ClientRepo.java @@ -0,0 +1,11 @@ +package be.naaturel.boardmateapi.repository; + + +import be.naaturel.boardmateapi.repository.dtos.ClientDto; +import org.springframework.data.mongodb.repository.MongoRepository; + +import java.util.Optional; + +public interface ClientRepo extends MongoRepository { + Optional findByServiceUsername(String serviceUsername); +} diff --git a/api/src/main/java/be/naaturel/boardmateapi/repository/dtos/ClientDto.java b/api/src/main/java/be/naaturel/boardmateapi/repository/dtos/ClientDto.java new file mode 100644 index 00000000..aa289db1 --- /dev/null +++ b/api/src/main/java/be/naaturel/boardmateapi/repository/dtos/ClientDto.java @@ -0,0 +1,59 @@ +package be.naaturel.boardmateapi.repository.dtos; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +@Document(collection = "clients") +public class ClientDto { + @Id + private String id; + + @Field("name") + private String name; + + @Field("clientId") + private String clientId; + + @Field("serviceUsername") + private String serviceUsername; + + @Field("serviceKey") + private String serviceKey; + + public String getId() { + return id; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getServiceUsername() { + return serviceUsername; + } + + public void setServiceUsername(String serviceUsername) { + this.serviceUsername = serviceUsername; + } + + public void setServiceKey(String serviceKey) { + this.serviceKey = serviceKey; + } + + public String getServiceKey() { + return serviceKey; + } +} diff --git a/api/src/main/java/be/naaturel/boardmateapi/services/ClientService.java b/api/src/main/java/be/naaturel/boardmateapi/services/ClientService.java new file mode 100644 index 00000000..de1a533a --- /dev/null +++ b/api/src/main/java/be/naaturel/boardmateapi/services/ClientService.java @@ -0,0 +1,56 @@ +package be.naaturel.boardmateapi.services; + +import be.naaturel.boardmateapi.common.exceptions.ServiceException; +import be.naaturel.boardmateapi.common.models.Client; +import be.naaturel.boardmateapi.repository.ClientRepo; +import be.naaturel.boardmateapi.repository.dtos.ClientDto; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +import static java.util.UUID.randomUUID; + +@Service +public class ClientService { + + private final ClientRepo repo; + private final PasswordEncoder passwordEncoder; + + @Autowired + public ClientService(ClientRepo repo, PasswordEncoder passwordEncoder){ + this.repo = repo; + this.passwordEncoder = passwordEncoder; + } + + public Client authenticate(String username, String key) throws ServiceException { + try { + ClientDto dto = repo.findByServiceUsername(username) + .orElseThrow(() -> new RuntimeException("Invalid username")); + + if (passwordEncoder.matches(key, dto.getServiceKey())) { + return new Client(dto.getClientId(), dto.getName(), dto.getServiceUsername(), dto.getServiceKey()); + } else { + throw new RuntimeException("Invalid username or password"); + } + } catch (Exception e){ + throw new ServiceException("Authentication failed", e); + } + } + + public String create(String name, String username, String key) throws ServiceException { + try{ + ClientDto dto = new ClientDto(); + dto.setClientId(randomUUID().toString()); + dto.setName(name); + dto.setServiceUsername(username); + String encodedKey = passwordEncoder.encode(key); + dto.setServiceKey(encodedKey); + ClientDto result = repo.save(dto); + return result.getClientId(); + } catch (Exception e){ + throw new ServiceException("Unable to create client", e); + } + } +} diff --git a/api/src/main/resources/application.properties b/api/src/main/resources/application.properties index d7571f8a..f74f8c0c 100644 --- a/api/src/main/resources/application.properties +++ b/api/src/main/resources/application.properties @@ -10,13 +10,20 @@ sec.cors.authorizedHots=* sec.cors.authorizedMethods=GET,POST,PUT,DELETE,OPTION sec.cors.authorizedHeader=Authorization,Content-type +jwt.secret=${JWT_SECRET} +jwt.expiration=3600 + +server.ssl.key-store=${SSL_KEYSTORE_PATH} +server.ssl.key-store-password=heplhepl +server.ssl.key-store-type=PKCS12 +server.ssl.key-alias=board-mate-api + #=============MQTT============= mqtt.broker-url=tcp://test.mosquitto.org:1883 mqtt.client-id=board-mate-client mqtt.topic=board-mate-test/topic - mqtt.username=yourUsername mqtt.password=yourPassword #=============METRICS=============