calling some online service from GWT - java

I have this JavaScript code which is connecting with the service and sending back the result.
Now the requirement is to call the same service from Pure Java.
Below is the javascript code for calling the service.
If some one can guide me to convert this Javascript to Java in my GWT Application
Thanks
function verifyValidationSyntax(textToValidate)
{
var url = "https://validation-grammar.example.com/validation_grammar_service/rest/validation_step_validation";
var client = new XMLHttpRequest();
client.open("POST", url, false);
client.setRequestHeader("Content-Type", "text/plain");
client.send(textToValidate);
if (client.responseText==='true') {
return "true";
} else {
return "false";
}
}

I wont convert your code, But here is the sweetest example from docs
String url = "http://www.myserver.com/getData?type=3";
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
// Couldn't connect to server (could be timeout, SOP violation, etc.)
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
// Process the response in response.getText()
} else {
// Handle the error. Can get the status text from response.getStatusText()
}
}
});
} catch (RequestException e) {
// Couldn't connect to server
}
You may miss this in docs
To use the HTTP types in your application, you'll need to first inherit the GWT HTTP module by adding the following tag to your module XML file:
<inherits name="com.google.gwt.http.HTTP" />

Related

SAMLResponse null in ACS request url :using onelogin toolkit

I am using Onelogin 2.0 toolkit . Instead of having Login and ACS as jsp files I have added them as rest services. I am getting this error when my IdP redirects to ACS Service Url.
SAML Response not found, Only supported HTTP_POST Binding
In request to ACS service SAMLResponse parameter is coming as null. How can I fix this ?
#Path("/saml")
public class SAMLAuthService {
#Context
HttpServletRequest request;
#Context
HttpServletResponse response;
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/dologin")
public void SAMLLogin(){
try {
Auth auth = new Auth(CommonUtils.samlPropertyFileName,request, response);
System.out.println("Calling SAML Login::");
auth.login();
} catch (Exception e) {
e.printStackTrace();
}
}
#POST
#Produces(MediaType.APPLICATION_JSON)
#Path("/acs")
public Response SAMLACS()
throws ExecException {
Response samlResponse = null;
try {
System.out.println("Calling SAML ACS::");
Auth auth = new Auth(CommonUtils.samlPropertyFileName,request, response);
auth.processResponse();
if (!auth.isAuthenticated()) {
System.out.println("Not Authenticated");
}
List<String> errors = auth.getErrors();
if (!errors.isEmpty()) {
if (auth.isDebugActive()) {
String errorReason = auth.getLastErrorReason();
if (errorReason != null && !errorReason.isEmpty()) {
System.out.println(errorReason);
}
}
} else {
Map<String, List<String>> attributes = auth.getAttributes();
String nameId = auth.getNameId();
System.out.println("NameId::"+nameId);
if (attributes.isEmpty()) {
System.out.println("No Attributes");
}
else {
Collection<String> keys = attributes.keySet();
for(String name :keys){
List<String> values = attributes.get(name);
System.out.println(name+"::");
for(String value :values) {
System.out.print(value);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return samlResponse;
}
}
The Auth constructor that you are using expects a HttpServletRequest request object with a SAMLResponse POST parameter
If you don't have that HttpServletRequest object, you can build it using the makeHttpRequest
You can use the SAML Tracer to analyze the SAML flow between the IdP and the SP. You may be sure that the IdP is sending a SAMLResponse. I'm not familiar with the "Rest approach" you are using, but you may see the way to get the SAMLResponse and build the HttpServletRequest object injecting that parameter.

soap webservice client using apache cxf, for ntlm authentication

I want to develop a SOAP client using CXF to connect to SharePoint. The authentication scheme is NTLM.
I am blocked on a scenario where the logged-in user of a machine (on which the SOAP client is being run) has access to SharePoint. The CXF soap client always uses the logged-in user. I want to specify some other user credentials (not the logged-in).
As CXF uses in-JDK HttpURLConnection; and what I have read about HttpURLConnection is, it bypasses the specified credentials when the logged-in user is NTLM authenticated.
Codes were tried on CXF version 2.7.11.
Solutions that I have tried out:
1) Setting Conduit authorization
String username = "user";
String password = "password";
JaxWsProxyfactoryBean factory1 = new JaxWsProxyfactoryBean();
factory1.setServiceClass(WebsSoap.class);
factory1.setAddress(url);
factory1.setUsername(username);
factory1.setPassword(password);
WebsSoap service = (WebsSoap) factory1.create();
Client client = ClientProxy.getClient(service);
HTTPconduit conduit = (HTTPconduit) client.getconduit();
conduit.getAuthorization().setAuthorizationType("NTLM");
conduit.getAuthorization().setUserName(username);
conduit.getAuthorization().setPassword(password);
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(36000);
httpClientPolicy.setAllowChunking(false);
conduit.setClient(httpClientPolicy);
service.getWeb(".");
Problem:
This does not work for the scenario specified above, as it always uses the logged-in credentials. And when I specify invalid credentials, it does not fail.
2) AsyncHTTPConduit
Another solution is to use AsyncHTTPConduit that uses HttpAsyncClient instead of HttpURLConnection. This is beacuse HTTP components do not bypass specified credentials and logged-in user can be ignored (I have successfully verified this with a test client using HttpClient).
Below is the code snippet::
Bus bus = BusFactory.getDefaultBus();
bus.setProperty( "use.async.http.conduit", "true" );
Client client = ClientProxy.getClient( service );
HTTPConduit http = (HTTPConduit)client.getConduit();
if ( http instanceof AsyncHTTPConduit ) {
AsyncHTTPConduit conduit = (AsyncHTTPConduit)http;
DefaultHttpAsyncClient defaultHttpAsyncClient;
try {
defaultHttpAsyncClient = conduit.getHttpAsyncClient();
}
catch ( IOException exception ) {
throw new RuntimeException( exception );
}
defaultHttpAsyncClient.getCredentialsProvider().setCredentials( AuthScope.ANY,
new NTCredentials( "username", "password", "", "domain" ) );
conduit.getClient().setAllowChunking( false );
conduit.getClient().setAutoRedirect( true );
}
Problem:
Above code throws error:
Authorization loop detected on conduit.
The above code snapshot shows the usage of DefaultHttpAsyncClient which is deprecated now and CloseableHttpAsyncClient is to be used instead. But CloseableHttpAsyncClient does not provide a way to specify credentials to an already existing CloseableHttpAsyncClient object. Not sure how to use CloseableHttpAsyncClient in this scenario.
3) Other solutions
The other solution that I tried out is to use sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback, to bypass logged-in user authentication, as mentioned here. Use this approach along with solution #1 mentioned above. This works as expected for valid/invalid credentials, and the code bypasses the logged-in credentials :). But when I specify invalid credentials, I do not get HTTP 401 error, instead I get
Could not send message, server reached max retries 20
I am trying to avoid this solution because it uses java’s internal package and there is no way to determine HTTP 401 error directly.
What can I do to arrive at a complete solution?
Try this interceptor. This will avoid automatic authentication.
public class DisableAutomaticNTLMAuthOutInterceptor extends AbstractPhaseInterceptor<Message>
{
private boolean isFieldsAvailable;
private Field tryTransparentNTLMProxyField;
private Field tryTransparentNTLMServerField;
public DisableAutomaticNTLMAuthOutInterceptor() {
super(Phase.PRE_STREAM);
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Void run() {
try {
DisableAutomaticNTLMAuthOutInterceptor.this.tryTransparentNTLMServerField = HttpURLConnection.class.getDeclaredField("tryTransparentNTLMServer");
DisableAutomaticNTLMAuthOutInterceptor.this.tryTransparentNTLMServerField.setAccessible(true);
DisableAutomaticNTLMAuthOutInterceptor.this.tryTransparentNTLMProxyField = HttpURLConnection.class.getDeclaredField("tryTransparentNTLMProxy");
DisableAutomaticNTLMAuthOutInterceptor.this.tryTransparentNTLMProxyField.setAccessible(true);
DisableAutomaticNTLMAuthOutInterceptor.this.isFieldsAvailable = true;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
}
#Override
public void handleMessage(final Message message) throws Fault {
if (this.isFieldsAvailable)
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Void run() {
try {
Object httpConnection = message.get("http.connection");
if (httpConnection != null) {
DisableAutomaticNTLMAuthOutInterceptor.this.processHttpConnection(message.get("http.connection"));
}
} catch (Throwable t) {
t.printStackTrace();
}
return null;
}
});
}
private void processHttpConnection(Object httpConnection) throws IllegalArgumentException, IllegalAccessException {
if (HttpURLConnection.class.isAssignableFrom(httpConnection.getClass())) {
tryTransparentNTLMServerField.set(httpConnection, Boolean.FALSE);
tryTransparentNTLMProxyField.set(httpConnection, Boolean.FALSE);
} else {
Field tempField = null;
for (Field field : httpConnection.getClass().getDeclaredFields()) {
if (HttpURLConnection.class.isAssignableFrom(field.getType())) {
field.setAccessible(true);
tempField = field;
break;
}
}
if (tempField != null) {
processHttpConnection(tempField.get(httpConnection));
}
}
}
}

Java web service : User defined meta-data

I have a SOAP web service implementation on Jboss 4.2.3. I want to add a version number check for the service. Whenever a client makes a call, I will pass the client version number. I will write an interceptor at the server that would check the client version number. If it is a client with a different version number, I would not process the request.
What I want to know is if there is a way to pass the version number from the client in some context parameter other than adding it in the web service method signature?
In general, if I want to pass some custom META-DATA from client to server, how do I do it ?
In general, if I want to pass some custom META-DATA from client to
server, how do I do it ?
This can be achieved through SOAP Message Handlers both side (Client and Server ) in Jax-WS .
Client Side:
The custom-meta-data , like version number, UUID , Signature information can be added via SOAP Headers.
1..Write a VersionNumberHandler as shown below.
public class VersionNumberHandler implements SOAPHandler<SOAPMessageContext> {
private static final String LoggerName = "ClientSideLogger";
private Logger logger;
private final boolean log_p = true; // set to false to turn off
public VersionNumberHandler() {
logger = Logger.getLogger(LoggerName);
}
public boolean handleMessage(SOAPMessageContext ctx) {
if (log_p)
logger.info("handleMessage");
// Is this an outbound message, i.e., a request?
Boolean request_p = (Boolean) ctx
.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
// Manipulate the SOAP only if it's a request
if (request_p) {
// Get the Version Number from some property file ,
// to place in the message header.
String versionNumber = "v1.0";
try {
SOAPMessage msg = ctx.getMessage();
SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
SOAPHeader hdr = env.getHeader();
// Ensure that the SOAP message has a header.
if (hdr == null)
hdr = env.addHeader();
QName qname = new QName("http://ticket.example.com/",
"versionnumber");
SOAPHeaderElement helem = hdr.addHeaderElement(qname);
// In SOAP 1.2, setting the actor is equivalent to
// setting the role.
helem.setActor(SOAPConstants.URI_SOAP_ACTOR_NEXT);
helem.setMustUnderstand(true);
helem.addTextNode(versionNumber);
msg.saveChanges();
// For tracking, write to standard output.
msg.writeTo(System.out);
} catch (SOAPException e) {
System.err.println(e);
} catch (IOException e) {
System.err.println(e);
}
}
return true; // continue down the chain
}
public boolean handleFault(SOAPMessageContext ctx) {
if (log_p)
logger.info("handleFault");
try {
ctx.getMessage().writeTo(System.out);
} catch (SOAPException e) {
System.err.println(e);
} catch (IOException e) {
System.err.println(e);
}
return true;
}
public Set<QName> getHeaders() {
if (log_p)
logger.info("getHeaders");
return null;
}
public void close(MessageContext messageContext) {
if (log_p)
logger.info("close");
}
2..Mention this class in the Handler-Chain.xml.
<javaee:handler>
<javaee:handler-class>
com.example.client.handler.VersionNumberHandler
</javaee:handler-class>
</javaee:handler>
3..Add the handler-chain in the client (Stub) also.
#WebServiceClient(name = "TicketWSImplService", targetNamespace = "http://ticket.example.com/", wsdlLocation = "http://localhost:8080/ticket?wsdl")
#HandlerChain(file = "handler-chain.xml")
public class TicketWSImplService extends Service {
#WebMethod
public void method(){
}
Here, we are adding a new header element "versionnumber" and mustunderstand=true, which means the server/intermediaries has to process this element, otherwise Jax-WS-Runtime will throw SOAP Fault exception to the client. Now we need to write a Validator(SOAP Handler) at the server side to validate this version number which is being passed by the clients.
Server Side:
1..Write a VersionNumberValidator as shown below.
public class VersionNumberValidator implements SOAPHandler<SOAPMessageContext> {
#SuppressWarnings("unused")
#Override
public boolean handleMessage(SOAPMessageContext ctx) {
// Is this an inbound message, i.e., a request?
Boolean response_p = (Boolean) ctx
.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
// Manipulate the SOAP only if it's incoming.
if (!response_p) {
try {
SOAPMessage msg = ctx.getMessage();
SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
SOAPHeader hdr = env.getHeader();
// Ensure that the SOAP message has a header.
if (hdr == null) {
generateSOAPFault(msg, "No message header.");
return true;
}
Iterator mustUnderstandHeaders = msg.getSOAPHeader()
.examineMustUnderstandHeaderElements(
"http://schemas.xmlsoap.org/soap/actor/next");
String value = null;
while (mustUnderstandHeaders.hasNext()) {
Node next = (Node) mustUnderstandHeaders.next();
System.out.println("mustUnderstandHeaders name:"
+ next.getValue());
if (next.getNodeName().equalsIgnoreCase("versionnumber"))
value = next.getValue();
if (value != null && !value.equalsIgnoreCase("v1.0")) {
generateSOAPFault(msg, "Version Number Mismatch");
}
}
// For tracking, write to standard output.
msg.writeTo(System.out);
} catch (SOAPException e) {
System.err.println(e);
} catch (IOException e) {
System.err.println(e);
}
}
return true; // continue down the chain
}
#Override
public boolean handleFault(SOAPMessageContext ctx) {
return true; // do continue down the chain
}
// For now, no-ops.
#Override
public Set<QName> getHeaders() {
Set<QName> headers = new HashSet<QName>();
QName qName = new QName("http://ticket.example.com/", "versionnumber");
headers.add(qName);
return headers;
}
#Override
public void close(MessageContext messageContext) {
}
private void generateSOAPFault(SOAPMessage msg, String reason) {
try {
SOAPBody body = msg.getSOAPBody();
SOAPFault fault = body.addFault();
QName fault_name = new QName(
SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE, "UltimateReceiver");
fault.setFaultCode(fault_name);
fault.setFaultRole("http://ticket.example.com/versionNumber_validator");
fault.addFaultReasonText(reason, Locale.US);
} catch (SOAPException e) {
}
}
2..Mention this class in the Handler-Chain-server.xml.
<javaee:handler>
<javaee:handler-class>
com.example.client.handler.VersionNumberValidator
</javaee:handler-class>
</javaee:handler>
3..Publish the webservices.
Now, the every client request will be having "version number =v1.0", At the server side , you will be validating this value is correct or not. If it is not correct, SOAPFaultException will be thrown.
You could add it to the http-headers but that would mean your client would need to do this which also means they can change it and give you wrong numbers causing issues on the server. It's only as reliable as the messages being sent in.
Either way, this isn't the right way to restrict access to your Web Service, you should use http basic authentication or if it's version differences then you should create multiple version endpoints giving clients access to the versions they need.
Also, JBoss 4.2.3 is so old it might not even work. See [1]
Mus
[1] https://community.jboss.org/message/534711
It's a bad idea to try to add out-of-band metadata to a web service. Just pick a new URL for each version if the data structures are incompatible. If they are compatible, put the version number inside the request.
This way you can still support interoperation with all different libraries and not require your clients to find a new hoop to jump through for each toolkit.

GWT RequestBuilder - Cross Site Requests

I'm trying to make Cross Site Request using GWT Request builder, which i couldn't get it to work yet. As you can see, this is much of a Sample GWT Project and i have gone through https://developers.google.com/web-toolkit/doc/latest/tutorial/Xsite . But still i'm missing something.
I'm Posting the code here. What am i missing ..?
package com.gwt.reqbuilder.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Window;
public class GWTRequestBuilder implements EntryPoint
{
private static final String JSON_URL = "http://localhost:8000/?q=ABC&callback=callback125";
public void onModuleLoad()
{
GWTPOSTHTTP();
}
public void GWTPOSTHTTP()
{
String postUrl="http://localhost:8000";
String requestData="q=ABC&callback=callback125";
RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, postUrl);
try {
builder.sendRequest(requestData.toString(), new RequestCallback()
{
public void onError(Request request, Throwable e)
{
Window.alert(e.getMessage());
}
public void onResponseReceived(Request request, Response response)
{
if (200 == response.getStatusCode())
{
Window.alert(response.getText());
} else {
Window.alert("Received HTTP status code other than 200 : "+ response.getStatusText());
}
}
});
} catch (RequestException e) {
// Couldn't connect to server
Window.alert(e.getMessage());
}
}
}
Actually we can make Cross Site Requests from GWT RequestBuilder if we can set in Servlet Response Header
Response.setHeader("Access-Control-Allow-Origin","http://myhttpserver");
It's working Cool , if anyone need the GWT Project and Python Servlet, please do let me know, i can upload the files.
GWT Client Code : https://github.com/manikandaraj/MLabs/tree/master/GWT/GWTClient
You've missed to finish reading the tutorial.
Direct quote from the tutorial :
The RequestBuilder code is replaced by a call to the getJson method. So you no longer need the following code in the refreshWatchList method:
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
displayError("Couldn't retrieve JSON");
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
updateTable(asArrayOfStockData(response.getText()));
} else {
displayError("Couldn't retrieve JSON (" + response.getStatusText()
+ ")");
}
}
});
} catch (RequestException e) {
displayError("Couldn't retrieve JSON");
}
Which is broadly what you've got, and should be replaced by a JSNI function given in the tutorial a few lines below :
/**
* Make call to remote server.
*/
public native static void getJson(int requestId, String url,
StockWatcher handler) /*-{
var callback = "callback" + requestId;
// [1] Create a script element.
var script = document.createElement("script");
script.setAttribute("src", url+callback);
script.setAttribute("type", "text/javascript");
// [2] Define the callback function on the window object.
window[callback] = function(jsonObj) {
// [3]
handler.#com.google.gwt.sample.stockwatcher.client.StockWatcher::handleJsonResponse(Lcom/google/gwt/core/client/JavaScriptObject;)(jsonObj);
window[callback + "done"] = true;
}
...

GET request using GWT to retrieve XML data?

Oh hello there, fellow SO members,
I have a web service that returns XML data using a simple get request that goes like this :
http://my-service:8082/qc/getData?paramX=0169&paramY=2
the service returns raw xml in the page according to the parameters' values.
I am trying to retrieve this data from a GET request in GWT using RequestBuilder, Request, etc.
However, the response gives me empty text, a Status code of ZERO (which doesn't mean anything and isn't supposed to happen), and so on.
Here's the simplified code that doesn't work.
public class SimpleXML implements EntryPoint {
public void onModuleLoad() {
this.doGet("http://my-service:8082/qc/getData", "0169", "2");
}
public void doGet(String serviceURL, String paramX, String paramY) {
final String getUrl = serviceURL + "?paramX=" + paramX + "&idTarification=" + paramY;
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, getUrl);
try {
Request response = builder.sendRequest(null, new RequestCallback() {
#Override
public void onResponseReceived(Request request, Response response) {
response.getStatusCode(); // Gives me 0 (zero) :(
}
#Override
public void onError(Request request, Throwable exception) {
// ... doesn't matter for this example
}
});
} catch (RequestException e) {
// ... doesn't matter for this example
}
}
}
I don't get why this wouldn't work, since this is REALLY simple, I've seen tutorials and they all show me this way of doing things..
Thanks in advance
The reason is, that browsers do not allow cross-site requests with AJAX (see Same Origin Policy).
This means, that you can only call a service on the same server, same port (using the same protocol) as your HTML page. If you want to perform cross-site requests, you can use JSONP, as explained in http://code.google.com/webtoolkit/doc/latest/tutorial/Xsite.html.

Categories

Resources