Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[webview_flutter] Support for handling basic authentication requests (iOS) #5455

Merged
merged 36 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
517e9d4
Implement http basic auth
JeroenWeener Aug 10, 2023
967879b
Apply feedback
JeroenWeener Aug 28, 2023
c8624c0
Create HttpAuthHandlerTest.java
JeroenWeener Aug 29, 2023
4f3574d
Format java files
JeroenWeener Aug 29, 2023
1e7f785
Regenerate build_runner files
JeroenWeener Aug 29, 2023
131bc56
Implement feedback
JeroenWeener Sep 11, 2023
bc01be4
Remove redundant key in `Info.plist`
JeroenWeener Sep 11, 2023
67aa00e
Update example apps
JeroenWeener Sep 11, 2023
32496d0
Implement http basic auth
JeroenWeener Aug 10, 2023
aeb8708
Apply feedback
JeroenWeener Aug 28, 2023
fffc4c7
Create HttpAuthHandlerTest.java
JeroenWeener Aug 29, 2023
b455040
Format java files
JeroenWeener Aug 29, 2023
2aa9bfe
Regenerate build_runner files
JeroenWeener Aug 29, 2023
db286ba
Implement feedback
JeroenWeener Sep 11, 2023
467feb3
Remove redundant key in `Info.plist`
JeroenWeener Sep 11, 2023
dad8ae6
Update example apps
JeroenWeener Sep 11, 2023
6f3d802
Merge branch 'webview-auth-request' of https://github.com/andreisas06…
JeroenWeener Nov 1, 2023
0fef591
Add platform interface dev dependency to example
JeroenWeener Nov 1, 2023
b2a4fbb
Merge branch 'main' into webview-auth-request
JeroenWeener Nov 1, 2023
ce35d9b
Update packages/webview_flutter/webview_flutter_platform_interface/li…
bparrishMines Nov 8, 2023
fc32898
Merge branch 'main' of github.com:flutter/packages into webview-auth-…
bparrishMines Nov 8, 2023
4673e65
Merge branch 'webview-auth-request' of github.com:andreisas06/package…
bparrishMines Nov 8, 2023
580521a
Fix some lints, errros and call on errors
bparrishMines Nov 8, 2023
d1f305b
fix lints
bparrishMines Nov 8, 2023
a3f74be
fix tests
bparrishMines Nov 8, 2023
ed3798f
add onProceed and onCancel back
bparrishMines Nov 8, 2023
154c1f8
dont require realm to be nonnull
bparrishMines Nov 8, 2023
3c61dbc
add line back
bparrishMines Nov 8, 2023
7cf0d7e
Merge remote-tracking branch 'upstream/main' into webview-auth-request
JeroenWeener Nov 21, 2023
a21f29a
Update changelogs
JeroenWeener Nov 21, 2023
7aca4a9
Separate ios changes
JeroenWeener Nov 21, 2023
a9e27d0
Delete packages/webview_flutter/webview_flutter_android/android/src/m…
JeroenWeener Nov 21, 2023
a42c1c4
Delete packages/webview_flutter/webview_flutter_android/android/src/m…
JeroenWeener Nov 21, 2023
e64c82f
Delete packages/webview_flutter/webview_flutter_android/android/src/t…
JeroenWeener Nov 21, 2023
3ccf157
Update pubspecs
JeroenWeener Nov 28, 2023
d0d4926
Merge branch 'webview-auth-request-ios' of https://github.com/andreis…
JeroenWeener Nov 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## NEXT
## 3.10.0

* Adds support for `PlatformNavigationDelegate.setOnHttpAuthRequest`.
* Updates minimum supported SDK version to Flutter 3.10/Dart 3.0.

## 3.9.4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ Future<void> main() async {
request.response.writeln('${request.headers}');
} else if (request.uri.path == '/favicon.ico') {
request.response.statusCode = HttpStatus.notFound;
} else if (request.uri.path == '/http-basic-authentication') {
final bool isAuthenticating = request.headers['Authorization'] != null;
if (isAuthenticating) {
request.response.writeln('Authorized');
} else {
request.response.headers
.add('WWW-Authenticate', 'Basic realm="Test realm"');
request.response.statusCode = HttpStatus.unauthorized;
}
} else {
fail('unexpected request: ${request.method} ${request.uri}');
}
Expand All @@ -43,6 +52,7 @@ Future<void> main() async {
final String primaryUrl = '$prefixUrl/hello.txt';
final String secondaryUrl = '$prefixUrl/secondary.txt';
final String headersUrl = '$prefixUrl/headers';
final String basicAuthUrl = '$prefixUrl/http-basic-authentication';

testWidgets(
'withWeakReferenceTo allows encapsulating class to be garbage collected',
Expand Down Expand Up @@ -1127,6 +1137,82 @@ Future<void> main() async {
});
});

