Programmatically login to Apple iCloud and Find My Network - c#

I try to programmatically connect to the find-my network (belonging to iCloud) to locate devices attached to my Apple-ID.
This should pe possible using web requests. For example I post a request with my credentials to:
https://setup.icloud.com/setup/ws/1/login
string jsonreq = Newtonsoft.Json.JsonConvert.SerializeObject(temp); //temp is an object with login credentials
byte[] dataStream = Encoding.UTF8.GetBytes(jsonreq);
WebRequest webRequest = WebRequest.Create("https://setup.icloud.com/setup/ws/1/login");
webRequest.Method = "POST";
webRequest.Headers.Set("Origin", "https://www.icloud.com");
webRequest.ContentLength = dataStream.Length;
Stream newStream = webRequest.GetRequestStream();
// Attach the data.
newStream.Write(dataStream, 0, dataStream.Length);
newStream.Close();
WebResponse webResponse = webRequest.GetResponse();
// read server url, dsid, Cookie from response
This is working in the first step, but now I'm facing the problem that 2 factor authentication is to be used for logging in.
Can someone help me/show me next steps in the login process via web request for 2 factor authentication? (Of course I receive the login authentication code on my apple devices)

Related

https request fails only in .net web app

I am trying to patch a .net web application that after years of working started failing to get UPS shipping quotes, which is impacting web business dramatically. After much trial and error, I found the following code that works just fine in a console application:
static string FindUPSPlease()
{
string post_data = "<xml data string>";
string uri = "https://onlinetools.ups.com/ups.app/xml/Rate";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
byte[] postBytes = Encoding.ASCII.GetBytes(post_data);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postBytes.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
// get response and send to console
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Console.WriteLine(new StreamReader(response.GetResponseStream()).ReadToEnd());
Console.WriteLine(response.StatusCode);
return "done";
}
This runs in Visual Studio just fine and gets a nice little response from UPS that the XML is, of course, malformed.
But, if I paste this function into the web application without changing a single character, an exception is thrown on request.GetRequestStream():
Authentication failed because the remote party has closed the transport stream.
I tried it in a couple of different place in the application with the same result.
What is there about the web application environment that would affect the request?
It turns out to be a TLS issue. I guess the console app uses a higher protocol by default than the web application, although none was specified. So, all you have to do is add the following line(s) of code sometime prior to making the request:
using System.Net;
...
System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
That was all it took, though I spent an enormous amount of getting there.
Here is the response from UPS on the issue:
Effective January 18, 2018, UPS will only accept TLS 1.1 and TLS 1.2 security protocols... 100% of requests from customers who are on TLS 1.0 while using production URLS (onlinetools.ups.com/tool name) will be rejected.
Anyway, hope this helps someone.
Jim
Can you try setting the Credentials to your request object like following.
request.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
Try setting the default credentials or check if there is any proxy server set and pass it like in the example below.
The example is given for WebClient.
I was having problem with setting Default Credential, as proxy was enabled on the server. So i passed the proxy URL and port with credentials which can access it.
using (System.Net.WebClient web = new System.Net.WebClient())
{
//IWebProxy defaultWebProxy = WebRequest.DefaultWebProxy;
//defaultWebProxy.Credentials = CredentialCache.DefaultCredentials;
//web.Proxy = defaultWebProxy;
var proxyURI = new Uri(string.Format("{0}:{1}", proxyURL, proxyPort));
//Set credentials
System.Net.ICredentials credentials = new System.Net.NetworkCredential(proxyUserId, proxyPassword);
//Set proxy
web.Proxy = new System.Net.WebProxy(proxyURI, true, null, credentials);
web.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
var result = web.UploadString(URL, "");
return result;
}

HttpWebRequest no accepting cookies C#

I'm having an issue with HttpWebRequest accepting cookies, this is my code:
HttpWebRequest req= (HttpWebRequest)WebRequest.Create("https://www.companyabc.com/security?action=authenticate");
req.CookieContainer = new CookieContainer();
req.CookieContainer.Add(new Uri("https://www.companyabc.com"), new CookieCollection());
string postData = "account_id=xxxx&password=xxxx";
req.KeepAlive = true;
byte[] send = Encoding.Default.GetBytes(postData);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = send.Length;
Stream sout = req.GetRequestStream();
sout.Write(send, 0, send.Length);
sout.Flush();
sout.Close();
The response I'm getting is:
Sorry...
We have detected that your browser is not set up to allow Session Cookies. Our platform uses cookies to help enhance your overall user experience. You cannot log in without them.
Please enable Session Cookies and try again. Contact us at ....
What am I doing wrong? Thank you in advanced.
FYI, I can access the web page and login without any issues from a browser. The issue comes when I try to automate the process.
Sounds like the url you're talking to is expecting some specific headers. Try setting the User-Agent header to Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0 (the default Firefox UserAgent).
Failing that, have a look at the request in Firefox (open the developer tools, and switch to the 'Network' tab before you press the login button) and see what other headers the request has.

Windows Authentication-enabled IIS Site performs differently with 2 different bindings

