ChickenFace
ChickenFace

Reputation: 37

Validate request signature and sign response in SOAP services with spring-ws

Premise: I need to create a SOAP service that uses the WS-Security standard to do what's described in the title, so that a SOAP client can consume this service.

What do I have

Basically, it involves sending the certificate (.cer file) in the soap:Header of the envelope that's sent/received. However, I've encountered several difficulties in achieving this. Based on what I've seen, I only have two options:

Neither of these approaches has worked for me.

Scenario 1:

After many questions and fine-tuning with my chat-gpt/gemini, all I get is code with made-up methods or ones that don't do what I need. I read the library's documentation, and the methods don't explain where to retrieve values from or how to calculate them.

So, I resort to trial and error, following the available info. I pass a crypto.properties file along with a .p12 file that contains my .cer and .key with valid password and alias. I've also tried with a .jks file, but in both cases, I get errors like "unrecognized character 111" or that the library wasn't initialized properly.

Overall, I try all the methods from the class using both p12 and jks formats, along with the crypto.properties file, but the service either doesn't start or fails to sign, instead sending a 202 response with an empty body to my endpoint.

Result? The service doesn't even start because of the aforementioned errores.

Scenario 2:

Using this and that to the letter, I create all the necessary tags.

If you look at the two references I'm using, you'll notice that some attributes like ID need to be considered, right?

Result? When the client validates my response, they get a "signature is invalid" exception. I tried with self-signed certificates, CA-issued certificates, and certificates without special characters, but none of these variations changed the outcome. We also verified that the .cer on their side matches the one I'm using.

Notes:

Edit 1

Additional notes:

closest thing to work, my client still cannot read it but the service starts, I have no idea if I am doing correctly


@Configuration
@EnableWs
public class SoapService extends WsConfigurerAdapter {
    
    // other soap-service-related beans like message dispatcher, marshaller, and so on.
    
    @Bean
    Wss4jSecurityInterceptor securityInterceptor() {
        Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
        
        try {
            // check incoming certificate, this does produce an output similar to the ones on my cites, but not equal
            interceptor.setSecurementActions(WSHandlerConstants.SIGNATURE);
            interceptor.setValidationCallbackHandler(this.securityCallback());
            
            // sign outgoing response
            interceptor.setSecurementActions(WSHandlerConstants.SIGNATURE);
            interceptor.setSecurementUsername("your_alias");
            interceptor.setSecurementPassword("your_password");
            interceptor.setSecurementSignatureCrypto(this.cryptoConfig().getObject());
        } catch(Exception e) {
            e.printStackTrace();
            System.out.println("error while initializing interceptor");
        }
        
        return interceptor;
    }
    
    @Bean
    CryptoFactoryBean cryptoConfig() throws IOException {
        CryptoFactoryBean bean = new CryptoFactoryBean();
        bean.setKeyStorePassword("your_password");
        bean.setKeyStoreLocation(new ClassPathResource("certificate.jks"));
        return bean;
    }
    
    @Bean
    CallbackHandler securityCallback() {
        // how am i supposed to check the .cer my client sends here?
        return new SimplePasswordValidationCallbackHandler() {{
            setUsers(new Properties() {
                private static final long serialVersionUID = 3422928594124631515L;

                {
                    setProperty("alias", "your_password");
                }
            });
        }};
    }
    
    @Override
    public void addInterceptors(List<EndpointInterceptor> interceptors) {
        interceptors.add(securityInterceptor());
    }
    
}

Upvotes: 0

Views: 168

Answers (0)

Related Questions