testWidgets('can receive HTTP basic auth requests',
(WidgetTester tester) async {
final Completer<void> authRequested = Completer<void>();
final PlatformWebViewController controller = PlatformWebViewController(
const PlatformWebViewControllerCreationParams(),
);

final PlatformNavigationDelegate navigationDelegate =
PlatformNavigationDelegate(
const PlatformNavigationDelegateCreationParams(),
);
await navigationDelegate.setOnHttpAuthRequest(
(HttpAuthRequest request) => authRequested.complete());
await controller.setPlatformNavigationDelegate(navigationDelegate);

// Clear cache so that the auth request is always received and we don't get
// a cached response.
await controller.clearCache();

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
WebKitWebViewWidgetCreationParams(controller: controller),
).build(context);
},
),
);

await controller.loadRequest(
LoadRequestParams(uri: Uri.parse(basicAuthUrl)),
);

await expectLater(authRequested.future, completes);
});

testWidgets('can reply to HTTP basic auth requests',
(WidgetTester tester) async {
final Completer<void> pageFinished = Completer<void>();
final PlatformWebViewController controller = PlatformWebViewController(
const PlatformWebViewControllerCreationParams(),
);

final PlatformNavigationDelegate navigationDelegate =
PlatformNavigationDelegate(
const PlatformNavigationDelegateCreationParams(),
);
await navigationDelegate.setOnPageFinished((_) => pageFinished.complete());
await navigationDelegate.setOnHttpAuthRequest(
(HttpAuthRequest request) => request.onProceed(
const WebViewCredential(user: 'user', password: 'password'),
),
);
await controller.setPlatformNavigationDelegate(navigationDelegate);

// Clear cache so that the auth request is always received and we don't get
// a cached response.
await controller.clearCache();

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
WebKitWebViewWidgetCreationParams(controller: controller),
).build(context);
},
),
);

await controller.loadRequest(
LoadRequestParams(uri: Uri.parse(basicAuthUrl)),
);

await expectLater(pageFinished.future, completes);
});

