How to properly connect strophe.js client with Prosody server using XMPP protocol - xmpp

I've installed and configured Prosody server. It listens on standard localhost:5222. Added admin in configuration file - user1#example.com. Every request to server ended up with error:
<stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" id="" version="1.0">
<stream:error>
<not-well-formed xmlns="urn:ietf:params:xml:ns:xmpp-streams"/>
</stream:error>
</stream:stream>
As a client I would like to use strophe.js. I'm sending only presence stanza ($pres). Here is my code.
'use strict';
angular.module('xmppTestApp')
.controller('ChatCtrl', function () {
var vm = this;
var url = "http://localhost:5222";
var connection = null;
var output = document.getElementById("output");
function log(message) {
var line = document.createElement("div");
line.textContent = message;
output.appendChild(line);
}
function connectHandler(cond) {
if (cond == Strophe.Status.CONNECTED) {
log("connected");
connection.send($pres());
}
else {
log("not connected");
}
}
vm.connectB = function() {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
console.info(url);
console.info(username);
console.info(password);
connection = new Strophe.Connection(url);
connection.connect(username, password, connectHandler);
}
});
In console i see error:
XMLHttpRequest cannot load http://localhost:5222/. No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:9000' is therefore not allowed access.
How can I add Access-Control-Allow-Origin' header to my request?
When I'm trying send request to localhost:5222 (without http) I'm getting:
XMLHttpRequest cannot load localhost:5222. Cross origin requests are only supported for HTTP.
And when I send it through websocket, I'm getting:
WebSocket connection to 'ws://localhost:5222/' failed: Error during WebSocket handshake: Unexpected response code: 200
Fiddler provides me protocol violation report:
The server didn't return properly-formatted HTTP Headers. Maybe missing altogether
(e.g. HTTP/0.9), maybe only \r\r instead of \r\n\r\n?

First and foremost, it looks like you're trying to connect directly to port 5222 (typically used for XMPP), but in order to use Strophe from a client-side webpage, you must use HTTP-Binding (aka BOSH).
XMPP vs BOSH
Strophe speaks XMPP, but it is unique in that it does not actually transmit data using the XMPP protocol, instead it relies on BOSH for this (that is, Bidirectional-streams Over Synchronous HTTP). This is because the XMPP protocol is designed to keep the client and server connected at all times, and we all know this isn't how HTTP works. To put it in simple terms, BOSH allows your HTTP client to asynchronously receive data without having to explicitly make a request for it. If you have more questions regarding BOSH let me know and I'll try my best to explain what is does and why you need it.
You must enable this feature in prosody before connecting with Strophe, check out this link to get setup.
Prosody Docs - Setting up BOSH
Once you've setup BOSH, you will need to change your client side code to use a different address. It is likely that you have setup the path+port for BOSH to something such as :5280/http-bind/. At this point you need to make sure that Strophe is using this URL instead of the actual XMPP port of 5222.
Finally, CORS is required for any resource outside of your websites domain and port. In your example, your client has to make a request to a URL which is running on a different port+domain as the page itself (the connection between Strophe and Prosody). Good news is, Prosody already supports CORS and enabling it is very straightforward. All of this is explained in much further detail on the page I linked earlier.
Hope that helps!

Related

Accessing ArcGIS data over HTTP