I have a site set up in IIS 7, and it is using Windows Authentication as the only enabled Authentication Mode. It utilizes a custom .NET 4 Application Pool - the pool uses the default ApplicationPoolIdentity. This site is a C#/ASP.NET application with its own page authorization rules (generated using Iron Speed Designer 9). I have the two bindings set up below:
servicedirectory.sampledomain.com
booking.sampledomain.com
Both of these bindings are mapped to the site on all available IPs on port 80.
For the most part, browsing through either binding works successfully, except for a certain page where I create a WebRequest that fetches another page as a Stream. (I am taking the other page's contents and embedding them as an attachment in an iCal (.ics) file for inclusion in meeting requests. The file is downloaded and sent out by the user)
String request = Request.Url.GetLeftPart(UriPartial.Path).
Replace("Conference.aspx", "Confirmation.aspx") +
"?Conference=" + conference.ConferenceId;
WebRequest webRequest = WebRequest.Create(request);
webRequest.UseDefaultCredentials = true;
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
Stream newStream = webRequest.GetRequestStream();
// Send the data.
newStream.Close();
WebResponse webResponse = webRequest.GetResponse();
Stream responseStream = webResponse.GetResponseStream();
using (MemoryStream ms = new MemoryStream())
{
responseStream.CopyTo(ms);
attachmentContent = Convert.ToBase64String(ms.ToArray());
}
responseStream.Close();
The problem is the following: this code succeeds and produces the content from the Confirmation.aspx page as String data (attachmentContent variable) when the user is browsing under the first binding (servicedirectory.sampledomain.com). However, I get a 401.1 error at the WebResponse webResponse = webRequest.GetResponse(); line when browsing via the other binding URL. There are no references in the application source code or web.config to either binding - everything was built with the intention of being deployed to any URL.
Why would two different bindings affect this?

Secure HttpWebRequest so I can send credentials possible?

I have the following code which connects to my php server and retrieves data from it. The only thing is, I need to send the username and password securely from this webrequest to the PHP server. Looking at the docs for the webrequest class, there is a credentials property as well as a preauthenticate property. I'm assuming these are for the network credentials (all my users are in AD).
Is it possible to secure this post request with credentials or is this just a bad idea? I've also found SetBasicAuthHeader - I'll read up on this and see if it might help. All traffic will be on SSL from ASPX site to the PHP site
// variables to store parameter values
string url = "https://myphpserver.php";
// creates the post data for the POST request
string postData = "Username=" + username + "&Password=" + "&UID=" + UniqueRecID;
// create the POST request
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ContentLength = postData.Length;
// POST the data
using (StreamWriter requestWriter2 = new StreamWriter(webRequest.GetRequestStream()))
{
requestWriter2.Write(postData);
}
// This actually does the request and gets the response back
HttpWebResponse resp = (HttpWebResponse)webRequest.GetResponse();
string responseData = string.Empty;
using (StreamReader responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream()))
{
// dumps the HTML from the response into a string variable
responseData = responseReader.ReadToEnd();
}
SetBasicAuthHeader is for HTTP Basic Access Authentication so won't help here as you're handling authentication at application level. Really, this is no more insecure than just going to the page in a browser. I see you're using SSL so your request will be encrypted anyway and you have nothing to worry about.
If you're concerned for some other reason (although I can't think why), it sounds like you have control over the PHP end so you could just encrypt the password and add an extra POST parameter so the server knows to decrypt it.
When using HTTPS your data is safe in the message and transport scope. It means no one can decode it or sniff the packets. I suggest you read this article HTTPS Wiki

Logging in to eBay using HttpWebRequest fails due to 'The browser you are using is rejecting cookies' response

I'm trying to log in to my eBay account using the following code:
string signInURL = "https://signin.ebay.com/ws/eBayISAPI.dll?co_partnerid=2&siteid=0&UsingSSL=1";
string postData = String.Format("MfcISAPICommand=SignInWelcome&userid={0}&pass={1}", "username", "password");
string contentType = "application/x-www-form-urlencoded";
string method = "POST";
string userAgent = "Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)";
CookieContainer cookieContainer = new CookieContainer();
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(signInURL);
req.CookieContainer = cookieContainer;
req.Method = method;
req.ContentType = contentType;
req.UserAgent = userAgent;
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] loginDataBytes = encoding.GetBytes(postData);
req.ContentLength = loginDataBytes.Length;
Stream stream = req.GetRequestStream();
stream.Write(loginDataBytes, 0, loginDataBytes.Length);
stream.Close();
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
StreamReader xsr = new StreamReader(res.GetResponseStream());
String responseText = xsr.ReadToEnd();
Obviously substituting my real username and password. When I look at the string responseText, I see that part of the response from eBay is
The browser you are using is rejecting cookies.
Any ideas what I'm doing wrong?
P.S. And yes, I am also using the eBay API, but this is for something slightly different than what I want to do with the API.
You're doing a direct http request. The Ebay site has functionality to talk to a browser (probably to store the session cookie). Unless you make the request code smart enough to use cookies correctly it won't work. You'll probably have to use the internet explorer object instead.
Before doing the POST you need to download the page with the form that you are submitting in your code, take the cookie they give you, put it in your CookieContainer (making sure you get the path right) and post it back up in your request.
To clarify, while you might be POSTing the correct data, you are not sending the cookie that needs to go with it. You will get this cookie from the login page.
You need to intercept the http traffic to see what exactly what had happened. I use Fiddler2. It is the good tools for debugging http. So I can know whos wrong, my application or the remote web server.
Using fiddler, you can see the request header, response header with its cookies as well as response content. It used in the middle of your app and the Ebay.
Based on my experience. I think it is because Ebay cookie sent to you is not send back to Ebay server. Fiddler will prove it whether yes or not.
Another thing, the response cookie you receive should be send back to next request by using the same CookieContainer.
You should notice that CookieContainer has a bug on .Add(Cookie) and .GetCookies(uri) method. You may not using it, but internal codes might use it.
See the details and fix here:
http://dot-net-expertise.blogspot.com/2009/10/cookiecontainer-domain-handling-bug-fix.html
CallMeLaNN

Categories