Skip to content

Commit fc14c26

Browse files
PalleasRomain Pouclet
andauthored
Preserve port when computing the login URL (#6715)
Co-authored-by: Romain Pouclet <[email protected]>
1 parent 5050d4c commit fc14c26

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
@@ -75,7 +75,7 @@ public final class RegistryClient: Cancellable {
7575

7676
if let authorizationProvider {
7777
self.authorizationProvider = { url in
78-
guard let registryAuthentication = configuration.authentication(for: url) else {
78+
guard let registryAuthentication = try? configuration.authentication(for: url) else {
7979
return .none
8080
}
8181
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
@@ -89,6 +89,20 @@ private func readpassword(_ prompt: String) throws -> String {
8989

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

153167
try registryURL.validateRegistryURL()
154168

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

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

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

238245
// Build a RegistryClient to test login credentials (fingerprints don't matter in this case)
239246
let registryClient = RegistryClient(
@@ -306,7 +313,7 @@ extension SwiftPackageRegistryTool {
306313

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

@@ -339,10 +346,6 @@ extension SwiftPackageRegistryTool {
339346

340347
try registryURL.validateRegistryURL()
341348

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

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

Tests/CommandsTests/PackageRegistryToolTests.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,23 @@ final class PackageRegistryToolTests: CommandsTestCase {
947947
}
948948
}
949949

950+
func testCreateLoginURL() {
951+
let registryURL = URL(string: "https://packages.example.com")!
952+
953+
XCTAssertEqual(try SwiftPackageRegistryTool.Login.loginURL(from: registryURL, loginAPIPath: nil).absoluteString, "https://packages.example.com/login")
954+
955+
XCTAssertEqual(try SwiftPackageRegistryTool.Login.loginURL(from: registryURL, loginAPIPath: "/secret-sign-in").absoluteString, "https://packages.example.com/secret-sign-in")
956+
957+
}
958+
959+
func testCreateLoginURLMaintainsPort() {
960+
let registryURL = URL(string: "https://packages.example.com:8081")!
961+
962+
XCTAssertEqual(try SwiftPackageRegistryTool.Login.loginURL(from: registryURL, loginAPIPath: nil).absoluteString, "https://packages.example.com:8081/login")
963+
964+
XCTAssertEqual(try SwiftPackageRegistryTool.Login.loginURL(from: registryURL, loginAPIPath: "/secret-sign-in").absoluteString, "https://packages.example.com:8081/secret-sign-in")
965+
}
966+
950967
private func testRoots(callback: (Result<[[UInt8]], Error>) -> Void) {
951968
do {
952969
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)