I am attempting am building a map data React app using GIS data. I am accessing public GIS endpoints.
The endpoint is http://gis.infrastructure.gov.au/infrastructure/rest/services/KeyFreightRoute/KFR/MapServer/0
On local development, it is working fine. However, once pushed to live it returns the error: net::ERR_CONNECTION_REFUSED. Due to it being an HTTP endpoint.
The ArcGIS docs describe a solution using config, and I have included the following code:
esriConfig.request.interceptors.push({
// set the `urls` property to the URL of the FeatureLayer so that this
// interceptor only applies to requests made to the FeatureLayer URL
urls: featureLayerUrl,
// use the BeforeInterceptorCallback to check if the query of the
// FeatureLayer has a maxAllowableOffset property set.
// if so, then set the maxAllowableOffset to 0
before: function (params) {
if (params.requestOptions.query.maxAllowableOffset) {
params.requestOptions.query.maxAllowableOffset = 0;
}
},
// use the AfterInterceptorCallback to check if `ssl` is set to 'true'
// on the response to the request, if it's set to 'false', change
// the value to 'true' before returning the response
after: function (response) {
if (!response.ssl) {
console.log('not ssl');
response.ssl = true;
}
},
});
However, it still isn't working!? In fact, the console.log('not ssl') isn't even logging on the live site (but it is logging on localhost).
How do you access HTTP GIS endpoints?
This is more of a browser limitation than a GIS-specific problem. If your current URL bar has "HTTPS", the page is not allowed to access HTTP resources - the browser enforces this as a security measure. You have two options:
Convince the owner of that site ("gis.infrastructure.gov.au") to enable HTTPS. This is standard practice these days and fairly trivial to do. They should do this.
You can run a proxy like the Esri Resource Proxy on your own server. That way your application will access the url via HTTPS (because your server is secured with HTTPS), but then the server makes the HTTP request on the server site, thus getting around the browser security limitation

How to secure a Jersey REST call in this case

