AGSXMPP disconnects with Google Cloud Connection (GCM) - xmpp

Connecting via XMPP to Google Cloud Connection Server (http://developer.android.com/google/gcm/ccs.html) for the purpose of sending/receiving notifications to Android devices.
Using AGSXMPP (latest version at time of writing) in a .NET4.5 Console Application to test in.
However, immediately after sending the opening XML - the connection is closed. And I cannot find any explanation.
What is sent:
<stream:stream to='gcm.googleapis.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en'>
Note that in the Google documenation, the stream is self-closed <stream /> where as AGSXMPP hasn't sent this - not sure if it makes a difference.
Using wireshark, I can see the message is sent in a stream, to which Google responds with a TCP Reset - the connection is then closed.
xmpp = new XmppClientConnection
{
UseSSL = true,
UseStartTLS = true,
Server = "gcm.googleapis.com",
ConnectServer = "gcm.googleapis.com",
Port = 5235,
Username = "<SENDER ID>#gcm.googleapis.com",
Password = <KEY>,
AutoResolveConnectServer = false,
SocketConnectionType = SocketConnectionType.Direct,
KeepAlive = true,
};
xmpp.Open();
I'm assuming that even if the other settings are incorrect (such as login) I should at least be able to get past this stream message and establish a connection of sorts.

There was some confusion over this scentence in the Google Documentation:
CCS requires a Transport Layer Security (TLS) connection. That means
the XMPP client must initiate a TLS connection.
In relation to agsXMPP, this means UseSSL and not UseStartTLS. I had both set to true, but UseStartTLS sets UseSSL to false. Google closes the connection on a non-SSL connection. Setting UseStartTLS to false (even though the docs talking about initating with a TLS connection) - will allow a SSL connection to establish, and the connection can setup normally.
Working code:
xmpp = new XmppClientConnection
{
UseSSL = true,
UseStartTLS = false,
Server = "gcm.googleapis.com",
ConnectServer = "gcm.googleapis.com",
Port = 5235,
Username = "<SENDER ID>#gcm.googleapis.com",
Password = <KEY>,
AutoResolveConnectServer = false,
SocketConnectionType = SocketConnectionType.Direct,
KeepAlive = true,
};
xmpp.Open();

Related

Sending email from specific server gives socket forbidden error

I get this error
An attempt was made to access a socket in a way forbidden by its access permissions xxx.xxx.xxx.xxx:587 when sending email from a godaddy server.
I have seen many questions like this but what's unique here is that, this code works on my local computer. It also works on my other Go daddy hosting Server.
This original server has TLS 1.0, because i needed TLS 1.2, I purchased a deluxe hosting plan and moved my code to this new server, then i start getting this error. I've searched everywhere and used every combination of port 587, 465, 25 along with ssl = false or true.
Any ideas please?
using (SmtpClient smtpClient = new SmtpClient("smtp.gmail.com", 587))
{
MailMessage mail = new MailMessage();
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = new NetworkCredential("********#gmail.com", "********");
smtpClient.EnableSsl = true;
string fromEmail = "********#gmail.com";
mail.From = new MailAddress(fromEmail, "System");
mail.To.Add(new MailAddress(toEmail));
mail.Body = body.ToString();
mail.Subject = subject;
smtpClient.Send(mail);
}
Sounds like a firewall or AV or other port blocking software preventing outbound connections to port 587. Check your server config and look in the windows event log as there might be an entry in there indicating who did the blocking.
Try to use port 2525 for 587, 465, 25. Some cloud providers disable all outbound traffic from 587, 465, 25 ports.
It seems like Godaddy is blocking emails from its servers when you use an outside smtp like smtp.gmail.com. At least that seems like the case with this Plesk Hosting Account. The other Economy Hosting works well with Gmail smtp.
Also, the emails will only send from Godaddy server, running the code locally on Visual studio gave an error.
I changed my code to this:
using (SmtpClient smtpClient = new SmtpClient("relay-hosting.secureserver.net", 25))
{
MailMessage mail = new MailMessage();
smtpClient.Credentials = new NetworkCredential("yourdomain#yourdomain.com", "****");
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
string fromEmail = "yourdomain#yourdomain.com";
mail.From = new MailAddress(fromEmail, "Name");
mail.To.Add(new MailAddress(toEmail));
mail.Body = body.ToString();
mail.Subject = subject;
smtpClient.Send(mail);
}

ASP Classic Email '80040213' The transport failed to connect to the server

I know there are plenty of questions out there with this but none seem to have an answer which works for me.
My application is ASP Classic, the server it is running on is Windows Server 2000 (very old I know), I am using an Office365 server and I'm using the information provided by the Office365 when I login to the email (Port 587, correct username and password, correct smtp server, TLS set to true).
I always get "CDO.Message.1 error '80040213' The transport failed to connect to the server." as an error message, the line it errors on is the .Send command.
Const cdoSendUsingMethod = "http://schemas.microsoft.com/cdo/configuration/sendusing"
Const cdoSendUsingPort = 2
Const cdoSMTPServer = "http://schemas.microsoft.com/cdo/configuration/smtpserver"
Const cdoSMTPServerPort = "http://schemas.microsoft.com/cdo/configuration/smtpserverport"
Const cdoSMTPConnectionTimeout = "http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout"
Const cdoSMTPAuthenticate = "http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"
Const cdoBasic = 1
Const cdoSendUserName = "http://schemas.microsoft.com/cdo/configuration/sendusername"
Const cdoSendPassword = "http://schemas.microsoft.com/cdo/configuration/sendpassword"
'Use SSL for the connection (False or True)
Const cdoSendTLS = "http://schemas.microsoft.com/cdo/configuration/smtpusessl"
' create CDOSYS objects
Set objCDOSYSMail = Server.CreateObject("CDO.Message")
Set objCDOSYSCon = Server.CreateObject ("CDO.Configuration")
'Set our smtp server
objCDOSYSCon.Fields.Item(cdoSMTPServer) = "smtp.office365.com"
objCDOSYSCon.Fields.Item(cdoSMTPAuthenticate) = cdoBasic
objCDOSYSCon.Fields.Item(cdoSendUserName) = "my.email#email.com"
objCDOSYSCon.Fields.Item(cdoSendPassword) = "password"
'objCDOSYSCon.Fields.Item(cdoSMTPServerPort) = 587
objCDOSYSCon.Fields.Item(cdoSendUsingMethod) = cdoSendUsingPort
objCDOSYSCon.Fields.Item(cdoSendTLS) = True
objCDOSYSCon.Fields.Item(cdoSMTPConnectionTimeout) = 30
objCDOSYSCon.Fields.Update
'Use our new configurations for our mailer
Set objCDOSYSMail.Configuration = objCDOSYSCon
strSpecFile = Application("px683_network_downloads_specs") & strSpecFileName
objCDOSYSMail.From = "to.email#email.com"
objCDOSYSMail.To = "my.email#email.com"
objCDOSYSMail.Subject = "A subject"
objCDOSYSMail.HTMLBody = "Some text for the body"
'Normal level of importance
objCDOSYSMail.Send
set objCDOSYSMail = nothing
set objCDOSYSCon = nothing
I have tried with port 25 without any luck as well. If I use another email service which doesn't use SSL at all (local service, not Office365) I have no issue (I comment out usessl and change the port to 25). Additionally if I try to use a different email service which I have running flawlessly in an ASP.Net application I get the same issues, this other email service uses port 25 and SSL and is not an Office365 service.
I have had this issue before. Basically you're not being authenticated to use the mail transport on the server.
Either your SMTP server isn't allowed to send outbound mail (e.g. to stop mail relay), you're username and password are incorrect or the port you are using needs a higher security level to send the mail. In the later instance it could be that Office365 requires SSL auth...maybe worth looking there.
If all else fails you can try using a 3rd party provider. We use SendInBlue on their £4.35 package. You're allowed to send up to 40,000 emails through their system. We found that sending the mail to a 3rd party totally removes issues over server settings stopping the mail transport function. We use this for both Classic ASP and PHP sites now.
Hope that helps.
I was finally able to get this working by moving the application to a Windows Server 2012 machine. I had to jump through a couple of loops which come with moving something that old between servers but I was able to get it working.
I was only able to use Port 25, 587 doesn't work. Keep in mind I tried port 25 on the original server and that didn't work there either.
With Office 365 and CDO you have to use port 25, even if you're using authenication. Looking at your code I think the port is the only thing to change, but here's a tried and tested configuration.
Set iConfg = Server.CreateObject("CDO.Configuration")
Set Flds = iConfg.Fields
With Flds
.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "smtp.office365.com"
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
.Item("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 60
.Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1
.Item("http://schemas.microsoft.com/cdo/configuration/smtpusessl") = true
.Item("http://schemas.microsoft.com/cdo/configuration/sendusername") = "myaccount#mydomain.com"
.Item("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "mypassword"
.Update
End With
objMail.Configuration = iConfg

Differentiate between TcpClient and WebSocket?

I am developing an application in which i am using socket for the communication between server application and client application(web and desktop both). My server application continuously listening the request of the client application and accept the request whenever comes.
Server code :
TcpListener listener = new TcpListener(IPAddress.Parse(ipAddStr), portNum);
listener.Start();
while (listen)
{
TcpClient handler = listener.AcceptTcpClient();
// doing some stuff
// for every client handler i am creating a new thread and start listening for the next request
}
and for web client i am using WebSocket, as for establishing the connection with WebSocket client we have to follow some handshaking process. and for that I am using the following code (which is working fine) :
static private string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private static string AcceptKey(ref string key)
{
string longKey = key + guid;
SHA1 sha1 = SHA1CryptoServiceProvider.Create();
byte[] hashBytes = sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(longKey));
return Convert.ToBase64String(hashBytes);
}
generating and sending response for handshaking with websocket client:
// generate accept key fromm client header request
var key = headerRequest.Replace("ey:", "`")
.Split('`')[1]
.Replace("\r", "").Split('\n')[0]
.Trim();
var responseKey = AcceptKey(ref key);
//create the response for the webclient
var newLine = "\r\n";
var response = "HTTP/1.1 101 Switching Protocols" + newLine
+ "Upgrade: websocket" + newLine
+ "Connection: Upgrade" + newLine
+ "Sec-WebSocket-Accept: " + responseKey + newLine + newLine;
//send respose to the webclient
Byte[] sendBytes = Encoding.ASCII.GetBytes(response);
networkStream.Write(sendBytes, 0, sendBytes.Length);
networkStream.Flush();
I have also TcpClient socket used for desktop application, so the problem is how to identify that the request is from WebSocket or from TcpClient ?
The easiest way would be to have a websocket listener and the vanilla TCP listener listen to different port numbers. You should do that anyway, because it is customary for websocket applications to run on the standard http port 80 (or standard https port 443 when you use websockets with TLS), while a custom protocol based on TCP should run on one of the ports from the "registered" range between 1024 to 49151. You are well-advised to follow this, because a well-secured client environment which allows web access but not much else might not allow the user to connect to other ports than 80 and 443, while any non-http traffic on these ports might trigger an intrusion detection system.
When you still want to handle both protocols on the same port for some reason, it will be a bit difficult. Websocket is a protocol based on TCP which looks like a vanilla HTTP GET request at first, until you receive the headers Connection: Upgrade and Upgrade: websocket.
That means connection requests for either protocol need to be accepted by the same listener at first. Only after the client sent enough data to identify its connection attempt as either your custom protocol or websocket (or something completely different which accidentally connected to your port - you will encounter that a lot when you deploy your application facing the internet) and then delegate the communication with the client to the appropriate handler class.
A TcpClient is a Socket wrapper.
WebSocket is a protocol that can run over a TcpClient. WebSocket protocol defines the handshake and how to frame data.
The best way of differentiate simple TCP connections and WebSocket connections is to have them listening in different ports, since you are going to use different protocols. It would be bad if you have them in the same port, it will become a mess.

Tomcat as Clients communicating with multiple separated Servers via SSL

Here is the scenario:
I have multiple application servers running locally for now (should be running in different host) --> each is listening on different port (at localhost).
I have a single client application running on Tomcat.
When startup Tomcat, login with different user's details with connect to different (above) servers remotely.
My problem is:
First, I startup Tomcat and logged in as userA, it then connected successfully to serverA(localhost:1000).
Then I logged out.
Logged in again as userB, it did NOT connect to serverB(localhost:1001) as expected; instead, it gave exception
"javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown"
However, if I restart Tomcat, and login as userB first, it then connects successfully to serverB.
Does anyone know what the problem is?
I really appreciate any suggestion :)
Code for client Tomcat:
SetupClientKeystore();
SetupServerKeystore();
SSLContext context = SetupSSLContext();
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket) socketFactory.createSocket(hostname, portNo);
GZIPOutputStream gZipOut = new GZIPOutputStream(socket.getOutputStream()); // no trust certificate found throws here
Code for serverA and B:
setupClientKeyStore();
setupServerKeystore();
setupSSLContext();
server = new ServerSocket(portNo);
SSLServerSocketFactory socketFactory = sslContext.getServerSocketFactory();
serverSocket = (SSLServerSocket) socketFactory.createServerSocket(portNo);
serverSocket.setNeedClientAuth(true);
while ( true )
{
Socket client = serverSocket.accept();
inStream = client.getInputStream();
BufferedInputStream bufferedIn = new BufferedInputStream(inStream); //unknown_certificate throws here
//do something here.....
}
"javax.net.ssl.SSLHandshakeException: Received fatal alert:
certificate_unknown"
This usually indicates that the server's certificate is not trusted.
Could it be that when you log-in as userA you load the trusted certificate of serverA and connect, and then when you try to connect to serverB you try to authenticate serverB using the certificate of ServerA (loaded when you logged in as userA)?
As a result the SSL handshake fails.
So when you restart and login as userB the appropriate certificate (i.e. of ServerB) is loaded and the connection is succesfull?
You have no code in your post but if you do it as I say, this explains the exception.

