Apple Push Notifications on Windows Server 2008 not working - asp.net

I'm stuck and I hope somebody here will help me.
For a few days I'm trying to send apple push notifications from windows server 2008. But nothing is send or received. In fact, I've moved everything to simple mvc application so it can be debug easier and I've noticed that it hangs when I try to force sending the push notifications (on push.StopAllServices(true); )
They were working (and still are) from windows server 2012R2 with the same approach to send notifications so I guess the certificates and code are fine.
I'm using windows service & push sharp to send notifications. target framework: 4
The test project is MVC 2.0 target framework 4
I've installed asp.net 4.5 on the server
I've installed certificate via mmc in Personal (the private key is available, granted permission for IUSR and IIS_USRS) and Trusted Root Certificate Authorities.
Port 2195 is open
Here's the code:
private void Initizalize()
{
push = new PushBroker();
//appleCert is path to my .p12 certificate on disk.
var cert = new ApplePushChannelSettings(false, appleCert, "***");
//I've read somewhere that it was helpful to force send notifications. Well, in my case it's not.
var settings = new PushServiceSettings();
settings.AutoScaleChannels = false;
settings.Channels = 3;
settings.MaxAutoScaleChannels = 3;
//Wire up the events for all the services that the broker registers
push.OnNotificationSent += NotificationSent;
push.OnChannelException += ChannelException;
push.OnServiceException += ServiceException;
push.OnNotificationFailed += NotificationFailed;
push.OnDeviceSubscriptionExpired += DeviceSubscriptionExpired;
push.OnDeviceSubscriptionChanged += DeviceSubscriptionChanged;
push.OnChannelCreated += ChannelCreated;
push.OnChannelDestroyed += ChannelDestroyed;
push.RegisterAppleService(cert, settings);
}
public void SendPush()
{
Initizalize();
var token = hard coded token that exists;
var output = "msg";
push.QueueNotification(new AppleNotification()
.ForDeviceToken(token)
.WithAlert(output)
.WithBadge(1)
.WithSound("default"));
push.StopAllServices(true);
}
It raises event "OnNotificationSent", nothing else.
One more thing that may be important. Sending and receiving push notifications was and is working from windows server 2012 but it's windows azure virtual machine so installing the certificate was different.
Any ideas?
Even the information that it cannot be done will be helpful!
edit:
One problem solved:
Apparently you need to have reference to NewtonSoft.Json in order to call StopAllServices. It doesn't hang now but nothing is received by the device.

Looks like on Windows Server 2008 apns certificates private key must have granted permission for user that wants to use it.
As I wrote before I've granted it for IIS_USRS but that's only for applications running under IIS. And since I was using windows service it wasn't working.
So what I did was check user for windows service (Services -> Log On As) and granted permission to certificates private key for this user.

Related

Signalr send message from browser to .net client on the same machine

