Spring Remoting with Security and SSL

One of my favorite features of the Spring Framework is the Spring Remoting part, which enables you to expose any bean in a Spring Application Context as a remote service over HTTP. It’s fast, it’s easy, and it’s really, really simple.

Basic Spring Remoting Configuration

In the general situation all you need to do is create a DispatcherServlet (just as you would with any Spring MVC application), add an Exporter on the server side and reference a ProxyFactoryBean on the client.
On the server side:

On the client side:

Now, in the client application all you need to do is ask for the ‘helloService‘ bean and you will be handed a proxy that talks to the target service on the server without the server or the client knowing anything about it.

Securing the Remote Service

Now, in many cases you’ll want to apply some security restrictions on the exposed HTTP service. Being in the Spring world the natural choice for this purpose will be Spring Security. Far from the complications of its predecessor Acegi, Spring Security configuration is now a matter of very few lines of XML code:

Note that we’re defining the Spring Security XML schema in the schema definition.

The AuthenticationSimpleHttpInvokerRequestExecutor will make sure that any Spring Security applied on the client side will be transferred to the server side using Basic HTTP Authentication. The filters and the XML configuration on the server side will make sure the Authentication headers are inspected and checked against the valid principals and credentials.

Applying SSL

As most of you probably know, Basic HTTP Authentication is pretty much the same thing as sending the authentication information over the network in plain text. This is why you will typically want to use encrypted connections whenever you are working with this type of authentication. This gets us into the core of this post, because it’s here it becomes tricky.

In the ideal world you would just configure your web server to expose the service over HTTPS, change the target URL on the client side and be on your way. The reality however is slightly more complicated.

The problem is that you the built-in HttpURLConnection class on which the AuthenticationSimpleHttpInvokerRequestExecutor relies is very picky when it comes to certificates. What you want to do when working with SSL in Spring Remoting is to use the CommonsHttpInvokerRequestExecutor, which relies on Commons HttpClient – a more flexible and capable HTTP client. Now, the problem with this is that then you cannot use the AuthenticationSimpleHttpInvokerRequestExecutor anymore – they plug into the HttpInvokerProxyFactoryBean at the same extension point.

It boils down to this: if you want to use Spring Remoting and Spring Security over SSL you will need to implement your own HttpInvokerRequestExecutor:

Now all you need to do is specify this implementation as HttpInvokerRequestExecutor for your client ProxyFactoryBean and you’re all set:

This Post Has 20 Comments

  1. and what about ssl whit client authentication (using digitals certificates in both sides, the client and the server.)

    1. Never had any reason to look into that. I would expect however that you could use a similar approach as the one described in this post. The HttpClient documentation suggests you’ll have to do some custom tweaks to make it work, but at least there seems to be places for you to hook in for doing custom authentication.

  2. I really appreciate your entry. I’m working on something that may be related, but I’am stuck somewhere. I’m trying to use spring remoting with spring security, but I’m not running a web app. I am trying to authenticate a user against an LDAP and then save his credentials in the spring security context. I removed the filter and filter mapping as it was trying to authenticate my request. However I created an authenticate class that authenticates and then I place the authentication object in the security context. However, the next time I call the function remotly, I don’t see the authentication object anymore. Have you tried to manipulate the security context manually like this? I have also tried SecurityContextHolder
    .setStrategyName(SecurityContextHolder.MODE_GLOBAL);

    Thanks in advance,

    1. The problem in this case is that there’s no concept of sessions; using Spring Remoting everything is typically stateless. This means that each request is ‘new’ to the server and that you’ll either have to authenticate each and every call (which is what happens with the built-in filters and basic authentication – the principal and credentials will be sent with each and every request), or you’ll have to introduce some kind of custom session token which you send back and forth between the server and client.

      I don’t think I understand your requirements completely; why can you not use the built-in filters and Spring Security out of the box to perform authentication? It’s perfectly manageable to use Spring Security to perform LDAP authentication.

  3. Thanks for the quick reply,
    Our architects don’t like the idea of authenticating each request due to the lag of hitting a remote LDAP server each and every time. I may have to go with the custom approach of passing back some kind of session id or something.

  4. Hello,
    I’ve actually been struggling with the for a while. Maybe you can point me in the right direction as there really isn’t any documentation except the spring docs which are brief and forums.
    I’ve already setup the LDAP authentication, but it happens manualy on the server side. If I want to use the out of the box implementation I think I need to do the following:

    1.) Add the credentials on the client side and then pass them to the server. I think I want to use CommonsHttpInvokerRequestExecutor, but it seems to only hold information for BASIC authentication. How do I send this via the request. In your example, you also utilize Authentication auth =
    SecurityContextHolder.getContext().getAuthentication();
    Do I manually create a local security context and set authentication information into it?

    2.) I assume once I send this, I can use the normal filters to authenticate.

    Thanks for the help.

  5. Unless you have very particular requirements you should avoid doing this manually and use the out-of-the-box implementation instead. Using CommonsHttpInvokerRequestExecutor the appropriate headers will automatically be added. The filters on the server side will extract that information and use it for authentication processing.

    Note that each request will not need to be authenticated against the actual storage (in this case your LDAP server). You can configure Spring Security to cache this information, which means that the only first request will hit the LDAP server; any subsequent requests will be validated against the cached values.

    A custom implementation (like the one you are suggesting) will certainly be possible but it will pretty much require you to re-invent the existing functionality – obviously not a recommended way to go. If you really, really want to do the actual authentication in your own code rather than using the built-in implementation you can provide your own custom AuthenticationProvider implementation and plug that into the Spring Security configuration.

  6. Thanks again for your reply,
    It seems that i’m still struggling with this and I’m glad that there is someone out there that has already figured this out. I agree, that I don’t want to reimplment anything out of the box. Essentially i’ve gotten this far, I would appreciate your insight to see if i’m on the right approach.

    1.) I’ve implemented CommonsHttpInvokerRequestExecutor where i’m temporarily adding login info (i’ll move it out later). Just like you’ve done above. I don’t have access to a security context on the client side so i’m trying this.

    ublic class ExtendedInvoker extends CommonsHttpInvokerRequestExecutor {
    @Override
    protected PostMethod createPostMethod(HttpInvokerClientConfiguration config) throws IOException {
    PostMethod postMethod = super.createPostMethod(config);

    String user = “dianne”;
    String pw = “emu”;
    UsernamePasswordCredentials creds = new UsernamePasswordCredentials(user, pw);

    HttpState shtate=new HttpState();
    shtate.setCredentials(AuthScope.ANY, creds);
    return postMethod;
    }

    2. On the server side i’ve tried to use the namespace config as such:

    However now its asking for an entry point to be defined, before I start that next step, I wanted to know if I was on the right path. All I basically want to do is authenticate each remoting request via LDAP.

    I appreciate the help

  7. I’m sorry, I forgot to place the namespace config.

  8. I figured it out..thanks.
    I just created a new UsernamePasswordAuthenticationToken and placed it into a newly created securitycontext.

    Thanks for you help.

  9. One question: How do you expose the service over HTTPS? Do you edit something in the web.xml? I imagine its easy, but I’m new to all this.

  10. Exposing the service over HTTPS is no different from exposing any web application over HTTPS. It is a configuration matter quite unrelated to Spring Remoting. There’s basically two approaches – either you configure your web container (e.g. Tomcat) to expose the web applications over HTTPS, or – the general approach – you have your web application available as-is in Tomcat, and then put a web proxy in front, e.g. Apache.

    Regardless of the approach you choose it’s a configuration matter outside of the web application. Google will help you find the answer to that configuration question. Good luck.

  11. Thanks for sharing the good knowledge.

    Can you please explain how we can have authorization in place? For example to only allow a certain role to invoke method1 or bean1

    Thanks.

  12. Hi
    Nice article, and it’s a great technic with spring.
    I don’t need ssl encryption but i have a problem with my firewall and load-balancer.

    The first communication is on HTTP for the connexion establishment but after, it’s just TCP binary data between client-server on random port for each remote call.
    There are no more data that the load-balancer can use to redirect to the good webserver.

    Is it possible to fix the port for the binary data for respect the firewall rules?
    And is it possible to add a ‘flag’ with the binary data (cookies, etc..) for the load-balancer?

    Thank.

  13. I’m trying to do this with SSL and I used your BasicAuthenticationCommonsHttpInvokerRequestExecutor class and I still get the following error:

    org.springframework.remoting.RemoteAccessException: Could not access HTTP invoker remote service at [https://127.0.0.1:8443/my-app/MyService]; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

  14. Chris,
    You’re getting this exception because the certificate on the target server is not properly signed by a CA. There are a number of solutions to this problem; the correct one would obviously to use a signed certificate on the server.

    Other solutions (not recommended, but possible as workarounds) are to add the server certificate to your trusted certs on the client machine, or specify the certificate as a trusted certificate using the javax.net.ssl.trustStore system property.

  15. Hi there terrific blog! Does running a blog similar
    to this require a great deal of work? I have absolutely no knowledge of programming but I
    had been hoping to start my own blog soon. Anyways, if you have any suggestions or techniques for new blog owners
    please share. I know this is off subject however I
    just needed to ask. Kudos!

  16. i tried above authentication technique but gives
    org.springframework.remoting.RemoteAccessException: Could not access HTTP invoker remote service

    i could not find why the authentication is blocking spring remoting

Leave a Reply

Close Menu