4

Hi I'm trying to add proxy with credentials to my App but whenever I'm tried, I got following (In Xcode) console warning:

*** WARNING: CFMachPortSetInvalidationCallBack() called on a CFMachPort with a Mach port (0x900b) which does not have any send rights.  This is not going to work.  Callback function: 0x181bcf524

Also Got Alert with following description

Authentication for HTTP proxy
MyProxyHost
MyProxyPort

When I cancel the popup then it's calling following method

func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)

I debug the challenge in Xcode console and got following debugDescription:

po challenge.protectionSpace.debugDescription
"<NSURLProtectionSpace: 0x12f685ad0>: Host: MyProxyHost, Server:http, Auth-Scheme:NSURLAuthenticationMethodHTTPBasic, Realm:(null), Port: MyProxyPort, Proxy:YES, Proxy-Type:http"

My Question is how to deal with proxy authentication ?

My code:

func getURLCredential() -> URLCredential {

        let credential = URLCredential(user: user, password: password, persistence: URLCredential.Persistence.forSession)
        return credential
    }

From below dictionary, I'm able to hit the proxy but unable to authenticate the proxy.

// Create an NSURLSessionConfiguration that uses the proxy
    let proxyDict: [AnyHashable: Any]? = [(kCFNetworkProxiesHTTPEnable as AnyHashable): Int(1), (kCFNetworkProxiesHTTPProxy as AnyHashable): proxyServerString, (kCFNetworkProxiesHTTPPort as AnyHashable): proxyPortNumber, (kCFProxyUsernameKey as AnyHashable): userNameKey, (kCFProxyPasswordKey as AnyHashable): password]
    let configuration = URLSessionConfiguration.default
    configuration.connectionProxyDictionary = proxyDict

I tried several below methods but fail:

let loginString = String(format: "%@:%@", user, password)
        let loginData = loginString.data(using: String.Encoding.utf8)!
        let base64LoginString = loginData.base64EncodedString()// base64EncodedData(options: [])
configuration.httpAdditionalHeaders = ["Authorization" : base64LoginString]

Another way:

let protectionSpace:URLProtectionSpace = URLProtectionSpace(host: proxyHost, port: proxyPort, protocol: "http", realm: nil, authenticationMethod: NSURLAuthenticationMethodHTTPBasic)
        let credentialStorage = URLCredentialStorage.shared//.allCredentials

        credentialStorage.set(getURLCredential(), for: protectionSpace)
        configuration.urlCredentialStorage = credentialStorage

ANOTHER WAY:

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        print("Challenge:")

        guard challenge.previousFailureCount == 0 else {
            print("Previous Failure Count = \(challenge.previousFailureCount)")
            print("Cancelling Challenge\n")
            challenge.sender?.cancel(challenge)

            // Inform the user that the user name and password are incorrect
            completionHandler(.cancelAuthenticationChallenge, nil)
            return
        }
        print("Use Credential ....\n")

        completionHandler(.useCredential, self.getURLCredential())
    }

    func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        if challenge.previousFailureCount > 0
        {
            print("Alert Please check the credential")
            debugPrint("Alert Please check the credential")
            completionHandler(.cancelAuthenticationChallenge, nil)
        }

        challenge.sender?.use(self.getURLCredential(), for: challenge)
        completionHandler(.useCredential, self.getURLCredential())
    }

unable to authenticate.

Please suggest me how to authenticate the proxy in swift 3?

Lion
  • 872
  • 1
  • 17
  • 43

2 Answers2

2
URLSessionConfiguration

need additional headers.

let configuration.httpAdditionalHeaders = ["Proxy-Authorization":  Request.authorizationHeader(user: "user", password: "password") ]
Wilson Campusano
  • 616
  • 9
  • 21
  • Hi, if I set the `connectionProxyDictionary` which is part of `NSURLSessionConfiguration`... do you know if it can set this header ("Proxy-Authorization") automatically ? thanks – Zohar81 May 07 '20 at 08:00
  • I don't know @Zohar81 . I built a Singleton of `URLSessionConfiguration` and reuse it every time I need proxy autorization. – Wilson Campusano May 08 '20 at 13:33
1

Each of your approaches has a different bug:

  • The Authorization header is for authenticating yourself to the remote server, not the proxy. You would want to set the Proxy-Authorization header.

  • The kCFProxy* keys you used are not valid in a proxy dictionary (and this is why using a dictionary as a data structure is a fundamentally bad design, BTW, for folks designing future APIs). Those keys are used solely when configuring a CF(Read|Write)Stream. You want kCFStreamPropertyHTTPProxyHost and friends. For a valid proxy dictionary example, see this closely related question.

  • You implemented a session-level delegate method for handling authentication challenges. Unfortunately, that method does not get called for proxy authentication. Only the task-level delegate method (URLSession:task:...) gets called for proxy authentication.

dgatwood
  • 10,129
  • 1
  • 28
  • 49