We need to communicate a native application with a web application.
We think to use signalr to send the message/command.
The pipeline would be:
User clicks to make an action.
Javascript (with signalr) send a message to a server in azure.
The server re-send the message a specific client. It must be the client installed on the same machine.
Once the result is completed, NET sends the resulting reverse.
The matter is, How I can find client from the same machine in the signalr Server?
The organization in our system is:
There is center/gym.
Every center has staff who can login.
We could identify client at the same center with some file configuration. Saving our key center, for example. But, in a center, could there are more than one.NET client installed on the different computer.
We think to use the private IP of the computer to make a key on the signalr server.
var ips = [];
var RTCPeerConnection = window.RTCPeerConnection ||
window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
var pc = new RTCPeerConnection({
// Don't specify any stun/turn servers, otherwise you will
// also find your public IP addresses.
iceServers: []
});
// Add a media line, this is needed to activate candidate gathering.
pc.createDataChannel('');
// onicecandidate is triggered whenever a candidate has been found.
pc.onicecandidate = function (e) {
if (!e.candidate) { // Candidate gathering completed.
pc.close();
console.log(ips);
return;
}
var ip = /^candidate:.+ (\S+) \d+ typ/.exec(e.candidate.candidate)[1];
ips.push(ip);
};
pc.createOffer(function (sdp) {
pc.setLocalDescription(sdp);
}, function onerror() { });
This data can be obtained in .NET client without a problem. But in javascript, the previous code works regularly. In some PC, it only returns ipv4. And in Mozilla it doesn't work.
How can we identify both clients? Do You know another way to reach the goal?
Thanks,
Finally, we didn't find a good solution filtering ip adress.
We did the as follow:
We used URI schema to launch our app. URI Schema windows
Public Class RegistrarURI
Const URI_SCHEME As String = "xxx"
Const URI_KEY As String = "URL:xxx"
Private Shared APP_PATH As String = Location.AssemblyDirectory() ' "C:\Program Files (x86)\xxx.exe"
Public Shared Sub RegisterUriScheme()
Using hkcrClass As RegistryKey = Registry.ClassesRoot.CreateSubKey(URI_SCHEME)
hkcrClass.SetValue(Nothing, URI_KEY)
hkcrClass.SetValue("URL Protocol", [String].Empty, RegistryValueKind.[String])
Using defaultIcon As RegistryKey = hkcrClass.CreateSubKey("DefaultIcon")
Dim iconValue As String = [String].Format("""{0}"",0", APP_PATH)
defaultIcon.SetValue(Nothing, iconValue)
End Using
Using shell As RegistryKey = hkcrClass.CreateSubKey("shell")
Using open As RegistryKey = shell.CreateSubKey("open")
Using command As RegistryKey = open.CreateSubKey("command")
Dim cmdValue As String = [String].Format("""{0}"" ""%1""", APP_PATH)
command.SetValue(Nothing, cmdValue)
End Using
End Using
End Using
End Using
End Sub
End Class
In an Azure WebApp we launch a SignalR Server. This server will send data from our .NET app to Chrome.
To achive that, when the web is loaded, we connect to the signalR server. To build de uri, We send the connectionId from Javascript client to the .NET Client.
Then, when the native process is completed. .NET client send the information to signalR server, and this server mirrored the data to javacript client using the connectionId.
To avoid launch some instance of our native app, we use IPC channel to send data to one instance to the previous and closind the new one.
Link to source Blog source

Using MailKit to connect to a mail server from a third-party hosting provider

If I am hosting an asp.net core app through a third-party hosting provider such as A2 Hosting is it possible to use this to send mail w/ Mail Kit? I have tried so many different things and client.Connect just hangs and eventually throws an exception. Ex is null.
Here is my code:
using (var client = new SmtpClient())
{
// For demo-purposes, accept all SSL certificates (in case the server supports STARTTLS)
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
client.Connect("mail.mydomain.com", 25, false);
// Note: since we don't have an OAuth2 token, disable
// the XOAUTH2 authentication mechanism.
client.AuthenticationMechanisms.Remove("XOAUTH2");
// Note: only needed if the SMTP server requires authentication
client.Authenticate("contact#mydomain.com", "PASSWORD");
client.Send(message);
client.Disconnect(true);
}
It turns out that my ISP (Comcast) blocks port 25. My hosting company told me they open up port 2525 for this reason. I changed it to 2525 and it worked. Contact your hosting company if you run into a similar issue and see what additional ports they might have opened up.

GPG encryption in an ASP.NET C# Web application - No Public Key

I have set-up Gpg4win on Windows Server 2008 R2 and the website is running .Net 4.5.
I'm using the Starksoft OpenPGP dll.
I've added the required public key to Gpg4win via remote desktop, however when testing in the browser I get the following in the browser:
gpg: EMAIL#EMAIL.COM: skipped: No public key gpg: [stdin]: encryption failed: No public key
I've tested locally on my machine and directly in GPA and Kleopatra on the server and the encryption is working correctly. This leads me to believe that the issue is with the public key being set-up via remote desktop and not being accessible to the application pool or similar.
I've tried copying the pubring.gpg, secring.gpg and trustdb.gpg in to a protected subfolder of the website as suggested somewhere (I forget where now) but this has not worked.
Any ideas how to set-up the public keys to be accessible to the IIS user?
Research
Continued research lead me to this SO question: Gpg encryption over web browser which then lead me down the lines of running it via cmd - Running Command line from an ASPX page, and returning output to page
Solution
Export the required keys somewhere (in this case c:\public.key
Create a page with the following code and execute it
System.Diagnostics.Process si = new System.Diagnostics.Process();
si.StartInfo.WorkingDirectory = "c:\\";
si.StartInfo.UseShellExecute = false;
si.StartInfo.FileName = "cmd.exe";
si.StartInfo.Arguments = "gpg --import c:\\public.key";
si.StartInfo.CreateNoWindow = false;
si.StartInfo.RedirectStandardInput = true;
si.StartInfo.RedirectStandardOutput = true;
si.StartInfo.RedirectStandardError = true;
si.Start();
string output = si.StandardOutput.ReadToEnd();
si.Close();
The key now works :)
GnuPG looks for keyrings in user's home directory, and IIS is run by other user, most likely this is the reason. You can specify the exact path to public and secret keyrings via --keyring and --secret-keyring command line switches.

Send email from ASP.NET application through an external exchange server

I have an ASP.NET application pointing the 2.0 version of the framework written in C# deployed in IIS6.
I am maintaining the application therefore some of its parts are not clear to me.
The application has to send email messages through an external exchange server to and from oldMailAddress and has been done correctly. Now I added a newMailAddress and I haven't changed anything else from the code.
The oldMailAddress receives the emails send through the application, the newMailAddress doesn't. I tried to send emails to newMailAddress from my mailbox and it works correctly.
I looked for solutions on the Internet and I saw that most of them are based on SMPT services installed in IIS6. Well, I do not have these services installed and I think it is not necessary since the application was working with oldMailAddress. Hereby I attach the code that I use, I hope anybody might help.
MailMessage oMail = new MailMessage();
switch (destination)
{
case "production":
strMailAddress = "newMailAdress#domain.eu";
oMail.From = new MailAddress(strMailAddress);
oMail.To.Add(strMailAddress);
break;
case "warehouse":
strMailAddress = "oldMailAdress#domain.eu";
oMail.From = new MailAddress(strMailAddress);
oMail.To.Add(strMailAddress);
break;
}
oMail.Subject = sTitle;
oMail.IsBodyHtml = true;
oMail.Body = sHTML;
SmtpClient oSmpt = new SmtpClient("external.smpt.eu");
oSmpt.Send(oMail);
My guess is that there is either an auth issue, or the email is being caught in a spam folder # newMailAddress.
If you still can't figure it out, then I would recommend enabling logging (if you have write permissions). I have an explanation of how to enable logging over at:
http://www.systemnetmail.com/faq/4.10.aspx

Certificate stored in cert store disappearing from ASP.NET application over time

I've got a code signing certificate from Thawte that I'm using to dynamically generate and sign ClickOnce deployment manifests. The problem is that the ASP.NET application that generates and signs these manifests works fine when we restart IIS or re-import the signing certificate, but over time the following function fails to find the certificate:
private static X509Certificate2 GetSigningCertificate(string thumbprint)
{
X509Store x509Store = new X509Store(StoreLocation.CurrentUser);
try
{
x509Store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection x509Certificate2Collection = x509Store.Certificates.Find(
X509FindType.FindByThumbprint, thumbprint, false);
if (x509Certificate2Collection.Count == 0)
throw new ApplicationException(
"SigningThumbprint returned 0 results. Does the code signing certificate exist in the personal store?",
null);
if (x509Certificate2Collection.Count > 1)
throw new ApplicationException(
"SigningThumbprint returned more than 1 result. This isn't possible", null);
var retval = x509Certificate2Collection[0];
if(retval.PrivateKey.GetType() != typeof(RSACryptoServiceProvider))
throw new ApplicationException("Only RSA certificates are allowed for code signing");
return retval;
}
finally
{
x509Store.Close();
}
}
Eventually the application starts throwing errors that it can't find the certificate. I'm stumped because I think the cert is installed correctly (or mostly correct) because it does find the cert when we start the ASP.NET application, but at some point we hit the Count==0 branch and it's just not true: the cert is in the application pool user's "Current User\Personal" cert store.
Question: Why might a cert all of a sudden "disappear" or not be able to be found?
Figured it out on our own (painfully).
The certificate needed to be installed in the LocalMachine store and the application pool account read permissions to the cert using WinHttpCertCfg or CACLS.exe if it's going to be used from an ASP.NET application. Using the CurrentUser store of the account running the application pool was causing the problem. I'm guessing there's some sort of race condition or something that's not entirely cool about accessing the CurrentUser store from a user that isn't running in a interactive logon session.
We were unable to do this at first because we were invoking the MAGE tool to do the ClickOnce deployment manifest creation/signing, and that requires the code signing cert to be in the CurrentUser\My store. However, we've eliminated the need for MAGE by a) creating the manifest from a template file and replacing the values we need to substitute out and b) by signing the manifest by calling the code MAGE calls via reflection that exists in the BuildTasks.v3.5 DLL. As a result we have more control over what cert we use to sign the manifest and can put it wherever we want. Otherwise we'd be stuck had we not gone a little "lower level".
We had the same issue, and it turns out the application pool needed to be set to load the the user profile of the (domain) account that we use to run the application.
If you notice that accessing the My certificate store works while you're signed in with the application pool's user, but not if you were not signed in while the apppool spun up, then this might be the cause for you, too.

Resources