Polish "Support WSS4J subject cert constraints"

See gh-1419
This commit is contained in:
Stéphane Nicoll
2025-03-11 10:10:25 +01:00
parent 8460ad8a94
commit 4a0daeb7b7
2 changed files with 22 additions and 35 deletions

View File

@@ -61,8 +61,6 @@ import org.springframework.ws.soap.security.callback.CallbackHandlerChain;
import org.springframework.ws.soap.security.callback.CleanupCallback;
import org.springframework.ws.soap.security.wss4j2.callback.UsernameTokenPrincipalCallback;
import static java.util.Collections.emptyList;
/**
* A WS-Security endpoint interceptor based on Apache's WSS4J. This interceptor supports
* messages created by the
@@ -211,7 +209,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
// To maintain same behavior as default, this flag is set to true
private boolean removeSecurityHeader = true;
private List<Pattern> signatureSubjectDnPatterns = emptyList();
private List<Pattern> signatureSubjectDnPatterns = Collections.emptyList();
/**
* Create a {@link WSSecurityEngine} by default.
@@ -244,15 +242,6 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
this.handler.setOption(WSHandlerConstants.ACTOR, securementActor);
}
/**
* Defines whether to use a single certificate or a whole certificate chain when
* constructing a BinarySecurityToken used for direct reference in signature. The
* default is "true", meaning that only a single certificate is used.
*/
public void setSecurementSignatureSingleCertificate(boolean useSingleCertificate) {
handler.setOption(WSHandlerConstants.USE_SINGLE_CERTIFICATE, useSingleCertificate);
}
public void setSecurementEncryptionCrypto(Crypto securementEncryptionCrypto) {
this.handler.setSecurementEncryptionCrypto(securementEncryptionCrypto);
}
@@ -545,13 +534,11 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
* Certificate constraints which will be applied to the subject DN of the certificate
* used for signature validation, after trust verification of the certificate chain
* associated with the certificate.
* @param patterns A list of regex patterns which will be applied to the subject DN.
*
* @see <a href="https://ws.apache.org/wss4j/config.html">WSS4J configuration:
* SIG_SUBJECT_CERT_CONSTRAINTS</a>
* @param patterns a list of regex patterns which will be applied to the subject DN.
* @see ConfigurationConstants#SIG_SUBJECT_CERT_CONSTRAINTS
*/
public void setValidationSubjectDnConstraints(List<Pattern> patterns) {
signatureSubjectDnPatterns = patterns;
this.signatureSubjectDnPatterns = patterns;
}
/**
@@ -768,7 +755,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
// allow for qualified password types for .Net interoperability
requestData.setAllowNamespaceQualifiedPasswordTypes(true);
requestData.setSubjectCertConstraints(signatureSubjectDnPatterns);
requestData.setSubjectCertConstraints(this.signatureSubjectDnPatterns);
return requestData;
}
@@ -808,8 +795,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
// allow for qualified password types for .Net interoperability
requestData.setAllowNamespaceQualifiedPasswordTypes(true);
requestData.setSubjectCertConstraints(signatureSubjectDnPatterns);
requestData.setSubjectCertConstraints(this.signatureSubjectDnPatterns);
return requestData;
}

View File

@@ -31,7 +31,7 @@ import org.springframework.ws.soap.security.wss4j2.support.CryptoFactoryBean;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
public abstract class Wss4jMessageInterceptorSignTest extends Wss4jTest {
@@ -131,31 +131,32 @@ public abstract class Wss4jMessageInterceptorSignTest extends Wss4jTest {
public void testValidateCertificateSubjectDnConstraintsShouldMatchSubject() throws Exception {
SoapMessage message = createSignedTestSoapMessage();
MessageContext messageContext = getSoap11MessageContext(createSignedTestSoapMessage());
interceptor.secureMessage(message, messageContext);
this.interceptor.secureMessage(message, messageContext);
interceptor.setValidationActions("Signature");
interceptor.setValidationSubjectDnConstraints(List.of(Pattern.compile(".*")));
assertThatCode(() -> interceptor.validateMessage(message, messageContext)).doesNotThrowAnyException();
this.interceptor.setValidationActions("Signature");
this.interceptor.setValidationSubjectDnConstraints(List.of(Pattern.compile(".*")));
assertThatCode(() -> this.interceptor.validateMessage(message, messageContext)).doesNotThrowAnyException();
}
@Test
public void testValidateCertificateSubjectDnConstraintsShouldFailForNotMatchingSubject() throws Exception {
SoapMessage message = createSignedTestSoapMessage();
MessageContext messageContext = getSoap11MessageContext(createSignedTestSoapMessage());
interceptor.secureMessage(message, messageContext);
this.interceptor.secureMessage(message, messageContext);
interceptor.setValidationActions("Signature");
interceptor.setValidationSubjectDnConstraints(List.of(Pattern.compile("O=Some Other Company")));
Throwable catched = catchThrowable(() -> interceptor.validateMessage(message, messageContext));
assertThat(catched).isInstanceOf(Wss4jSecurityValidationException.class);
this.interceptor.setValidationActions("Signature");
this.interceptor.setValidationSubjectDnConstraints(List.of(Pattern.compile("O=Some Other Company")));
assertThatExceptionOfType(Wss4jSecurityValidationException.class)
.isThrownBy(() -> this.interceptor.validateMessage(message, messageContext))
.withMessage("The security token could not be authenticated or authorized");
}
private SoapMessage createSignedTestSoapMessage() throws Exception {
interceptor.setSecurementActions("Signature");
interceptor.setSecurementSignatureKeyIdentifier("DirectReference");
interceptor.setSecurementSignatureSingleCertificate(false);
interceptor.setSecurementPassword("123456");
interceptor.setSecurementUsername("testkey");
this.interceptor.setSecurementActions("Signature");
this.interceptor.setSecurementSignatureKeyIdentifier("DirectReference");
this.interceptor.setUseSingleCertificate(false);
this.interceptor.setSecurementPassword("123456");
this.interceptor.setSecurementUsername("testkey");
return loadSoap11Message("empty-soap.xml");
}