Bug 1081 - MonoTouch does not use saved proxy authentication
Summary: MonoTouch does not use saved proxy authentication
Alias: None
Product: iOS
Classification: Xamarin
Component: XI runtime ()
Version: 4.x
Hardware: PC Windows
: --- normal
Target Milestone: Untriaged
Assignee: Martin Baulig
: 20868 ()
Depends on:
Reported: 2011-09-27 11:44 UTC by Matt Jones
Modified: 2015-04-16 13:45 UTC (History)
8 users (show)

Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description Matt Jones 2011-09-27 11:44:11 UTC
In MonoTouch 4.2, under the simulator, my app does not pass through authentication to my network's proxy server, even though the username and password is saved in my Mac's system preferences.

I'm going to test this and see if it is a problem in the app itself too.
Comment 1 Matt Jones 2011-10-20 06:33:07 UTC
It is a problem in the app on the device but for different reasons - the proxy address is used correctly, but the stored authentication information in the device's proxy settings is not passed through automatically on the proxy request.
Comment 2 Jeffrey Stedfast 2011-11-09 16:38:33 UTC
do you have a test case and a description of how your proxy is configured?
Comment 3 Matt Jones 2011-11-10 05:12:11 UTC
The proxy is configured as requiring authentication in the WiFi connection settings. I enter my username and password there.

To see what it's doing:

- set up an HTTP proxy that requires authentication
- in the WiFi connection settings on the phone, configure it to use that proxy, and enter your username/password
- run Safari on the phone - everthing works, without a popup login screen: you are being authenticated silently by Safari using the credentials you entered in the WiFi connection settings
- write a test app that makes a web request. For example, NSData imgData=NSData.FromUrl(new NSUrl("http://someimageurl")) is enough to test it.
- start a packet sniffer so you can see the HTTP traffic
- run the app on the phone. You will see the HTTP request go out and the proxy come back asking for authentication.

(If getting a packet sniffer on your wifi network is too much hassle, you can probably do a HttpWebRequest and just look at the return data.)

Hope this helps. If you need any more info please let me know.
Comment 4 Jeffrey Stedfast 2011-11-10 16:30:09 UTC
Just an FYI, but:

NSData imgData=NSData.FromUrl(new NSUrl("http://someimageurl"));

Does not use System.Net.HttpWebRequest. it translates directly to:

NSData *imgData = [NSData dataWithContentsOfURL: [NSURL URLWithString:@"http://someimageurl"]];

I've tried googling around to see if dataWithContentsOfURL grabs the username/password from the proxy settings, but I haven't found any definitive answer to that.

Unfortunately I can't figure out how to setup a proxy server that requires authentication, at least not with the trial version of Charles.
Comment 5 Matt Jones 2011-11-14 05:47:11 UTC
Interesting. Possibly it would fail in a native Objective-C app as well? That would be interesting to find out. Somehow I doubt that it would as FromUrl must be being called by the native apps on the 'phone, and I don't have any other problems behind this proxy.
Comment 6 Ali Özgür 2012-10-15 22:01:44 UTC
Any progress on this? A user using our iPad app reported the same problem. The app is showing "The remote server returned an error: (407) Proxy Authentication Required" error.
Comment 7 Brad Moore 2012-11-27 00:18:48 UTC

I have the same issue, kinda revealed that it seems like a bug, and not an issue of mine... kinda concerned that there is only 6 posts over the last 14 months...
Comment 8 Brad Moore 2012-11-27 02:40:19 UTC
Looked at this some more.

In obj-c using "[NSString stringWithContentsOfURL:..." the app went streight through the proxy.

In MonoTouch there is no String.FromUrl, instead NSData.FromURL  was tested and works. WebClient and WebRequest both get a 407 error.

I guess in the mean time the only solution is to prompt for proxy details if the user gets a 407.
Comment 9 Brad Moore 2012-11-27 02:41:08 UTC
Jeffrey Stedfast, CCProxy is a simple proxy program for windows if you have a spare windows box. Free version allows max user limit of 3, 2 more than required for testing :P
Comment 10 Martin Baulig 2012-12-01 06:12:58 UTC
Just stumbled upon this while browsing stackoverflow ...

I still have an authenticating Squid proxy on my Windows machine and already figured out how to test different authentication mechanisms with it while doing these NTLM fixes, so looks like I'm the perfect man for this ;-)

I'll have a look next week.

@Brad and Ali: is your proxy using any "non-standard" authentication schemes (ie. Kerberos or NTLM with non-standard settings) or is the problem simply getting the credentials from iOS ?
Comment 11 Ali Özgür 2012-12-02 11:12:17 UTC
The problem seems to be a bug or missing implementation of getting the credentials ( our webrequests are configured to use default proxy instance which seem to work on ms implementation). Recently i installed FreeProxy on my Win machine and added app secific proxy configuration to our app so that our web requests use this information if provided by the user and bypass thedefault proxy instance.
Comment 12 Brad Moore 2012-12-02 17:11:27 UTC
@Martin, I would not know sorry.
When I request information about the proxy with CFNetwork.GetSystemProxySettings() it does not list password, for a good reason I would assume. In the mean time I was able to write this class to help me get through proxy issues.

Comment 13 Jeffrey Stedfast 2012-12-03 12:29:19 UTC
I'm pretty sure the problem is that my CFNetwork proxy implementation doesn't set the credentials and just returns the user/pass in the Uri in the GetProxy(Uri targetUri) method.
Comment 14 Jeffrey Stedfast 2012-12-03 16:34:33 UTC
I've committed a fix to monotouch master and mono master (and mono-2-10 branch)

