Simeon Leyzerzon
Simeon Leyzerzon

Reputation: 19074

Spring Boot @RestController rejects a POST request

A POST request

http://localhost:9278/submitEnrollment

to a Spring Boot application that encapsulates an external SOAP call results in the following:

{
  "timestamp": 1439480941381,
  "status": 401,
  "error": "Unauthorized",
  "message": "Full authentication is required to access this resource",
  "path": "/submitEnrollment"
}

This doesn't seem to be a normal behavior, I'm wondering what Spring Boot configurations I need to relax/disable to prevent this client authentication.

Here are relevant pieces of code:

Configuration for the app (that entails all the necessary plumbing to send a secured SOAP call over SSL and should affect web tier):

    @Configuration
@ComponentScan({"a.b.c.d", "com.submit.enrollment"})
@PropertySource("classpath:/submit-enrollment.properties")
public class SubmitEnrollmentConfig {

    @Value("${marshaller.contextPaths}")
    private String[] marshallerContextPaths;

    @Value("${default.Uri}")
    private String defaultUri;

    @Bean
    public FfmSoapClient connectivityClient() throws Throwable {
        FfmSoapClient client = new FfmSoapClient();
        client.setWebServiceTemplate(webServiceTemplate());
        return client;
    }

    @Bean
    public KeyStore keyStore() throws Throwable {
        KeyStoreFactoryBean keyStoreFactory = new KeyStoreFactoryBean();
        keyStoreFactory.setPassword("!zxy!36!");
        keyStoreFactory.setLocation(new ClassPathResource("zxy.jks"));
        keyStoreFactory.setType("jks");
        keyStoreFactory.afterPropertiesSet();
        return keyStoreFactory.getObject();
    }

    @Bean 
    public KeyManager[] keyManagers() throws Throwable{
        KeyManagersFactoryBean keyManagerFactory = new KeyManagersFactoryBean();
        keyManagerFactory.setKeyStore(keyStore());
        keyManagerFactory.setPassword("!zxy!36!");
        keyManagerFactory.afterPropertiesSet();
        return keyManagerFactory.getObject();
    }

    @Bean
    public HttpsUrlConnectionMessageSender httpsUrlSender() throws Throwable {
        HttpsUrlConnectionMessageSender sender = new HttpsUrlConnectionMessageSender();
        sender.setSslProtocol("TLS");
        sender.setKeyManagers(keyManagers());
        return sender;
    }

    @Bean
    public WebServiceTemplate webServiceTemplate() throws Throwable {
        WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
        webServiceTemplate.setMarshaller(marshaller());
        webServiceTemplate.setUnmarshaller(marshaller());
        webServiceTemplate.setDefaultUri(defaultUri);
        webServiceTemplate.setMessageFactory(messageFactory());
        webServiceTemplate.setMessageSender(/*new HttpComponentsMessageSender()*/httpsUrlSender());
        webServiceTemplate.setInterceptors(new ClientInterceptor[] { wss4jSecurityInterceptor(),  new LogbackInterceptor() }); //order matters
        webServiceTemplate.setMessageSender(httpsUrlSender());
        return webServiceTemplate;
    }

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setContextPaths(marshallerContextPaths);
        return marshaller;
    }

    @Bean
    public SaajSoapMessageFactory messageFactory() {
        SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory();
        messageFactory.setSoapVersion(SoapVersion.SOAP_12);
        return messageFactory;
    }

    @Bean
     public Wss4jSecurityInterceptor wss4jSecurityInterceptor() throws Throwable{
        Wss4jSecurityInterceptor wss4jSecurityInterceptor = new Wss4jSecurityInterceptor();
        wss4jSecurityInterceptor.setSecurementActions(/*"UsernameToken"*/WSHandlerConstants.USERNAME_TOKEN + " "+ WSHandlerConstants.TIMESTAMP);
        //wss4jSecurityInterceptor.setSecurementActions("Signature");
        wss4jSecurityInterceptor.setSecurementUsername("07.ZIP.NJ*.390.639");
        wss4jSecurityInterceptor.setSecurementPassword("oLD@cDh$(dKnCM");
        wss4jSecurityInterceptor.setSecurementPasswordType(/*"PasswordDigest"*/WSConstants.PW_DIGEST);
        wss4jSecurityInterceptor.setSecurementEncryptionCrypto(crypto());
        wss4jSecurityInterceptor.setSecurementEncryptionKeyIdentifier("DirectReference");
        //wss4jSecurityInterceptor.setValidationActions("Signature");
        //wss4jSecurityInterceptor.setValidationSignatureCrypto( crypto() );

        wss4jSecurityInterceptor.setSecurementTimeToLive(300);
        return wss4jSecurityInterceptor;
    }




    @Bean
    public Crypto crypto() throws Throwable {
        CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
        cryptoFactoryBean.setKeyStoreLocation(new ClassPathResource("zipari.jks"));
        cryptoFactoryBean.setKeyStorePassword("!zxy!36!");
        cryptoFactoryBean.afterPropertiesSet();
        Crypto crypto = cryptoFactoryBean.getObject();
        System.out.println("created crypto store: "+ crypto);
        return crypto;
    }




    @Configuration
     static class DatabaseConfig {
         @Bean @Lazy
         DataSource dataSource() {
             return null;
         }
     }

}

Application:

public static void main(String[] args) throws Throwable {
    SpringApplication app = new SpringApplication(SubmitEnrollmentApplication.class);
    //app.addListeners(new ApplicationPidFileWriter());
    ApplicationContext ctx = app.run(args);

Controller:

@RestController
public class SubmitEnrollmentController {

    private final Logger logger = LoggerFactory.getLogger(SubmitEnrollmentController.class);

    //@Autowired @Qualifier("brokerService")private BrokerService service;



    @RequestMapping(value = "/submitEnrollment", method = RequestMethod.POST, consumes="application/json")
    public String submitEnrollment(@RequestBody String jsonIn){

        logger.info("Received submit enrollment request: {}, start processing...", jsonIn);

Upvotes: 0

Views: 5793

Answers (2)

Simeon Leyzerzon
Simeon Leyzerzon

Reputation: 19074

The following addition to the main Spring config file helped me achieve what I needed:

@Configuration
    static class WebSecurityConfig extends WebSecurityConfigurerAdapter{
        @Override
        public void configure(WebSecurity web) throws Exception {
             web.ignoring().antMatchers("/**");
        }
    }

Upvotes: 5

Maleen Abewardana
Maleen Abewardana

Reputation: 14572

Your problem is, your rest endpoints are authenticated with spring security. So the error message clearly indicates that, you want to be authenticate yourself before sending the request. You can ignore the authentication, until you make sure everything is working. What you will need is something like this.

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers("/submitEnrollment").permitAll().and().csrf().disable();
}

You can find a good config from here. If you need more complex config, go through this jhipster project, and specifically this file.

It is better you can go through these docs as well. Hope this helps.

Upvotes: 1

Related Questions