testWidgets('launches with gestureNavigationEnabled on iOS',
(WidgetTester tester) async {
final WebKitWebViewController controller = WebKitWebViewController(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
8F4FF949299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F4FF948299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m */; };
8F4FF94B29AC223F000A6586 /* FWFURLTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F4FF94A29AC223F000A6586 /* FWFURLTests.m */; };
8F562F902A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F562F8F2A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m */; };
8F562F922A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F562F912A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m */; };
8F562F942A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F562F932A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m */; };
8F78EAAA2A02CB9100C2E520 /* FWFErrorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F78EAA92A02CB9100C2E520 /* FWFErrorTests.m */; };
8FA6A87928062CD000A4B183 /* FWFInstanceManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8FA6A87828062CD000A4B183 /* FWFInstanceManagerTests.m */; };
8FB79B5328134C3100C101D3 /* FWFWebViewHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8FB79B5228134C3100C101D3 /* FWFWebViewHostApiTests.m */; };
Expand Down Expand Up @@ -81,6 +84,9 @@
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
8F4FF948299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FWFWebViewFlutterWKWebViewExternalAPITests.m; sourceTree = "<group>"; };
8F4FF94A29AC223F000A6586 /* FWFURLTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLTests.m; sourceTree = "<group>"; };
8F562F8F2A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLCredentialHostApiTests.m; sourceTree = "<group>"; };
8F562F912A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLProtectionSpaceHostApiTests.m; sourceTree = "<group>"; };
8F562F932A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLAuthenticationChallengeHostApiTests.m; sourceTree = "<group>"; };
8F78EAA92A02CB9100C2E520 /* FWFErrorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFErrorTests.m; sourceTree = "<group>"; };
8FA6A87828062CD000A4B183 /* FWFInstanceManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFInstanceManagerTests.m; sourceTree = "<group>"; };
8FB79B5228134C3100C101D3 /* FWFWebViewHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFWebViewHostApiTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -167,6 +173,9 @@
8FB79B902820BAC700C101D3 /* FWFUIViewHostApiTests.m */,
8FB79B962821985200C101D3 /* FWFObjectHostApiTests.m */,
8F4FF94A29AC223F000A6586 /* FWFURLTests.m */,
8F562F8F2A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m */,
8F562F912A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m */,
8F562F932A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m */,
8F78EAA92A02CB9100C2E520 /* FWFErrorTests.m */,
);
path = RunnerTests;
Expand Down Expand Up @@ -318,7 +327,7 @@
isa = PBXProject;
attributes = {
DefaultBuildSystemTypeForWorkspace = Original;
LastUpgradeCheck = 1300;
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "The Flutter Authors";
TargetAttributes = {
68BDCAE823C3F7CB00D9C032 = {
Expand All @@ -327,7 +336,6 @@
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = 7624MWN53C;
};
F7151F73266057800028CB91 = {
CreatedOnToolsVersion = 12.5;
Expand Down Expand Up @@ -474,12 +482,15 @@
8FB79B852820A3A400C101D3 /* FWFUIDelegateHostApiTests.m in Sources */,
8FB79B972821985200C101D3 /* FWFObjectHostApiTests.m in Sources */,
8FB79B672820453400C101D3 /* FWFHTTPCookieStoreHostApiTests.m in Sources */,
8F562F942A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m in Sources */,
8FB79B5328134C3100C101D3 /* FWFWebViewHostApiTests.m in Sources */,
8FB79B73282096B500C101D3 /* FWFScriptMessageHandlerHostApiTests.m in Sources */,
8FB79B7928209D1300C101D3 /* FWFUserContentControllerHostApiTests.m in Sources */,
8F562F902A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m in Sources */,
8F4FF949299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m in Sources */,
8FB79B6B28204EE500C101D3 /* FWFWebsiteDataStoreHostApiTests.m in Sources */,
8FB79B8F2820BAB300C101D3 /* FWFScrollViewHostApiTests.m in Sources */,
8F562F922A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m in Sources */,
8FB79B912820BAC700C101D3 /* FWFUIViewHostApiTests.m in Sources */,
8FB79B55281B24F600C101D3 /* FWFDataConvertersTests.m in Sources */,
8FB79B6D2820533B00C101D3 /* FWFWebViewConfigurationHostApiTests.m in Sources */,
Expand Down Expand Up @@ -689,6 +700,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 7624MWN53C;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
Expand All @@ -715,6 +727,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 7624MWN53C;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,58 @@ - (void)testWebViewWebContentProcessDidTerminate {
webViewIdentifier:1
completion:OCMOCK_ANY]);
}

- (void)testDidReceiveAuthenticationChallenge {
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];

FWFNavigationDelegate *mockDelegate = [self mockNavigationDelegateWithManager:instanceManager
identifier:0];
FWFNavigationDelegateFlutterApiImpl *mockFlutterAPI =
[self mockFlutterApiWithManager:instanceManager];

OCMStub([mockDelegate navigationDelegateAPI]).andReturn(mockFlutterAPI);

WKWebView *mockWebView = OCMClassMock([WKWebView class]);
[instanceManager addDartCreatedInstance:mockWebView withIdentifier:1];

NSURLAuthenticationChallenge *mockChallenge = OCMClassMock([NSURLAuthenticationChallenge class]);
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"host"
port:0
protocol:nil
realm:@"realm"
authenticationMethod:nil];
OCMStub([mockChallenge protectionSpace]).andReturn(protectionSpace);
[instanceManager addDartCreatedInstance:mockChallenge withIdentifier:2];

NSURLCredential *credential = [NSURLCredential credentialWithUser:@"user"
password:@"password"
persistence:NSURLCredentialPersistenceNone];
[instanceManager addDartCreatedInstance:credential withIdentifier:5];

OCMStub([mockFlutterAPI
didReceiveAuthenticationChallengeForDelegateWithIdentifier:0
webViewIdentifier:1
challengeIdentifier:2
completion:
([OCMArg
invokeBlockWithArgs:
[FWFAuthenticationChallengeResponse
makeWithDisposition:
FWFNSUrlSessionAuthChallengeDispositionCancelAuthenticationChallenge
credentialIdentifier:@(5)],
[NSNull null], nil])]);

