This is Xamarin's bug tracking system. For product support, please use the support links listed in your Xamarin Account.
Bug 1081 - MonoTouch does not use saved proxy authentication
: MonoTouch does not use saved proxy authentication
Status: NEW
Product: iOS
Classification: Xamarin
Component: Runtime
: 4.x
: PC Windows
: --- normal
: Untriaged
Assigned To: Martin Baulig
:
:
:
:
  Show dependency treegraph
 
Reported: 2011-09-27 11:44 EDT by Matt Jones
Modified: 2012-12-04 15:50 EST (History)
5 users (show)

See Also:
Tags:
Test Case URL:
External Submit: ---


Attachments

Description Matt Jones 2011-09-27 11:44:11 EDT
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 EDT
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 EST
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 EST
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 EST
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 EST
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 EDT
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 EST
http://stackoverflow.com/questions/13576522/monotouch-auto-proxy-network-credentials-not-working

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 EST
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 EST
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 EST
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 EST
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 EST
@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.

https://github.com/ytn3rd/FourPiLibs/blob/master/FourPiLib/FourPiLib/Web/DataDownloader.cs
Comment 13 Jeffrey Stedfast 2012-12-03 12:29:19 EST
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 EST
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 EST
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 EST
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:
http://stackoverflow.com/questions/13576522/monotouch-auto-proxy-network-credentials-not-working/13693988#13693988
Comment 17 Martin Baulig 2012-12-04 14:17:11 EST
I added my test code to my workspace module:
https://github.com/baulig/Provcon-Faust/commit/9a5d5545828b5eb31519f30c672d77c86de7de49

This one calls CFNetworkCopySystemProxySettings(), then dumps the received
dictionary to the Console:
https://github.com/baulig/Provcon-Faust/blob/9a5d5545828b5eb31519f30c672d77c86de7de49/NativeTestApp/NativeTestApp/AppDelegate.m

There's also a method in there to retrieve the password from the keychain.
Comment 18 Jeffrey Stedfast 2012-12-04 14:29:11 EST
There's a kCFProxyUsernameKey *and* a kCFProxyPasswordKey
Comment 19 Jeffrey Stedfast 2012-12-04 14:34:14 EST
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 EST
Yeah, we can retrieve them from the user's login keychain using something like
this:

- (void) getPassword {
    const char *server = "192.168.16.101";
    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 EST
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 EST
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]);
        }
    }
    printf("DONE!\n");
}

- (void)getProxy {
    [self getPassword];
    return;
    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 EST
thanks for checking, Martin

Note You need to log in before you can comment on or make changes to this bug.