Majid Laissi
Majid Laissi

Reputation: 19778

Implementing Spring Security with Java Client

Client Side

I have a java application that connects to a remote server using basic POST or GET methods:

URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setAllowUserInteraction(false);
conn.setRequestProperty("Content-type", "text/xml; charset=" + ENCODING);

conn.connect();
conn.getOutputStream().write(data.getBytes(ENCODING));
conn.getOutputStream().close();

(I cannot change this code, the only things I can change is the urlStr and the data sent to the server when calling the method).

[EDIT] : The client can be a java client or any other client (c++, objective-c, ..). The point here is that I can only access what's in the body of my post as well as the URL.

Server Side

On my server side, I would like to implement Spring Security (SecurityContext and session persistance).

I understand that spring security is based on the browser's cookies when it's a WebApp to hold the information about the session id. But in my case there's no Browser.

Thank you.

[EDIT]

as pointed out by @zagyi, I can use the URL to pass session token to Spring, but I still can't figure out how.

Upvotes: 2

Views: 2187

Answers (2)

zagyi
zagyi

Reputation: 17518

Passing the jsessionid in the url is just a matter of appending it at the end of the url like this:

http://localhost:8080/example/auth/login;jsessionid=A06F00609BBA8A4C2B005FB25F90C4C9

You can see this in working if you configure a browser not to accept any cookies, in which case the server automatically includes the session id in the url (assuming a default tomcat configuration). This topic is also discussed in this question.

Upvotes: 2

gaborsch
gaborsch

Reputation: 15748

There may be a client-side solution for that.

The action point where we can interact is here:

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

We will provide an own (wrapped) HttpURLConnection, which will handle the JSESSIONID. But unfortunately we have to start a bit further.

The trick is that we register a new protocol, e.g. "xhttp", that we use to wrap a real "http" protocol connection. So, your URL will look like:

xhttp://www.example.com/...

First, define a URLStreamHandlerFactory class

public class MyURLStreamHandlerFactory implements URLStreamHandlerFactory {
    public URLStreamHandler createURLStreamHandler(String protocol) {
        if ("xhttp".equals(protocol)) {
            return new MyURLStreamHandler();
        }
        return null;
    }
}

At Java (or application) init time we can set it. You can do it only once per JVM.

URLStreamHandlerFactory fac = new MyURLStreamHandlerFactory();
URL.setURLStreamHandlerFactory(fac);

So, let's go ahead with MyURLStreamHandler.

public class MyURLStreamHandler extends URLStreamHandler {
    @Override
    protected URLConnection openConnection(URL url) throws IOException {
        return new MyHttpURLConnection(url);
    }
}

This is quite simple, we create our own connection. Let's do the dirty stuff:

public final class MyHttpURLConnection extends HttpURLConnection {
    private HttpURLConnection conn;
    public MyHttpURLConnection(URL url) throws MalformedURLException, IOException {
        super(url);
        String newUrlString = url.toExternalForm().substring(1);
        conn = (HttpURLConnection) new URL(newUrlString).openConnection();
    }
    @Override
    public void disconnect() {
        conn.disconnect();
    }
    @Override
    public boolean usingProxy() {
        return false;
    }
    @Override
    public void connect() throws IOException {
        conn.connect();
        conn.setRequestProperty("JSESSIONID", "X");
    }
}

And voilá, we managed to access our connection, and set the JSESSIONID header.

All you need is to compile your classes, add the class files to the client jar, and make the init code running some way in the same JVM where the above code runs.

If you cannot do it, there is another possibility: set the following system parameter to the client Java application:

-Djava.protocol.handler.pkgs=com.example.myprotocol

In this case create a com.example.myprotocol.xhttp (xhttp like your protocol name), and rename our MyURLStreamHandler class to com.example.myprotocol.xhttp.Handler. This is the fixed name where the protocol resolver will look for it. Note, that this java.protocol.handler.pkgs property is checked by the security manager.

Upvotes: 1

Related Questions