I have a Windows Phone App, built for 8.1, and one of the tasks was a client-server certificate scenario. My app worked fine, I could send the client certificate and login to the server. However after upgrading to windows 8.10.14xxxx that was not possible. I took wireshark traces and it seems that the certificate is never send.
The content length of the message is 0.
I use HttpClient.SendAsync (await) and HttpBaseProtocolFilter to enter the certificate. It worked perfect before the upgrade.
Any idea? Is something broken?
First I am installing the pfx
async private void btnInstall_Click(object sender, RoutedEventArgs e)
{
//Install the self signed client cert to the user certificate store
string CACertificate = null;
try
{
Uri uri = new Uri("ms-appx:///certificates/test.pfx");
var file = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
IBuffer buffer = await FileIO.ReadBufferAsync(file);
using (DataReader dataReader = DataReader.FromBuffer(buffer))
{
byte[] bytes = new byte[buffer.Length];
dataReader.ReadBytes(bytes);
// convert to Base64 for using with ImportPfx
CACertificate = System.Convert.ToBase64String(bytes);
}
await CertificateEnrollmentManager.UserCertificateEnrollmentManager.ImportPfxDataAsync(
CACertificate,
"xxxxx",
ExportOption.Exportable,
KeyProtectionLevel.NoConsent,
InstallOptions.None,
"ClientCert1");
}
catch (Exception ex)
{
//;
}
}
Then I am calling the service
string serviceURL = "https://my.web.services";
Certificate cert = null;
CertificateQuery query = new CertificateQuery();
query.FriendlyName = "ClientCert1";
IReadOnlyCollection<Certificate> certs = await CertificateStores.FindAllAsync(query);
HttpBaseProtocolFilter bpf = new HttpBaseProtocolFilter();
//if you install the CA you don't need to ignore the ServerCertificate Errors
//bpf.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
if (certs.Count > 0)
{
cert = certs.ElementAt(0);
bpf.ClientCertificate = cert;
}
HttpClient httpClient = new HttpClient(bpf);
try
{
var response = await httpClient.GetInputStreamAsync(new Uri(serviceURL));
//take data
}
catch (Exception ex)
{
//0x80072F0D
}
I am always taking an excepting (0x80072F0D) when running in 8.10.14xxxx windows phone. My code worked before the update, now I am always taking this return code. The certificate is loaded in httpClient. When I stop the app with the debugger it seems that the certificate is there, however the 0x800072F0D probably means that the certificate is not sent???
There is an intermediate certificate authority in the scenario. That certificate is included in the pfx. Do I need to install this somehow?
I am assuming that you have already put the client certificate in app certificate store.
If not then do these:
1) Download the PFX file.
2) Install certificate in the App's certificate store by following
await CertificateEnrollmentManager.ImportPfxDataAsync(certString, "Your_PFX_Password", ExportOption.Exportable, KeyProtectionLevel.NoConsent, InstallOptions.None, friendlyName);
3) Check for the certificate in certificate store.
CertificateQuery certQuery = new CertificateQuery();
certQuery.FriendlyName = friendlyName;
IReadOnlyList<Certificate> certs = await CertificateStores.FindAllAsync(certQuery);
The certs[0] should have the certificate that you need.
4) Now, to attach the certificate to HTTP request
HttpBaseProtocolFilter protolFilter = new HttpBaseProtocolFilter();
protolFilter.ClientCertificate = certs[0] //from previous step
HttpClient client = new HttpClient(protolFilter)
PS : You should not use System.Net.htpp.HttpClient. Instead of that you should use Windows.Web.Http.HttpClient.
Related
I have a spec in which there is a need to ignore HTTPS certificates and also to get the status of Upload/Download.
I am using HttpClient to ignore the certificate but i could not find the way to get the status of downloading/Uploading.
I know it was there in WebClient Windows Phone 8 and Webclient not there in Windows 8.1.
So please guide me to accomplish both these things.
For Download progress, You can return response stream from your Http request and can use below code to write to file which also display progress status
IInputStream inputStream = null;
IRandomAccessStream fs = null;
try
{
inputStream = responseStream.AsInputStream();
ulong totalBytesRead = 0;
fs = await file.OpenAsync(FileAccessMode.ReadWrite);
ulong fileSize = Convert.ToUInt64(Size);
while (true)
{
// Read from the web.
if (!cancellationToken.IsCancellationRequested)
{
IBuffer buffer = new Windows.Storage.Streams.Buffer(512);
buffer = await inputStream.ReadAsync(
buffer,
buffer.Capacity,
InputStreamOptions.None);
if (buffer.Length == 0)
{
// There is nothing else to read.
break;
}
// Report progress.
totalBytesRead += buffer.Length;
double progress = ((double)totalBytesRead / fileSize);
double Value = progress * 100;
System.Diagnostics.Debug.WriteLine("Bytes read: {0}", totalBytesRead);
await fs.WriteAsync(buffer);
}
else
{
inputStream.Dispose();
fs.Dispose();
await file.DeleteAsync();
break;
}
}
inputStream.Dispose();
fs.Dispose();
}
catch
{
}
For upload Progress, there is no in built support to do that, but you can use
ProgressMessageHandler found in System.Net.Http.Handler which you can found on Nuget and than hook that to your HttpClient Object.
I am new in Windows phone application development.
I have created my app in Google developer Console.
From my windows phone application I am using "webview" to render the Google login page and with successfull login I got a code like: 4/akd.........
Can anyone tell me how to access the code using "code" first time ?
I have try by following way :
public void GetProfileDetail(string code)
{
StringBuilder authLink = new StringBuilder();
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "POST";
authLink.AppendFormat("code={0}", code);
authLink.AppendFormat("&client_id={0}", clientId);
authLink.AppendFormat("&client_secret={0}", clientSecret);
authLink.AppendFormat("&redirect_uri={0}", redirect_url);
authLink.Append("&grant_type=authorization_code");
UTF8Encoding utfenc = new UTF8Encoding();
byte[] bytes = utfenc.GetBytes(authLink.ToString());
Stream os = null;
try // send the post
{
//webRequest.ContentLength = bytes.Length; // Count bytes to send
os = webRequest.GetRequestStreamAsync().Result;
os.Write(bytes, 0, bytes.Length); // Send it
}
catch (Exception ex)
{
}
}
but it gives me an error. Let me know what to do next
Thanks in advance.
You are trying to do the OAuth authentication through the webview, but that is not the recommended way to go.
Since wp8.1 there is a WebAuthenticationBroker class that you can use to initiate an OAuth process with a provider ( like Google in your case ).
A good detailed example can be found on MSDN here https://code.msdn.microsoft.com/windowsapps/Web-Authentication-d0485122
I got a request from customer to create a service for traffic control of WMS service. The idea is:
a company buys some amount of data from WMS provider;
the company shares this data among its clients ;
the service should track how much traffic and requests have been consumed.
So I need some kind of proxy which passes requests to a target WMS services and meanwhile logs passed traffic.
The problem is that I have no clue how to start and where to start from. I will appreciate any idea, concept or so.
Thanks in advance!
Here is how I implemented proxy that passes requests to GeoServer WMS service and returns the map image. I use Web API, NET 4.5. You can customize my example with logging and authorization.
public async Task<HttpResponseMessage> GetMapAsync()
{
HttpClient client = new HttpClient();
WmsLayer layer = _unitOfWork.LayerRepository.GetById(model.LayerId) as WmsLayer;
// This is typical WMS request url pointing to server behind the firewall,
// something like http://localhost:8081/geoserver/data/wms?service=WMS&version=1.1.0&request=GetMap&layers=data:layer1&styles=&bbox=337098.1084,4972868.3433,368833.6,5014800.3417&width=387&height=512&srs=EPSG:3765&format=image%2Fpng%3B+mode%3D8bit
string url = layer.GetWmsRequestUrl(layer.Url, model.SRS, model.Width, model.Height, model.BBox);
// See http://developer.greenbutton.com/downloading-large-files-with-the-net-httpclient/
var responseMessage = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
var response = Request.CreateResponse();
response.Content = new PushStreamContent(
async (outputStream, httpContent, transportContext) =>
{
var buffer = new byte[65536];
using (var httpStream = await responseMessage.Content.ReadAsStreamAsync())
{
var bytesRead = 1;
while ((bytesRead = httpStream.Read(buffer, 0, buffer.Length)) > 0)
{
await outputStream.WriteAsync(buffer, 0, bytesRead);
}
}
outputStream.Close();
}
, new MediaTypeHeaderValue("image/png"));
return response;
}
I am building my first windowsPhone 8.1 application ,the role of my application is to create connection with server to get information from it, so I am writing the code to do this process by sending json-rpc request to server to get some information ,I am successful to get it in first time but when I send the second request I am receiving an empty response with 404 error (page not found).
But when I call the service without https (http only) it works fine regardless how many time I call it !
public async Task<string> GetDataFromServer(string urlToCall, string JSONData,string RR)
{
string UserName = “XXXXXXX”
string Password = "XXX";
using ( var handler = new HttpClientHandler())
{
handler.Credentials = new NetworkCredential(UserName, Password);
HttpClient client = new HttpClient(handler);
HttpResponseMessage response = null;
try
{
response = await client.PostAsync(urlToCall, new StringContent(JSONData.ToString(), Encoding.UTF8, " application/json"));
string res = response.Content.ReadAsStringAsync().Result;
Windows.UI.Popups.MessageDialog g = new Windows.UI.Popups.MessageDialog(res);
await g.ShowAsync();
return res;
}
catch (Exception ex)
{
Windows.UI.Popups.MessageDialog g = new Windows.UI.Popups.MessageDialog("Error is : " + ex.Message);
g.ShowAsync();
return "Error";
}
finally
{
response.Dispose();
client.CancelPendingRequests();
client.Dispose();
handler.Dispose();
}
}
}
Again, when call the URL of service (start with https) on first time I got response with seeked data, but second time I receive an empty response with 404 error (page not found) !!
Any help please
Please try to use this solution.
public async Task<string> SendJSONData3(string urlToCall, string JSONData)
{
string UserName = "XXXXXXXXX";
string Password = "XXXXXXXXX";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(urlToCall);
httpWebRequest.Credentials = new NetworkCredential(UserName, Password);
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync()))
{
string json = JSONData;
streamWriter.Write(json);
streamWriter.Flush();
}
var httpResponse = (HttpWebResponse)await httpWebRequest.GetResponseAsync();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
return result;
}
}
A couple of ideas:
Do not use the .Result property. Just use await instead to avoid deadlocks.
Remove the additional space in front of the media type parameter " application/json"
Enable logging on the webserver and see if the second request arrives on the server.
Get a network trace, for example with Wireshark or Fiddler.
Try puting WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp); in your initialization code, as proposed in this answer.
I am trying to get a reference to a response stream before its complete in windows phone 8.
In other .Net platforms you can do
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(myUri);
WebResponse subscribeWebResponse = null;
Stream subscribeStream = null;
subscribeWebResponse = httpRequest.GetResponse();
subscribeStream = subscribeWebResponse.GetResponseStream();
For the purpose of creating Portable class libraries I've used the HttpClientLibrary from nuget.
This Adds ref to extensions assembly Microsoft.Net.Http
this allows me to return the async request at the time the headers have been read instead of waiting for the content transfer to be complete with
var clientResponse = await httpClient.SendAsync(requestmessage, HttpCompletionOption.ResponseHeadersRead);
The problem I'm having is that in windows phone 8 it doesn't work correctly, and still awaits the completion of the content stream to return.
Additionally
await httpWebRequest.BeginGetResponse(callback, request)
has the same behavior as these async methods are actually waiting for the completion of the web's response to continue execution.
So, is there any way to achieve the returning the response/stream at the point that i have received the response headers without Microsoft.Http.Net package?
Even if it has to be a Windows Phone 8 Platform Specific Solution?
Possibly an extension of HttpWebRequest?
From what I can tell, ResponseHeadersRead works on the WP8 emulator as it does on the desktop.
I installed the Win8 SDK. Created a windows phone app. I added this code to the MainPage ctor. This demonstrates a very rudimentary long polling example.
var client = new HttpClient();
var request = new HttpRequestMessage()
{
RequestUri = new Uri("http://oak:1001/longpolling")
};
client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, new CancellationToken())
.ContinueWith((t) =>
{
var response = t.Result;
response.Content.ReadAsStreamAsync()
.ContinueWith(s =>
{
var st = s.Result;
while (true)
{
var message= ReadNextMessage(st);
}
});
});
}
private static string ReadNextMessage(Stream stream)
{
int chr = 0;
string output = "";
while (chr != 10)
{
chr = stream.ReadByte();
output += Convert.ToChar(chr);
}
return output;
}
On my host dev machine I have a web api with a controller that looks like this...
public class LongPollingController : ApiController
{
public HttpResponseMessage Get()
{
Thread.Sleep(2000);
var content = new PushStreamContent( (s,c,t) =>
{
int i = 0;
while (true)
{
try
{
var message = String.Format("The current count is {0} " + Environment.NewLine, i++);
var buffer = Encoding.UTF8.GetBytes(message);
s.Write(buffer, 0, buffer.Length);
}
catch (IOException exception)
{
s.Close();
return;
}
Thread.Sleep(1000);
}
});
return new HttpResponseMessage(HttpStatusCode.OK)
{
RequestMessage = Request,
Content = content
};
}
}
So here's the deal. I would say that what you want to do is not possible, due to platform limitations... But SignalR has a WP client and is able to manage it. So it seems to me you have two options:
1) Dig into the SignalR source code to see how they do it (I'm on my phone right now so I can't provide a link).
UPDATE: Here is the link. They do some pretty neat tricks, like setting the Timeout to -1 for long-running clients. I think you should definitely use the techniques here.
OR
2) You can move whatever you're doing over to SignalR, which would gain the benefit of having a robust infrastructure and being cross-platform compatible.
HTH