SASL authorization failing while connecting to XMPP server

I am trying to connect to gmail using SMACK API through XMPP server. but getting the
error : SASL authentication failed using mechanism PLAIN
you can check a glimpse of code. I got it from net only
ConnectionConfiguration connConfig = new ConnectionConfiguration("talk.google.com", 5222, "gmail.com");
connection = new XMPPConnection(connConfig);
connection.connect();
SASLAuthentication.supportSASLMechanism("PLAIN", 0);
I checked in the smack debug window. it says in XML :
< invalid-authzid />
I am already having account on gmail and my gtalk is also running.
You need to set the authentication before you connect viz
SASLAuthentication.supportSASLMechanism("PLAIN", 0);
must appear before connection.connect().
See my blog.
ConnectionConfiguration cc = new ConnectionConfiguration(
"vietnam.agilemobile.com", 5222, vietnam.agilemobile.com");
XMPPConnection connection = new XMPPConnection(cc);
try {
SASLAuthentication.supportSASLMechanism("PLAIN", 0);
connection.connect();
Log.e("LOGIN", "" + 111);
// You have to put this code before you login
Log.e("LOGIN", "" + 222);
// You have to specify your gmail addres WITH #gmail.com at the end
connection.login("nemodo", "123456", "resource");
Log.e("LOGIN", "" + 333);
// See if you are authenticated
System.out.println(connection.isAuthenticated());
} catch (XMPPException e1) {
e1.printStackTrace();
}
I also get this mistake, but i can not work.
For anyone looking for possible solutions to this many years after this was originally asked and answered, I recently was able to get past this authentication error by explicitly setting the authzid value on the XMPPTCPConnectionConfiguration.
I was running into an issue where my connection configuration worked fine for some client XMPP servers, but not for others, even though they were all using SASL PLAIN authentication. After some troubleshooting, I learned that the ones that were failing were expecting an authzid value. After adjusting my code to set this, it works in both the environments that were working before, as well as the environments that were failing.
Here is how I am building my connection configuration:
XMPPTCPConnectionConfiguration.builder()
.setHost(XMPP_DOMAIN)
.setXmppDomain(XMPP_DOMAIN)
.setPort(XMPP_PORT)
.setCompressionEnabled(true) // optional, not all servers will support this
.setUsernameAndPassword(XMPP_USER, XMPP_PASSWORD)
.setResource(XMPP_RESOURCE)
.setAuthzid(JidCreate.entityBareFrom(String.format("%s#%s", XMPP_USER, XMPP_DOMAIN))) // <-- this was the change I needed
.build();
Specifically I needed to add this line:
.setAuthzid(JidCreate.entityBareFrom(String.format("%s#%s", XMPP_USER, XMPP_DOMAIN)))