Skip to content

Commit f8a4a39

Browse files
committed
renew token from token file before it expires
1 parent 96c4914 commit f8a4a39

3 files changed

Lines changed: 367 additions & 306 deletions

File tree

Sources/SwiftkubeClient/Config/AuthInfo+Authentication.swift

Lines changed: 116 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -33,91 +33,83 @@ import Foundation
3333
import Logging
3434
import NIOSSL
3535

36-
public extension AuthInfo {
37-
38-
func authentication(logger: Logger?) -> KubernetesClientAuthentication? {
39-
if let username = username, let password = password {
40-
return .basicAuth(username: username, password: password)
41-
}
42-
43-
if let token = token {
44-
return .bearer(token: token)
45-
}
46-
47-
do {
48-
if let tokenFile = tokenFile {
49-
let fileURL = URL(fileURLWithPath: tokenFile)
50-
let token = try String(contentsOf: fileURL, encoding: .utf8)
51-
return .bearer(token: token)
52-
}
53-
} catch {
54-
logger?.warning(
55-
"Error initializing authentication from token file \(String(describing: tokenFile)): \(error)"
56-
)
57-
}
58-
59-
do {
60-
if let clientCertificateFile = clientCertificate, let clientKeyFile = clientKey {
61-
let clientCertificate = try NIOSSLCertificate(
62-
file: clientCertificateFile,
63-
format: .pem
64-
)
65-
let clientKey = try NIOSSLPrivateKey(
66-
file: clientKeyFile,
67-
format: .pem
68-
)
69-
return .x509(
70-
clientCertificate: clientCertificate,
71-
clientKey: clientKey
72-
)
73-
}
74-
75-
if let clientCertificateData = clientCertificateData, let clientKeyData = clientKeyData {
76-
let clientCertificate = try NIOSSLCertificate(
77-
bytes: [UInt8](clientCertificateData),
78-
format: .pem
79-
)
80-
let clientKey = try NIOSSLPrivateKey(
81-
bytes: [UInt8](clientKeyData),
82-
format: .pem
83-
)
84-
return .x509(
85-
clientCertificate: clientCertificate,
86-
clientKey: clientKey
87-
)
88-
}
89-
} catch {
90-
logger?.warning(
91-
"Error initializing authentication from client certificate: \(error)"
92-
)
93-
}
94-
95-
#if os(Linux) || os(macOS)
96-
do {
97-
if let exec {
98-
let outputData = try run(
99-
command: exec.command,
100-
arguments: exec.args
101-
)
102-
103-
let decoder = JSONDecoder()
104-
decoder.dateDecodingStrategy = .iso8601
105-
let credential = try decoder.decode(
106-
ExecCredential.self,
107-
from: outputData
108-
)
109-
110-
return .bearer(token: credential.status.token)
111-
}
112-
} catch {
113-
logger?.warning(
114-
"Error initializing authentication from exec \(error)"
115-
)
116-
}
117-
#endif
118-
119-
return nil
120-
}
36+
extension AuthInfo {
37+
38+
public func authentication(logger: Logger?) -> KubernetesClientAuthentication? {
39+
if let username = username, let password = password {
40+
return .basicAuth(username: username, password: password)
41+
}
42+
43+
if let token = token {
44+
return .bearer(token: token)
45+
}
46+
47+
if let tokenFile = tokenFile {
48+
return .tokenFile(source: CachedFileTokenSource(path: tokenFile))
49+
}
50+
51+
do {
52+
if let clientCertificateFile = clientCertificate, let clientKeyFile = clientKey {
53+
let clientCertificate = try NIOSSLCertificate(
54+
file: clientCertificateFile,
55+
format: .pem
56+
)
57+
let clientKey = try NIOSSLPrivateKey(
58+
file: clientKeyFile,
59+
format: .pem
60+
)
61+
return .x509(
62+
clientCertificate: clientCertificate,
63+
clientKey: clientKey
64+
)
65+
}
66+
67+
if let clientCertificateData = clientCertificateData, let clientKeyData = clientKeyData {
68+
let clientCertificate = try NIOSSLCertificate(
69+
bytes: [UInt8](clientCertificateData),
70+
format: .pem
71+
)
72+
let clientKey = try NIOSSLPrivateKey(
73+
bytes: [UInt8](clientKeyData),
74+
format: .pem
75+
)
76+
return .x509(
77+
clientCertificate: clientCertificate,
78+
clientKey: clientKey
79+
)
80+
}
81+
} catch {
82+
logger?.warning(
83+
"Error initializing authentication from client certificate: \(error)"
84+
)
85+
}
86+
87+
#if os(Linux) || os(macOS)
88+
do {
89+
if let exec {
90+
let outputData = try run(
91+
command: exec.command,
92+
arguments: exec.args
93+
)
94+
95+
let decoder = JSONDecoder()
96+
decoder.dateDecodingStrategy = .iso8601
97+
let credential = try decoder.decode(
98+
ExecCredential.self,
99+
from: outputData
100+
)
101+
102+
return .bearer(token: credential.status.token)
103+
}
104+
} catch {
105+
logger?.warning(
106+
"Error initializing authentication from exec \(error)"
107+
)
108+
}
109+
#endif
110+
111+
return nil
112+
}
121113
}
122114

123115
// MARK: - ExecCredential
@@ -126,50 +118,50 @@ public extension AuthInfo {
126118
// Acordingly with the doc https://kubernetes.io/docs/reference/config-api/client-authentication.v1beta1/
127119
// ExecCredential.Spec.interactive is required as long as the ones in the Status object.
128120
public struct ExecCredential: Codable {
129-
let apiVersion: String
130-
let kind: String
131-
let spec: Spec
132-
let status: Status
121+
let apiVersion: String
122+
let kind: String
123+
let spec: Spec
124+
let status: Status
133125
}
134126

135-
public extension ExecCredential {
127+
extension ExecCredential {
136128

137-
struct Spec: Codable {
138-
let cluster: Cluster?
139-
let interactive: Bool?
140-
}
129+
public struct Spec: Codable {
130+
let cluster: Cluster?
131+
let interactive: Bool?
132+
}
141133

142-
struct Status: Codable {
143-
let expirationTimestamp: Date
144-
let token: String
145-
let clientCertificateData: String?
146-
let clientKeyData: String?
147-
}
134+
public struct Status: Codable {
135+
let expirationTimestamp: Date
136+
let token: String
137+
let clientCertificateData: String?
138+
let clientKeyData: String?
139+
}
148140
}
149141

150142
#if os(Linux) || os(macOS)
151-
internal func run(command: String, arguments: [String]? = nil) throws -> Data {
152-
func run(_ command: String, _ arguments: [String]?) throws -> Data {
153-
let task = Process()
154-
task.executableURL = URL(fileURLWithPath: command)
155-
arguments.flatMap { task.arguments = $0 }
156-
157-
let pipe = Pipe()
158-
task.standardOutput = pipe
159-
160-
try task.run()
161-
162-
return pipe.fileHandleForReading.availableData
163-
}
164-
165-
func resolve(command: String) throws -> String {
166-
try String(
167-
decoding:
168-
run("/usr/bin/which", ["\(command)"]),
169-
as: UTF8.self
170-
).trimmingCharacters(in: .whitespacesAndNewlines)
171-
}
172-
173-
return try run(resolve(command: command), arguments)
174-
}
143+
internal func run(command: String, arguments: [String]? = nil) throws -> Data {
144+
func run(_ command: String, _ arguments: [String]?) throws -> Data {
145+
let task = Process()
146+
task.executableURL = URL(fileURLWithPath: command)
147+
arguments.flatMap { task.arguments = $0 }
148+
149+
let pipe = Pipe()
150+
task.standardOutput = pipe
151+
152+
try task.run()
153+
154+
return pipe.fileHandleForReading.availableData
155+
}
156+
157+
func resolve(command: String) throws -> String {
158+
try String(
159+
decoding:
160+
run("/usr/bin/which", ["\(command)"]),
161+
as: UTF8.self
162+
).trimmingCharacters(in: .whitespacesAndNewlines)
163+
}
164+
165+
return try run(resolve(command: command), arguments)
166+
}
175167
#endif

0 commit comments

Comments
 (0)