NSURLSessionAuthChallengeDisposition __block callbackDisposition = -1;
NSURLCredential *__block callbackCredential;
[mockDelegate webView:mockWebView
didReceiveAuthenticationChallenge:mockChallenge
completionHandler:^(NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential *credential) {
callbackDisposition = disposition;
callbackCredential = credential;
}];

XCTAssertEqual(callbackDisposition, NSURLSessionAuthChallengeCancelAuthenticationChallenge);
XCTAssertEqualObjects(callbackCredential, credential);
}
@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

@import Flutter;
@import XCTest;
@import webview_flutter_wkwebview;

#import <OCMock/OCMock.h>

@interface FWFURLAuthenticationChallengeHostApiTests : XCTestCase

@end

@implementation FWFURLAuthenticationChallengeHostApiTests
- (void)testFlutterApiCreate {
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
FWFURLAuthenticationChallengeFlutterApiImpl *flutterApi =
[[FWFURLAuthenticationChallengeFlutterApiImpl alloc]
initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
instanceManager:instanceManager];

flutterApi.api = OCMClassMock([FWFNSUrlAuthenticationChallengeFlutterApi class]);

NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"host"
port:0
protocol:nil
realm:@"realm"
authenticationMethod:nil];

NSURLAuthenticationChallenge *mockChallenge = OCMClassMock([NSURLAuthenticationChallenge class]);
OCMStub([mockChallenge protectionSpace]).andReturn(protectionSpace);

[flutterApi createWithInstance:mockChallenge
protectionSpace:protectionSpace
completion:^(FlutterError *error){

}];

long identifier = [instanceManager identifierWithStrongReferenceForInstance:mockChallenge];
long protectionSpaceIdentifier =
[instanceManager identifierWithStrongReferenceForInstance:protectionSpace];
OCMVerify([flutterApi.api createWithIdentifier:identifier
protectionSpaceIdentifier:protectionSpaceIdentifier
completion:OCMOCK_ANY]);
}
@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

@import Flutter;
@import XCTest;
@import webview_flutter_wkwebview;

#import <OCMock/OCMock.h>

@interface FWFURLCredentialHostApiTests : XCTestCase
@end

@implementation FWFURLCredentialHostApiTests
- (void)testHostApiCreate {
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];

FWFURLCredentialHostApiImpl *hostApi = [[FWFURLCredentialHostApiImpl alloc]
initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
instanceManager:instanceManager];

FlutterError *error;
[hostApi createWithUserWithIdentifier:0
user:@"user"
password:@"password"
persistence:FWFNSUrlCredentialPersistencePermanent
error:&error];
XCTAssertNil(error);

NSURLCredential *credential = (NSURLCredential *)[instanceManager instanceForIdentifier:0];
XCTAssertEqualObjects(credential.user, @"user");
XCTAssertEqualObjects(credential.password, @"password");
XCTAssertEqual(credential.persistence, NSURLCredentialPersistencePermanent);
}
@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

@import Flutter;
@import XCTest;
@import webview_flutter_wkwebview;

#import <OCMock/OCMock.h>

@interface FWFURLProtectionSpaceHostApiTests : XCTestCase
@end

@implementation FWFURLProtectionSpaceHostApiTests
- (void)testFlutterApiCreate {
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
FWFURLProtectionSpaceFlutterApiImpl *flutterApi = [[FWFURLProtectionSpaceFlutterApiImpl alloc]
initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
instanceManager:instanceManager];

flutterApi.api = OCMClassMock([FWFNSUrlProtectionSpaceFlutterApi class]);

NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"host"
port:0
protocol:nil
realm:@"realm"
authenticationMethod:nil];
[flutterApi createWithInstance:protectionSpace
host:@"host"
realm:@"realm"
authenticationMethod:@"method"
completion:^(FlutterError *error){

}];

long identifier = [instanceManager identifierWithStrongReferenceForInstance:protectionSpace];
OCMVerify([flutterApi.api createWithIdentifier:identifier
host:@"host"
realm:@"realm"
authenticationMethod:@"method"
completion:OCMOCK_ANY]);
}
@end
Loading