Martin: could you test that the fix works? I don't have a proxy setup
Comment 15 Jeffrey Stedfast 2012-12-03 16:35:13 UTC
btw, itf the fix works in standalone mono on MacOS, it should work in MonoTouch (since it is the same logic)
Comment 16 Martin Baulig 2012-12-04 13:27:19 UTC
Oops, I completely forgot to also update the bug, only commented on stackoverflow yesterday.

If you're talking about this one: https://github.com/mono/mono/commit/4e5ecefa684231c2ec12f8ad792aa1c41f19f2f6

No, this won't help at all - the CFProxySupport API doesn't give you access to the credentials according the Apple's Documentation and my tests confirm this.

My research indicates that this bug is impossible to fix for Monotouch, we could only make this work on Mac OS X.

See my detailed reply on stackoverflow:
Comment 17 Martin Baulig 2012-12-04 14:17:11 UTC
I added my test code to my workspace module:

This one calls CFNetworkCopySystemProxySettings(), then dumps the received dictionary to the Console:

There's also a method in there to retrieve the password from the keychain.
Comment 18 Jeffrey Stedfast 2012-12-04 14:29:11 UTC
There's a kCFProxyUsernameKey *and* a kCFProxyPasswordKey
Comment 19 Jeffrey Stedfast 2012-12-04 14:34:14 UTC
Ah, n/m... in a comment at the top of CFProxySupport.h:

	The keys for username and password are optional and will only be present if the username 
	or password could be extracted from the information passed in (i.e. either the URL itself
	or the proxy dictionary supplied).  These APIs do not consult any external credential stores
	(such as the Keychain).
Comment 20 Martin Baulig 2012-12-04 14:36:59 UTC
Yeah, we can retrieve them from the user's login keychain using something like this:

- (void) getPassword {
	const char *server = "";
	const char *user = "mono";
	int pwLength = 0;
	void *password;
	SecKeychainItemRef item;
	OSStatus status = SecKeychainFindInternetPassword (
		NULL, strlen(server), server, 0, NULL, strlen (user), user, 0, NULL, 3128,
		kSecProtocolTypeAny, kSecAuthenticationTypeAny,
		&pwLength, &password, &item);
	printf("TEST: %x - %d - %p\n", status, pwLength, password);
	CFStringRef error = SecCopyErrorMessageString(status, NULL);
	printf("ERROR: %s\n", CFStringGetCStringPtr(error, kCFStringEncodingASCII));


But this won't work on iOS.  I don't even know whether something like a system keychain exists there.

That SecKeychainFindInternetPassword() function does not.
Comment 21 Jeffrey Stedfast 2012-12-04 14:40:00 UTC
btw, for the record, the commit I was hoping fixed this was: https://github.com/mono/mono/commit/ec3740aa803f594718e5080f733bd2b5988f7d4d

but with this new info, it looks like it probably won't - that is, unless the kCFProxyPasswordKey actually does get the user/pass from the keychain in iOS (i.e. works differently from MacOSX).
Comment 22 Martin Baulig 2012-12-04 14:43:47 UTC
I ran this on my iPad running iOS 6:

- (void)dumpDictionary:(CFDictionaryRef)dictionary {
	int count = (int)CFDictionaryGetCount(dictionary);
	void **keys, **values;
	printf ("DUMPING DICTIONARY: %d - %p\n", count, dictionary);

	keys = alloca((count+1) * sizeof (void*));
	values = alloca((count+1) * sizeof (void*));
	CFDictionaryGetKeysAndValues(dictionary, keys, values);
	for (int i = 0; i < count; i++) {
		NSString* string = (NSString*)keys[i];
		const char *key = [string cString];
		printf("DICT: %p - %p - %s\n", keys[i], values[i], key);
		if (!strcmp(key, "HTTPProxyUsername")) {
			NSString *value = (NSString*)values[i];
			printf("PROXY USERNAME: %s\n", [value cString]);

- (void)getProxy {
	[self getPassword];
	CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings();
	[self dumpDictionary:proxySettings];

	CFStringRef urlString = CFStringCreateWithCString(NULL, "http://www.heise.de/", kCFStringEncodingUTF8);
	CFURLRef url = CFURLCreateWithString(NULL, urlString, NULL);

	CFArrayRef proxies = CFNetworkCopyProxiesForURL(url, proxySettings);
	printf("PROXIES: %p\n", proxies);
	int count = (int)CFArrayGetCount(proxies);

	for (int i = 0; i < count; i++) {
		CFDictionaryRef proxy = (CFDictionaryRef)CFArrayGetValueAtIndex(proxies, i);
		printf("PROXY: %p\n", proxy);
		[self dumpDictionary:proxy];
		void *user = CFDictionaryGetValue(proxy, kCFProxyUsernameKey);
		printf("PROXY USER: %p - %p\n", kCFProxyUsernameKey, user);

	printf("ALL DONE!\n");

Neither username nor password are included.
Comment 23 Jeffrey Stedfast 2012-12-04 15:50:52 UTC
thanks for checking, Martin
Comment 24 Rolf Bjarne Kvinge [MSFT] 2015-04-16 13:37:33 UTC
It looks like we can't fix this, since iOS doesn't provide access to the saved proxy user/password, so I'm closing it.
Comment 25 Rolf Bjarne Kvinge [MSFT] 2015-04-16 13:45:41 UTC
*** Bug 20868 has been marked as a duplicate of this bug. ***