2020import java .security .Principal ;
2121import java .security .cert .X509Certificate ;
2222import java .util .ArrayList ;
23+ import java .util .Arrays ;
2324import java .util .Collections ;
2425import java .util .List ;
26+ import java .util .regex .Pattern ;
27+ import java .util .stream .Collectors ;
2528
2629import javax .security .auth .callback .Callback ;
2730import javax .security .auth .callback .CallbackHandler ;
5962import org .w3c .dom .Document ;
6063import org .w3c .dom .Element ;
6164
65+ import static java .util .Collections .emptyList ;
66+ import static java .util .Collections .unmodifiableList ;
67+
6268/**
6369 * A WS-Security endpoint interceptor based on Apache's WSS4J. This interceptor supports messages created by the
6470 * {@link org.springframework.ws.soap.axiom.AxiomSoapMessageFactory} and the
@@ -194,6 +200,8 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl
194200 // To maintain same behavior as default, this flag is set to true
195201 private boolean removeSecurityHeader = true ;
196202
203+ private List <Pattern > signatureSubjectDnPatterns = emptyList ();
204+
197205 /**
198206 * Create a {@link WSSecurityEngine} by default.
199207 */
@@ -210,6 +218,20 @@ public Wss4jSecurityInterceptor(WSSecurityEngine securityEngine) {
210218 this .securityEngine = securityEngine ;
211219 }
212220
221+ /**
222+ * Certificate constraints which will be applied to the subject DN of the certificate used for
223+ * signature validation, after trust verification of the certificate chain associated with the
224+ * certificate.
225+ *
226+ * @param patterns A comma separated String of regular expressions which will be applied to
227+ * the subject DN.
228+ *
229+ * @see <a href="https://ws.apache.org/wss4j/config.html">WSS4J configuration: SIG_SUBJECT_CERT_CONSTRAINTS</a>
230+ */
231+ public void setValidationSubjectDnConstraints (List <Pattern > patterns ) {
232+ signatureSubjectDnPatterns = patterns ;
233+ }
234+
213235 public void setSecurementActions (String securementActions ) {
214236 this .securementActions = securementActions ;
215237 }
@@ -225,6 +247,15 @@ public void setSecurementActor(String securementActor) {
225247 handler .setOption (WSHandlerConstants .ACTOR , securementActor );
226248 }
227249
250+ /**
251+ * Defines whether to use a single certificate or a whole certificate chain when constructing
252+ * a BinarySecurityToken used for direct reference in signature.
253+ * The default is "true", meaning that only a single certificate is used.
254+ */
255+ public void setSecurementSignatureSingleCertificate (boolean useSingleCertificate ) {
256+ handler .setOption (WSHandlerConstants .USE_SINGLE_CERTIFICATE , useSingleCertificate );
257+ }
258+
228259 public void setSecurementEncryptionCrypto (Crypto securementEncryptionCrypto ) {
229260 handler .setSecurementEncryptionCrypto (securementEncryptionCrypto );
230261 }
@@ -670,6 +701,7 @@ protected RequestData initializeRequestData(MessageContext messageContext) {
670701 // allow for qualified password types for .Net interoperability
671702 requestData .setAllowNamespaceQualifiedPasswordTypes (true );
672703
704+ requestData .setSubjectCertConstraints (signatureSubjectDnPatterns );
673705 return requestData ;
674706 }
675707
@@ -710,6 +742,8 @@ protected RequestData initializeValidationRequestData(MessageContext messageCont
710742 // allow for qualified password types for .Net interoperability
711743 requestData .setAllowNamespaceQualifiedPasswordTypes (true );
712744
745+ requestData .setSubjectCertConstraints (signatureSubjectDnPatterns );
746+
713747 return requestData ;
714748 }
715749
@@ -888,4 +922,14 @@ protected void cleanUp() {
888922 }
889923 }
890924 }
925+
926+ private List <Pattern > parseSubjectCertConstrainsAsPatternList () {
927+ String commaSeparatedCertConstraintPatterns = handler .getStringOption (ConfigurationConstants .SIG_SUBJECT_CERT_CONSTRAINTS );
928+ if (commaSeparatedCertConstraintPatterns != null && !commaSeparatedCertConstraintPatterns .isEmpty ()) {
929+ String [] patternStrings = commaSeparatedCertConstraintPatterns .split ("," );
930+ return unmodifiableList (Arrays .stream (patternStrings ).map (Pattern ::compile ).collect (Collectors .toList ()));
931+ } else {
932+ return emptyList ();
933+ }
934+ }
891935}
0 commit comments