Skip to content

Commit f8fa4f6

Browse files
committed
fix: inject auth info to appsync handshake headers
1 parent 6936a28 commit f8fa4f6

File tree

10 files changed

+99
-113
lines changed

10 files changed

+99
-113
lines changed

Sources/AWSAppSyncApolloExtensions/Utilities/Base64Encoder.swift

-18
This file was deleted.

Sources/AWSAppSyncApolloExtensions/Utilities/EndpointHelper.swift

+2-12
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func appSyncApiEndpoint(_ url: URL) -> URL {
2424
}
2525

2626
urlComponents.host = host.replacingOccurrences(of: "appsync-realtime-api", with: "appsync-api")
27+
urlComponents.scheme = "https"
2728
guard let apiUrl = urlComponents.url else {
2829
return url
2930
}
@@ -44,20 +45,9 @@ func appSyncRealTimeEndpoint(_ url: URL) -> URL {
4445
}
4546

4647
urlComponents.host = host.replacingOccurrences(of: "appsync-api", with: "appsync-realtime-api")
48+
urlComponents.scheme = "wss"
4749
guard let realTimeUrl = urlComponents.url else {
4850
return url
4951
}
50-
5152
return realTimeUrl
5253
}
53-
54-
func useWebSocketProtocolScheme(url: URL) -> URL {
55-
guard var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
56-
return url
57-
}
58-
if urlComponents.scheme == "ws" || urlComponents.scheme == "wss" {
59-
return url
60-
}
61-
urlComponents.scheme = urlComponents.scheme == "http" ? "ws" : "wss"
62-
return urlComponents.url ?? url
63-
}

Sources/AWSAppSyncApolloExtensions/Websocket/AppSyncWebSocketClient.swift

+13-21
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ public class AppSyncWebSocketClient: NSObject, ApolloWebSocket.WebSocketClient,
3030
// MARK: - Internal
3131

3232
private let taskQueue: TaskQueue<Void>
33-
private let endpointURL: URL
3433

3534
/// The underlying URLSessionWebSocketTask
3635
private var connection: URLSessionWebSocketTask? {
@@ -72,13 +71,11 @@ public class AppSyncWebSocketClient: NSObject, ApolloWebSocket.WebSocketClient,
7271
callbackQueue: DispatchQueue,
7372
authorizer: AppSyncAuthorizer
7473
) {
75-
self.endpointURL = useWebSocketProtocolScheme(url: appSyncRealTimeEndpoint(endpointURL))
76-
self.request = URLRequest(url: self.endpointURL)
74+
self.request = URLRequest(url: appSyncRealTimeEndpoint(endpointURL))
7775
self.delegate = delegate
7876
self.callbackQueue = callbackQueue
7977
self.authorizer = authorizer
8078
self.taskQueue = TaskQueue()
81-
request.setValue("graphql-ws", forHTTPHeaderField: "Sec-WebSocket-Protocol")
8279
}
8380