The problem i am facing is that clicking on F12 on Chrome Browser , i could see all the Rest Calls which are made to fetch the data
For example , one of the REST API call is
(When clicked on the above link , it fetches the data )
This is my front code consists of Jquery
function displaymarketupdates() {
var updatedon = "";
var html = '';
var t = "",
$.ajax({
type: "GET",
url: e,
crossDomain: !0,
dataType: "json",
timeout: 17e3,
async: !0,
cacheResults: !1,
cache: !1,
contentType: "application/json",
charset: "utf-8",
beforeSend: function() {
$(".loadingWrapformarketupdates").show()
},
complete: function() {
$(".loadingWrapformarketupdates").hide()
},
success: function(response) {
},
error: function(t, e, a) {
$(".loadingWrapformarketupdates").hide()
}
}).done(function() {
})
}
And this is my service
#Path("/fetchallvalues")
public class FetchAllValues {
public FetchAllValues() {}
private final static Logger logger = Logger.getLogger(FetchAllValues.class);
#GET#Produces("text/plain")
public Response Fetch_all_values() {
PreparedStatement fetch_all_pstmt = null;
ResultSet fetch_all_Rset = null;
Connection dbConnection = null;
ResponseBuilder builder = Response.status(Status.NOT_FOUND);
final JSONArray fetch_array = new JSONArray();
final String inputsql = "select * from all_values";
try {
dbConnection = DBConnection.getDBConnection();
fetch_all_pstmt = dbConnection.prepareStatement(inputsql);
fetch_all_Rset = fetch_all_pstmt.executeQuery();
while (fetch_all_Rset.next()) {
====
}
Response.status(Status.OK);
builder = Response.ok(fetch_array.toString());
} catch (Exception e) {
e.printStackTrace();
logger.error("Error description", e);
} finally {
try {
DBConnection.close(fetch_all_pstmt, fetch_all_Rset);
} catch (Exception e) {
logger.error("Error description", e);
}
try {
DBConnection.close(dbConnection);
} catch (Exception e) {
logger.error("Error description", e);
}
}
return builder.build();
}
}
Could you please let me know how to secure the REST CALL in this case
You cannot hide an URL from a Browser's network monitoring. It is meant to be displayed so that it can be inferred that what is happening when you hit a button or click something.
Securing a REST Jersey call is a totally different thing. That means you do not want people to see your data that you are going to pass. As correctly mentioned by Martingreber that if you call this URL on HTTPS that may help you encrypt data that you send across the servers. Or securing a REST call actually means you provide some kind of authentication to it . Like Basic , Hashing like MD5, Token based Authentication like JWT.
The only thing that you can do to hide explicit details from your browser that runs your JavaScript is minify your script . But still your URL remains exposed as many times as it is called by someone who fiddles with the F12 key on Chrome to see what's going on. One more thing can be if you are concerned about your main service call, and don't want to expose that , then just PROXY it using some service, which you are already doing . But by no means, you can avoid your URL being getting displayed, when someone calls it.
In your case fetchAllValues service is fetching the data and exposing it to anybody on the web who clicks it, but that can be prevented if you authenticate the service, like the minute i click that URL, it asks me for a password! Then i cannot access it. A very simple way to authenticate this service would to call a Filter or an Interceptor just before the request to ask for username and password like credentials.
I hope you got the point. Hope this helps :)
You will always be able to see the URL that is being processed. Still, you could obfuscate the Service Endpoint to hide the purpose of the service itself, e.g. #Path("/XYZ")instead of #Path("fetchallvalues")
If you want to hide the data that is being transmitted between the client and the server, so noone can read it, simply use https. Depending on your webserver (Jetty, Tomcat) you will have to configure it differently, still you will need a ssl certificate for your domain, which you can get here for example: https://letsencrypt.org
If you want to secure your webservice, so it can't be used by anyone, but only by specific users, you might want to give Spring Security a try: User authentication on a Jersey REST service
This is a problem that needs some smart hacks to fix it.
In the hyperlinked stackoverflow page, you will get an example of how to make a SOAP request from client side JavaScript.
SOAP request from JavaScript
Now here's the plan:
In the server side, we have a random number generator, which generates a random number in short intervals, say 5 minutes.
The random number generator will be exposed as a SOAP service and it will produce the random number generated.
From the client side, we will invoke the SOAP random generator service (refering to the stackoverflow page mentioned above) and get the generated random number as the response. We will invoke the service from a JS function which will be fired when your page is loaded (onLoad). So, now we have the random number at the client side.
Then, we pass the random number as a path param in the GET request URL of the REST call and fire the GET request.
In the server side, once the Rest GET request is received, we check if the number received as path param is the same number that is generated in the server side.
If the numbers match, then we give the required response, else do not send the response.
Here we are trying to introduce an unique key, which is the random number generated at the server side. This unique key, when passed as the path param of the Rest GET request URL, serves as an identity of the origin of the Rest GET call. For someone who wants to invoke the Rest Api by referring to the Network Tab of the Chrome Dev console, will not get the unique key for a long time ( as it is refreshed/regenerated after every 5 minutes). Thus the hacker will not be able to use the Rest Api for a long duration. Also, since we are transporting the unique key (the random number) from the server to client side using SOAP, it is not possible for the hacker to get it from the Chrome's developer console.
Hope this approach helps!
Unfortunately, there is nothing you can do to prevent the client from inspecting the requested URL. But you always can require credentials to access your API endpoints.
Authentication in REST APIs
In REST applications, each request from the client to the server must contain all the necessary information to be understood by the server. With it, you are not depending on any session context stored on the server and you do not break the REST stateless constraint, defined by Roy Thomas Fielding in his dissertation:
5.1.3 Stateless
[...] communication must be stateless in nature [...], such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. [...]
When accessing protected resources (endpoints that require authentication), every request must contain all necessary data to be properly authenticated/authorized. And authentication data should belong to the standard HTTP Authorization header. From the RFC 7235:
4.2. Authorization
The Authorization header field allows a user agent to authenticate
itself with an origin server -- usually, but not necessarily, after
receiving a 401 (Unauthorized) response. Its value consists of
credentials containing the authentication information of the user
agent for the realm of the resource being requested. [...]
In other words, the authentication will be performed for each request.
Basic authentication
The Basic Authentication scheme, defined in the RFC 7617, is a good start for securing a REST API:
2. The 'Basic' Authentication Scheme
The Basic authentication scheme is based on the model that the client
needs to authenticate itself with a user-id and a password for each
protection space ("realm"). [...] The server will service the request only if it can validate
the user-id and password for the protection space applying to the
requested resource.
[...]
To receive authorization, the client
obtains the user-id and password from the user,
constructs the user-pass by concatenating the user-id, a single
colon (":") character, and the password,
encodes the user-pass into an octet sequence,
and obtains the basic-credentials by encoding this octet sequence
using Base64 into a sequence of US-ASCII
characters.
[...]
If the user agent wishes to send the user-id "Aladdin" and password
"open sesame", it would use the following header field:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
[...]
Token-based authentication
If you don't want to send the username and the password over the wire for every request, you could consider using a token-based authentication. In this approach, you exchange your hard credentials (username and password) for a token which the client must send to the server in each request:
The client sends their credentials (username and password) to the server.
The server authenticates the credentials and generates a token.
The server stores the previously generated token in some storage along with the user identifier and an expiration date.
The server sends the generated token to the client.
In every request, the client sends the token to the server.
The server, in each request, extracts the token from the incoming request. With the token, the server looks up the user details to perform authentication and authorization.
If the token is valid, the server accepts the request.
If the token is invalid, the server refuses the request.
The server can provide an endpoint to refresh tokens.
Again, the authentication must be performed for every request.
The token can be opaque (which reveals no details other than the value itself, like a random string) or can be self-contained (like JSON Web Token).
Random String: A token can be issued by generating a random string and persisting it to a database with an expiration date and with a user identifier associated to it.
JSON Web Token (JWT): Defined by the RFC 7519, it's a standard method for representing claims securely between two parties. JWT is a self-contained token and enables you to store a user identifier, an expiration date and whatever you want (but don't store passwords) in a payload, which is a JSON encoded as Base64. The payload can be read by the client and the integrity of the token can be easily checked by verifying its signature on the server. You won't need to persist JWT tokens if you don't need to track them. Althought, by persisting the tokens, you will have the possibility of invalidating and revoking the access of them. To find some great resources to work with JWT, have a look at http://jwt.io.
In a token-based authentication, tokens are your credentials. So the tokens should be sent to the server in the standard HTTP Authorization header as described above.
Once you are using Jersey, you could have a look at this answer for more details on how to implement a token-based authentication in Jersey.
HTTPS
When sending sensitive data over the wire, your best friend is HTTPS and it protects your application against the man-in-the-middle attack.
To use HTTPS, you need a certificate issued by a certificate authority such as Let’s Encrypt, that claims to be a free, automated, and open certificate authority.

