Skip to content

Commit

Permalink
[flutter_appauth] & [flutter_appauth_platform] - Add support for ephe…
Browse files Browse the repository at this point in the history
…meral sessions on iOS (MaikuB#112)

* Add support for ephemeral session on iOS

* Bump version

* Update tests

* Fix more tests

* PR clean up

* Clean up method names
Fix AppAuth references

* Switch example min version to Dart 2.3

* Remove preferEphemeralSession from TokenRequest

* Move preferEphemeralSession to authorization_parameters
  • Loading branch information
matthewtsmith authored May 28, 2020
1 parent b9d9d18 commit 8437fd2
Show file tree
Hide file tree
Showing 15 changed files with 387 additions and 71 deletions.
17 changes: 4 additions & 13 deletions flutter_appauth/example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
Expand All @@ -29,8 +25,6 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -42,7 +36,6 @@
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
2DC2228EEEB793370F099718 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
4F7E3F7F795925272C34A8EF /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
Expand All @@ -51,7 +44,6 @@
8385D1EB6F7F47CF119F4F61 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
Expand All @@ -65,8 +57,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
FB408306AD207A14C39768B9 /* libPods-Runner.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -77,9 +67,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
Expand Down Expand Up @@ -233,7 +221,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
Expand Down Expand Up @@ -273,9 +261,12 @@
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../Flutter/Flutter.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand Down

This file was deleted.

27 changes: 23 additions & 4 deletions flutter_appauth/example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_appauth/flutter_appauth.dart';
Expand Down Expand Up @@ -75,8 +76,20 @@ class _MyAppState extends State<MyApp> {
),
RaisedButton(
child: const Text('Sign in with auto code exchange'),
onPressed: _signInWithAutoCodeExchange,
onPressed: () => _signInWithAutoCodeExchange(),
),
if (Platform.isIOS)
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
child: const Text(
'Sign in with auto code exchange using ephemeral session (iOS only)',
textAlign: TextAlign.center,
),
onPressed: () => _signInWithAutoCodeExchange(
preferEphemeralSession: true),
),
),
RaisedButton(
child: const Text('Refresh token'),
onPressed: _refreshToken != null ? _refresh : null,
Expand Down Expand Up @@ -167,15 +180,21 @@ class _MyAppState extends State<MyApp> {
}
}

Future<void> _signInWithAutoCodeExchange() async {
Future<void> _signInWithAutoCodeExchange(
{bool preferEphemeralSession = false}) async {
try {
_setBusyState();

// show that we can also explicitly specify the endpoints rather than getting from the details from the discovery document
final AuthorizationTokenResponse result =
await _appAuth.authorizeAndExchangeCode(
AuthorizationTokenRequest(_clientId, _redirectUrl,
serviceConfiguration: _serviceConfiguration, scopes: _scopes),
AuthorizationTokenRequest(
_clientId,
_redirectUrl,
serviceConfiguration: _serviceConfiguration,
scopes: _scopes,
preferEphemeralSession: preferEphemeralSession,
),
);

// this code block demonstrates passing in values for the prompt parameter. in this case it prompts the user login even if they have already signed in. the list of supported values depends on the identity provider
Expand Down
2 changes: 1 addition & 1 deletion flutter_appauth/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version: 1.0.0+1
publish_to: 'none'

environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.3.0 <3.0.0"

dependencies:
flutter:
Expand Down
45 changes: 29 additions & 16 deletions flutter_appauth/ios/Classes/FlutterAppauthPlugin.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "FlutterAppauthPlugin.h"
#import "AppAuth.h"

#import "OIDExternalUserAgentIOSNoSSO.h"
@interface ArgumentProcessor : NSObject
+ (id _Nullable)processArgumentValue:(NSDictionary *)arguments withKey:(NSString *)key;
@end
Expand All @@ -26,6 +27,7 @@ @interface TokenRequestParameters : NSObject
@property(nonatomic, strong) NSArray *scopes;
@property(nonatomic, strong) NSDictionary *serviceConfigurationParameters;
@property(nonatomic, strong) NSDictionary *additionalParameters;
@property(nonatomic, readwrite) BOOL preferEphemeralSession;

@end

Expand All @@ -43,6 +45,7 @@ - (void)processArguments:(NSDictionary *)arguments {
_scopes = [ArgumentProcessor processArgumentValue:arguments withKey:@"scopes"];
_serviceConfigurationParameters = [ArgumentProcessor processArgumentValue:arguments withKey:@"serviceConfiguration"];
_additionalParameters = [ArgumentProcessor processArgumentValue:arguments withKey:@"additionalParameters"];
_preferEphemeralSession = [[ArgumentProcessor processArgumentValue:arguments withKey:@"preferEphemeralSession"] isEqual:@YES];
}

- (id)initWithArguments:(NSDictionary *)arguments {
Expand Down Expand Up @@ -123,7 +126,7 @@ -(void)handleAuthorizeMethodCall:(NSDictionary*)arguments result:(FlutterResult)
[[OIDServiceConfiguration alloc]
initWithAuthorizationEndpoint:[NSURL URLWithString:requestParameters.serviceConfigurationParameters[@"authorizationEndpoint"]]
tokenEndpoint:[NSURL URLWithString:requestParameters.serviceConfigurationParameters[@"tokenEndpoint"]]];
[self performAuthorization:serviceConfiguration clientId:requestParameters.clientId clientSecret:requestParameters.clientSecret scopes:requestParameters.scopes redirectUrl:requestParameters.redirectUrl additionalParameters:requestParameters.additionalParameters result:result exchangeCode:exchangeCode];
[self performAuthorization:serviceConfiguration clientId:requestParameters.clientId clientSecret:requestParameters.clientSecret scopes:requestParameters.scopes redirectUrl:requestParameters.redirectUrl additionalParameters:requestParameters.additionalParameters preferEphemeralSession:requestParameters.preferEphemeralSession result:result exchangeCode:exchangeCode];
} else if (requestParameters.discoveryUrl) {
NSURL *discoveryUrl = [NSURL URLWithString:requestParameters.discoveryUrl];
[OIDAuthorizationService discoverServiceConfigurationForDiscoveryURL:discoveryUrl
Expand All @@ -135,7 +138,7 @@ -(void)handleAuthorizeMethodCall:(NSDictionary*)arguments result:(FlutterResult)
return;
}

[self performAuthorization:configuration clientId:requestParameters.clientId clientSecret:requestParameters.clientSecret scopes:requestParameters.scopes redirectUrl:requestParameters.redirectUrl additionalParameters:requestParameters.additionalParameters result:result exchangeCode:exchangeCode];
[self performAuthorization:configuration clientId:requestParameters.clientId clientSecret:requestParameters.clientSecret scopes:requestParameters.scopes redirectUrl:requestParameters.redirectUrl additionalParameters:requestParameters.additionalParameters preferEphemeralSession:requestParameters.preferEphemeralSession result:result exchangeCode:exchangeCode];
}];
} else {
NSURL *issuerUrl = [NSURL URLWithString:requestParameters.issuer];
Expand All @@ -148,14 +151,14 @@ -(void)handleAuthorizeMethodCall:(NSDictionary*)arguments result:(FlutterResult)
return;
}

[self performAuthorization:configuration clientId:requestParameters.clientId clientSecret:requestParameters.clientSecret scopes:requestParameters.scopes redirectUrl:requestParameters.redirectUrl additionalParameters:requestParameters.additionalParameters result:result exchangeCode:exchangeCode];
[self performAuthorization:configuration clientId:requestParameters.clientId clientSecret:requestParameters.clientSecret scopes:requestParameters.scopes redirectUrl:requestParameters.redirectUrl additionalParameters:requestParameters.additionalParameters preferEphemeralSession:requestParameters.preferEphemeralSession result:result exchangeCode:exchangeCode];
}];
}


}

- (void)performAuthorization:(OIDServiceConfiguration *)serviceConfiguration clientId:(NSString*)clientId clientSecret:(NSString*)clientSecret scopes:(NSArray *)scopes redirectUrl:(NSString*)redirectUrl additionalParameters:(NSDictionary *)additionalParameters result:(FlutterResult)result exchangeCode:(BOOL)exchangeCode{
- (void)performAuthorization:(OIDServiceConfiguration *)serviceConfiguration clientId:(NSString*)clientId clientSecret:(NSString*)clientSecret scopes:(NSArray *)scopes redirectUrl:(NSString*)redirectUrl additionalParameters:(NSDictionary *)additionalParameters preferEphemeralSession:(BOOL)preferEphemeralSession result:(FlutterResult)result exchangeCode:(BOOL)exchangeCode{
OIDAuthorizationRequest *request =
[[OIDAuthorizationRequest alloc] initWithConfiguration:serviceConfiguration
clientId:clientId
Expand All @@ -167,18 +170,20 @@ - (void)performAuthorization:(OIDServiceConfiguration *)serviceConfiguration cli
UIViewController *rootViewController =
[UIApplication sharedApplication].delegate.window.rootViewController;
if(exchangeCode) {
_currentAuthorizationFlow = [OIDAuthState authStateByPresentingAuthorizationRequest:request presentingViewController: rootViewController
callback:^(OIDAuthState *_Nullable authState,
NSError *_Nullable error) {
if(authState) {
result([self processResponses:authState.lastTokenResponse authResponse:authState.lastAuthorizationResponse]);

} else {
[self finishWithError:AUTHORIZE_AND_EXCHANGE_CODE_ERROR_CODE message:[self formatMessageWithError:AUTHORIZE_ERROR_MESSAGE_FORMAT error:error] result:result];
}
}];
NSObject<OIDExternalUserAgent> *agent = [self userAgentWithViewController:rootViewController useEphemeralSession:preferEphemeralSession];

_currentAuthorizationFlow = [OIDAuthState authStateByPresentingAuthorizationRequest:request externalUserAgent:agent callback:^(OIDAuthState *_Nullable authState,
NSError *_Nullable error) {
if(authState) {
result([self processResponses:authState.lastTokenResponse authResponse:authState.lastAuthorizationResponse]);

} else {
[self finishWithError:AUTHORIZE_AND_EXCHANGE_CODE_ERROR_CODE message:[self formatMessageWithError:AUTHORIZE_ERROR_MESSAGE_FORMAT error:error] result:result];
}
}];
} else {
_currentAuthorizationFlow = [OIDAuthorizationService presentAuthorizationRequest:request presentingViewController:rootViewController callback:^(OIDAuthorizationResponse *_Nullable authorizationResponse, NSError *_Nullable error) {
NSObject<OIDExternalUserAgent> *agent = [self userAgentWithViewController:rootViewController useEphemeralSession:preferEphemeralSession];
_currentAuthorizationFlow = [OIDAuthorizationService presentAuthorizationRequest:request externalUserAgent:agent callback:^(OIDAuthorizationResponse *_Nullable authorizationResponse, NSError *_Nullable error) {
if(authorizationResponse) {
NSMutableDictionary *processedResponse = [[NSMutableDictionary alloc] init];
[processedResponse setObject:authorizationResponse.additionalParameters forKey:@"authorizationAdditionalParameters"];
Expand All @@ -189,10 +194,18 @@ - (void)performAuthorization:(OIDServiceConfiguration *)serviceConfiguration cli
[self finishWithError:AUTHORIZE_ERROR_CODE message:[self formatMessageWithError:AUTHORIZE_ERROR_MESSAGE_FORMAT error:error] result:result];
}
}];

}
}

- (NSObject<OIDExternalUserAgent> *)userAgentWithViewController:(UIViewController *)rootViewController useEphemeralSession:(BOOL)useEphemeralSession {
if (useEphemeralSession) {
return [[OIDExternalUserAgentIOSNoSSO alloc]
initWithPresentingViewController:rootViewController];
}
return [[OIDExternalUserAgentIOS alloc]
initWithPresentingViewController:rootViewController];
}

- (NSString *) formatMessageWithError:(NSString *)messageFormat error:(NSError * _Nullable)error {
NSString *formattedMessage = [NSString stringWithFormat:messageFormat, [error localizedDescription]];
return formattedMessage;
Expand Down
Loading

0 comments on commit 8437fd2

Please sign in to comment.