8481
public func connect() {
@@ -160,27 +157,22 @@ public class AppSyncWebSocketClient: NSObject, ApolloWebSocket.WebSocketClient,
160157
// MARK: - Connect Internals
161158

162159
private func createWebSocketConnection() async throws -> URLSessionWebSocketTask {
163-
let host = appSyncApiEndpoint(endpointURL).host!
164-
var headers = ["host": host]
160+
guard let url = request.url else {
161+
fatalError("""
162+
Empty endpoint. This should not happen.
163+
Please take a look at https://github.com/aws-amplify/aws-appsync-apollo-extensions-swift/issues
164+
to see if there are any existing issues that match your scenario, and file an issue with
165+
the details of the bug if there isn't.
166+
""")
167+
}
165168

166-
let authHeaders = try await authorizer.getWebsocketConnectionHeaders(endpoint: endpointURL)
169+
request.setValue("graphql-ws", forHTTPHeaderField: "Sec-WebSocket-Protocol")
170+
request.setValue(appSyncApiEndpoint(url).host, forHTTPHeaderField: "host")
171+
let authHeaders = try await authorizer.getWebsocketConnectionHeaders(endpoint: url)
167172
for authHeader in authHeaders {
168-
headers[authHeader.key] = authHeader.value
173+
request.setValue(authHeader.value, forHTTPHeaderField: authHeader.key)
169174
}
170175

171-
let payload = "{}"
172-
173-
let headerJsonData = try Self.jsonEncoder.encode(headers)
174-
var urlComponents = URLComponents(url: endpointURL, resolvingAgainstBaseURL: false)
175-
176-
urlComponents?.queryItems = [
177-
URLQueryItem(name: "header", value: headerJsonData.base64EncodedString()),
178-
URLQueryItem(name: "payload", value: try? payload.base64EncodedString())
179-
]
180-
181-
let decoratedURL = urlComponents?.url ?? endpointURL
182-
request.url = decoratedURL
183-
AppSyncApolloLogger.debug("[AppSyncWebSocketClient] connecting to server \(decoratedURL)")
184176
let urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
185177
return urlSession.webSocketTask(with: request)
186178
}

Tests/AWSAppSyncApolloExtensionsTests/Utilities/Base64EncoderTests.swift

-20
This file was deleted.

Tests/AWSAppSyncApolloExtensionsTests/Utilities/EndpointHelperTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ final class EndpointHelperTests: XCTestCase {
1414
let appSyncEndpoint = URL(string: "https://abc.appsync-api.amazonaws.com/graphql")!
1515
XCTAssertEqual(
1616
appSyncRealTimeEndpoint(appSyncEndpoint),
17-
URL(string: "https://abc.appsync-realtime-api.amazonaws.com/graphql")
17+
URL(string: "wss://abc.appsync-realtime-api.amazonaws.com/graphql")
1818
)
1919
}
2020

2121
func testAppSyncRealTimeEndpoint_withAWSAppSyncRealTimeDomain_returnTheSameDomain() {
2222
let appSyncEndpoint = URL(string: "https://abc.appsync-realtime-api.amazonaws.com/graphql")!
2323
XCTAssertEqual(
2424
appSyncRealTimeEndpoint(appSyncEndpoint),
25-
URL(string: "https://abc.appsync-realtime-api.amazonaws.com/graphql")
25+
URL(string: "wss://abc.appsync-realtime-api.amazonaws.com/graphql")
2626
)
2727
}
2828

Tests/IntegrationTestApp/IntegrationTestApp.xcodeproj/project.pbxproj

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
218CFDC02C5A8714009D70B9 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 218CFDBF2C5A8714009D70B9 /* Preview Assets.xcassets */; };
1717
218CFDF62C5AD23D009D70B9 /* AWSCognitoAuthPlugin in Frameworks */ = {isa = PBXBuildFile; productRef = 218CFDF52C5AD23D009D70B9 /* AWSCognitoAuthPlugin */; };
1818
218CFDF82C5AD23D009D70B9 /* Amplify in Frameworks */ = {isa = PBXBuildFile; productRef = 218CFDF72C5AD23D009D70B9 /* Amplify */; };
19-
218CFDFA2C5AD408009D70B9 /* amplify_outputs.json in Resources */ = {isa = PBXBuildFile; fileRef = 218CFDF92C5AD408009D70B9 /* amplify_outputs.json */; };
2019
218CFDFD2C5AD4BB009D70B9 /* Authenticator in Frameworks */ = {isa = PBXBuildFile; productRef = 218CFDFC2C5AD4BB009D70B9 /* Authenticator */; };
2120
218CFE152C5AD66D009D70B9 /* TodoList.graphql in Resources */ = {isa = PBXBuildFile; fileRef = 218CFE112C5AD66D009D70B9 /* TodoList.graphql */; };
2221
218CFE162C5AD66D009D70B9 /* schema.json in Resources */ = {isa = PBXBuildFile; fileRef = 218CFE122C5AD66D009D70B9 /* schema.json */; };
@@ -30,6 +29,7 @@
3029
21CFD7C92C76641E0071C70F /* AWSAppSyncApolloExtensions in Frameworks */ = {isa = PBXBuildFile; productRef = 21CFD7C82C76641E0071C70F /* AWSAppSyncApolloExtensions */; };
3130
21FDF39C2C62B20200481EA0 /* APIKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21FDF39B2C62B20200481EA0 /* APIKeyTests.swift */; };
3231
21FDF39E2C62B3E500481EA0 /* IntegrationTestBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21FDF39D2C62B3E500481EA0 /* IntegrationTestBase.swift */; };
32+
60CE34112C9CDC1700DEAB45 /* amplify_outputs.json in Resources */ = {isa = PBXBuildFile; fileRef = 60CE34102C9CDC1700DEAB45 /* amplify_outputs.json */; };
3333
/* End PBXBuildFile section */
3434