Fiddlercore: how to block and redirect sites

Fiddler core .net api proxy server captures network traffic.
how to redirect any http/https url to another site.?
suppose if I browse yahoo.com, then proxy server should redirect to another site such as wikipedia.com. Browser should open wikipedia instead of yahoo.com.
how to block any web site.?
suppose when I hit espncricinfo.com in browser, then site must be blocked and stopped its session
These topics are well-covered in the Fiddler book and in numerous tutorials around the web.
Inside your BeforeRequest handler, add code that examines the request and returns a redirect (or an error page)
if (oSession.urlContains("whatever"))
{
oS.utilCreateResponseAndBypassServer();
oS.oResponse.headers.SetStatus(307, "Redirect");
oS.oResponse["Cache-Control"] = "nocache";
oS.oResponse["Location"] = "http://newurl/";
oS.utilSetResponseBody("<html><body>sending request elsewhere</body></html>");
return;
}

Is it normal for IBM Connections opensocial gadgets to make 2 HTTP requests on gadgets.io.makeRequest?

Within an IBM Connections sharebox/share dialog gadget my-sharebox.xml, I make the following request:
gadgets.io.makeRequest(url, function (response) { ... });
Using tcpflow on the IBM Connections server to capture the outgoing request & response, I see 2 HTTP requests.
The first one to the url specified above, and a second request to the gadget XML file, my-sharebox.xml.
Is this second request expected behaviour?
Is it possible to somehow suppress the second request?
In a production environment it should be caching the gadget XML and only fetch it once. That will usually happen when the gadget is rendered. Do you have all debug parameters related to opensocial disabled?

