mirror of
https://github.com/swift-server/async-http-client.git
synced 2026-05-03 07:32:29 +00:00
Added: ability to set basic authentication on requests (#778)
Motivation: As an HTTP library, async-http-client should have authentication support. Modifications: This adds a `setBasicAuth()` method to both HTTPClientRequest and `HTTPClient.Request` and their related unit tests. Result: Library users will be able to leverage this method to use basic authentication on their requests without implementing this in their own projects. Note: I also ran the tests (`swift test`) with the `docker.io/library/swift:6.0-focal` and `docker.io/library/swift:5.10.1-focal` to ensure linux compatibility. Signed-off-by: Agam Dua <agam_dua@apple.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the AsyncHTTPClient open source project
|
||||
//
|
||||
// Copyright (c) 2024 Apple Inc. and the AsyncHTTPClient project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Foundation
|
||||
|
||||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
|
||||
extension HTTPClientRequest {
|
||||
/// Set basic auth for a request.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - username: the username to authenticate with
|
||||
/// - password: authentication password associated with the username
|
||||
public mutating func setBasicAuth(username: String, password: String) {
|
||||
self.headers.setBasicAuth(username: username, password: password)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the AsyncHTTPClient open source project
|
||||
//
|
||||
// Copyright (c) 2024 Apple Inc. and the AsyncHTTPClient project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Foundation
|
||||
import NIOHTTP1
|
||||
|
||||
/// Generates base64 encoded username + password for http basic auth.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - username: the username to authenticate with
|
||||
/// - password: authentication password associated with the username
|
||||
/// - Returns: encoded credentials to use the Authorization: Basic http header.
|
||||
func encodeBasicAuthCredentials(username: String, password: String) -> String {
|
||||
var value = Data()
|
||||
value.reserveCapacity(username.utf8.count + password.utf8.count + 1)
|
||||
value.append(contentsOf: username.utf8)
|
||||
value.append(UInt8(ascii: ":"))
|
||||
value.append(contentsOf: password.utf8)
|
||||
return value.base64EncodedString()
|
||||
}
|
||||
|
||||
extension HTTPHeaders {
|
||||
/// Sets the basic auth header
|
||||
mutating func setBasicAuth(username: String, password: String) {
|
||||
let encoded = encodeBasicAuthCredentials(username: username, password: password)
|
||||
self.replaceOrAdd(name: "Authorization", value: "Basic \(encoded)")
|
||||
}
|
||||
}
|
||||
@@ -285,6 +285,15 @@ extension HTTPClient {
|
||||
|
||||
return (head, metadata)
|
||||
}
|
||||
|
||||
/// Set basic auth for a request.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - username: the username to authenticate with
|
||||
/// - password: authentication password associated with the username
|
||||
public mutating func setBasicAuth(username: String, password: String) {
|
||||
self.headers.setBasicAuth(username: username, password: password)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an HTTP response.
|
||||
|
||||
@@ -57,6 +57,17 @@ class HTTPClientRequestTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
func testBasicAuth() {
|
||||
XCTAsyncTest {
|
||||
var request = Request(url: "https://example.com/get")
|
||||
request.setBasicAuth(username: "foo", password: "bar")
|
||||
var preparedRequest: PreparedRequest?
|
||||
XCTAssertNoThrow(preparedRequest = try PreparedRequest(request))
|
||||
guard let preparedRequest = preparedRequest else { return }
|
||||
XCTAssertEqual(preparedRequest.head.headers.first(name: "Authorization")!, "Basic Zm9vOmJhcg==")
|
||||
}
|
||||
}
|
||||
|
||||
func testUnixScheme() {
|
||||
XCTAsyncTest {
|
||||
var request = Request(url: "unix://%2Fexample%2Ffolder.sock/some_path")
|
||||
|
||||
@@ -3668,4 +3668,11 @@ final class HTTPClientTests: XCTestCaseHTTPClientTestsBaseClass {
|
||||
let response3 = try await client.execute(request, timeout: /* infinity */ .hours(99))
|
||||
XCTAssertEqual(.ok, response3.status)
|
||||
}
|
||||
|
||||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
|
||||
func testRequestBasicAuth() async throws {
|
||||
var request = try HTTPClient.Request(url: self.defaultHTTPBinURLPrefix)
|
||||
request.setBasicAuth(username: "foo", password: "bar")
|
||||
XCTAssertEqual(request.headers.first(name: "Authorization"), "Basic Zm9vOmJhcg==")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user