Skip to content

Commit ebf428e

Browse files
authored
Merge pull request #12 from ftn-projects/feature/sign-and-verify
Key Sign/Verify and logging system restructuring
2 parents 3cc6e25 + 8c8da2a commit ebf428e

15 files changed

Lines changed: 240 additions & 276 deletions

File tree

MiniKms/logs/controller.log

Lines changed: 0 additions & 208 deletions
This file was deleted.

MiniKms/logs/entity.log

Lines changed: 0 additions & 4 deletions
This file was deleted.

MiniKms/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@
9191
<artifactId>mapstruct</artifactId>
9292
<version>1.6.0</version>
9393
</dependency>
94+
<dependency>
95+
<groupId>net.logstash.logback</groupId>
96+
<artifactId>logstash-logback-encoder</artifactId>
97+
<version>8.1</version>
98+
</dependency>
99+
94100
</dependencies>
95101

96102
<build>

MiniKms/src/main/java/ftn/security/minikms/config/SecurityConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
5454
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
5555
.requestMatchers("/api/v1/auth/**").permitAll()
5656
.requestMatchers("/api/v1/test/**").permitAll()
57+
.requestMatchers("/api/v1/crypto/**").permitAll()
58+
.requestMatchers("/api/v1/signatures/**").permitAll()
5759
.requestMatchers(HttpMethod.GET, "/api/v1/keys/**").authenticated() // Allow all roles to GET
5860
.requestMatchers("/api/v1/keys/**").hasRole("MANAGER")
5961
.anyRequest().authenticated()
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package ftn.security.minikms.controller;
2+
3+
import ftn.security.minikms.dto.SignRequestDTO;
4+
import ftn.security.minikms.dto.VerifyRequestDTO;
5+
import ftn.security.minikms.service.SignatureService;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.http.HttpStatus;
8+
import org.springframework.http.ResponseEntity;
9+
import org.springframework.transaction.annotation.Transactional;
10+
import org.springframework.web.bind.annotation.*;
11+
12+
import java.security.GeneralSecurityException;
13+
import java.security.Principal;
14+
import java.util.Base64;
15+
import java.util.UUID;
16+
17+
@RestController
18+
@RequestMapping("/api/v1/signatures")
19+
public class SignatureController {
20+
21+
@Autowired
22+
private SignatureService signatureService;
23+
24+
@PostMapping("/sign")
25+
@Transactional(readOnly = true)
26+
public ResponseEntity<String> sign(@RequestParam UUID keyId,
27+
@RequestBody SignRequestDTO request) {
28+
try {
29+
byte[] signature = signatureService.sign(keyId, request.getMessage(), request.getVersion());
30+
return ResponseEntity.ok(Base64.getEncoder().encodeToString(signature));
31+
} catch (GeneralSecurityException | IllegalArgumentException e) {
32+
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
33+
}
34+
}
35+
36+
@PostMapping("/verify")
37+
@Transactional(readOnly = true)
38+
public ResponseEntity<String> verify(@RequestParam UUID keyId,
39+
@RequestParam(required = false) Integer version,
40+
@RequestBody VerifyRequestDTO req) {
41+
try {
42+
boolean valid = signatureService.verify(
43+
keyId,
44+
req.getMessage(),
45+
Base64.getDecoder().decode(req.getSignature()),
46+
version
47+
);
48+
return ResponseEntity.ok(valid ? "VALID" : "INVALID");
49+
} catch (GeneralSecurityException | IllegalArgumentException e) {
50+
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
51+
}
52+
}
53+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package ftn.security.minikms.dto;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class SignRequestDTO {
7+
private String message;
8+
private Integer version;
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package ftn.security.minikms.dto;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class VerifyRequestDTO {
7+
private String message;
8+
private String signature;
9+
}

MiniKms/src/main/java/ftn/security/minikms/logging/EntityLogger.java

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,41 @@
22

33
import jakarta.persistence.*;
44
import lombok.extern.slf4j.Slf4j;
5+
import org.springframework.beans.factory.annotation.Value;
6+
7+
import java.util.Map;
58

69
@Slf4j
710
public class EntityLogger {
811

9-
@PrePersist
10-
public void prePersist(Object entity) {
11-
log.info("Creating: {}", entity);
12+
@Value("${logging.entity.enabled:true}")
13+
private boolean loggingEnabled;
14+
15+
private void logEntity(String action, String phase, Object entity) {
16+
if (!loggingEnabled) return;
17+
18+
log.info("{}", Map.of(
19+
"action", action,
20+
"phase", phase,
21+
"entity", entity.getClass().getSimpleName()
22+
));
1223
}
1324

25+
@PrePersist
26+
public void prePersist(Object entity) { logEntity("create", "pre", entity); }
27+
1428
@PostPersist
15-
public void postPersist(Object entity) {
16-
log.info("Created: {}", entity);
17-
}
29+
public void postPersist(Object entity) { logEntity("create", "post", entity); }
1830

1931
@PreUpdate
20-
public void preUpdate(Object entity) {
21-
log.info("Updating: {}", entity);
22-
}
32+
public void preUpdate(Object entity) { logEntity("update", "pre", entity); }
2333

2434
@PostUpdate
25-
public void postUpdate(Object entity) {
26-
log.info("Updated: {}", entity);
27-
}
35+
public void postUpdate(Object entity) { logEntity("update", "post", entity); }
2836

2937
@PreRemove
30-
public void preRemove(Object entity) {
31-
log.info("Deleting: {}", entity);
32-
}
38+
public void preRemove(Object entity) { logEntity("delete", "pre", entity); }
3339

3440
@PostRemove
35-
public void postRemove(Object entity) {
36-
log.info("Deleted: {}", entity);
37-
}
41+
public void postRemove(Object entity) { logEntity("delete", "post", entity); }
3842
}

MiniKms/src/main/java/ftn/security/minikms/logging/RequestResponseLoggingFilter.java

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,57 +5,56 @@
55
import jakarta.servlet.http.HttpServletRequest;
66
import jakarta.servlet.http.HttpServletResponse;
77
import lombok.extern.slf4j.Slf4j;
8+
import org.springframework.beans.factory.annotation.Value;
89
import org.springframework.stereotype.Component;
910
import org.springframework.web.filter.OncePerRequestFilter;
10-
import org.springframework.web.util.ContentCachingRequestWrapper;
11-
import org.springframework.web.util.ContentCachingResponseWrapper;
1211

1312
import java.io.IOException;
14-
import java.nio.charset.StandardCharsets;
13+
import java.util.Map;
1514
import java.util.UUID;
1615

1716
@Slf4j
1817
@Component
1918
public class RequestResponseLoggingFilter extends OncePerRequestFilter {
2019

20+
@Value("${logging.controller.enabled:true}")
21+
private boolean loggingEnabled;
22+
2123
@Override
2224
protected void doFilterInternal(HttpServletRequest request,
2325
HttpServletResponse response,
2426
FilterChain filterChain) throws ServletException, IOException {
2527

26-
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
27-
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
28+
if (!loggingEnabled) {
29+
filterChain.doFilter(request, response);
30+
return;
31+
}
2832

2933
String requestId = request.getHeader("X-Request-ID");
3034
if (requestId == null || requestId.isBlank()) {
3135
requestId = UUID.randomUUID().toString();
3236
}
37+
response.setHeader("X-Request-ID", requestId);
3338

34-
responseWrapper.setHeader("X-Request-ID", requestId);
39+
String username = request.getUserPrincipal() != null
40+
? request.getUserPrincipal().getName()
41+
: "anonymous";
3542

3643
long start = System.currentTimeMillis();
3744
try {
38-
filterChain.doFilter(requestWrapper, responseWrapper);
45+
filterChain.doFilter(request, response);
3946
} finally {
4047
long duration = System.currentTimeMillis() - start;
4148

42-
String requestBody = new String(requestWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
43-
log.info("[{}] REQUEST {} {} | Body={}",
44-
requestId,
45-
request.getMethod(),
46-
request.getRequestURI(),
47-
requestBody);
48-
49-
String responseBody = new String(responseWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
50-
log.info("[{}] RESPONSE {} {} | Status={} | Duration={}ms | Body={}",
51-
requestId,
52-
request.getMethod(),
53-
request.getRequestURI(),
54-
responseWrapper.getStatus(),
55-
duration,
56-
responseBody);
57-
58-
responseWrapper.copyBodyToResponse();
49+
log.info("{}", Map.of(
50+
"message", "HTTP request completed",
51+
"requestId", requestId,
52+
"username", username,
53+
"method", request.getMethod(),
54+
"uri", request.getRequestURI(),
55+
"status", response.getStatus(),
56+
"durationMs", duration
57+
));
5958
}
6059
}
6160
}

MiniKms/src/main/java/ftn/security/minikms/repository/KeyMetadataRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import ftn.security.minikms.entity.KeyMetadata;
44
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.data.jpa.repository.Query;
6+
import org.springframework.data.repository.query.Param;
57

68
import java.util.UUID;
79

0 commit comments

Comments
 (0)