Skip to content

Commit

Permalink
Send Basic Auth credentials in an Authorization header (#208)
Browse files Browse the repository at this point in the history
* Send Basic Auth credentials in an Authorization header

The username and password are currently sent as a part of the url. This can be a challenge
if the url need to be percent encoded. The username and password also need to be percent
encoded then. It is easier to send username and password in the Authorization header. Note that
this will change the behaviour of `ClientRequent.url`.
  • Loading branch information
RudraniW authored and Pushkar N Kulkarni committed Jul 24, 2019
1 parent dfdbff2 commit ee75eeb
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 19 deletions.
24 changes: 11 additions & 13 deletions Sources/KituraNet/ClientRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,17 @@ public class ClientRequest {
if let username = url.user {
self.userName = username
}

if let password = url.password {
self.password = password
}

if let username = self.userName, let password = self.password {
self.headers["Authorization"] = createHTTPBasicAuthHeader(username: username, password: password)
}

self.url = "\(url.scheme ?? "http")://\(self.hostName ?? "unknown")\(self.port.map { ":\($0)" } ?? "")/\(fullPath)"

}

/**
Expand Down Expand Up @@ -355,17 +363,11 @@ public class ClientRequest {
}
}

// Support for Basic HTTP authentication
let user = self.userName ?? ""
let pwd = self.password ?? ""
var authenticationClause = ""
// If either the userName or password are non-empty, add the authenticationClause
if !user.isEmpty || !pwd.isEmpty {
authenticationClause = "\(user):\(pwd)@"
if let username = self.userName, let password = self.password {
self.headers["Authorization"] = createHTTPBasicAuthHeader(username: username, password: password)
}

//the url string
self.url = "\(theSchema)\(authenticationClause)\(hostName)\(port)\(path)"
self.url = "\(theSchema)\(hostName)\(port)\(path)"
self.percentEncodedURL = percentEncode(self.url)
}

Expand Down Expand Up @@ -567,10 +569,6 @@ public class ClientRequest {
self.headers["Connection"] = "close"
}

if let username = self.userName, let password = self.password {
self.headers["Authorization"] = createHTTPBasicAuthHeader(username: username, password: password)
}

if self.port == nil {
self.port = isHTTPS ? 443 : 80
}
Expand Down
25 changes: 19 additions & 6 deletions Tests/KituraNetTests/ClientRequestTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ class ClientRequestTests: KituraNetTest {
let testCallback: ClientRequest.Callback = {_ in }
// 1 test URL that is build when initializing with ClientRequestOptions

private func httpBasicAuthHeader(username: String, password: String) -> String {
let authHeader = "\(username):\(password)"
let data = Data(authHeader.utf8)
return "Basic \(data.base64EncodedString())"
}

func testClientRequestWhenInitializedWithValidURL() {
let options: [ClientRequest.Options] = [ .method("GET"),
.schema("https://"),
Expand Down Expand Up @@ -91,14 +97,15 @@ class ClientRequestTests: KituraNetTest {
testRequest.set(.headers(["X-Custom": "Swift"]))
testRequest.set(.maxRedirects(3))
testRequest.set(.disableSSLVerification)
XCTAssertEqual(testRequest.url, "https://66o.tech:8080")
XCTAssertEqual(testRequest.url, "https://66o.tech:8080/")
}

func testClientRequestParse() {
let options = ClientRequest.parse("https://username:password@66o.tech:8080/path?key=value")
let testRequest = ClientRequest(options: options, callback: testCallback)
XCTAssertEqual(testRequest.url, "https://username:password@66o.tech:8080/path?key=value")

XCTAssertEqual(testRequest.url, "https://66o.tech:8080/path?key=value")
let authHeaderValue = testRequest.headers["Authorization"] ?? ""
XCTAssertEqual(authHeaderValue, httpBasicAuthHeader(username: "username", password: "password"))
let options1: [ClientRequest.Options] = [ .schema("https"),
.hostname("66o.tech"),
.path("/view/matching?key=\"viewTest\"")
Expand All @@ -121,22 +128,28 @@ class ClientRequestTests: KituraNetTest {
.hostname("66o.tech")
]
var testRequest = ClientRequest(options: options, callback: testCallback)
XCTAssertEqual(testRequest.url, "http://myusername:@66o.tech")
XCTAssertNil(testRequest.headers["Authorization"])
XCTAssertEqual(testRequest.userName, "myusername")
XCTAssertEqual(testRequest.url, "http://66o.tech")

// ensure an empty username works
let options2: [ClientRequest.Options] = [ .password("mypassword"),
.hostname("66o.tech")
]
testRequest = ClientRequest(options: options2, callback: testCallback)
XCTAssertEqual(testRequest.url, "http://:mypassword@66o.tech")
XCTAssertNil(testRequest.headers["Authorization"])
XCTAssertEqual(testRequest.password, "mypassword")
XCTAssertEqual(testRequest.url, "http://66o.tech")

// ensure username:password works
let options3: [ClientRequest.Options] = [ .username("myusername"),
.password("mypassword"),
.hostname("66o.tech")
]
testRequest = ClientRequest(options: options3, callback: testCallback)
XCTAssertEqual(testRequest.url, "http://myusername:mypassword@66o.tech")
let authHeaderValue = testRequest.headers["Authorization"] ?? ""
XCTAssertEqual(authHeaderValue, httpBasicAuthHeader(username: "myusername", password: "mypassword"))
XCTAssertEqual(testRequest.url, "http://66o.tech")
}

func testClientRequestSyncBehavior() {
Expand Down

0 comments on commit ee75eeb

Please sign in to comment.