Skip to content

Commit

Permalink
Logging, validations and REST API documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
romanstrobl committed Dec 11, 2024
1 parent 308eff1 commit cf9be61
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

package com.wultra.security.powerauth.client.model.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

/**
Expand All @@ -28,7 +30,12 @@
@Data
public class CreateNonPersonalizedOfflineSignaturePayloadRequest {

@Schema(description = "The identifier of the application")
@NotBlank(message = "Application ID must not be empty when creating offline signature payload")
private String applicationId;

@Schema(description = "Signed data")
@NotBlank(message = "Signed data must not be empty when creating offline signature payload")
private String data;

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.ToString;
Expand All @@ -32,7 +33,12 @@
@Data
public class CreatePersonalizedOfflineSignaturePayloadRequest {

@Schema(description = "Activation identifier")
@NotBlank(message = "Activation ID must not be empty when creating offline signature payload")
private String activationId;

@Schema(description = "Signed data")
@NotBlank(message = "Signed data must not be empty when creating offline signature payload")
private String data;

@Schema(description = "Optional nonce (16 bytes base64 encoded into 24 characters), otherwise it will be generated by PowerAuth server. Needed to be set when proximity check is enabled.", maxLength = 24)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

package com.wultra.security.powerauth.client.model.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

import java.util.Date;
Expand All @@ -30,9 +32,18 @@
@Data
public class SignatureAuditRequest {

@Schema(description = "The identifier of the user")
@NotBlank(message = "User ID must not be empty when requesting signature audit")
private String userId;

@Schema(description = "The identifier of the application")
@NotBlank(message = "Application ID must not be empty when requesting signature audit")
private String applicationId;

@Schema(description = "The timestamp from parameter in date filter")
private Date timestampFrom;

@Schema(description = "The timestamp to parameter in date filter")
private Date timestampTo;

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
public class UnblockActivationRequest {

@Schema(description = "Activation identifier")
@NotBlank(message = "Activation ID must not be empty when blocking activation")
@NotBlank(message = "Activation ID must not be empty when unblocking activation")
private String activationId;

@Schema(description = "External user identifier")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.ToString;
Expand All @@ -34,11 +35,23 @@
@Data
public class VerifyOfflineSignatureRequest {

@Schema(description = "Activation identifier")
@NotBlank(message = "Activation ID must not be empty when verifying offline signature")
private String activationId;

@Schema(description = "Signed data")
@NotBlank(message = "Parameter data must not be empty when verifying signature")
private String data;

@Schema(description = "Signature")
@NotBlank(message = "Signature must not be empty when verifying signature")
@ToString.Exclude
private String signature;

@Schema(description = "Signature component length")
private BigInteger componentLength;

@Schema(description = "Whether biometric factor is allowed")
private boolean allowBiometry;

@Schema(description = "Optional proximity check configuration of TOTP.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
package com.wultra.security.powerauth.client.model.request;

import com.wultra.security.powerauth.client.model.enumeration.SignatureType;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.ToString;

Expand All @@ -30,13 +33,32 @@
@Data
public class VerifySignatureRequest {

@Schema(description = "Activation identifier")
@NotBlank(message = "Activation ID must not be empty when verifying signature")
private String activationId;

@Schema(description = "Application key")
@NotBlank(message = "Application key must not be empty when verifying signature")
private String applicationKey;

@Schema(description = "Signed data")
@NotBlank(message = "Parameter data must not be empty when verifying signature")
private String data;

@Schema(description = "Signature")
@NotBlank(message = "Signature must not be empty when verifying signature")
@ToString.Exclude
private String signature;

@Schema(description = "Signature")
@NotNull(message = "Signature type must not be null when verifying signature")
private SignatureType signatureType;

@Schema(description = "Signature protocol version")
@NotBlank(message = "Signature version must not be empty when verifying signature")
private String signatureVersion;

@Schema(description = "Forced signature protocol version used during protocol upgrade")
private Integer forcedSignatureVersion;

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
import io.getlime.security.powerauth.app.server.service.behavior.tasks.OfflineSignatureServiceBehavior;
import io.getlime.security.powerauth.app.server.service.behavior.tasks.OnlineSignatureServiceBehavior;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -43,6 +45,7 @@
@RestController("signatureController")
@RequestMapping("/rest/v3/signature")
@Tag(name = "PowerAuth Signature Controller (V3)")
@Validated
@Slf4j
public class SignatureController {

Expand All @@ -65,10 +68,13 @@ public SignatureController(OnlineSignatureServiceBehavior onlineSignatureService
* @throws Exception In case the service throws exception.
*/
@PostMapping("/verify")
public ObjectResponse<VerifySignatureResponse> verifySignature(@RequestBody ObjectRequest<VerifySignatureRequest> request) throws Exception {
logger.info("VerifySignatureRequest received: {}", request);
public ObjectResponse<VerifySignatureResponse> verifySignature(@Valid @RequestBody ObjectRequest<VerifySignatureRequest> request) throws Exception {
final VerifySignatureRequest req = request.getRequestObject();
logger.info("action: verifySignature, state: initiated, activationId: {}", req.getActivationId());
logger.debug("action: verifySignature, state: initiated, request: {}", request);
final ObjectResponse<VerifySignatureResponse> response = new ObjectResponse<>(onlineSignatureService.verifySignature(request.getRequestObject(), new ArrayList<>()));
logger.info("VerifySignatureRequest succeeded: {}", request);
logger.info("action: verifySignature, state: succeeded");
logger.debug("action: verifySignature, state: succeeded, response: {}", response);
return response;
}

Expand All @@ -80,10 +86,11 @@ public ObjectResponse<VerifySignatureResponse> verifySignature(@RequestBody Obje
* @throws Exception In case the service throws exception.
*/
@PostMapping("/offline/personalized/create")
public ObjectResponse<CreatePersonalizedOfflineSignaturePayloadResponse> createPersonalizedOfflineSignaturePayload(@RequestBody ObjectRequest<CreatePersonalizedOfflineSignaturePayloadRequest> request) throws Exception {
logger.info("action: createPersonalizedOfflineSignaturePayload, state: initiated, activationId: {}", request.getRequestObject().getActivationId());
public ObjectResponse<CreatePersonalizedOfflineSignaturePayloadResponse> createPersonalizedOfflineSignaturePayload(@Valid @RequestBody ObjectRequest<CreatePersonalizedOfflineSignaturePayloadRequest> request) throws Exception {
final CreatePersonalizedOfflineSignaturePayloadRequest req = request.getRequestObject();
logger.info("action: createPersonalizedOfflineSignaturePayload, state: initiated, activationId: {}", req.getActivationId());
logger.debug("action: createPersonalizedOfflineSignaturePayload, state: initiated, {}", request);
final ObjectResponse<CreatePersonalizedOfflineSignaturePayloadResponse> response = new ObjectResponse<>(offlineSignatureService.createPersonalizedOfflineSignaturePayload(request.getRequestObject()));
final ObjectResponse<CreatePersonalizedOfflineSignaturePayloadResponse> response = new ObjectResponse<>(offlineSignatureService.createPersonalizedOfflineSignaturePayload(req));
logger.info("action: createPersonalizedOfflineSignaturePayload, state: succeeded");
logger.debug("action: createPersonalizedOfflineSignaturePayload, state: succeeded, {}", response);
return response;
Expand All @@ -97,12 +104,13 @@ public ObjectResponse<CreatePersonalizedOfflineSignaturePayloadResponse> createP
* @throws Exception In case the service throws exception.
*/
@PostMapping("/offline/non-personalized/create")
public ObjectResponse<CreateNonPersonalizedOfflineSignaturePayloadResponse> createNonPersonalizedOfflineSignaturePayload(@RequestBody ObjectRequest<CreateNonPersonalizedOfflineSignaturePayloadRequest> request) throws Exception {
logger.info("action: createNonPersonalizedOfflineSignaturePayload state: initiated, activationId: {}", request.getRequestObject().getApplicationId());
logger.debug("action: createNonPersonalizedOfflineSignaturePayload state: initiated, {}", request);
final ObjectResponse<CreateNonPersonalizedOfflineSignaturePayloadResponse> response = new ObjectResponse<>(offlineSignatureService.createNonPersonalizedOfflineSignaturePayload(request.getRequestObject()));
logger.info("action: createNonPersonalizedOfflineSignaturePayload state: succeeded");
logger.debug("action: createNonPersonalizedOfflineSignaturePayload state: succeeded, {}", response);
public ObjectResponse<CreateNonPersonalizedOfflineSignaturePayloadResponse> createNonPersonalizedOfflineSignaturePayload(@Valid @RequestBody ObjectRequest<CreateNonPersonalizedOfflineSignaturePayloadRequest> request) throws Exception {
final CreateNonPersonalizedOfflineSignaturePayloadRequest req = request.getRequestObject();
logger.info("action: createNonPersonalizedOfflineSignaturePayload, state: initiated, applicationId: {}", req.getApplicationId());
logger.debug("action: createNonPersonalizedOfflineSignaturePayload, state: initiated, {}", request);
final ObjectResponse<CreateNonPersonalizedOfflineSignaturePayloadResponse> response = new ObjectResponse<>(offlineSignatureService.createNonPersonalizedOfflineSignaturePayload(req));
logger.info("action: createNonPersonalizedOfflineSignaturePayload, state: succeeded");
logger.debug("action: createNonPersonalizedOfflineSignaturePayload, state: succeeded, {}", response);
return response;
}

Expand All @@ -114,10 +122,13 @@ public ObjectResponse<CreateNonPersonalizedOfflineSignaturePayloadResponse> crea
* @throws Exception In case the service throws exception.
*/
@PostMapping("/offline/verify")
public ObjectResponse<VerifyOfflineSignatureResponse> verifyOfflineSignature(@RequestBody ObjectRequest<VerifyOfflineSignatureRequest> request) throws Exception {
logger.info("VerifyOfflineSignatureRequest received: {}", request);
public ObjectResponse<VerifyOfflineSignatureResponse> verifyOfflineSignature(@Valid @RequestBody ObjectRequest<VerifyOfflineSignatureRequest> request) throws Exception {
final VerifyOfflineSignatureRequest req = request.getRequestObject();
logger.info("action: verifyOfflineSignature, state: initiated, activationId: {}", req.getActivationId());
logger.debug("action: verifyOfflineSignature, state: initiated, {}", request);
final ObjectResponse<VerifyOfflineSignatureResponse> response = new ObjectResponse<>(offlineSignatureService.verifyOfflineSignature(request.getRequestObject()));
logger.info("VerifyOfflineSignatureRequest succeeded: {}", response);
logger.info("action: verifyOfflineSignature, state: succeeded");
logger.debug("action: verifyOfflineSignature, state: succeeded, {}", response);
return response;
}

Expand All @@ -129,7 +140,7 @@ public ObjectResponse<VerifyOfflineSignatureResponse> verifyOfflineSignature(@Re
* @throws Exception In case the service throws exception.
*/
@PostMapping("/list")
public ObjectResponse<SignatureAuditResponse> getSignatureAuditLog(@RequestBody ObjectRequest<SignatureAuditRequest> request) throws Exception {
public ObjectResponse<SignatureAuditResponse> getSignatureAuditLog(@Valid @RequestBody ObjectRequest<SignatureAuditRequest> request) throws Exception {
logger.info("SignatureAuditRequest received: {}", request);
final ObjectResponse<SignatureAuditResponse> response = new ObjectResponse<>(auditingService.getSignatureAuditLog(request.getRequestObject()));
logger.info("SignatureAuditRequest succeeded: {}", response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import io.getlime.security.powerauth.app.server.database.model.entity.MasterKeyPairEntity;
import io.getlime.security.powerauth.app.server.database.model.enumeration.ActivationStatus;
import io.getlime.security.powerauth.app.server.database.model.enumeration.EncryptionMode;
import io.getlime.security.powerauth.app.server.database.repository.ActivationRepository;
import io.getlime.security.powerauth.app.server.database.repository.ApplicationRepository;
import io.getlime.security.powerauth.app.server.database.repository.MasterKeyPairRepository;
import io.getlime.security.powerauth.app.server.service.exceptions.GenericServiceException;
Expand Down Expand Up @@ -106,12 +105,6 @@ public class OfflineSignatureServiceBehavior {
public VerifyOfflineSignatureResponse verifyOfflineSignature(final VerifyOfflineSignatureRequest request)
throws GenericServiceException {
try {
if (request.getActivationId() == null || request.getData() == null || request.getSignature() == null) {
logger.warn("Invalid request parameters in method verifyOfflineSignature");
// Rollback is not required, error occurs before writing to database
throw localizationProvider.buildExceptionForCode(ServiceError.INVALID_REQUEST);
}
final String activationId = request.getActivationId();
final BigInteger componentLength = request.getComponentLength();
final List<SignatureType> allowedSignatureTypes = new ArrayList<>();
// The order of signature types is important. PowerAuth server logs first found signature type
Expand Down Expand Up @@ -158,12 +151,6 @@ public VerifyOfflineSignatureResponse verifyOfflineSignature(final VerifyOffline
@Transactional
public CreatePersonalizedOfflineSignaturePayloadResponse createPersonalizedOfflineSignaturePayload(final CreatePersonalizedOfflineSignaturePayloadRequest request) throws GenericServiceException {
try {
if (request.getActivationId() == null || request.getData() == null) {
logger.warn("Invalid request parameters in method createPersonalizedOfflineSignaturePayload");
// Rollback is not required, database is not used for writing
throw localizationProvider.buildExceptionForCode(ServiceError.INVALID_REQUEST);
}

// Fetch activation details from the repository
final String activationId = request.getActivationId();
final ActivationRecordEntity activation = activationQueryService.findActivationWithoutLock(activationId).orElseThrow(() -> {
Expand Down Expand Up @@ -260,12 +247,6 @@ public CreateNonPersonalizedOfflineSignaturePayloadResponse createNonPersonalize
final String applicationId = request.getApplicationId();
final String data = request.getData();

if (data == null) {
logger.warn("Invalid request parameter data in method createNonPersonalizedOfflineSignaturePayload");
// Rollback is not required, database is not used for writing
throw localizationProvider.buildExceptionForCode(ServiceError.INVALID_REQUEST);
}

// Fetch associated master key pair data from the repository
final Optional<ApplicationEntity> applicationEntityOptional = applicationRepository.findById(applicationId);
if (applicationEntityOptional.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,6 @@ public VerifySignatureResponse verifySignature(VerifySignatureRequest request, L
if (request.getForcedSignatureVersion() != null && request.getForcedSignatureVersion() == 3) {
forcedSignatureVersion = 3;
}

if (activationId == null || applicationKey == null || dataString == null
|| signature == null || signatureType == null || signatureVersion == null) {
logger.warn("Invalid request parameters in method verifySignature");
// Rollback is not required, error occurs before writing to database
throw localizationProvider.buildExceptionForCode(ServiceError.INVALID_REQUEST);
}
return verifySignatureImpl(activationId, signatureType, signature, signatureVersion, additionalInfo, dataString, applicationKey, forcedSignatureVersion, keyConvertor);
} catch (InvalidKeySpecException | InvalidKeyException ex) {
logger.error(ex.getMessage(), ex);
Expand Down

0 comments on commit cf9be61

Please sign in to comment.