dev.fitko.fitconnect.core.cases.SecurityEventTokenService Maven / Gradle / Ivy
package dev.fitko.fitconnect.core.cases;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import dev.fitko.fitconnect.api.config.ApplicationConfig;
import dev.fitko.fitconnect.api.domain.model.event.Event;
import dev.fitko.fitconnect.api.domain.model.event.EventClaimFields;
import dev.fitko.fitconnect.api.domain.model.event.EventHeaderFields;
import dev.fitko.fitconnect.api.domain.model.event.EventPayload;
import dev.fitko.fitconnect.api.domain.model.event.authtags.AuthenticationTags;
import dev.fitko.fitconnect.api.domain.validation.ValidationResult;
import dev.fitko.fitconnect.api.exceptions.internal.EventCreationException;
import dev.fitko.fitconnect.api.exceptions.internal.ValidationException;
import dev.fitko.fitconnect.api.services.events.SecurityEventService;
import dev.fitko.fitconnect.api.services.validation.ValidationService;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import static dev.fitko.fitconnect.api.domain.model.event.Event.ACCEPT_SUBMISSION;
import static dev.fitko.fitconnect.api.domain.model.event.Event.REJECT_SUBMISSION;
public class SecurityEventTokenService implements SecurityEventService {
private final RSAKey signingKey;
private final ValidationService validationService;
private final ApplicationConfig config;
public SecurityEventTokenService(final ApplicationConfig config, final ValidationService validationService, final RSAKey signingKey) {
this.config = config;
this.signingKey = signingKey;
this.validationService = validationService;
}
@Override
public SignedJWT createAcceptSubmissionEvent(final EventPayload eventPayload) {
return signJWT(ACCEPT_SUBMISSION, eventPayload);
}
@Override
public SignedJWT createRejectSubmissionEvent(final EventPayload eventPayload) {
return signJWT(REJECT_SUBMISSION, eventPayload);
}
private SignedJWT signJWT(final Event event, final EventPayload eventPayload) {
final String transactionId = "case:" + eventPayload.getCaseId();
final String subject = "submission:" + eventPayload.getSubmissionId();
final JWSSigner signer = getJwsSigner(signingKey);
final JWSHeader header = buildJwsHeader(signingKey.getKeyID());
final JWTClaimsSet claimsSet = buildJwtClaimsSet(event, eventPayload, transactionId, subject);
final SignedJWT signedJWT = new SignedJWT(header, claimsSet);
try {
signedJWT.sign(signer);
validateEventSchema(signedJWT.getPayload().toString());
return signedJWT;
} catch (final JOSEException | ValidationException e) {
throw new EventCreationException("Creating " + event + " event JWT failed", e.getCause());
}
}
private JWSSigner getJwsSigner(final RSAKey rsaKey) {
try {
return new RSASSASigner(rsaKey);
} catch (final JOSEException e) {
throw new EventCreationException("Error creating the RSASigner", e);
}
}
private JWSHeader buildJwsHeader(final String keyId) {
try {
return JWSHeader.parse(Map.of(
EventHeaderFields.TYPE, "secevent+jwt",
EventHeaderFields.KEY_ID, keyId,
EventHeaderFields.ALGORITHM, "PS512"
));
} catch (final ParseException e) {
throw new EventCreationException("Parsing JWS header failed", e);
}
}
private JWTClaimsSet buildJwtClaimsSet(final Event event, final EventPayload eventPayload, final String transactionId, final String subject) {
return new JWTClaimsSet.Builder()
.claim(EventClaimFields.CLAIM_SCHEMA, config.getSetSchemaWriteVersion())
.issuer(eventPayload.getDestinationId().toString())
.issueTime(new Date())
.jwtID(UUID.randomUUID().toString())
.subject(subject)
.claim(EventClaimFields.CLAIM_TXN, transactionId)
.claim(EventClaimFields.CLAIM_EVENTS, buildEventsClaim(event, eventPayload))
.build();
}
private Map buildEventsClaim(final Event event, final EventPayload eventPayload) {
final Map events = new HashMap<>();
if (eventPayload.getProblems() != null && !eventPayload.getProblems().isEmpty()) {
events.put("problems", eventPayload.getProblems());
}
if (event.equals(ACCEPT_SUBMISSION)) {
final String dataAuthTag = eventPayload.getDataAuthTag();
final String metadataAuthTag = eventPayload.getMetadataAuthTag();
final Map attachmentAuthTags = eventPayload.getAttachmentAuthTags();
events.put("authenticationTags", new AuthenticationTags(dataAuthTag, metadataAuthTag, attachmentAuthTags));
}
return Map.of(event.getSchemaUri(), events);
}
private void validateEventSchema(final String eventPayload) {
final ValidationResult validationResult = validationService.validateSetEventSchema(eventPayload);
if (validationResult.hasError()) {
throw new ValidationException("Set event is invalid", validationResult.getError());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy