diff --git a/authn/saml/src/main/java/se/swedenconnect/signservice/authn/saml/AbstractSamlAuthenticationHandler.java b/authn/saml/src/main/java/se/swedenconnect/signservice/authn/saml/AbstractSamlAuthenticationHandler.java index 242033ae..1b137140 100644 --- a/authn/saml/src/main/java/se/swedenconnect/signservice/authn/saml/AbstractSamlAuthenticationHandler.java +++ b/authn/saml/src/main/java/se/swedenconnect/signservice/authn/saml/AbstractSamlAuthenticationHandler.java @@ -15,16 +15,11 @@ */ package se.swedenconnect.signservice.authn.saml; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.security.cert.X509Certificate; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.shared.resolver.ResolverException; +import net.shibboleth.shared.xml.SerializeSupport; import org.apache.commons.lang3.StringUtils; import org.opensaml.core.xml.io.MarshallingException; import org.opensaml.core.xml.io.Unmarshaller; @@ -42,12 +37,6 @@ import org.opensaml.saml.saml2.metadata.IDPSSODescriptor; import org.opensaml.xmlsec.signature.support.SignatureException; import org.w3c.dom.Element; - -import jakarta.annotation.Nonnull; -import jakarta.annotation.Nullable; -import lombok.extern.slf4j.Slf4j; -import net.shibboleth.shared.resolver.ResolverException; -import net.shibboleth.shared.xml.SerializeSupport; import se.idsec.signservice.xml.DOMUtils; import se.swedenconnect.opensaml.saml2.core.build.RequestedAuthnContextBuilder; import se.swedenconnect.opensaml.saml2.metadata.EntityDescriptorContainer; @@ -88,6 +77,17 @@ import se.swedenconnect.signservice.protocol.msg.AuthnRequirements; import se.swedenconnect.signservice.protocol.msg.SignMessage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.Serial; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + /** * Abstract base class for SAML authentication handlers. */ @@ -272,7 +272,7 @@ public AuthenticationResultChoice resumeAuthentication(@Nonnull final HttpUserRe } final String sentRelayState = context.get(RELAY_STATE_KEY, String.class); - // Setup the response processing input object ... + // Set up the response processing input object ... // final ResponseProcessingInput input = this.createResponseProcessingInput(authnRequest, sentRelayState, httpRequest, context); @@ -314,6 +314,7 @@ public AuthenticationResultChoice resumeAuthentication(@Nonnull final HttpUserRe return new AuthenticationResultChoice( new AuthenticationResult() { + @Serial private static final long serialVersionUID = 3481951951577173265L; @Override @@ -345,6 +346,11 @@ else if (StatusCode.NO_SUPPORTED_IDP.equals(status.getMinorStatusCode()) throw new UserAuthenticationException(AuthenticationErrorCode.UNKNOWN_AUTHENTICATION_SERVICE, status.getStatusMessage("Requested IdP is not available"), e); } + else if (SamlStatus.FRAUD_STATUS_CODE.equals(status.getMinorStatusCode()) + || SamlStatus.POSSIBLE_FRAUD_STATUS_CODE.equals(status.getMinorStatusCode())) { + throw new UserAuthenticationException(AuthenticationErrorCode.SECURITY_VIOLATION, + status.getStatusMessage("Possible fraud detected"), e); + } else { throw new UserAuthenticationException(AuthenticationErrorCode.FAILED_AUTHN, String.format("Authentication failure: %s (%s)", status.getStatusMessage("Unknown authentication error"), @@ -384,9 +390,9 @@ public boolean canProcess(@Nonnull final HttpUserRequest httpRequest, @Nullable final String requestPath = httpRequest.getServerServletPath(); if (!(requestPath.equalsIgnoreCase(this.urlConfiguration.getAssertionConsumerPath()) || (this.urlConfiguration.getAdditionalAssertionConsumerPath() != null - && requestPath.equalsIgnoreCase(this.urlConfiguration.getAdditionalAssertionConsumerPath())))) { + && requestPath.equalsIgnoreCase(this.urlConfiguration.getAdditionalAssertionConsumerPath())))) { log.info("{}: Path {} is not supported by handler '{}'", - Optional.ofNullable(context).map(SignServiceContext::getId).orElseGet(() -> ""), requestPath, this.getName()); + Optional.ofNullable(context).map(SignServiceContext::getId).orElse(""), requestPath, this.getName()); return false; } @@ -525,8 +531,8 @@ protected AuthnRequestGeneratorContext createAuthnRequestContext( && !authnRequirements.getAuthnContextIdentifiers().isEmpty()) { final List supportedUris = EntityDescriptorUtils.getAssuranceCertificationUris(idpMetadata); final boolean match = authnRequirements.getAuthnContextIdentifiers().stream() - .map(AuthnContextIdentifier::getIdentifier) - .anyMatch(a -> supportedUris.contains(a)); + .map(AuthnContextIdentifier::getIdentifier) + .anyMatch(supportedUris::contains); if (!match) { final String msg = "None of the requested authn context URIs are supported by the IdP"; log.info("{}: {}", context.getId(), msg); @@ -539,7 +545,7 @@ protected AuthnRequestGeneratorContext createAuthnRequestContext( @Override @Nonnull public String getPreferredBinding() { - return getPreferredBindingUri(); + return AbstractSamlAuthenticationHandler.this.getPreferredBindingUri(); } @Override @@ -558,7 +564,7 @@ public RequestedAuthnContextBuilderFunction getRequestedAuthnContextBuilderFunct // final List uris = authnRequirements.getAuthnContextIdentifiers().stream() .map(AuthnContextIdentifier::getIdentifier) - .filter(i -> list.contains(i)) + .filter(list::contains) .collect(Collectors.toList()); if (uris.isEmpty()) { @@ -585,7 +591,7 @@ public RequestedAuthnContextBuilderFunction getRequestedAuthnContextBuilderFunct */ @Nonnull protected ResponseProcessingInput createResponseProcessingInput( - @Nonnull AuthnRequest authnRequest, @Nullable String sentRelayState, + @Nonnull final AuthnRequest authnRequest, @Nullable final String sentRelayState, @Nonnull final HttpUserRequest httpRequest, @Nonnull final SignServiceContext context) { final Instant received = Instant.now(); @@ -617,7 +623,7 @@ public Instant getReceiveInstant() { @Override public String getClientIpAddress() { - // We don't check IP addresses - it's too error prone. + // We don't check IP addresses - it's too error-prone. return null; } @@ -731,12 +737,12 @@ protected void assertAttributes(@Nonnull final AuthnRequirements authnRequiremen throw new UserAuthenticationException(AuthenticationErrorCode.MISMATCHING_IDENTITY_ATTRIBUTES, msg); } // OK, the attribute is provided. Let's check its value. - // Since we support multi-valued attributes, we have a match if at least one of the values + // Since we support multivalued attributes, we have a match if at least one of the values // from the requested attribute is found in the issued attribute. // boolean match = false; for (final Object value : requestedAttribute.getValues()) { - if (issuedAttribute.getValues().stream().filter(v -> Objects.equals(v, value)).findAny().isPresent()) { + if (issuedAttribute.getValues().stream().anyMatch(v -> Objects.equals(v, value))) { match = true; break; } @@ -771,7 +777,7 @@ protected void assertAuthnContext(@Nonnull final AuthnRequest authnRequest, final List requestedContexts = authnRequest.getRequestedAuthnContext().getAuthnContextClassRefs() .stream() .map(AuthnContextClassRef::getURI) - .collect(Collectors.toList()); + .toList(); if (requestedContexts.isEmpty()) { return; @@ -798,7 +804,7 @@ protected void assertAuthnContext(@Nonnull final AuthnRequest authnRequest, * @param signMessage the sign message that was requsted (may be null) * @param attributes the received attributes * @param result the processing result - * @param authnRequest the sent authentication request + * @param authnRequest the authentication request * @param context the SignService context * @throws UserAuthenticationException for errors asserting the sign message */ @@ -810,7 +816,7 @@ protected void assertSignMessage(@Nullable final SignMessage signMessage, } /** - * A method that enables sub-classes to extend the verification of the received assertion. The default implementation + * A method that enables subclasses to extend the verification of the received assertion. The default implementation * does nothing. * * @param authnRequirements the authentication requirements @@ -820,7 +826,7 @@ protected void assertSignMessage(@Nullable final SignMessage signMessage, * @throws UserAuthenticationException for verification errors */ protected void extendedAssertionVerification(@Nonnull final AuthnRequirements authnRequirements, - @Nonnull final AuthnRequest authnRequest, @Nonnull ResponseProcessingResult result, + @Nonnull final AuthnRequest authnRequest, @Nonnull final ResponseProcessingResult result, @Nonnull final SignServiceContext context) throws UserAuthenticationException { } @@ -868,10 +874,11 @@ protected IdentityAssertion buildIdentityAssertion( * @param authnRequest the authentication request * @param context the SignService context * @return a flag indicating whether the sign message was displayed or not - * @throws UserAuthenticationException for processing errors, i.e., the proof for a displayed sign message is illegal + * @throws UserAuthenticationException for processing errors, i.e., the proof for a displayed sign message is + * illegal */ protected boolean wasSignMessageDisplayed(@Nonnull final ResponseProcessingResult result, - @Nonnull List> attributes, @Nonnull final AuthnRequest authnRequest, + @Nonnull final List> attributes, @Nonnull final AuthnRequest authnRequest, @Nonnull final SignServiceContext context) throws UserAuthenticationException { return false; } @@ -915,7 +922,7 @@ protected AuthnRequest getAuthnRequest(@Nonnull final SignServiceContext context final Element xml = DOMUtils.bytesToDocument(encodedAuthnRequest).getDocumentElement(); final Unmarshaller unmarshaller = Optional.ofNullable(XMLObjectSupport.getUnmarshaller(xml)) .orElseThrow(() -> new UnmarshallingException("No unmarshaller for AuthnRequest available")); - return AuthnRequest.class.cast(unmarshaller.unmarshall(xml)); + return (AuthnRequest) unmarshaller.unmarshall(xml); } catch (final Exception e) { final String msg = "Failed to unmarshall AuthnRequest object"; @@ -931,7 +938,7 @@ protected AuthnRequest getAuthnRequest(@Nonnull final SignServiceContext context */ @Nonnull protected String getPreferredBindingUri() { - return Optional.ofNullable(this.preferredBindingUri).orElseGet(() -> SAMLConstants.SAML2_REDIRECT_BINDING_URI); + return Optional.ofNullable(this.preferredBindingUri).orElse(SAMLConstants.SAML2_REDIRECT_BINDING_URI); } /** diff --git a/authn/saml/src/main/java/se/swedenconnect/signservice/authn/saml/SamlStatus.java b/authn/saml/src/main/java/se/swedenconnect/signservice/authn/saml/SamlStatus.java index 32b17381..20ec1343 100644 --- a/authn/saml/src/main/java/se/swedenconnect/signservice/authn/saml/SamlStatus.java +++ b/authn/saml/src/main/java/se/swedenconnect/signservice/authn/saml/SamlStatus.java @@ -15,15 +15,14 @@ */ package se.swedenconnect.signservice.authn.saml; -import java.util.Objects; -import java.util.Optional; - +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; import org.opensaml.saml.saml2.core.Status; import org.opensaml.saml.saml2.core.StatusCode; import org.opensaml.saml.saml2.core.StatusMessage; -import jakarta.annotation.Nonnull; -import jakarta.annotation.Nullable; +import java.util.Objects; +import java.util.Optional; /** * A utility class for working with SAML {@link Status} objects. @@ -33,8 +32,13 @@ public class SamlStatus { /** The status code for cancel (defined by the Swedish eID framework). */ public static final String CANCEL_STATUS_CODE = "http://id.elegnamnden.se/status/1.0/cancel"; + /** Status code for fraud detection. */ + public static final String FRAUD_STATUS_CODE = "http://id.elegnamnden.se/status/1.0/fraud"; + + /** Status code for possible fraud detection. */ + public static final String POSSIBLE_FRAUD_STATUS_CODE = "http://id.elegnamnden.se/status/1.0/possibleFraud"; + /** The status object. */ - @Nonnull private final Status status; /** @@ -108,7 +112,7 @@ public boolean isCancel() { /** {@inheritDoc} */ @Override public String toString() { - final StringBuffer sb = new StringBuffer("code='"); + final StringBuilder sb = new StringBuilder("code='"); sb.append(this.getMinorStatusCode()).append("'"); final String minor = this.getMinorStatusCode(); if (minor != null) { diff --git a/core/src/main/java/se/swedenconnect/signservice/authn/AuthenticationErrorCode.java b/core/src/main/java/se/swedenconnect/signservice/authn/AuthenticationErrorCode.java index b3ef65da..10bc25a5 100644 --- a/core/src/main/java/se/swedenconnect/signservice/authn/AuthenticationErrorCode.java +++ b/core/src/main/java/se/swedenconnect/signservice/authn/AuthenticationErrorCode.java @@ -35,6 +35,9 @@ public enum AuthenticationErrorCode { /** The user failed to authenticate - general authentication error. */ FAILED_AUTHN, + /** Possible security violation. */ + SECURITY_VIOLATION, + /** General error for bad authentication setup. For example, the IdP does not recognize the SP. */ INTERNAL_AUTHN_ERROR; diff --git a/core/src/main/java/se/swedenconnect/signservice/engine/SignServiceErrorCode.java b/core/src/main/java/se/swedenconnect/signservice/engine/SignServiceErrorCode.java index 02e64d48..1257bd85 100644 --- a/core/src/main/java/se/swedenconnect/signservice/engine/SignServiceErrorCode.java +++ b/core/src/main/java/se/swedenconnect/signservice/engine/SignServiceErrorCode.java @@ -45,6 +45,9 @@ public enum SignServiceErrorCode { /** General authentication error. */ AUTHN_FAILURE("The user failed to authenticate"), + /** Security violation. */ + SECURITY_VIOLATION("A security violation was detected"), + /** Error generating the signing key. */ KEY_GENERATION_FAILED("The generation of the signature key failed"), diff --git a/core/src/main/java/se/swedenconnect/signservice/protocol/msg/MessageConditions.java b/core/src/main/java/se/swedenconnect/signservice/protocol/msg/MessageConditions.java index 1ef8b42d..dcb58d09 100644 --- a/core/src/main/java/se/swedenconnect/signservice/protocol/msg/MessageConditions.java +++ b/core/src/main/java/se/swedenconnect/signservice/protocol/msg/MessageConditions.java @@ -15,6 +15,9 @@ */ package se.swedenconnect.signservice.protocol.msg; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; + import java.io.Serializable; import java.time.Instant; @@ -28,6 +31,7 @@ public interface MessageConditions extends Serializable { * * @return not before instant */ + @Nullable Instant getNotBefore(); /** @@ -35,6 +39,7 @@ public interface MessageConditions extends Serializable { * * @return not after instant */ + @Nullable Instant getNotAfter(); /** @@ -46,6 +51,6 @@ public interface MessageConditions extends Serializable { * @param instant the instant to test * @return true if the supplied instant meets the criteria and false otherwise */ - boolean isWithinRange(final Instant instant); + boolean isWithinRange(@Nonnull final Instant instant); } diff --git a/core/src/main/java/se/swedenconnect/signservice/protocol/msg/impl/DefaultMessageConditions.java b/core/src/main/java/se/swedenconnect/signservice/protocol/msg/impl/DefaultMessageConditions.java index 2556887e..1483b4ce 100644 --- a/core/src/main/java/se/swedenconnect/signservice/protocol/msg/impl/DefaultMessageConditions.java +++ b/core/src/main/java/se/swedenconnect/signservice/protocol/msg/impl/DefaultMessageConditions.java @@ -15,9 +15,12 @@ */ package se.swedenconnect.signservice.protocol.msg.impl; +import java.io.Serial; import java.time.Instant; import java.util.Objects; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; import se.swedenconnect.signservice.core.annotations.GeneratedMethod; import se.swedenconnect.signservice.protocol.msg.MessageConditions; @@ -27,6 +30,7 @@ public class DefaultMessageConditions implements MessageConditions { /** For serializing. */ + @Serial private static final long serialVersionUID = -1228444313739138273L; /** Not before condition. */ @@ -38,10 +42,10 @@ public class DefaultMessageConditions implements MessageConditions { /** * Constructor. * - * @param notBefore the not before condition - * @param notAfter the not after condition + * @param notBefore the not-before condition + * @param notAfter the not-after condition */ - public DefaultMessageConditions(final Instant notBefore, final Instant notAfter) { + public DefaultMessageConditions(@Nullable final Instant notBefore, @Nullable final Instant notAfter) { this.notBefore = notBefore; this.notAfter = notAfter; @@ -52,19 +56,21 @@ public DefaultMessageConditions(final Instant notBefore, final Instant notAfter) /** {@inheritDoc} */ @Override + @Nullable public Instant getNotBefore() { return this.notBefore; } /** {@inheritDoc} */ @Override + @Nullable public Instant getNotAfter() { return this.notAfter; } /** {@inheritDoc} */ @Override - public boolean isWithinRange(final Instant instant) { + public boolean isWithinRange(@Nonnull final Instant instant) { if (instant == null) { return false; } @@ -91,10 +97,9 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } - if (!(obj instanceof DefaultMessageConditions)) { + if (!(obj instanceof final DefaultMessageConditions other)) { return false; } - final DefaultMessageConditions other = (DefaultMessageConditions) obj; return Objects.equals(this.notAfter, other.notAfter) && Objects.equals(this.notBefore, other.notBefore); } diff --git a/protocol/dss-ext11/src/main/java/se/swedenconnect/signservice/protocol/dss/DssSignRequestMessage.java b/protocol/dss-ext11/src/main/java/se/swedenconnect/signservice/protocol/dss/DssSignRequestMessage.java index d5b71bf7..3351f72d 100644 --- a/protocol/dss-ext11/src/main/java/se/swedenconnect/signservice/protocol/dss/DssSignRequestMessage.java +++ b/protocol/dss-ext11/src/main/java/se/swedenconnect/signservice/protocol/dss/DssSignRequestMessage.java @@ -15,28 +15,12 @@ */ package se.swedenconnect.signservice.protocol.dss; -import java.security.SignatureException; -import java.security.cert.X509Certificate; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Collections; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import javax.xml.datatype.XMLGregorianCalendar; -import javax.xml.xpath.XPathExpressionException; - -import org.apache.commons.lang3.StringUtils; -import org.apache.xml.security.Init; -import org.w3c.dom.Document; - import jakarta.annotation.Nonnull; import jakarta.xml.bind.JAXBException; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.xml.security.Init; +import org.w3c.dom.Document; import se.idsec.signservice.security.sign.xml.XMLMessageSignatureValidator; import se.idsec.signservice.security.sign.xml.XMLSignatureLocation; import se.idsec.signservice.security.sign.xml.XMLSignatureLocation.ChildPosition; @@ -84,6 +68,21 @@ import se.swedenconnect.signservice.signature.impl.DefaultRequestedSignatureTask; import se.swedenconnect.xml.jaxb.JAXBMarshaller; +import javax.xml.datatype.XMLGregorianCalendar; +import javax.xml.xpath.XPathExpressionException; +import java.io.Serial; +import java.security.SignatureException; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + /** * An implementation of the {@link SignRequestMessage} interface for sign request messages according to DSS @@ -93,25 +92,26 @@ class DssSignRequestMessage implements SignRequestMessage { /** For serializing. */ + @Serial private static final long serialVersionUID = -5875475186053392826L; /** Processing requirements. */ private static final ProtocolProcessingRequirements processingRequirements = new DssProtocolProcessingRequirements(); /** Where to find the XML signatures. */ - private static XMLSignatureLocation xmlSignatureLocation; + private static final XMLSignatureLocation xmlSignatureLocation; /** For validating signatures on SignResponse messages. */ private static final XMLMessageSignatureValidator signatureValidator = new DefaultXMLMessageSignatureValidator(); /** Maximum supported version. */ - private static ProtocolVersion MAX_VERSION = ProtocolVersion.valueOf("1.4"); + private static final ProtocolVersion MAX_VERSION = ProtocolVersion.valueOf("1.5"); /** Minimum supported version. */ - private static ProtocolVersion MIN_VERSION = ProtocolVersion.valueOf("1.1"); + private static final ProtocolVersion MIN_VERSION = ProtocolVersion.valueOf("1.1"); /** The attribute converter that converts between JAXB and the generic attribute representation. */ - private static JaxbAttributeConverter attributeConverter = new JaxbAttributeConverter(); + private static final JaxbAttributeConverter attributeConverter = new JaxbAttributeConverter(); static { try { @@ -273,22 +273,6 @@ else if (!DssConstants.DSS_PROFILE.equals(this.signRequest.getProfile())) { // Conditions // - final MessageConditions conditions = this.getConditions(); - if (conditions == null) { - final String msg = "Conditions is missing - this element is required"; - log.info("{} [request-id: '{}']", msg, this.signRequest.getRequestID()); - throw new ProtocolException(msg); - } - else if (conditions.getNotBefore() == null) { - final String msg = "Conditions.notBefore is missing - this field is required"; - log.info("{} [request-id: '{}']", msg, this.signRequest.getRequestID()); - throw new ProtocolException(msg); - } - else if (conditions.getNotAfter() == null) { - final String msg = "Conditions.notOnOrAfter is missing - this field is required"; - log.info("{} [request-id: '{}']", msg, this.signRequest.getRequestID()); - throw new ProtocolException(msg); - } if (this.getResponseUrl() == null) { final String msg = "Conditions.AudienceRestriction is missing - the response URL must be given here"; log.info("{} [request-id: '{}']", msg, this.signRequest.getRequestID()); @@ -300,14 +284,14 @@ else if (conditions.getNotAfter() == null) { final AttributeStatement signer = extension.getSigner(); if (signer != null && signer.isSetAttributesAndEncryptedAttributes()) { for (final Object object : signer.getAttributesAndEncryptedAttributes()) { - if (Attribute.class.isInstance(object)) { + if (object instanceof final Attribute attribute) { try { // By converting, we check if the attributes given are correct ... - attributeConverter.convert(Attribute.class.cast(object)); + attributeConverter.convert(attribute); } catch (final AttributeException e) { final String msg = String.format("Invalid attribute (%s) under Signer - %s", - Attribute.class.cast(object).getName(), e.getMessage()); + attribute.getName(), e.getMessage()); log.info("{} [request-id: '{}']", msg, this.signRequest.getRequestID()); throw new ProtocolException(msg, e); } @@ -330,7 +314,7 @@ else if (conditions.getNotAfter() == null) { // The profile states: "If this element is set, the Version attribute of the SignRequestExtension element MUST be // set to "1.4" or higher. Implementations prior to version 1.4 of this specification do not support the element." // - // But it really doesn't matter so we just issue a log entry noting this... + // But it really doesn't matter, so we just issue a log entry noting this... // if (this.getVersion().compareTo(ProtocolVersion.valueOf("1.4")) < 0) { log.info("Invalid use of AuthnProfile - requires version 1.4 higher, but version is {} [request-id: '{}']", @@ -503,7 +487,7 @@ public AuthnRequirements getAuthnRequirements() { if (certRequestProperties != null && certRequestProperties.isSetAuthnContextClassRefs()) { authnRequirements.setAuthnContextIdentifiers(certRequestProperties.getAuthnContextClassRefs() .stream() - .map(s -> new SimpleAuthnContextIdentifier(s)) + .map(SimpleAuthnContextIdentifier::new) .collect(Collectors.toList())); } @@ -511,9 +495,9 @@ public AuthnRequirements getAuthnRequirements() { if (signer != null && signer.isSetAttributesAndEncryptedAttributes()) { final List> attributes = new ArrayList<>(); for (final Object object : signer.getAttributesAndEncryptedAttributes()) { - if (Attribute.class.isInstance(object)) { + if (object instanceof final Attribute attribute) { try { - attributes.add(attributeConverter.convert(Attribute.class.cast(object))); + attributes.add(attributeConverter.convert(attribute)); } catch (final AttributeException e) { // Already checked in assertCorrectMessage @@ -527,7 +511,7 @@ public AuthnRequirements getAuthnRequirements() { .map(SignRequestExtension::getCertRequestProperties) .map(CertRequestProperties::getCertType) .map(CertificateType::fromType) - .orElseGet(() -> CertificateType.PKC); + .orElse(CertificateType.PKC); final int docCount = Optional.ofNullable(this.signRequest.getSignTasks()) .filter(t -> t.getSignTaskDatas() != null) .map(t -> t.getSignTaskDatas().size()) @@ -545,7 +529,7 @@ public AuthnRequirements getAuthnRequirements() { public SignMessage getSignMessage() { return Optional.ofNullable(this.signRequest.getSignRequestExtension()) .map(SignRequestExtension::getSignMessage) - .map(m -> new DssSignMessage(m)) + .map(DssSignMessage::new) .orElse(null); } @@ -556,7 +540,7 @@ public SignatureRequirements getSignatureRequirements() { return Optional.ofNullable(this.signRequest.getSignRequestExtension()) .map(SignRequestExtension::getRequestedSignatureAlgorithm) .filter(StringUtils::isNotBlank) - .map(a -> new DefaultSignatureRequirements(a)) + .map(DefaultSignatureRequirements::new) .orElseThrow(() -> new DssProtocolException("RequestedSignatureAlgorithm is missing - this field is required")); } @@ -593,7 +577,7 @@ public SigningCertificateRequirements getSigningCertificateRequirements() { for (final PreferredSAMLAttributeNameType samlAttr : a.getSamlAttributeNames()) { final DefaultIdentityAttributeIdentifier sa = new DefaultIdentityAttributeIdentifier("SAML", samlAttr.getValue(), null); - sources.put(Integer.valueOf(samlAttr.getOrder()), sa); + sources.put(samlAttr.getOrder(), sa); } cam.setSources(sources.entrySet() .stream() diff --git a/protocol/dss-ext11/src/main/java/se/swedenconnect/signservice/protocol/dss/DssSignResponseMessage.java b/protocol/dss-ext11/src/main/java/se/swedenconnect/signservice/protocol/dss/DssSignResponseMessage.java index 4289db7a..8ccdc7a0 100644 --- a/protocol/dss-ext11/src/main/java/se/swedenconnect/signservice/protocol/dss/DssSignResponseMessage.java +++ b/protocol/dss-ext11/src/main/java/se/swedenconnect/signservice/protocol/dss/DssSignResponseMessage.java @@ -15,6 +15,7 @@ */ package se.swedenconnect.signservice.protocol.dss; +import java.io.Serial; import java.io.Serializable; import java.security.SignatureException; import java.security.cert.CertificateEncodingException; @@ -38,6 +39,7 @@ import jakarta.xml.bind.JAXBException; import lombok.extern.slf4j.Slf4j; +import se.idsec.signservice.dss.DSSStatusCodes; import se.idsec.signservice.security.sign.xml.XMLSignatureLocation; import se.idsec.signservice.security.sign.xml.XMLSignatureLocation.ChildPosition; import se.idsec.signservice.security.sign.xml.XMLSignerResult; @@ -88,28 +90,29 @@ class DssSignResponseMessage implements SignResponseMessage { /** For serializing. */ + @Serial private static final long serialVersionUID = -3890374307064822991L; /** 1.1 version. */ - private static ProtocolVersion VERSION_1_1 = ProtocolVersion.valueOf("1.1"); + private static final ProtocolVersion VERSION_1_1 = ProtocolVersion.valueOf("1.1"); /** Processing requirements. */ private static final ProtocolProcessingRequirements processingRequirements = new DssProtocolProcessingRequirements(); /** For creating JAXB/XML objects. */ - private static DatatypeFactory datatypeFactory; + private static final DatatypeFactory datatypeFactory; /** The attribute converter that converts between JAXB and the generic attribute representation. */ - private static JaxbAttributeConverter attributeConverter = new JaxbAttributeConverter(); + private static final JaxbAttributeConverter attributeConverter = new JaxbAttributeConverter(); /** Where to insert the XML signature. */ - private static XMLSignatureLocation xmlSignatureLocation; + private static final XMLSignatureLocation xmlSignatureLocation; /** Configuration object used when building a response. */ - private ResponseConfiguration configuration; + private final ResponseConfiguration configuration; /** The JAXB representation of the SignResponse. */ - private SignResponseWrapper signResponse; + private final SignResponseWrapper signResponse; /** * The destination URL is not represented in a SignResponse, but we need the information when sending the response. @@ -147,7 +150,7 @@ class DssSignResponseMessage implements SignResponseMessage { * @param signRequest the corresponding SignRequest */ public DssSignResponseMessage(final ResponseConfiguration configuration, final DssSignRequestMessage signRequest) { - this.configuration = Optional.ofNullable(configuration).orElseGet(() -> new ResponseConfiguration()); + this.configuration = Optional.ofNullable(configuration).orElseGet(ResponseConfiguration::new); Objects.requireNonNull(signRequest, "signRequest must not be null"); final ProtocolVersion version = signRequest.getVersion(); @@ -185,7 +188,7 @@ public void sign(final PkiCredential signatureCredential) throws SignatureExcept throw new DssProtocolException("No SignResponseResult has been assigned"); } - // If it still haven't been assigned, set the "issued at" to the current time. + // If issued-at still hasn't been assigned, set the "issued at" to the current time. if (this.getIssuedAt() == null) { this.setIssuedAt(Instant.now()); } @@ -321,7 +324,7 @@ public void setDestinationUrl(final String destinationUrl) { @Override public SignResponseResult getSignResponseResult() { return Optional.ofNullable(this.signResponse.getResult()) - .map(r -> new DssSignResponseResult(r)) + .map(DssSignResponseResult::new) .orElse(null); } @@ -335,6 +338,18 @@ public void setSignResponseResult(final SignResponseResult signResponseResult) { final Result result = new Result(); result.setResultMajor(signResponseResult.getErrorCode()); result.setResultMinor(signResponseResult.getMinorErrorCode()); + + final ProtocolVersion version = ProtocolVersion.valueOf(this.signResponse.getSignResponseExtension().getVersion()); + if (version.compareTo(ProtocolVersion.valueOf("1.5")) < 0) { + // Avoid sending back error codes introduced in 1.5 ... + if (DSSStatusCodes.DSS_MINOR_AUTHN_FAILED.equals(signResponseResult.getMinorErrorCode())) { + result.setResultMinor(DSSStatusCodes.DSS_MINOR_REQUESTER_ERROR_USER_MISMATCH); + } + else if (DSSStatusCodes.DSS_MINOR_SECURITY_VIOLATION.equals(signResponseResult.getMinorErrorCode())) { + result.setResultMinor(DSSStatusCodes.DSS_MINOR_RESPONDER_ERROR_GENERAL_ERROR); + } + } + if (signResponseResult.getMessage() != null) { final InternationalStringType msg = new InternationalStringType(); msg.setLang("en"); @@ -354,9 +369,7 @@ public void setSignResponseResult(final SignResponseResult signResponseResult) { /** {@inheritDoc} */ @Override public SignerAuthnInfo getSignerAuthnInfo() { - final SignerAssertionInfo sai = - Optional.ofNullable(this.signResponse.getSignResponseExtension().getSignerAssertionInfo()) - .orElse(null); + final SignerAssertionInfo sai = this.signResponse.getSignResponseExtension().getSignerAssertionInfo(); final ContextInfo ci = Optional.ofNullable(sai) .map(SignerAssertionInfo::getContextInfo) .orElse(null); @@ -370,7 +383,7 @@ public SignerAuthnInfo getSignerAuthnInfo() { .map(NameIDType::getValue) .orElse(null)); identityAssertion.setAuthnContext(Optional.ofNullable(ci.getAuthnContextClassRef()) - .map(a -> new SimpleAuthnContextIdentifier(a)) + .map(SimpleAuthnContextIdentifier::new) .orElse(null)); identityAssertion.setAuthnInstant(Optional.ofNullable(ci.getAuthenticationInstant()) .map(XMLGregorianCalendar::toGregorianCalendar) @@ -386,9 +399,9 @@ public SignerAuthnInfo getSignerAuthnInfo() { if (sai.isSetAttributeStatement() && sai.getAttributeStatement().isSetAttributesAndEncryptedAttributes()) { final List> attributes = new ArrayList<>(); for (final Object object : sai.getAttributeStatement().getAttributesAndEncryptedAttributes()) { - if (Attribute.class.isInstance(object)) { + if (object instanceof final Attribute attribute) { try { - attributes.add(attributeConverter.convert(Attribute.class.cast(object))); + attributes.add(attributeConverter.convert(attribute)); } catch (final AttributeException e) { throw new DssProtocolException("Attribute conversion error", e); @@ -397,7 +410,7 @@ public SignerAuthnInfo getSignerAuthnInfo() { } identityAssertion.setIdentityAttributes(attributes); } - identityAssertion.setScheme(Optional.ofNullable(ci.getAuthType()).orElseGet(() -> "SAML")); + identityAssertion.setScheme(Optional.ofNullable(ci.getAuthType()).orElse("SAML")); return new DefaultSignerAuthnInfo(identityAssertion); } @@ -616,6 +629,7 @@ public String toString() { */ static class ResponseConfiguration implements Serializable { + @Serial private static final long serialVersionUID = 288455638407072741L; /** Setting that tells whether SAML assertions should be included in the response messages. */ diff --git a/protocol/dss-ext11/src/main/java/se/swedenconnect/signservice/protocol/dss/DssSignResponseResult.java b/protocol/dss-ext11/src/main/java/se/swedenconnect/signservice/protocol/dss/DssSignResponseResult.java index 42fdd518..1fd31f0f 100644 --- a/protocol/dss-ext11/src/main/java/se/swedenconnect/signservice/protocol/dss/DssSignResponseResult.java +++ b/protocol/dss-ext11/src/main/java/se/swedenconnect/signservice/protocol/dss/DssSignResponseResult.java @@ -15,6 +15,7 @@ */ package se.swedenconnect.signservice.protocol.dss; +import java.io.Serial; import java.util.Objects; import java.util.Optional; @@ -33,6 +34,7 @@ class DssSignResponseResult implements SignResponseResult { /** For serialization. */ + @Serial private static final long serialVersionUID = -1342465930360409621L; /** Corresponds to the dss:ResultMajor element. */ @@ -62,8 +64,11 @@ public DssSignResponseResult(final SignServiceError error) { switch (error.getErrorCode()) { case AUTHN_FAILURE: this.resultMajor = DSSStatusCodes.DSS_RESPONDER_ERROR; - // The DSS extension lacks an error code for a general user authentication error ... - this.resultMinor = DSSStatusCodes.DSS_MINOR_REQUESTER_ERROR_USER_MISMATCH; + this.resultMinor = DSSStatusCodes.DSS_MINOR_AUTHN_FAILED; + break; + case SECURITY_VIOLATION: + this.resultMajor = DSSStatusCodes.DSS_RESPONDER_ERROR; + this.resultMinor = DSSStatusCodes.DSS_MINOR_SECURITY_VIOLATION; break; case AUTHN_SIGNMESSAGE_NOT_DISPLAYED: this.resultMajor = DSSStatusCodes.DSS_RESPONDER_ERROR; @@ -167,10 +172,9 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } - if (!(obj instanceof SignResponseResult)) { + if (!(obj instanceof final SignResponseResult other)) { return false; } - final SignResponseResult other = (SignResponseResult) obj; return Objects.equals(this.resultMajor, other.getErrorCode()) && Objects.equals(this.resultMinor, other.getMinorErrorCode()) && Objects.equals(this.resultMessage, other.getMessage()); @@ -179,7 +183,7 @@ public boolean equals(final Object obj) { /** {@inheritDoc} */ @Override public String toString() { - final StringBuffer sb = new StringBuffer("result-major='").append(this.resultMajor).append("'"); + final StringBuilder sb = new StringBuilder("result-major='").append(this.resultMajor).append("'"); if (this.resultMinor != null) { sb.append(", result-minor='").append(this.resultMinor).append("'"); } diff --git a/protocol/dss-ext11/src/test/java/se/swedenconnect/signservice/protocol/dss/DssSignRequestMessageTest.java b/protocol/dss-ext11/src/test/java/se/swedenconnect/signservice/protocol/dss/DssSignRequestMessageTest.java index bddfd488..9991c1f7 100644 --- a/protocol/dss-ext11/src/test/java/se/swedenconnect/signservice/protocol/dss/DssSignRequestMessageTest.java +++ b/protocol/dss-ext11/src/test/java/se/swedenconnect/signservice/protocol/dss/DssSignRequestMessageTest.java @@ -15,18 +15,10 @@ */ package se.swedenconnect.signservice.protocol.dss; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.security.cert.X509Certificate; -import java.util.Arrays; - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.w3c.dom.Document; import org.w3c.dom.Element; - import se.idsec.signservice.security.certificate.CertificateUtils; import se.idsec.signservice.xml.DOMUtils; import se.swedenconnect.schemas.dss_1_0.SignRequest; @@ -34,6 +26,13 @@ import se.swedenconnect.signservice.protocol.ProtocolProcessingRequirements.SignatureRequirement; import se.swedenconnect.xml.jaxb.JAXBUnmarshaller; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.cert.X509Certificate; +import java.util.Collections; + /** * Test cases for DssSignRequestMessage. */ @@ -62,7 +61,7 @@ public void testCorrect1() throws Exception { // Verify the signature final X509Certificate cert = CertificateUtils.decodeCertificate(this.getClass().getResourceAsStream("/cert1.crt")); - request.verifySignature(Arrays.asList(cert)); + request.verifySignature(Collections.singletonList(cert)); // Assert reqs Assertions.assertEquals(SignatureRequirement.REQUIRED, @@ -80,9 +79,7 @@ public void testMissingRequestId() throws Exception { final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage); } @Test @@ -101,9 +98,7 @@ public void testBadProfile() throws Exception { final DssSignRequestMessage request2 = new DssSignRequestMessage(signRequest2, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request2.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request2::assertCorrectMessage); } @Test @@ -116,33 +111,25 @@ public void testVersion() throws Exception { e.setAttribute("Version", "1.0"); final SignRequest signRequest = JAXBUnmarshaller.unmarshall(doc, SignRequest.class); final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage); // Too high version e.setAttribute("Version", "2.0"); final SignRequest signRequest2 = JAXBUnmarshaller.unmarshall(doc, SignRequest.class); final DssSignRequestMessage request2 = new DssSignRequestMessage(signRequest2, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request2.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request2::assertCorrectMessage); // Missing version - should be ok e.removeAttribute("Version"); final SignRequest signRequest3 = JAXBUnmarshaller.unmarshall(doc, SignRequest.class); final DssSignRequestMessage request3 = new DssSignRequestMessage(signRequest3, doc); - Assertions.assertDoesNotThrow(() -> { - request3.assertCorrectMessage(); - }); + Assertions.assertDoesNotThrow(request3::assertCorrectMessage); // Invalid version e.setAttribute("Version", "foobar"); final SignRequest signRequest4 = JAXBUnmarshaller.unmarshall(doc, SignRequest.class); final DssSignRequestMessage request4 = new DssSignRequestMessage(signRequest4, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request4.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request4::assertCorrectMessage); } @Test @@ -157,9 +144,7 @@ public void testMissingSignTasks() throws Exception { final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage); } @Test @@ -171,9 +156,7 @@ public void testMissingSignTaskId() throws Exception { final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage); } @Test @@ -185,10 +168,8 @@ public void testMissingSignTaskIdOneTask() throws Exception { final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - // If the SignTaskID is missing and we only have one task it is ok - Assertions.assertDoesNotThrow(() -> { - request.assertCorrectMessage(); - }); + // If the SignTaskID is missing, and we only have one task it is ok + Assertions.assertDoesNotThrow(request::assertCorrectMessage); } @Test @@ -200,9 +181,7 @@ public void testMissingSignatureType() throws Exception { final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage); } @Test @@ -214,9 +193,7 @@ public void testMissingTbsData() throws Exception { final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage); } @Test @@ -228,9 +205,7 @@ public void testMissingSignRequestExtension() throws Exception { final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage); } @Test @@ -243,9 +218,7 @@ public void testNoRequestTime() throws Exception { final SignRequest signRequest = JAXBUnmarshaller.unmarshall(doc, SignRequest.class); final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage); } @Test @@ -260,9 +233,7 @@ public void testMissingConditions() throws Exception { e.removeAttribute("NotBefore"); final DssSignRequestMessage request = new DssSignRequestMessage(JAXBUnmarshaller.unmarshall(doc, SignRequest.class), doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }, "Conditions.notBefore is missing - this field is required"); + Assertions.assertDoesNotThrow(request::assertCorrectMessage); e.setAttribute("NotBefore", notBefore); } @@ -272,9 +243,7 @@ public void testMissingConditions() throws Exception { e.removeAttribute("NotOnOrAfter"); final DssSignRequestMessage request = new DssSignRequestMessage(JAXBUnmarshaller.unmarshall(doc, SignRequest.class), doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }, "Conditions.notOnOrAfter is missing - this field is required"); + Assertions.assertDoesNotThrow(request::assertCorrectMessage); e.setAttribute("NotOnOrAfter", notOnOrAfter); } @@ -283,19 +252,8 @@ public void testMissingConditions() throws Exception { e.removeChild(e.getElementsByTagName("saml2:AudienceRestriction").item(0)); final DssSignRequestMessage request = new DssSignRequestMessage(JAXBUnmarshaller.unmarshall(doc, SignRequest.class), doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }, "Conditions.AudienceRestriction is missing - the response URL must be given here"); - } - - // Missing Conditions - { - e.getParentNode().removeChild(e); - final DssSignRequestMessage request = - new DssSignRequestMessage(JAXBUnmarshaller.unmarshall(doc, SignRequest.class), doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }, "Conditions is missing - this element is required"); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage, + "Conditions.AudienceRestriction is missing - the response URL must be given here"); } } @@ -321,9 +279,7 @@ public void testBadAttributes() throws Exception { final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage); } @Test @@ -336,9 +292,8 @@ public void testMissingIdp() throws Exception { final SignRequest signRequest = JAXBUnmarshaller.unmarshall(doc, SignRequest.class); final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }, "IdentityProvider is missing - this field is required"); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage, + "IdentityProvider is missing - this field is required"); } @Test @@ -351,9 +306,8 @@ public void testMissingSignRequester() throws Exception { final SignRequest signRequest = JAXBUnmarshaller.unmarshall(doc, SignRequest.class); final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }, "SignRequester is missing - this field is required"); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage, + "SignRequester is missing - this field is required"); } @Test @@ -366,9 +320,8 @@ public void testMissingSignService() throws Exception { final SignRequest signRequest = JAXBUnmarshaller.unmarshall(doc, SignRequest.class); final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }, "SignService is missing - this field is required"); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage, + "SignService is missing - this field is required"); } @Test @@ -382,9 +335,8 @@ public void testMissingAlgorithm() throws Exception { final SignRequest signRequest = JAXBUnmarshaller.unmarshall(doc, SignRequest.class); final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }, "RequestedSignatureAlgorithm is missing - this field is required"); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage, + "RequestedSignatureAlgorithm is missing - this field is required"); } @Test @@ -411,9 +363,8 @@ public void testMissingSignMessageMessage() throws Exception { final SignRequest signRequest = JAXBUnmarshaller.unmarshall(doc, SignRequest.class); final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }, "Bad SignMessage provided - either Message or EncryptedMessage must be assigned"); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage, + "Bad SignMessage provided - either Message or EncryptedMessage must be assigned"); } @Test @@ -462,9 +413,7 @@ public void testBadCertReqProperties() throws Exception { final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); - Assertions.assertThrows(ProtocolException.class, () -> { - request.assertCorrectMessage(); - }); + Assertions.assertThrows(ProtocolException.class, request::assertCorrectMessage); } @Test @@ -475,15 +424,15 @@ public void testJavaSerialization() throws Exception { final DssSignRequestMessage request = new DssSignRequestMessage(signRequest, doc); // Serialize - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(bos); + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + final ObjectOutputStream out = new ObjectOutputStream(bos); out.writeObject(request); - byte[] serialization = bos.toByteArray(); + final byte[] serialization = bos.toByteArray(); Assertions.assertNotNull(serialization); // Deserialize - ByteArrayInputStream bis = new ByteArrayInputStream(serialization); - ObjectInputStream in = new ObjectInputStream(bis); + final ByteArrayInputStream bis = new ByteArrayInputStream(serialization); + final ObjectInputStream in = new ObjectInputStream(bis); final DssSignRequestMessage request2 = (DssSignRequestMessage) in.readObject(); Assertions.assertNotNull(request2); Assertions.assertEquals(request.getRequestId(), request2.getRequestId()); @@ -491,7 +440,7 @@ public void testJavaSerialization() throws Exception { request2.assertCorrectMessage(); final X509Certificate cert = CertificateUtils.decodeCertificate(this.getClass().getResourceAsStream("/cert1.crt")); - request2.verifySignature(Arrays.asList(cert)); + request2.verifySignature(Collections.singletonList(cert)); } // TODO: Many more test cases ...