3535
/* Begin PBXContainerItemProxy section */
@@ -50,7 +50,6 @@
5050
218CFDBF2C5A8714009D70B9 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
5151
218CFDC52C5A8714009D70B9 /* IntegrationTestAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IntegrationTestAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5252
218CFDF32C5AD177009D70B9 /* aws-appsync-apollo-interceptors-swift */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "aws-appsync-apollo-interceptors-swift"; path = ../..; sourceTree = "<group>"; };
53-
218CFDF92C5AD408009D70B9 /* amplify_outputs.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = amplify_outputs.json; sourceTree = "<group>"; };
5453
218CFE112C5AD66D009D70B9 /* TodoList.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; name = TodoList.graphql; path = IntegrationTestApp/graphql/TodoList.graphql; sourceTree = SOURCE_ROOT; };
5554
218CFE122C5AD66D009D70B9 /* schema.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = schema.json; path = IntegrationTestApp/graphql/schema.json; sourceTree = SOURCE_ROOT; };
5655
218CFE132C5AD66D009D70B9 /* SubscribeTodo.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; name = SubscribeTodo.graphql; path = IntegrationTestApp/graphql/SubscribeTodo.graphql; sourceTree = SOURCE_ROOT; };
@@ -61,6 +60,7 @@
6160
21B8F2D32C6298580042981F /* IAMTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAMTests.swift; sourceTree = "<group>"; };
6261
21FDF39B2C62B20200481EA0 /* APIKeyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIKeyTests.swift; sourceTree = "<group>"; };
6362
21FDF39D2C62B3E500481EA0 /* IntegrationTestBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationTestBase.swift; sourceTree = "<group>"; };
63+
60CE34102C9CDC1700DEAB45 /* amplify_outputs.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = amplify_outputs.json; path = "../../../../tmp/apollo-extension-integ-test/amplify_outputs.json"; sourceTree = "<group>"; };
6464
/* End PBXFileReference section */
6565