Handle see-other-host in smack

I'm trying to use smack in order to connect to Microsoft's Xmpp Msn api. Last april they made a change in their implementation which forces clients to implement the "see-other-host" xmpp specification. When I try to connect to "xmpp.messenger.live.com" I get
stream:error (see-other-host)
at org.jivesoftware.smack.PacketReader.parsePackets(PacketReader.java:260)
at org.jivesoftware.smack.PacketReader.access$000(PacketReader.java:43)
at org.jivesoftware.smack.PacketReader$1.run(PacketReader.java:70)
I'm debugging and I can see the raw received packets
<stream:stream from="messenger.live.com" version="1.0" id="59784" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">
<stream:features xmlns:stream="http://etherx.jabber.org/streams"><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required /></starttls></stream:features>
<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls" />
<stream:stream from="messenger.live.com" version="1.0" id="59785" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">
<stream:error xmlns:stream="http://etherx.jabber.org/streams"><see-other-host xmlns="urn:ietf:params:xml:ns:xmpp-streams">BY2MSG3020517.gateway.edge.messenge r.live.com</see-other-host></stream:error>
But I'm unable to find a way in order to intercept and handle that redirect.
Has anybody done this? Any help would be appreciated. Thanks.
BTW I've already post this on smack forums but got no reply, hope this is isn't considered cross-posting.
This background may help in fixing the problem
The see-other-host stream error redirects a client to another server. In the case of Messenger, it's intended to allow clients to cleanly switch to another server should their current server go out of service, or to connect to another server for load-balancing purposes.
Based on Sample Java Codes that uses SAMCK there are two problems:
The registered connection listeners don't receive notification of the exception
there's no way to access the text element of a stream error from XMPPException
Handling the redirection internally would be the friendliest solution, but notifying the client of the new server would at least allow clients to make a new connection without user intervention.
I added see-other-host support to SMACK API for try. Now i can get see-other-host address as an Exception. For Example when i try to connect to messenger.live.com address i'm successfully getting see-other-host : BAYMSG1020118.gateway.messenger.live.com .
Then i try to connect BAYMSG1020118.gateway.messenger.live.com , i'm getting see-other-host again with different address: BY2MSG4010610.gateway.messenger.live.com
Finally when i try to connect BY2MSG4010610.gateway.messenger.live.com , i'm getting this exception :
No response from the server.:
java.lang.NullPointerException
at org.jivesoftware.smack.NonSASLAuthentication.authenticate(NonSASLAuthentication.java:73)
at org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:211)
at org.jivesoftware.smack.Connection.login(Connection.java:348)
at com.ms.wlm.XmppClient.logIn(XmppClient.java:161)
at com.ms.wlm.Program.main(Program.java:62)
I'll share this result with Smack guys also. If you want, I can send to you the capture of our xmpp traffic via email.
Best Regards,
Alper Ozdamar
I finally found a solution for this issue by changing hostname from messenger.live.com to 64.4.61.217 in ConnectionConfiguration constructor as shown in the code below:
I got this IP by executing (nslookup messenger.live.com) in Dos Command Prompt then I got an Address which I have used in the ConnectionConfiguration.
SASLAuthentication.registerSASLMechanism("X-MESSENGER-OAUTH2",
XMessengerOAuth2.class);
SASLAuthentication.supportSASLMechanism("X-MESSENGER-OAUTH2");
ConnectionConfiguration config = new ConnectionConfiguration("64.4.61.217", 5222, "messenger.live.com");
config.setRosterLoadedAtLogin(true);
config.setSASLAuthenticationEnabled(true);
connection = new XMPPConnection(config);
connection.connect();
connection.login(username, password);
Hope this would help,,,