I'm new to Java, what I'm trying to accomplish is to provide some sort of "session" between Java client and ASMX web-service.
Using wsimport.exe and wsdl I managed to generate a bunch of classes for proxy interaction, web methods are called, and I can get response as predifined class "WebResponse".
I pass Login and Password parameters in SOAP, the service returns OK status from login method. But when I invoke other methods, I get access denied. When I do the same in chrome, it works fine.
I guess I have to extract cookies from generated inherited objects like "Provider"(service), "ProviderSoap" somehow and set it again for next request.
Any advice would be helpful, thank you in advance.
You check the SOAP response of the login operation. What are all the values you are getting in the response? You need to see what the the contains and what contains. Because the service may use a token in the soap header.
I made it work with this code.
ProviderService service = new ProviderService ();
ProviderSoap soap = service.getPort(ProviderSoap.class);
soap.login("Administrator", "");
Map<String, List<String>> map = (Map<String, List<String>>)
((BindingProvider)soap).getResponseContext().get(MessageContext.HTTP_RESPONSE_HEADERS);
String cookieParams = "";
List<String> cookies = map.get("Set-Cookie");
if (cookies != null) {
StringBuffer strBuf = new StringBuffer();
for (String type : cookies) {
strBuf.append(type);
}
cookieParams = strBuf.toString();
}
((BindingProvider)soap).getRequestContext().put(
MessageContext.HTTP_REQUEST_HEADERS,
Collections.singletonMap("Cookie", Collections.singletonList(cookieParams)
)
);
response = soap.isSessionEstablished();
this.Context.Request.Cookies works for me in a class that inherits from System.Web.Services.WebService
Related
I need my Java application to make a PATCH request to a web server using SSL.
I have tried the following:
public String patchForm(FormDataMultiPart f, Map<String,String> headers) {
Entity<FormDataMultiPart> entity = Entity.entity(f, f.getMediaType());
webTarget.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
Builder request = webTarget.request();
if (headers != null){
for (String key : headers.keySet()){
request = request.header(key, headers.get(key));
}
}
Response result = request.method("PATCH", entity);
return result.readEntity(String.class);
}
Where Entity is javax.ws.rs.client.Entity and webTarget is a javax.ws.rs.client.WebTarget.
However, when I make the request, the server interprets it as a POST request and gives me the wrong response.
What could be the cause of the problem? Is there any way to fix it?
Thank you in advance.
For a Patch you need to set which url you are hitting to be secure.
For example
Your webTarget will have
webTarget.path("https://secureUrlWichWillForceSsl.com");
if it starts with http:// it will not be secure and no SSL.
After a lot of trial and error, doing and undoing, adding _HttpMethod=PATCH to the query string and then removing it because it turned out not to be necessary, especially adding a missing break to a switch close which was causing the patchForm function to not be called at all (yes, that was a stupid oversight which cost me hours of work), and then fixing the errors which kept cropping up, I have finally arrived at something which works.
The code which finally worked was the following:
public String patchForm(FormDataMultiPart f, Map<String,String> headers) {
Entity<FormDataMultiPart> entity = Entity.entity(f, f.getMediaType());
webTarget.register(MultiPartFeature.class);
webTarget.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
Builder request = webTarget.request();
headers.put("X-HTTP-Method-Override", "PATCH");
if (headers != null){
for (String key : headers.keySet()){
request = request.header(key, headers.get(key));
}
}
Response result = request.patch(entity);
return result.readEntity(String.class);
}
Note that the Builder class has a built-in patch method. I was using an old library which did not have it. And yet, the method workaround is still necessary because otherwise I get an exception since the PATCH method is non-standard.
Also note that, when submitting multipart forms, it is important to register the Multipart feature. I have read that it is possible to register it either on the client by overriding the configureClient method (when writing a custom client) or on the web target. Doing it on the web target suited my needs better, but you can do it in whatever way works best for you.
I want a java way to extract the parameters of a URL regardless the way these parameters are written in it, in the regular way like( https://www.facebook.com/Doly.mohamed.Smile9?ref=stream&hc_location=stream ) it's so easy because all i have to do is :
URL url = new URL("www.blabla....etc");
String query = url.getQuery();
try{
String [] params = query.split("&");
for(int i= 0 ; i < params.length; i++){
String [] split = params[i].split("=");
parameters.put(split[0], split[1]);
}
}catch(NullPointerException ex){}
so the parameters values would be :
key = ref value = stream , key = hc_location value = stream
but what shall i do if the URL has parameters written in another way or if the URL does't has it's parameters written in it like in the case of the doPost() way.
and is there is a way to get the extraPathInfo from a URL without using servlets?
You could do that easily with Apache's HTTP utils.
URIBuilder uriBuilder = new URIBuilder(uriString);
List<NameValuePair> urlParameters = uriBuilder.getQueryParams();
String uriWithoutParameters = uriBuilder.clearParameters().toString();
Now you could, for example, easily convert the GET request to a POST request, using other classes from the http utils API.
There is a difference between GET and POST urls
In GET url, parameters are part of URL and in POST they are part of Request-body.
So in POST, the URL may or may not contain the request params, and unless you don't have them in the URL its not possible to extract.
The POST request method is designed to request that a web server
accept the data enclosed in the request message's body for storage.1
It is often used when uploading a file or submitting a completed web
form.
So unless you have the POST request's body. Its difficult to extract the Parameter.
Typically you need HTTP request parameters on HTTP server side. Java HTTP server will parse the request and pass it as ServletRequest object to Servlet.service method. ServletRequest has methods to access the request parameters.
This may be standard stuff but unable to get it wokring.
I'm using org.apache.commons.httpclient.methods for making Http request from my Java code. In one instance I've to make a PUT request and pass some parameters. I'm doing it the following way:
PutMethod putMethod = new PutMethod(url);
putMethod.getParams().setParameter("param1", "param1Value");
putMethod.getParams().setParameter("param2", "param2Value");
httpClient.executeMethod(putMethod);
But at the server, when it tries to read these parameters - it can only get null.
However, When I modify my url as url?param1=param1Value¶m2=param2Value it works.
How do I get it working using setParameter method?
To add Query Params to PutMethod, follow this method.
NameValuePair[] putParameters = new NameValuePair[2];
putParameters[0] = new NameValuePair(Param1, value1);
putParameters[1] = new NameValuePair(Param2, value2);
HttpClient client = new HttpClient();
PutMethod putMethod = new PutMethod(url);
putMethod.setQueryString(putParameters);
Then Call,
int response = client.executeMethod(putMethod);
Instead of putMethod.setQueryString(putParameters); you could also use
putMethod.setRequestBody(EncodingUtil.formUrlEncode(putParameters, "UTF-8"));
(This is deprecated)
GetMethod, PostMethod have slight differences when adding Query Params compared to the above code.
For More Code Examples : http://www.massapi.com/class/pu/PutMethod.html
Hope this helps.
your server side code has to support the PUT method
for example if its a Servlet you can include the method
doPUT(); // your put request will be delivered to this method
if you use REST based frameworks such as jersey
you can use
#PUT
Response yourPutMethod(){..}
I'm currently using the OAuth-Signpost Java library to sign requests sent from a client to a server which implements OAuth authentication. When making GET requests (using HttpURLConnection) everything works fine: requests are signed, parameters are included and signatures match in destination. However, it doesn't seem to work with POST requests. I'm aware of the issues that may come up when signing POST using HttpURLConnection, so I moved to the Apache HttpComponents library for these requests. The parameters I send in the following example are plain strings and a XML-like string ('rxml'). My code goes as follows:
public Response exampleMethod(String user, String sp, String ep, String rn, String rxml){
//All these variables are proved to be correct (they work right in GET requests)
String uri = "...";
String consumerKey = "...";
String consumerSecret = "...";
String token = "...";
String secret = "...";
//create the parameters list
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("user", user));
params.add(new BasicNameValuePair("sp", sp));
params.add(new BasicNameValuePair("ep", ep));
params.add(new BasicNameValuePair("rn", rn));
params.add(new BasicNameValuePair("rxml", rxml));
// create a consumer object and configure it with the access
// token and token secret obtained from the service provider
OAuthConsumer consumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
consumer.setTokenWithSecret(token, secret);
// create an HTTP request to a protected resource
HttpPost request = new HttpPost(uri);
// sign the request
consumer.sign(request);
// set the parameters into the request
request.setEntity(new UrlEncodedFormEntity(params));
// send the request
HttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);
//if request was unsuccessful
if(response.getStatusLine().getStatusCode()!=200){
return Response.status(response.getStatusLine().getStatusCode()).build();
}
//if successful, return the response body
HttpEntity resEntity = response.getEntity();
String responseBody = "";
if (resEntity != null) {
responseBody = EntityUtils.toString(resEntity);
}
EntityUtils.consume(resEntity);
httpClient.getConnectionManager().shutdown();
return Response.status(200).entity(responseBody).build();
}
When I send a POST request to the server I get an error telling that the signatures (the one I send and the one the server calculates by itself) don't match, so I guess it has to do with the base string they are signing and the way the POST signing works, since they're handling the same keys and secrets in both sides (checked).
I've read that a way to go through this is setting the parameters as part of the URL (as in a GET request). It wouldn't work for me though, since the XML parameter may exceed the URL length so it needs to be sent as a POST parameter.
I suppose I'm doing something wrong either signing the POST requests or handling the parameters, but I don't know what it is. Please, could you help me out?
P.S: I apologize if I lack context, error traces or additional information regarding this issue, but I'm newbie around here. So please don't hesitate to ask me for more information if you need it.
A bit of backstory/explanation
I've been having a similar problem for the past couple of days, and had almost given up. Until I heard that the guy at my company that was putting up the services I was communicating with, had configured them to read the OAuth information from the query string instead of header parameters.
So instead of reading it from the header parameter Authorization that Signpost puts into the request when you pass it on to be signed, for instance [Authorization: OAuth oauth_consumer_key="USER", oauth_nonce="4027096421883800497", oauth_signature="Vd%2BJEb0KnUhEv1E1g3nf4Vl3SSM%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1363100774", oauth_version="1.0"], the services where trying to read the query string, for example http://myservice.mycompany.com?oauth_consumer_key=USER&oauth_nonce=4027096421883800497&oauth_signature=Vd%2BJEb0KnUhEv1E1g3nf4Vl3SSM%3D&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1363100774&oauth_version=1.0.
The problem with this is that when I tried to sign the url and then build a HttpPost request with it, the url got a basestring with the prefix GET instead of POST which gave another signature then the one the service computed. Signpost isn't doing anything wrong, its url signing method is just by default set to GET with no other possibility available out of the box. This is so because you should read header parameters when doing POST, not the query string (Going to egg the house of that "colleague" of mine), and Signpost adds these when signing request which you should do when doing POST.
The signingbasestring can be observed in the SigningBaseString class method generate in Signpost.
Solution
Now this is how I did it, but other ways may be possible or even better.
Get the signpost source code and add it to your project. Can get it here
Locate the OAuthConsumer class and change the signing method so that you can pass on information that the request should be POST. In my case I added a boolean like so public String sign(String url, boolean POST)
Now you need to change the sign method in the AbstractOAuthConsumer class, which CommonsHttpOAuthConsumer and DefaultOAuthConsumer extend. In my case I added the boolean variable to the method and the following if(POST) request.setMethod("POST"); right before the method calls sign(request);
Now the request is a Signpost specific object, HTTPRequest, so this will throw an error. You'll need to change it and add the method public void setMethod(String method);.
This will cause an error in the following classes HttpURLConnectionRequestAdapter, HttpRequestAdapter and UrlStringRequestAdapter. You'll need to add the method implementation to them all, but in different flavors. For the first you'll add
public void setMethod(String method){
try {
this.connection.setRequestMethod(method);
} catch (ProtocolException e) {
e.printStackTrace();
}
}
for the second you'll add
public void setMethod(String method){
try {
RequestWrapper wrapper = new RequestWrapper(this.request);
wrapper.setMethod(method);
request = wrapper;
} catch (org.apache.http.ProtocolException e) {
e.printStackTrace();
}
}
and for the last you'll add
public void setMethod(String method){
mMethod = method;
}
Be warned that I've only used and tried the first and last. But this at least gives you an idea about how to fix the problem, if you are having the same one as I.
Hope this helps in anyway.
-MrDresden
Signing POST requests using oauth-signpost and HttpURLConnection is doable, but it requires a bit of a hack:
The trick is to percent-encode the POST parameters, and add them to the OAuth library using method setAdditionalParameters().
See this article for an example.
This answer helped me.
but for PALINTEXT method, you do not need to have params and also url.
they don't change the signature. signature is constant and based on secrets.
but for SHA1 (and other methods) you can use the above answer.
I'm working on an ESB project and I need to call a REST service using a POST request. HttpRouter seems to be the right way to do it since it supports both GET and POST methods but I can't find a way to inject parameters inside my call.
How can I do that ?
You can try Apache HTTP library. It's very easy to use and have comprehensive set of class needed to manipulate HTTP request.
Found the answer... It was pretty dumb. All you need to do is to inject parameters inside the Message object and they will be in the body of the request. Here is a sample code created by JBoss and found from a unit test of HttpRouter :
final ConfigTree tree = new ConfigTree("WrappedMessage");
tree.setAttribute("endpointUrl", "http://127.0.0.1:8080/esb-echo");
tree.setAttribute("method", "post");
tree.setAttribute("unwrap", "false");
tree.setAttribute("MappedHeaderList", "SOAPAction, Content-Type, Accept, If-Modified-Since");
HttpRouter router = new HttpRouter(tree);
Message message = MessageFactory.getInstance().getMessage(type);
message.getBody().add("bar");
Message response = router.process(message);
String responseBody = (String)response.getBody().get();
String responseStr = null;
if (deserialize)
responseStr = Encoding.decodeToObject(responseBody).toString();
else
responseStr = responseBody;
return responseStr;