6666
/* Begin PBXFrameworksBuildPhase section */
@@ -113,7 +113,7 @@
113113
isa = PBXGroup;
114114
children = (
115115
21B8F2D02C5D8ACF0042981F /* graphql */,
116-
218CFDF92C5AD408009D70B9 /* amplify_outputs.json */,
116+
60CE34102C9CDC1700DEAB45 /* amplify_outputs.json */,
117117
218CFDB82C5A8711009D70B9 /* IntegrationTestAppApp.swift */,
118118
218CFDBA2C5A8711009D70B9 /* ContentView.swift */,
119119
218CFE192C5AD6B1009D70B9 /* Network.swift */,
@@ -259,7 +259,7 @@
259259
buildActionMask = 2147483647;
260260
files = (
261261
218CFE172C5AD66D009D70B9 /* SubscribeTodo.graphql in Resources */,
262-
218CFDFA2C5AD408009D70B9 /* amplify_outputs.json in Resources */,
262+
60CE34112C9CDC1700DEAB45 /* amplify_outputs.json in Resources */,
263263
218CFE162C5AD66D009D70B9 /* schema.json in Resources */,
264264
218CFDC02C5A8714009D70B9 /* Preview Assets.xcassets in Resources */,
265265
218CFDBD2C5A8714009D70B9 /* Assets.xcassets in Resources */,

Tests/IntegrationTestApp/IntegrationTestApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

+8-8
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"kind" : "remoteSourceControl",
66
"location" : "https://github.com/aws-amplify/amplify-swift.git",
77
"state" : {
8-
"branch" : "lawmicha.apollo",
9-
"revision" : "22ae18b521a1d67deced0d06dcacce0bfabd2165"
8+
"revision" : "36e5e92a5c8e1df92b69c5575de1c1f02ed1611e",
9+
"version" : "2.41.1"
1010
}
1111
},
1212
{
@@ -41,26 +41,26 @@
4141
"kind" : "remoteSourceControl",
4242
"location" : "https://github.com/awslabs/aws-crt-swift",
4343
"state" : {
44-
"revision" : "0d0a0cf2e2cb780ceeceac190b4ede94f4f96902",
45-
"version" : "0.26.0"
44+
"revision" : "7b42e0343f28b3451aab20840dc670abd12790bd",
45+
"version" : "0.36.0"
4646
}
4747
},
4848
{
4949
"identity" : "aws-sdk-swift",
5050
"kind" : "remoteSourceControl",
5151
"location" : "https://github.com/awslabs/aws-sdk-swift.git",
5252
"state" : {
53-
"revision" : "47922c05dd66be717c7bce424651a534456717b7",
54-
"version" : "0.36.2"
53+
"revision" : "828358a2c39d138325b0f87a2d813f4b972e5f4f",
54+
"version" : "1.0.0"
5555
}
5656
},
5757
{
5858
"identity" : "smithy-swift",
5959
"kind" : "remoteSourceControl",
6060
"location" : "https://github.com/smithy-lang/smithy-swift",
6161
"state" : {
62-
"revision" : "8a5b0105c1b8a1d26a9435fb0af3959a7f5de578",
63-
"version" : "0.41.1"
62+
"revision" : "0ed3440f8c41e27a0937364d5035d2d4fefb8aa3",
63+
"version" : "0.71.0"
6464
}
6565
},
6666
{

Tests/IntegrationTestApp/IntegrationTestAppTests/APIKeyTests.swift

+23-10
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,23 @@ final class APIKeyTests: IntegrationTestBase {
2424

2525
func testAPIKeyApolloClientMutation() throws {
2626
let completed = expectation(description: "mutation completed")
27-
28-
Network.shared.apolloAPIKey.perform(mutation: CreateTodoMutation(createTodoInput: .init())) { result in
27+
let todoId = UUID().uuidString
28+
Network.shared.apolloAPIKey.perform(
29+
mutation: CreateTodoMutation(createTodoInput: .init(id: .some(todoId)))
30+
) { result in
2931
switch result {
3032
case .success(let graphQLResult):
31-
guard (graphQLResult.data?.createTodo) != nil else {
33+
guard let newlyCreatedTodo = graphQLResult.data?.createTodo else {
3234
XCTFail("Missing created Todo")
3335
return
3436
}
3537
if let errors = graphQLResult.errors {
3638
XCTFail("Failed with errors \(errors)")
3739
}
38-
completed.fulfill()
40+
41+
if newlyCreatedTodo.id == todoId {
42+
completed.fulfill()
43+
}
3944
case .failure(let error):
4045
XCTFail("Could not create todo \(error)")
4146
}
@@ -84,18 +89,21 @@ final class APIKeyTests: IntegrationTestBase {
8489
func testSubscriptionReceivesMutation() async throws {
8590
AppSyncApolloLogger.logLevel = .verbose
8691
let receivedMutation = expectation(description: "received mutation")
87-
92+
let todoId = UUID().uuidString
8893
let activeSubscription = Network.shared.apolloAPIKey.subscribe(subscription: OnCreateSubscription()) { result in
8994
switch result {
9095
case .success(let graphQLResult):
91-
guard (graphQLResult.data?.onCreateTodo) != nil else {
96+
guard let newlyCreatedTodo = graphQLResult.data?.onCreateTodo else {
9297
XCTFail("Missing created Todo")
9398
return
9499
}
95100
if let errors = graphQLResult.errors {
96101
XCTFail("Failed with errors \(errors)")
97102
}
98-
receivedMutation.fulfill()
103+
104+
if newlyCreatedTodo.id == todoId {
105+
receivedMutation.fulfill()
106+
}
99107
case .failure(let error):
100108
XCTFail("Could not create todo \(error)")
101109
}
@@ -104,17 +112,22 @@ final class APIKeyTests: IntegrationTestBase {
104112
try await Task.sleep(nanoseconds: 5 * 1_000_000_000) // 5 seconds
105113

106114
let completed = expectation(description: "mutation completed")
107-
Network.shared.apolloAPIKey.perform(mutation: CreateTodoMutation(createTodoInput: .init())) { result in
115+
Network.shared.apolloAPIKey.perform(
116+
mutation: CreateTodoMutation(createTodoInput: .init(id: .some(todoId)))
117+
) { result in
108118
switch result {
109119
case .success(let graphQLResult):
110-
guard (graphQLResult.data?.createTodo) != nil else {
120+
guard let newlyCreatedTodo = graphQLResult.data?.createTodo else {
111121
XCTFail("Missing created Todo")
112122
return
113123
}
114124
if let errors = graphQLResult.errors {
115125
XCTFail("Failed with errors \(errors)")
116126
}
117-
completed.fulfill()
127+
128+
if newlyCreatedTodo.id == todoId {
129+
completed.fulfill()
130+
}
118131
case .failure(let error):
119132
XCTFail("Could not create todo \(error)")
120133
}

0 commit comments

Comments
 (0)