Skip to content

Commit d8e22aa

Browse files
PalleasRomain Poucletyim-lee
authored
Preserve port when computing the login URL (#6711)
* Preserve port when computing the login URL * Remove extra testing target * Add helper to compute storage key * Add methods to add authentication to config * Remove old test * Update Sources/PackageRegistryTool/PackageRegistryTool+Auth.swift Co-authored-by: Yim Lee <[email protected]> --------- Co-authored-by: Romain Pouclet <[email protected]> Co-authored-by: Yim Lee <[email protected]>
1 parent 1e72ef8 commit d8e22aa

File tree

5 files changed

+61
-23
lines changed

5 files changed

+61
-23
lines changed

Sources/PackageRegistry/RegistryClient.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public final class RegistryClient: Cancellable {
7676

7777
if let authorizationProvider {
7878
self.authorizationProvider = { url in
79-
guard let registryAuthentication = configuration.authentication(for: url) else {
79+
guard let registryAuthentication = try? configuration.authentication(for: url) else {
8080
return .none
8181
}
8282
guard let (user, password) = authorizationProvider.authentication(for: url) else {

Sources/PackageRegistry/RegistryConfiguration.swift

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ import Foundation
1515
import PackageModel
1616

1717
public struct RegistryConfiguration: Hashable {
18+
static func authenticationStorageKey(for registryURL: URL) throws -> String {
19+
guard let host = registryURL.host?.lowercased() else {
20+
throw RegistryError.invalidURL(registryURL)
21+
}
22+
23+
return [host, registryURL.port?.description].compactMap { $0 }.joined(separator: ":")
24+
}
25+
1826
public enum Version: Int, Codable {
1927
case v1 = 1
2028
}
@@ -66,9 +74,19 @@ public struct RegistryConfiguration: Hashable {
6674
self.defaultRegistry != nil || !self.scopedRegistries.isEmpty
6775
}
6876

69-
public func authentication(for registryURL: URL) -> Authentication? {
70-
guard let host = registryURL.host else { return nil }
71-
return self.registryAuthentication[host]
77+
public func authentication(for registryURL: URL) throws -> Authentication? {
78+
let key = try Self.authenticationStorageKey(for: registryURL)
79+
return self.registryAuthentication[key]
80+
}
81+
82+
public mutating func add(authentication: Authentication, for registryURL: URL) throws {
83+
let key = try Self.authenticationStorageKey(for: registryURL)
84+
self.registryAuthentication[key] = authentication
85+
}
86+
87+
public mutating func removeAuthentication(for registryURL: URL) {
88+
guard let key = try? Self.authenticationStorageKey(for: registryURL) else { return }
89+
self.registryAuthentication.removeValue(forKey: key)
7290
}
7391

7492
public func signing(for package: PackageIdentity.RegistryIdentity, registry: Registry) -> Security.Signing {

Sources/PackageRegistryTool/PackageRegistryTool+Auth.swift

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,20 @@ private func readpassword(_ prompt: String) throws -> String {
9090

9191
extension SwiftPackageRegistryTool {
9292
struct Login: SwiftCommand {
93+
94+
static func loginURL(from registryURL: URL, loginAPIPath: String?) throws -> URL {
95+
// Login URL must be HTTPS
96+
var loginURLComponents = URLComponents(url: registryURL, resolvingAgainstBaseURL: true)
97+
loginURLComponents?.scheme = "https"
98+
loginURLComponents?.path = loginAPIPath ?? "/login"
99+
100+
guard let loginURL = loginURLComponents?.url else {
101+
throw ValidationError.invalidURL(registryURL)
102+
}
103+
104+
return loginURL
105+
}
106+
93107
static let configuration = CommandConfiguration(
94108
abstract: "Log in to a registry"
95109
)
@@ -153,10 +167,6 @@ extension SwiftPackageRegistryTool {
153167

154168
try registryURL.validateRegistryURL()
155169

156-
guard let host = registryURL.host?.lowercased() else {
157-
throw ValidationError.invalidURL(registryURL)
158-
}
159-
160170
let authenticationType: RegistryConfiguration.AuthenticationType
161171
let storeUsername: String
162172
let storePassword: String
@@ -226,15 +236,12 @@ extension SwiftPackageRegistryTool {
226236
loginAPIPath = registryURL.path
227237
}
228238

229-
// Login URL must be HTTPS
230-
guard let loginURL = URL(string: "https://\(host)\(loginAPIPath ?? "/login")") else {
231-
throw ValidationError.invalidURL(registryURL)
232-
}
239+
let loginURL = try Self.loginURL(from: registryURL, loginAPIPath: loginAPIPath)
240+
233241

234242
// Build a RegistryConfiguration with the given authentication settings
235243
var registryConfiguration = configuration.configuration
236-
registryConfiguration
237-
.registryAuthentication[host] = .init(type: authenticationType, loginAPIPath: loginAPIPath)
244+
try registryConfiguration.add(authentication: .init(type: authenticationType, loginAPIPath: loginAPIPath), for: registryURL)
238245

239246
// Build a RegistryClient to test login credentials (fingerprints don't matter in this case)
240247
let registryClient = RegistryClient(
@@ -307,7 +314,7 @@ extension SwiftPackageRegistryTool {
307314

308315
// Update user-level registry configuration file
309316
let update: (inout RegistryConfiguration) throws -> Void = { configuration in
310-
configuration.registryAuthentication[host] = .init(type: authenticationType, loginAPIPath: loginAPIPath)
317+
try configuration.add(authentication: .init(type: authenticationType, loginAPIPath: loginAPIPath), for: registryURL)
311318
}
312319
try configuration.updateShared(with: update)
313320

@@ -340,10 +347,6 @@ extension SwiftPackageRegistryTool {
340347

341348
try registryURL.validateRegistryURL()
342349

343-
guard let host = registryURL.host?.lowercased() else {
344-
throw ValidationError.invalidURL(registryURL)
345-
}
346-
347350
// We need to be able to read/write credentials
348351
guard let authorizationProvider = try swiftTool.getRegistryAuthorizationProvider() else {
349352
throw ValidationError.unknownCredentialStore
@@ -362,7 +365,7 @@ extension SwiftPackageRegistryTool {
362365

363366
// Update user-level registry configuration file
364367
let update: (inout RegistryConfiguration) throws -> Void = { configuration in
365-
configuration.registryAuthentication.removeValue(forKey: host)
368+
configuration.removeAuthentication(for: registryURL)
366369
}
367370
try configuration.updateShared(with: update)
368371

Tests/CommandsTests/PackageRegistryToolTests.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,23 @@ final class PackageRegistryToolTests: CommandsTestCase {
903903
}
904904
}
905905

906+
func testCreateLoginURL() {
907+
let registryURL = URL(string: "https://packages.example.com")!
908+
909+
XCTAssertEqual(try SwiftPackageRegistryTool.Login.loginURL(from: registryURL, loginAPIPath: nil).absoluteString, "https://packages.example.com/login")
910+
911+
XCTAssertEqual(try SwiftPackageRegistryTool.Login.loginURL(from: registryURL, loginAPIPath: "/secret-sign-in").absoluteString, "https://packages.example.com/secret-sign-in")
912+
913+
}
914+
915+
func testCreateLoginURLMaintainsPort() {
916+
let registryURL = URL(string: "https://packages.example.com:8081")!
917+
918+
XCTAssertEqual(try SwiftPackageRegistryTool.Login.loginURL(from: registryURL, loginAPIPath: nil).absoluteString, "https://packages.example.com:8081/login")
919+
920+
XCTAssertEqual(try SwiftPackageRegistryTool.Login.loginURL(from: registryURL, loginAPIPath: "/secret-sign-in").absoluteString, "https://packages.example.com:8081/secret-sign-in")
921+
}
922+
906923
private func testRoots(callback: (Result<[[UInt8]], Error>) -> Void) {
907924
do {
908925
try fixture(name: "Signing", createGitRepo: false) { fixturePath in

Tests/PackageRegistryTests/RegistryConfigurationTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,10 +372,10 @@ final class RegistryConfigurationTests: XCTestCase {
372372

373373
func testGetAuthenticationConfigurationByRegistryURL() throws {
374374
var configuration = RegistryConfiguration()
375-
configuration.registryAuthentication[defaultRegistryBaseURL.host!] = .init(type: .token)
375+
try configuration.add(authentication: .init(type: .token), for: defaultRegistryBaseURL)
376376

377-
XCTAssertEqual(configuration.authentication(for: defaultRegistryBaseURL)?.type, .token)
378-
XCTAssertNil(configuration.authentication(for: customRegistryBaseURL))
377+
XCTAssertEqual(try configuration.authentication(for: defaultRegistryBaseURL)?.type, .token)
378+
XCTAssertNil(try configuration.authentication(for: customRegistryBaseURL))
379379
}
380380

381381
func testGetSigning_noOverrides() throws {

0 commit comments

Comments
 (0)