Skip to content

Commit

Permalink
Experimenting with signing.
Browse files Browse the repository at this point in the history
  • Loading branch information
jzonthemtn committed Nov 25, 2024
1 parent 7551623 commit 3e196a3
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 17 deletions.
2 changes: 1 addition & 1 deletion distribution/example-filter.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/bash
curl -k "https://localhost:8080/api/filter" \
curl "http://localhost:8080/api/filter" \
--data "George Washington was president and his ssn was 123-45-6789 and he lived in 90210." -H "Content-type: text/plain"
9 changes: 0 additions & 9 deletions distribution/policies/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,6 @@
"ignored": [],
"identifiers": {
"dictionaries": [],
"person": {
"phEyeConfiguration": {
"endpoint": "http://philter-ph-eye-1:5000"
},
"personFilterStrategies": [{
"strategy": "REDACT",
"redactionFormat": "{{{REDACTED-%t}}}"
}]
},
"age": {
"ageFilterStrategies": [{
"strategy": "REDACT",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ai.philterd.philter.api;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.TEXT_PLAIN);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public ExplainApiController(FilterService filterService, Gson gson) {
final FilterResponse response = filterService.filter(policies, context, documentId, body, MimeType.TEXT_PLAIN);

return ResponseEntity.status(HttpStatus.OK)
.header("x-document-id", response.documentId())
.header("x-document-id", response.getDocumentId())
.contentType(MediaType.APPLICATION_JSON)
.body(gson.toJson(response));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package ai.philterd.philter.api.controllers;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Filter;

import ai.philterd.philter.api.model.SignedFilterResponse;
import ai.philterd.philter.services.PhilterService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand Down Expand Up @@ -45,7 +47,7 @@ public FilterApiController(FilterService filterService) {

LOGGER.info("Received uploaded binary PDF file to be returned as ZIP.");

final List<String> policies = Arrays.asList(policyName);
final List<String> policies = Collections.singletonList(policyName);
final BinaryDocumentFilterResponse response = filterService.filter(policies, context, documentId, body, MimeType.APPLICATION_PDF, MimeType.IMAGE_JPEG);

return ResponseEntity.status(HttpStatus.OK)
Expand All @@ -63,7 +65,7 @@ public FilterApiController(FilterService filterService) {

LOGGER.info("Received uploaded binary PDF file to be returned as PDF.");

final List<String> policies = Arrays.asList(policyName);
final List<String> policies = Collections.singletonList(policyName);
final BinaryDocumentFilterResponse response = filterService.filter(policies, context, documentId, body, MimeType.APPLICATION_PDF, MimeType.APPLICATION_PDF);

return ResponseEntity.status(HttpStatus.OK)
Expand All @@ -72,19 +74,35 @@ public FilterApiController(FilterService filterService) {

}

@RequestMapping(value="/api/filter", method=RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.TEXT_PLAIN_VALUE)
public @ResponseBody ResponseEntity<FilterResponse> filterTextPlainAsJson(
@RequestParam(value="c", defaultValue="none") String context,
@RequestParam(value="d", defaultValue="") String documentId,
@RequestParam(value="p", defaultValue="default") String policyName,
@RequestBody String body) throws Exception {

final List<String> policies = Collections.singletonList(policyName);
final FilterResponse response = filterService.filter(policies, context, documentId, body, MimeType.TEXT_PLAIN);

return ResponseEntity.status(HttpStatus.OK)
.header("x-document-id", response.getDocumentId())
.body(response);

}

@RequestMapping(value="/api/filter", method=RequestMethod.POST, produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.TEXT_PLAIN_VALUE)
public @ResponseBody ResponseEntity<String> filterTextPlainAsTextPlain(
@RequestParam(value="c", defaultValue="none") String context,
@RequestParam(value="d", defaultValue="") String documentId,
@RequestParam(value="p", defaultValue="default") String policyName,
@RequestBody String body) throws Exception {

final List<String> policies = Arrays.asList(policyName);
final List<String> policies = Collections.singletonList(policyName);
final FilterResponse response = filterService.filter(policies, context, documentId, body, MimeType.TEXT_PLAIN);

return ResponseEntity.status(HttpStatus.OK)
.header("x-document-id", response.documentId())
.body(response.filteredText());
.header("x-document-id", response.getDocumentId())
.body(response.getFilteredText());

}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ai.philterd.philter.api.model;

import ai.philterd.phileas.model.responses.FilterResponse;

public class SignedFilterResponse extends FilterResponse {

private final String signature;

public SignedFilterResponse(final FilterResponse filterResponse, String signature) {
super(filterResponse.getFilteredText(), filterResponse.getContext(), filterResponse.getDocumentId(), filterResponse.getPiece(), filterResponse.getExplanation(), filterResponse.getAttributes());
this.signature = signature;
}

public String getSignature() {
return signature;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package ai.philterd.test.philter.api;

import org.junit.Assert;
import org.junit.Test;

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.util.Base64;

public class SignTextTest {

@Test
public void test() throws Exception {

// Have to create the private/public keys.
// Have to sign the text and send back the signature

// Load private key for signing:
// keytool -genkeypair -alias senderKeyPair -keyalg RSA -keysize 2048 -dname "CN=Baeldung" -validity 365 -storetype JKS -keystore sender_keystore.jks -storepass changeit

// Export public key:
// keytool -exportcert -alias senderKeyPair -storetype JKS -keystore sender_keystore.jks -file sender_certificate.cer -rfc -storepass changeit

final KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream("/tmp/sender_keystore.jks"), "changeit".toCharArray());

final PrivateKey privateKey = (PrivateKey) keyStore.getKey("senderKeyPair", "changeit".toCharArray());

// Create empty key store on the receiver side.
// keytool -genkeypair -alias receiverKeyPair -keyalg RSA -keysize 2048 -dname "CN=Baeldung" -validity 365 -storetype JKS -keystore receiver_keystore.jks -storepass changeit
// keytool -delete -alias receiverKeyPair -storepass changeit -keystore receiver_keystore.jks

// Import the public key into the empty key store.
// keytool -importcert -alias receiverKeyPair -storetype JKS -keystore receiver_keystore.jks -file sender_certificate.cer -rfc -storepass changeit

// Load the public key

final KeyStore keyStore2 = KeyStore.getInstance("JKS");
keyStore2.load(new FileInputStream("/tmp/receiver_keystore.jks"), "changeit".toCharArray());
final Certificate certificate = keyStore2.getCertificate("receiverKeyPair");
final PublicKey publicKey = certificate.getPublicKey();

//final String encodedPublicKey = Base64.getEncoder().encodeToString(publicKey.getEncoded());
//System.out.println(encodedPublicKey);

// ---------------------------

final Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);

final byte[] messageBytes = "hello world".getBytes();

signature.update(messageBytes);
final byte[] digitalSignature = signature.sign();

// Convert the signature to a string to be returned.
final String encodedDigitalSignature = Base64.getEncoder().encodeToString(digitalSignature);
//System.out.println(encodedDigitalSignature);

boolean valid = verify(encodedDigitalSignature, "hello world");

Assert.assertTrue(valid);

}

public boolean verify(final String digitalSignature, final String redactedText) throws Exception {

// Load the public key

final KeyStore keyStore2 = KeyStore.getInstance("JKS");
keyStore2.load(new FileInputStream("/tmp/receiver_keystore.jks"), "changeit".toCharArray());

final Certificate certificate = keyStore2.getCertificate("receiverKeyPair");
final PublicKey publicKey = certificate.getPublicKey();

final String encodedPublicKey = Base64.getEncoder().encodeToString(publicKey.getEncoded());
//System.out.println(encodedPublicKey);

final Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);

byte[] messageBytes = "hello world".getBytes();

signature.update(messageBytes);

return signature.verify(Base64.getDecoder().decode(digitalSignature));

}

}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
<junit.version>4.13.2</junit.version>
<micrometer.version>1.13.3</micrometer.version>
<mockito.version>1.10.19</mockito.version>
<phileas.version>2.9.1</phileas.version>
<phileas.version>2.10.0-SNAPSHOT</phileas.version>
<philter.sdk.version>1.4.0</philter.sdk.version>
<spring.boot.version>3.3.1</spring.boot.version>
<spring.version>6.1.10</spring.version>
Expand Down

0 comments on commit 3e196a3

Please sign in to comment.