CXF JAX-RS client proxy not maintaining cookies - java

I am using CXF to build client code for a JAX-RS REST service. This REST service unfortunately relies on cookies to authenticate each request and maintain other key session state. Accessing the user's account info involves two requests: one to login, and one to get account info. The session cookies retrieved in the first request must be sent with the second request.
Here is my code.
// Login (POST /sessions)
Response response = proxy.login(userCredentials);
assertEquals(200, response.getStatus());
// Get user's account info (GET /user)
response = proxy.getUser();
User user = response.readEntity(User.class);
The second request fails authentication because it does not include the required session cookies that were returned by the prior login operation.
I believe there is a way to configure the WebClient to maintain cookies across requests. I have searched high and low, but I cannot seem to find out how. I'm hoping someone can point me to an example. Thanks in advance!

I finally found a solution. I had to do the following before using the proxy.
WebClient.getConfig(proxy).getRequestContext().put(
org.apache.cxf.message.Message.MAINTAIN_SESSION, Boolean.TRUE);

Related

Google OAuth2 Flow in Server Side Web Application in Java

I am facing an issue understanding the oauth2 flow.
A user(identified by a user_id) initiates the GoogleAccounts connection in the browser.The request is passed to Servlet that sends Redirect String To Client (Javascript), which in turn redirects user to that Auth URL.
On User Consent, the response is returned to callback url (mapped to a servlet).
My Confusion here is when callback servlet is called,how do i identify to which user(user_id) does this authCode belong to?
Do i have to use state param of oAuth2 ?
Please help.
As the comments suggest, the state param is your friend. The simplest way would be to simply set state=user_id. An alternate approach would be to start a server session and store the user ID in the session object. This latter approach assumes you have a relatively simple server, or your cluster supports shared sessions.

Implementing a token style security when doing GET requests

I'm implementing a temporary and very simple token-style authentication mechanism for an application.
The idea is very simple. Whenever a user logs in to the application, a token is returned to the client, which stores it in the sessionStorage data structure of the browser.
Now, whenever I do a request through AJAX I can send the token with the request and the server can verify if this token is associated with an authentication or username. If it is, it parses the request normally, if not, a error page or the initial page is returned or displayed.
I'm not sure if this is the way that token-style authentication and authorization is implemented in real or serious applications, but I've now no idea how to send the token when doing GET requests by just clicking on the link of a view.
My only idea would be to intercept the get requests so that I can fill them with the token, but this all seems to be quite odd, and I've already a lot of links and views.
Search for Json Web Tokens and for implementations on java. This is exactly what you need.
If you want to send to the user some sensitive data inside the jwt, use Json Web Encryption.
You can send that token on each request header or as a request parameter
You can set a cookie, ensure to set it httponly (ans secure if you are on an https site) and read the cookie on every request that reach the server.
You can use JWT token (see https://jwt.io/introduction/). JWT is basically a JSON data structure. Usually, the token is passed along in the authorization http header.

How to pass session id as part of Soap request?

I invoke an authentication request in order receive a session id :
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<loginResponse xmlns="urn:company" xmlns:ns2="urn:company">
<result>
<sessionId>2342422342.dc8bizxsfapi03</sessionId>
<msUntilPwdExpiration>2342342342342353452323</msUntilPwdExpiration>
</result>
</loginResponse>
</S:Body>
</S:Envelope>
In the docs for the Soap API that I'm using it states :
A successful login will return a
session ID as an HTTP Cookie. This cookie must be passed back to all subsequent HTTP
Requests that invoke API operations in order to authenticate.
How is the session id passed to the next http reqeust as this is not described ?
I'm assuming I need to embed the session ID within an XML tag as part of the subsequesnt request but this should be detailed in the API or is there a standard mechanism I can use ?
The API documentation you reference states that the service will set a cookie on the response that needs to be set on any subsequent request. Cookies are sent via HTTP headers, not the body of of the request/response, and are commonly used to establish and maintain sessions. The underlying HTTP client library the web service framework uses is well equipped to handle this for you, but because SOAP web services are designed to be stateless, you usually have to ask the framework if you want it to maintain sessions. When you enable this functionality, it simply means the framework will send any cookies back to the server that the server sends to it, which is precisely what your SOAP API documentation is asking that you do.
To enable this functionality in jax-ws, you set BindingProvider.SESSION_MAINTAIN_PROPERTY to true on the RequestContext. This article gives an example and more details.
Yes, that is a popular mechanism.
As the API states the session key was returned in the Cookie (it is a HTTP header). What is in a response body is only a repetition of the session key (I hope so). You need to extract the cookie from HTTP headers. If you are using the JAX-WS you may enable the session awareness using BindingProvider.SESSION_MAINTAIN_PROPERTY:
Hello proxy = new HelloService().getHelloPort();
((BindingProvider)proxy).getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY,true);
String result = proxy.getMessage();
System.out.println(result);
If not, then try to find how to get and set the HTTP headers using your web services framework.
There are multiple ways you can extract the session id.
From the xml you have provided it seems the session id is in the xml response. If this is the case the you can use the method suggested by olyv and extract the session id from the xml response.
As lakshman suggest you could use groovy to parse the session id
from the xml response.
The below code may be of help.
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def holder = groovyUtils.getXmlHolder("Properties#response")
log.info holder.getNodeValue("//sessionId")
log.info holder['//sessionId']
This code and its explanation is available at Are you a hot cup? blog.
Another option using groovy is to extract the cookie from the header and store it in a property. The value of this property will be set in each request by creating a header property called cookie and assigning the session id to it. You'll have to verify the property name and value format by looking at the raw response/request.
try this code for example
//in script assertion
String message_size = messageExchange.responseHeaders["session-id"] /or whatever if the cookie name
or
def state = context.getProperty( com.eviware.soapui.model.testsuite.TestRunContext.HTTP_STATE_PROPERTY )
assert state != null : "Missing HttpState.. Try to set 'Maintain HTTP session' in test case options"
def cookies = state.cookies
Above code sample is from http://forum.soapui.org/viewtopic.php?t=3066#p10957
Lastly, there is a test case level option to maintain http session, if you select this option you wouldn't have to worry about extracting the session id. The soapUI guide on this says..
For example, soapUI uses this internally to store an HttpState object in the context when the "Maintain HTTP Session" option has been selected in the TestCase Options dialog.
link to the above line: http://www.soapui.org/Functional-Testing/testcase-execution.html
API description you have attached points out that all you need to do is to manage your cookies correctly.
Successful login response will have the cookie with session ID (also duplicated as a <sessionId>xxxx</sessionId> element in the response).
All you have to do is to include this cookie in all subsequent calls to this API.
Depending on your HTTP/SOAP client these things just need setting up and the client simply follows the contract of HTTP Cookie standard, so it receives cookies, stores them for as long as they are valid, and passes them with all subsequent requests made to the same URI.
If you are using SoapUI, just add session management to your test case as per the picture below:
If that is not enough and you want to pop the bonnet up and see what is what see this blog
HTH

