Skip to content

Instantly share code, notes, and snippets.

@CodeEagle
Created November 10, 2017 02:21
Show Gist options
  • Save CodeEagle/6fc136bc0ea1d336b9bc6b41cb2d87d4 to your computer and use it in GitHub Desktop.
Save CodeEagle/6fc136bc0ea1d336b9bc6b41cb2d87d4 to your computer and use it in GitHub Desktop.
Digest Proxy Authorization
public static func proxyAuthorizationFor(host: String, port: Int, username: String, password: String, destHost: String, destPort: Int) -> [String : String]? {
var input: InputStream?
var output: OutputStream?
Stream.getStreamsToHost(withName: host, port: port, inputStream: &input, outputStream: &output)
guard let input_ = input, let output_ = output else { return nil }
input_.open()
output_.open()
guard input_.streamError == nil, output_.streamError == nil else { return nil }
let method = "CONNECT"
let uri = "\(destHost):\(destPort)"
let host = uri
let queryString = "\(method) \(uri) HTTP/1.1\r\nHost: \(host)\r\n\r\n"
let queryData = [UInt8](queryString.utf8)
output_.write(UnsafePointer<UInt8>(queryData), maxLength: queryData.count)
let size = 256
let buffer = malloc(size).assumingMemoryBound(to: UInt8.self)
defer { free(buffer) }
var totalText = ""
while true {
let read = input_.read(buffer, maxLength: size)
if read <= 0 { break }
if read < size {
let p = malloc(read).assumingMemoryBound(to: UInt8.self)
defer { free(p) }
memcpy(p, buffer, read)
totalText += String(cString: p)
break
} else {
totalText += String(cString: buffer)
}
}
let prefix = "Proxy-Authenticate: Digest"
guard let proxyAuthenticate = totalText.components(separatedBy: "\r\n").filter({$0.hasPrefix(prefix)}).first?.replacingOccurrences(of: prefix, with: "") else { return nil }
let array = proxyAuthenticate.components(separatedBy: ",").flatMap { (raw) -> [String : String]? in
let kv = raw.components(separatedBy: "=").flatMap({Optional($0.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).replacingOccurrences(of: "\"", with: ""))})
guard kv.count == 2 else { return nil }
return [kv[0] : kv[1]]
}
let map = array.reduce([:]) { (result, dict) -> [String : String] in
var old = result
for (k, v) in dict { old[k] = v }
return old
}
guard let realm = map["realm"], let qop = map["qop"], let nonce = map["nonce"] else { return nil }
let A1 = "\(username):\(realm):\(password)"
let A2 = "\(method.uppercased()):\(uri)"
let HA1 = A1.md5()
var HA2 = ""
let nc = "00000001"
let cnonce = UUID().uuidString
var response = ""
if qop.contains("auth") {
HA2 = A2.md5()
let raw = "\(HA1):\(nonce):\(nc):\(cnonce):\(qop):\(HA2)"
response = raw.md5()
}
let ret = "Digest username=\"\(username)\", realm=\"\(realm)\", nonce=\"\(nonce)\", uri=\"\(uri)\", cnonce=\"\(cnonce)\", nc=\(nc), qop=\(qop), response=\"\(response)\""
return ["Proxy-Authenticate" : ret]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment