Reputation: 19778
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.
Do I need to simulate the storage of the JSESSIONID
and send it back to the server? I'm not sure this is possible since I would need to call conn.addRequestProperty(key, value)
which is not possible.
Is there any other way?
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
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
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