Programming and So

Tips and tricks in Java

Archive for November 2008

WebServiceTemplate and Timeout

with one comment

Spring WS 1.0 API doesn’t support timeout for web service invocations. This feature can be achieved by using Jakarta Commons HttpClient. SSL timeout requires moreover the use of Not Yet Commons SSL (in fact, this product is just only an extension of JSSE).

Below a sample class and a sample application context configuration.

import java.io.IOException;
import java.io.File;

// commons-httpclient
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
// not-yet-commons-ssl
import org.apache.commons.ssl.HttpSecureProtocol;
import org.apache.commons.ssl.KeyMaterial;
import org.apache.commons.ssl.TrustMaterial;
// spring ws
import org.springframework.oxm.xmlbeans.XmlBeansMarshaller;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.transport.http.CommonsHttpMessageSender;

public class SpringWSClient extends WebServiceGatewaySupport {

  // Marshalling
  private XmlBeansMarshaller xmlBeansMarshaller;

  // Truststore
  private String pathToJksTrustStore;
  private String jksTrustStorePassword;

  // Keystore
  private String pathToJksKeyStore;
  private String jksKeyStorePassword;

  // Timeout
  private int timeOutMs;

  // SSL Port
  private static final int SSL_PORT = 443;

  // Default constructor
  public SpringWSClient(XmlBeansMarshaller xmlBeansMarshaller) {
    this.xmlBeansMarshaller = xmlBeansMarshaller;
  }

  // Do WS invocation
  public Object callWs(Object input) {

    // SSL connection?
    if (getWebServiceTemplate().getDefaultUri().toLowerCase().startsWith(
        "https")) {
      sslProtocolInit();
    }

    // Marshalling stuff (XMLBeans)
    WebServiceTemplate wst = getWebServiceTemplate();
    wst.setMarshaller(getXmlBeansMarshaller());
    wst.setUnmarshaller(getXmlBeansMarshaller());

    // Timeout (commons-httpclient)
    HttpClient client = new HttpClient();
    client.getParams().setSoTimeout(new Integer(getTimeOutMs()));
    CommonsHttpMessageSender messageSender = new CommonsHttpMessageSender(
        client);
    wst.setMessageSender(messageSender);

    // Invocation
    Object result = wst.marshalSendAndReceive(input,
        new WebServiceMessageCallback() {
          public void doWithMessage(WebServiceMessage message)
              throws IOException {
            // ...
          }
        });
    return result;
  }