is it possible to check the authentication status of an HTTP post request before getting the response?

I'm using java.net.HttpURLConnection.
I first write the body of the post request to the OutputStream associated with the URLConnection object.
After I have done that, I close the OutputStream and then call getInputStream() or getResponseCode() or getHeaderFields(). That's when I find out if the provided credentials were considered valid or not valid.
This is problematic, because I don't want to make the same post request again (and have to re-upload its contents, which could include large files) in the event that the user credentials were rejected for some reason.
Since an exception is thrown if there is an attempt to call getOutputStream() after getResponseCode() or getHeaderFields() have been called, how can I ensure that the user credentials were accepted before attempting to upload the data?
Is there a way around this or is it just the way the server is configured?
The short answer is: You can't do that.
Basic auth is stateless. When you're doing a POST/PUT the user credentials are sent as headers for that HTTP request. They are not processed until the entire operation is complete (i.e. after you've sent the data payload).
In order to do what you're talking about you'd need to write a web service that managed login and file/data uploading separately through session management, allowing you to first authenticate (returning a session token of some sort) then send the data via a separate HTTP request.
Edit to add: In reality, you could hack your way around this by simply doing a GET to something that also requires auth. If it succeeds, you know the POST will also succeed baring the credentials being invalidated server side between the two requests. I would not advise this, but it would work.

Can not understand the session object behavior

I am confused on the documentation of the javax.servlet.http.HttpSession.
It says:
Sessions are used to maintain state and user identity across multiple
page requests. A session can be maintained either by using cookies or
by URL rewriting.
Now both cookies and URL rewriting are handled by application code in server (i.e. our code).
Then it says relating to when a session is considered as new:
The server considers a session to be new until it has been joined by
the client. Until the client joins the session, the isNew method
returns true.A value of true can indicate one of these three cases:
1. the client does not yet know about the session
2. the session has not yet begun
3. the client chooses not to join the session. This case will occur if the client supports only cookies and chooses to reject any cookies
sent by the server. If the server supports URL rewriting, this case
will not commonly occur.
I am not clear on when it is considered/meant that the client has joined the session.
I mean if I don't use cookies from my web application (or URL rewriting) and I have the following:
POST from IP A to server
200 OK from server to A
POST from IP A to server
In step 3 will the session.isNew() return true or false? It is not clear to me from the doc.
Will it return false (i.e. the session is not new) and I will have to call session.invalidate() in order to create a new session?
The reason this confuses me more is because I am debugging a piece of code where the client is an HTTP application but not a web brower and I see that in step 3 the session.isNew() does not return true although there is no cookies or url rewriting in the server code.
So I can not figure out what is going out under the hood.
Any info that could help understand this?
Here is a nice example of Session Tracking
Client has joined the session means that client made subsequent request and included session id, which can be recognized by your webserver. If cookies are enabled - jsessionid will be passed with cookies, otherwise - it should be include in the URL itself - like this http://localhost:8080/bookstore1/cashier;jsessionid=c0o7fszeb1.
In JSP c:url from Core Tag Library will handle URL rewriting for you.
In case of B2B communication you have to obtain session id by yourself and include it in subsequent requests manually.
Example:
POST from IP A to server
200 OK from server to A
A obtains session id from the response
POST from IP A to server and includes obtained session id
UPDATE:
Consider reading a great article - "Web Based Session Management: Best practices in managing HTTP-based client sessions." It's a general overview of how HTTP sessions can be emulated and is not tied to Java.

Categories