  // SSL protocol (not-yet-commons-ssl)
  protected void sslProtocolInit() {

    HttpSecureProtocol protocolSocketFactory;

    try {

      protocolSocketFactory = new HttpSecureProtocol();

      File jksTrustStore = new File(pathToJksTrustStore);     

      TrustMaterial trustMaterial = new TrustMaterial(jksTrustStore,
          jksTrustStorePassword.toCharArray());
      protocolSocketFactory.addTrustMaterial(trustMaterial);

      // No host name verification
      protocolSocketFactory.setCheckHostname(false);

      File jksKeyStore = new File(pathToJksKeyStore);

      KeyMaterial key = new KeyMaterial(jksKeyStore, jksKeyStorePassword
          .toCharArray());
      protocolSocketFactory.setKeyMaterial(key);

      // Timeout
      protocolSocketFactory.setConnectTimeout(getTimeOutMs());

      // Register protocol
      Protocol protocol = new Protocol("https",
          (ProtocolSocketFactory) protocolSocketFactory, SSL_PORT);
      Protocol.registerProtocol("https", protocol);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public XmlBeansMarshaller getXmlBeansMarshaller() {
    return xmlBeansMarshaller;
  }

  public void setXmlBeansMarshaller(XmlBeansMarshaller xmlBeansMarshaller) {
    this.xmlBeansMarshaller = xmlBeansMarshaller;
  }

  public int getTimeOutMs() {
    return timeOutMs;
  }

  public void setTimeOutMs(int timeOutMs) {
    this.timeOutMs = timeOutMs;
  }

  public String getPathToJksFile() {
    return pathToJksFile;
  }

  public void setPathToJksFile(String pathToJksFile) {
    this.pathToJksFile = pathToJksFile;
  }

  public String getJksPassword() {
    return jksPassword;
  }

  public void setJksPassword(String jksPassword) {
    this.jksPassword = jksPassword;
  }

}
<bean id="springWSClient" class="SpringWSClient">
    <constructor -arg ref="xmlBeansMarshaller"/>
    <property name="defaultUri" value="${ws.url}" />
    <property name="pathToJksTrustStore" value="${trustStore.location}" />
    <property name="jksTrustStorePassword" value="${trustStore.password}" />
    <property name="pathToJksKeyStore" value="${keyStore.location}" />
    <property name="jksKeyStorePassword" value="${keyStore.password}" />
    <property name="timeOutMs" value="${ws.timeout}" />
</bean>

Written by angelborroy

November 20, 2008 at 10:25 am

Posted in java

Tagged with

Customize target URL according to the user ROLE with Spring Security 2

without comments

It’s there some idea about this issue, but I think there’s no simple solution exposed.

You can achieve this behaviour by modifying applicationContext.xml and by extending Spring’s AuthenticationProcessingFilter.

applicationContext.xml

<!-- Spring Security Authentication -->
<http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint">
<!-- LITERAL user can only access to literal pages -->
<intercept -url pattern="/*iteral.htm" access="ROLE_LITERAL,ROLE_ADMIN" />
<!-- ADMIN user can access everywhere -->
<intercept -url pattern="/**.htm" access="ROLE_ADMIN" />
</http>

<!-- User list -->
<authentication -provider>
<password -encoder hash="md5"/>
<user -service>
<user name="admin" password="21232f297a57a5a743894a0e4a801fc3" authorities="ROLE_ADMIN" />
<user name="literals" password="b284ec8f1c7a6208901d2a5d27d17a32" authorities="ROLE_LITERAL" />
</user>
</authentication>

<!-- Entry point properties -->
<authentication -manager alias="authenticationManagerAlias"/>
<bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/login.htm"/>
<property name="forceHttps" value="false" />
</bean>
< -- Custom Authentication Processing Filter -->
<bean id="customAuthenticationProcessingFilter" class="CustomAuthenticationProcessingFilter">
<property name="filterProcessesUrl" value="/j_spring_security_check" />
<property name="defaultTargetUrl" value="/index.sdf"/>
<property name="authenticationManager" ref="authenticationManagerAlias"/>
<custom -filter position="AUTHENTICATION_PROCESSING_FILTER"/>
</bean>

Custom Authentication Processing Filter

public class CustomAuthenticationProcessingFilter extends AuthenticationProcessingFilter {

  public static final String ROLE_ADMIN = "ROLE_ADMIN";

  private static final String ROLE_ADMIN_TARGET_URL = "/index.htm";
  private static final String NON_ROLE_ADMIN_TARGET_URL = "/literal.htm";

  @Override
  protected String determineTargetUrl(HttpServletRequest request) {

    boolean isAdmin = hasRole(ROLE_ADMIN); 

    String targetUrl;
    if (isAdmin) {
      targetUrl = ROLE_ADMIN_TARGET_URL;
    } else {
      targetUrl = NON_ROLE_ADMIN_TARGET_URL;
    }

    return targetUrl;
  }

  /**
    * Returns true is user authenticated has role
    */
  public static boolean hasRole(String role) {

    boolean userHasRole = false;
    GrantedAuthority[] grantedAuthorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();

    for (GrantedAuthority grantedAuthority : grantedAuthorities) {
      if (role.equals(grantedAuthority.toString())) {
        userHasRole = true;
        break;
      }
    }

    return userHasRole;

  }

}

It seems simple, however, it becomes complex because of Spring Security documentation, which is results very poor for integration purposes.

Written by angelborroy

November 6, 2008 at 6:24 pm

Posted in java

Tagged with