diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 000000000..45de502e0 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,2 @@ +ignore: + - "UnitTests" diff --git a/Examples/Example-iOS_ObjC-Carthage/Example.xcodeproj/project.pbxproj b/Examples/Example-iOS_ObjC-Carthage/Example.xcodeproj/project.pbxproj index 9318b369a..839e13e5b 100644 --- a/Examples/Example-iOS_ObjC-Carthage/Example.xcodeproj/project.pbxproj +++ b/Examples/Example-iOS_ObjC-Carthage/Example.xcodeproj/project.pbxproj @@ -7,6 +7,11 @@ objects = { /* Begin PBXBuildFile section */ + 06375C8521A4E46500338E3F /* AppAuthCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06375C8421A4E46500338E3F /* AppAuthCore.framework */; }; + 06462457205ED68000072191 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06462456205ED68000072191 /* NotificationCenter.framework */; }; + 0646245B205ED68000072191 /* TodayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0646245A205ED68000072191 /* TodayViewController.m */; }; + 0646245E205ED68000072191 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0646245C205ED68000072191 /* MainInterface.storyboard */; }; + 06462463205ED68000072191 /* Example_Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 06462455205ED68000072191 /* Example_Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 346E916E1C29D42800D3620B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 346E916D1C29D42800D3620B /* main.m */; }; 346E91711C29D42800D3620B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 346E91701C29D42800D3620B /* AppDelegate.m */; }; 346E91791C29D42800D3620B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 346E91781C29D42800D3620B /* Assets.xcassets */; }; @@ -17,7 +22,40 @@ 5FEA25251E75C17E00C2D71B /* AppAuth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5FEA25241E75C17E00C2D71B /* AppAuth.framework */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 06462460205ED68000072191 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 346E91611C29D42800D3620B /* Project object */; + proxyType = 1; + remoteGlobalIDString = 06462454205ED68000072191; + remoteInfo = Example_Extension; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 06462462205ED68000072191 /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 06462463205ED68000072191 /* Example_Extension.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ + 06375C8421A4E46500338E3F /* AppAuthCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppAuthCore.framework; path = Carthage/Build/iOS/AppAuthCore.framework; sourceTree = ""; }; + 06462455205ED68000072191 /* Example_Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Example_Extension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 06462456205ED68000072191 /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; }; + 06462459205ED68000072191 /* TodayViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TodayViewController.h; sourceTree = ""; }; + 0646245A205ED68000072191 /* TodayViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TodayViewController.m; sourceTree = ""; }; + 0646245D205ED68000072191 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; + 0646245F205ED68000072191 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 06462467205EDB5400072191 /* Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Example.entitlements; sourceTree = ""; }; + 06462468205EDB9900072191 /* Example_Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Example_Extension.entitlements; sourceTree = ""; }; 346E91691C29D42800D3620B /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 346E916D1C29D42800D3620B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 346E916F1C29D42800D3620B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -33,6 +71,15 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 06462452205ED68000072191 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 06375C8521A4E46500338E3F /* AppAuthCore.framework in Frameworks */, + 06462457205ED68000072191 /* NotificationCenter.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 346E91661C29D42800D3620B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -45,11 +92,25 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 06462458205ED68000072191 /* Example_Extension */ = { + isa = PBXGroup; + children = ( + 06462459205ED68000072191 /* TodayViewController.h */, + 0646245A205ED68000072191 /* TodayViewController.m */, + 0646245C205ED68000072191 /* MainInterface.storyboard */, + 0646245F205ED68000072191 /* Info.plist */, + 06462468205EDB9900072191 /* Example_Extension.entitlements */, + ); + path = Example_Extension; + sourceTree = ""; + }; 341564001C487ABA00ECA3D9 /* Frameworks */ = { isa = PBXGroup; children = ( + 06375C8421A4E46500338E3F /* AppAuthCore.framework */, 5FEA25241E75C17E00C2D71B /* AppAuth.framework */, 346E91981C2A245000D3620B /* SafariServices.framework */, + 06462456205ED68000072191 /* NotificationCenter.framework */, ); name = Frameworks; sourceTree = ""; @@ -58,6 +119,7 @@ isa = PBXGroup; children = ( 346E916B1C29D42800D3620B /* Source */, + 06462458205ED68000072191 /* Example_Extension */, 341564001C487ABA00ECA3D9 /* Frameworks */, 346E916A1C29D42800D3620B /* Products */, ); @@ -67,6 +129,7 @@ isa = PBXGroup; children = ( 346E91691C29D42800D3620B /* Example.app */, + 06462455205ED68000072191 /* Example_Extension.appex */, ); name = Products; sourceTree = ""; @@ -83,6 +146,7 @@ 346E91781C29D42800D3620B /* Assets.xcassets */, 346E917A1C29D42800D3620B /* LaunchScreen.storyboard */, 346E917D1C29D42800D3620B /* Info.plist */, + 06462467205EDB5400072191 /* Example.entitlements */, ); path = Source; sourceTree = ""; @@ -90,6 +154,24 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 06462454205ED68000072191 /* Example_Extension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 06462466205ED68000072191 /* Build configuration list for PBXNativeTarget "Example_Extension" */; + buildPhases = ( + 06462451205ED68000072191 /* Sources */, + 06462452205ED68000072191 /* Frameworks */, + 06462453205ED68000072191 /* Resources */, + 06375C8621A4E48800338E3F /* Carthage */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Example_Extension; + productName = Example_Extension; + productReference = 06462455205ED68000072191 /* Example_Extension.appex */; + productType = "com.apple.product-type.app-extension"; + }; 346E91681C29D42800D3620B /* Example */ = { isa = PBXNativeTarget; buildConfigurationList = 346E91801C29D42800D3620B /* Build configuration list for PBXNativeTarget "Example" */; @@ -98,10 +180,12 @@ 346E91661C29D42800D3620B /* Frameworks */, 346E91671C29D42800D3620B /* Resources */, 5FEA25261E75C1CF00C2D71B /* Carthage */, + 06462462205ED68000072191 /* Embed App Extensions */, ); buildRules = ( ); dependencies = ( + 06462461205ED68000072191 /* PBXTargetDependency */, ); name = Example; productName = Example; @@ -117,8 +201,22 @@ LastUpgradeCheck = 0720; ORGANIZATIONNAME = "William Denniss"; TargetAttributes = { + 06462454205ED68000072191 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; + }; + }; 346E91681C29D42800D3620B = { CreatedOnToolsVersion = 7.2; + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; + }; }; }; }; @@ -136,11 +234,20 @@ projectRoot = ""; targets = ( 346E91681C29D42800D3620B /* Example */, + 06462454205ED68000072191 /* Example_Extension */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 06462453205ED68000072191 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0646245E205ED68000072191 /* MainInterface.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 346E91671C29D42800D3620B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -154,6 +261,25 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 06375C8621A4E48800338E3F /* Carthage */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/iOS/AppAuth.framework", + ); + name = Carthage; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks\n"; + }; 5FEA25261E75C1CF00C2D71B /* Carthage */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -167,11 +293,19 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks"; + shellScript = "/usr/local/bin/carthage copy-frameworks\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 06462451205ED68000072191 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0646245B205ED68000072191 /* TodayViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 346E91651C29D42800D3620B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -184,7 +318,23 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 06462461205ED68000072191 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 06462454205ED68000072191 /* Example_Extension */; + targetProxy = 06462460205ED68000072191 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ + 0646245C205ED68000072191 /* MainInterface.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 0646245D205ED68000072191 /* Base */, + ); + name = MainInterface.storyboard; + sourceTree = ""; + }; 346E917A1C29D42800D3620B /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -196,6 +346,76 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 06462464205ED68000072191 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = Example_Extension/Example_Extension.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = Example_Extension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "net.openid.appauth.Example.Example-Extension"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 06462465205ED68000072191 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = Example_Extension/Example_Extension.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = Example_Extension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "net.openid.appauth.Example.Example-Extension"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; 346E917E1C29D42800D3620B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -286,6 +506,9 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Source/Example.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", @@ -303,6 +526,9 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Source/Example.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", @@ -319,6 +545,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 06462466205ED68000072191 /* Build configuration list for PBXNativeTarget "Example_Extension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 06462464205ED68000072191 /* Debug */, + 06462465205ED68000072191 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 346E91641C29D42800D3620B /* Build configuration list for PBXProject "Example" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Examples/Example-iOS_ObjC-Carthage/Example.xcodeproj/xcshareddata/xcschemes/Example_Extension.xcscheme b/Examples/Example-iOS_ObjC-Carthage/Example.xcodeproj/xcshareddata/xcschemes/Example_Extension.xcscheme new file mode 100644 index 000000000..7dff3414d --- /dev/null +++ b/Examples/Example-iOS_ObjC-Carthage/Example.xcodeproj/xcshareddata/xcschemes/Example_Extension.xcscheme @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Example-iOS_ObjC-Carthage/Example_Extension/Base.lproj/MainInterface.storyboard b/Examples/Example-iOS_ObjC-Carthage/Example_Extension/Base.lproj/MainInterface.storyboard new file mode 100644 index 000000000..c2f74e69f --- /dev/null +++ b/Examples/Example-iOS_ObjC-Carthage/Example_Extension/Base.lproj/MainInterface.storyboard @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Example-iOS_ObjC-Carthage/Example_Extension/Example_Extension.entitlements b/Examples/Example-iOS_ObjC-Carthage/Example_Extension/Example_Extension.entitlements new file mode 100644 index 000000000..c250a2746 --- /dev/null +++ b/Examples/Example-iOS_ObjC-Carthage/Example_Extension/Example_Extension.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.net.openid.appauth.Example + + + diff --git a/Examples/Example-iOS_ObjC-Carthage/Example_Extension/Info.plist b/Examples/Example-iOS_ObjC-Carthage/Example_Extension/Info.plist new file mode 100644 index 000000000..6ea3c3dc6 --- /dev/null +++ b/Examples/Example-iOS_ObjC-Carthage/Example_Extension/Info.plist @@ -0,0 +1,31 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Example_Extension + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionMainStoryboard + MainInterface + NSExtensionPointIdentifier + com.apple.widget-extension + + + diff --git a/Examples/Example-iOS_ObjC-Carthage/Example_Extension/TodayViewController.h b/Examples/Example-iOS_ObjC-Carthage/Example_Extension/TodayViewController.h new file mode 100644 index 000000000..9053ba197 --- /dev/null +++ b/Examples/Example-iOS_ObjC-Carthage/Example_Extension/TodayViewController.h @@ -0,0 +1,24 @@ +/*! @file TodayViewController.h + @brief AppAuth iOS SDK Example + @copyright + Copyright 2015 Google Inc. All Rights Reserved. + @copydetails + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +@interface TodayViewController : UIViewController + +@end + diff --git a/Examples/Example-iOS_ObjC-Carthage/Example_Extension/TodayViewController.m b/Examples/Example-iOS_ObjC-Carthage/Example_Extension/TodayViewController.m new file mode 100644 index 000000000..82681feb5 --- /dev/null +++ b/Examples/Example-iOS_ObjC-Carthage/Example_Extension/TodayViewController.m @@ -0,0 +1,223 @@ +/*! @file TodayViewController.m + @brief AppAuth iOS SDK Example + @copyright + Copyright 2015 Google Inc. All Rights Reserved. + @copydetails + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "TodayViewController.h" +#import +#import + +static NSString *const kAppAuthExampleAuthStateKey = @"authState"; + +@interface TodayViewController () + +@property(nonatomic, readonly, nullable) OIDAuthState *authState; +@property (weak, nonatomic) IBOutlet UITextView *logTextView; + +@end + +@implementation TodayViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + if (@available(iOS 10.0, *)) { + [self.extensionContext setWidgetLargestAvailableDisplayMode:NCWidgetDisplayModeExpanded]; + } else { + self.preferredContentSize = CGSizeMake(0, 400.0); + } + + [self loadState]; +} + +- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode + withMaximumSize:(CGSize)maxSize NS_AVAILABLE_IOS(10.0) { + + if (activeDisplayMode == NCWidgetDisplayModeExpanded) { + self.preferredContentSize = CGSizeMake(maxSize.width, 400.0); + } else if (activeDisplayMode == NCWidgetDisplayModeCompact) { + self.preferredContentSize = maxSize; + } +} + +- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler { + // Perform any setup necessary in order to update the view. + + // If an error is encountered, use NCUpdateResultFailed + // If there's no update required, use NCUpdateResultNoData + // If there's an update, use NCUpdateResultNewData + + completionHandler(NCUpdateResultNewData); +} + +/*! @brief Loads the @c OIDAuthState from @c NSUSerDefaults. + */ +- (void)loadState { + // loads OIDAuthState from NSUSerDefaults + NSUserDefaults* userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.net.openid.appauth.Example"]; + NSData *archivedAuthState = [userDefaults objectForKey:kAppAuthExampleAuthStateKey]; + OIDAuthState *authState = [NSKeyedUnarchiver unarchiveObjectWithData:archivedAuthState]; + [self setAuthState:authState]; +} + +/*! @brief Saves the @c OIDAuthState to @c NSUSerDefaults. + */ +- (void)saveState { + // for production usage consider using the OS Keychain instead + NSUserDefaults* userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.net.openid.appauth.Example"]; + NSData *archivedAuthState = [NSKeyedArchiver archivedDataWithRootObject:_authState]; + [userDefaults setObject:archivedAuthState + forKey:kAppAuthExampleAuthStateKey]; + [userDefaults synchronize]; +} + +- (void)setAuthState:(nullable OIDAuthState *)authState { + if (_authState == authState) { + return; + } + _authState = authState; + _authState.stateChangeDelegate = self; + [self stateChanged]; +} + +- (void)stateChanged { + [self saveState]; +} + +- (void)didChangeState:(OIDAuthState *)state { + [self stateChanged]; +} + +- (IBAction)getUserInfo:(UIButton *)sender { + NSURL *userinfoEndpoint = + _authState.lastAuthorizationResponse.request.configuration.discoveryDocument.userinfoEndpoint; + if (!userinfoEndpoint) { + [self logMessage:@"Userinfo endpoint not declared in discovery document"]; + return; + } + NSString *currentAccessToken = _authState.lastTokenResponse.accessToken; + + [self logMessage:@"Performing userinfo request"]; + + [_authState performActionWithFreshTokens:^(NSString *_Nonnull accessToken, + NSString *_Nonnull idToken, + NSError *_Nullable error) { + if (error) { + [self logMessage:@"Error fetching fresh tokens: %@", [error localizedDescription]]; + return; + } + + // log whether a token refresh occurred + if (![currentAccessToken isEqual:accessToken]) { + [self logMessage:@"Access token was refreshed automatically (%@ to %@)", + currentAccessToken, + accessToken]; + } else { + [self logMessage:@"Access token was fresh and not updated [%@]", accessToken]; + } + + // creates request to the userinfo endpoint, with access token in the Authorization header + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:userinfoEndpoint]; + NSString *authorizationHeaderValue = [NSString stringWithFormat:@"Bearer %@", accessToken]; + [request addValue:authorizationHeaderValue forHTTPHeaderField:@"Authorization"]; + + NSURLSessionConfiguration *configuration = + [NSURLSessionConfiguration defaultSessionConfiguration]; + NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration + delegate:nil + delegateQueue:nil]; + + // performs HTTP request + NSURLSessionDataTask *postDataTask = + [session dataTaskWithRequest:request + completionHandler:^(NSData *_Nullable data, + NSURLResponse *_Nullable response, + NSError *_Nullable error) { + dispatch_async(dispatch_get_main_queue(), ^() { + if (error) { + [self logMessage:@"HTTP request failed %@", error]; + return; + } + if (![response isKindOfClass:[NSHTTPURLResponse class]]) { + [self logMessage:@"Non-HTTP response"]; + return; + } + + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + id jsonDictionaryOrArray = + [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]; + + if (httpResponse.statusCode != 200) { + // server replied with an error + NSString *responseText = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + if (httpResponse.statusCode == 401) { + // "401 Unauthorized" generally indicates there is an issue with the authorization + // grant. Puts OIDAuthState into an error state. + NSError *oauthError = + [OIDErrorUtilities resourceServerAuthorizationErrorWithCode:0 + errorResponse:jsonDictionaryOrArray + underlyingError:error]; + [_authState updateWithAuthorizationError:oauthError]; + // log error + [self logMessage:@"Authorization Error (%@). Response: %@", oauthError, responseText]; + } else { + [self logMessage:@"HTTP: %d. Response: %@", + (int)httpResponse.statusCode, + responseText]; + } + return; + } + + // success response + [self logMessage:@"Success: %@", jsonDictionaryOrArray]; + }); + }]; + + [postDataTask resume]; + }]; +} + +/*! @brief Logs a message to stdout and the textfield. + @param format The format string and arguments. + */ +- (void)logMessage:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2) { + // gets message as string + va_list argp; + va_start(argp, format); + NSString *log = [[NSString alloc] initWithFormat:format arguments:argp]; + va_end(argp); + + // outputs to stdout + NSLog(@"%@", log); + + // appends to output log + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.dateFormat = @"hh:mm:ss"; + NSString *dateString = [dateFormatter stringFromDate:[NSDate date]]; + _logTextView.text = [NSString stringWithFormat:@"%@%@%@: %@", + _logTextView.text, + ([_logTextView.text length] > 0) ? @"\n" : @"", + dateString, + log]; +} + +- (IBAction)clearLogTextView:(UIButton *)sender { + _logTextView.text = @""; +} + +@end + diff --git a/Examples/Example-iOS_ObjC-Carthage/Source/AppAuthExampleViewController.m b/Examples/Example-iOS_ObjC-Carthage/Source/AppAuthExampleViewController.m index 68354c436..dc76a8c9c 100644 --- a/Examples/Example-iOS_ObjC-Carthage/Source/AppAuthExampleViewController.m +++ b/Examples/Example-iOS_ObjC-Carthage/Source/AppAuthExampleViewController.m @@ -102,18 +102,19 @@ - (void)viewDidLoad { */ - (void)saveState { // for production usage consider using the OS Keychain instead + NSUserDefaults* userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.net.openid.appauth.Example"]; NSData *archivedAuthState = [ NSKeyedArchiver archivedDataWithRootObject:_authState]; - [[NSUserDefaults standardUserDefaults] setObject:archivedAuthState - forKey:kAppAuthExampleAuthStateKey]; - [[NSUserDefaults standardUserDefaults] synchronize]; + [userDefaults setObject:archivedAuthState + forKey:kAppAuthExampleAuthStateKey]; + [userDefaults synchronize]; } /*! @brief Loads the @c OIDAuthState from @c NSUSerDefaults. */ - (void)loadState { // loads OIDAuthState from NSUSerDefaults - NSData *archivedAuthState = - [[NSUserDefaults standardUserDefaults] objectForKey:kAppAuthExampleAuthStateKey]; + NSUserDefaults* userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.net.openid.appauth.Example"]; + NSData *archivedAuthState = [userDefaults objectForKey:kAppAuthExampleAuthStateKey]; OIDAuthState *authState = [NSKeyedUnarchiver unarchiveObjectWithData:archivedAuthState]; [self setAuthState:authState]; } diff --git a/Examples/Example-iOS_ObjC-Carthage/Source/Example.entitlements b/Examples/Example-iOS_ObjC-Carthage/Source/Example.entitlements new file mode 100644 index 000000000..c250a2746 --- /dev/null +++ b/Examples/Example-iOS_ObjC-Carthage/Source/Example.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.net.openid.appauth.Example + + + diff --git a/Examples/Example-iOS_ObjC/Example-iOS_ObjC.xcodeproj/project.pbxproj b/Examples/Example-iOS_ObjC/Example-iOS_ObjC.xcodeproj/project.pbxproj index 0e1a19c74..eb38b576d 100644 --- a/Examples/Example-iOS_ObjC/Example-iOS_ObjC.xcodeproj/project.pbxproj +++ b/Examples/Example-iOS_ObjC/Example-iOS_ObjC.xcodeproj/project.pbxproj @@ -7,6 +7,10 @@ objects = { /* Begin PBXBuildFile section */ + 06D4812F2055C3D400D9DC32 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06D4812E2055C3D400D9DC32 /* NotificationCenter.framework */; }; + 06D481332055C3D400D9DC32 /* TodayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 06D481322055C3D400D9DC32 /* TodayViewController.m */; }; + 06D481362055C3D400D9DC32 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 06D481342055C3D400D9DC32 /* MainInterface.storyboard */; }; + 06D4813A2055C3D400D9DC32 /* Example-iOS_ObjC_Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 06D4812D2055C3D400D9DC32 /* Example-iOS_ObjC_Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 341310AA1E6DEF7000D5DEE5 /* AppAuthExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 341310A91E6DEF7000D5DEE5 /* AppAuthExampleTests.m */; }; 346E916E1C29D42800D3620B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 346E916D1C29D42800D3620B /* main.m */; }; 346E91711C29D42800D3620B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 346E91701C29D42800D3620B /* AppDelegate.m */; }; @@ -15,10 +19,18 @@ 346E91991C2A245000D3620B /* SafariServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 346E91981C2A245000D3620B /* SafariServices.framework */; }; 34CB09BD1C42007600A54261 /* AppAuthExampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34CB09BB1C42007600A54261 /* AppAuthExampleViewController.m */; }; 34CB09BE1C42007600A54261 /* AppAuthExampleViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 34CB09BC1C42007600A54261 /* AppAuthExampleViewController.xib */; }; + D0B5FA33D74A6F7924A47471 /* libPods-Example-iOS_ObjC_Extension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 715EDB7EC4271193E47615ED /* libPods-Example-iOS_ObjC_Extension.a */; }; E46F8589CE9E5DDFA69D835B /* libPods-Example-iOS_ObjC.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B61A918CBE7B8142CD7D8B3 /* libPods-Example-iOS_ObjC.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 06D481382055C3D400D9DC32 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 346E91611C29D42800D3620B /* Project object */; + proxyType = 1; + remoteGlobalIDString = 06D4812C2055C3D400D9DC32; + remoteInfo = "Example-iOS_ObjC_Extension"; + }; 341310AC1E6DEF7000D5DEE5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 346E91611C29D42800D3620B /* Project object */; @@ -28,7 +40,29 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + 06D4813E2055C3D400D9DC32 /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 06D4813A2055C3D400D9DC32 /* Example-iOS_ObjC_Extension.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ + 06462428205EB35400072191 /* Example-iOS_ObjC.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Example-iOS_ObjC.entitlements"; sourceTree = ""; }; + 06462429205EB37A00072191 /* Example-iOS_ObjC_Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Example-iOS_ObjC_Extension.entitlements"; sourceTree = ""; }; + 06D4812D2055C3D400D9DC32 /* Example-iOS_ObjC_Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Example-iOS_ObjC_Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; + 06D4812E2055C3D400D9DC32 /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; }; + 06D481312055C3D400D9DC32 /* TodayViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TodayViewController.h; sourceTree = ""; }; + 06D481322055C3D400D9DC32 /* TodayViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TodayViewController.m; sourceTree = ""; }; + 06D481352055C3D400D9DC32 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; + 06D481372055C3D400D9DC32 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 09795EAF079B07A1781675D9 /* libPods-Example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Example.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 0D29B2A58C931A5D41332144 /* Pods-Example-iOS_ObjC.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example-iOS_ObjC.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example-iOS_ObjC/Pods-Example-iOS_ObjC.debug.xcconfig"; sourceTree = ""; }; 341310A71E6DEF7000D5DEE5 /* AppAuthExample-iOS_ObjCTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "AppAuthExample-iOS_ObjCTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -46,6 +80,9 @@ 34CB09BA1C42007600A54261 /* AppAuthExampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAuthExampleViewController.h; sourceTree = ""; }; 34CB09BB1C42007600A54261 /* AppAuthExampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAuthExampleViewController.m; sourceTree = ""; }; 34CB09BC1C42007600A54261 /* AppAuthExampleViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AppAuthExampleViewController.xib; sourceTree = ""; }; + 3A18DF082AC2FA0980C9DE57 /* Pods-Example-iOS_ObjC_Extension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example-iOS_ObjC_Extension.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example-iOS_ObjC_Extension/Pods-Example-iOS_ObjC_Extension.release.xcconfig"; sourceTree = ""; }; + 715EDB7EC4271193E47615ED /* libPods-Example-iOS_ObjC_Extension.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Example-iOS_ObjC_Extension.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 86C7660572AE6FF7A4D1592A /* Pods-Example-iOS_ObjC_Extension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example-iOS_ObjC_Extension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example-iOS_ObjC_Extension/Pods-Example-iOS_ObjC_Extension.debug.xcconfig"; sourceTree = ""; }; 8B61A918CBE7B8142CD7D8B3 /* libPods-Example-iOS_ObjC.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Example-iOS_ObjC.a"; sourceTree = BUILT_PRODUCTS_DIR; }; C4C31DB4A4928F246AA03805 /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = ""; }; D9867DC6FA9089CD613D4728 /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = ""; }; @@ -53,6 +90,15 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 06D4812A2055C3D400D9DC32 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 06D4812F2055C3D400D9DC32 /* NotificationCenter.framework in Frameworks */, + D0B5FA33D74A6F7924A47471 /* libPods-Example-iOS_ObjC_Extension.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 341310A41E6DEF7000D5DEE5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -72,6 +118,18 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 06D481302055C3D400D9DC32 /* Example-iOS_ObjC_Extension */ = { + isa = PBXGroup; + children = ( + 06D481312055C3D400D9DC32 /* TodayViewController.h */, + 06D481322055C3D400D9DC32 /* TodayViewController.m */, + 06D481342055C3D400D9DC32 /* MainInterface.storyboard */, + 06D481372055C3D400D9DC32 /* Info.plist */, + 06462429205EB37A00072191 /* Example-iOS_ObjC_Extension.entitlements */, + ); + path = "Example-iOS_ObjC_Extension"; + sourceTree = ""; + }; 341310A81E6DEF7000D5DEE5 /* Tests */ = { isa = PBXGroup; children = ( @@ -88,6 +146,8 @@ 346E91981C2A245000D3620B /* SafariServices.framework */, 09795EAF079B07A1781675D9 /* libPods-Example.a */, 8B61A918CBE7B8142CD7D8B3 /* libPods-Example-iOS_ObjC.a */, + 06D4812E2055C3D400D9DC32 /* NotificationCenter.framework */, + 715EDB7EC4271193E47615ED /* libPods-Example-iOS_ObjC_Extension.a */, ); name = Frameworks; sourceTree = ""; @@ -97,6 +157,7 @@ children = ( 346E916B1C29D42800D3620B /* Source */, 341310A81E6DEF7000D5DEE5 /* Tests */, + 06D481302055C3D400D9DC32 /* Example-iOS_ObjC_Extension */, 341564001C487ABA00ECA3D9 /* Frameworks */, 346E916A1C29D42800D3620B /* Products */, 6DB0B0125441549B9E4A3E6C /* Pods */, @@ -108,6 +169,7 @@ children = ( 346E91691C29D42800D3620B /* Example-iOS_ObjC.app */, 341310A71E6DEF7000D5DEE5 /* AppAuthExample-iOS_ObjCTests.xctest */, + 06D4812D2055C3D400D9DC32 /* Example-iOS_ObjC_Extension.appex */, ); name = Products; sourceTree = ""; @@ -124,6 +186,7 @@ 346E91781C29D42800D3620B /* Assets.xcassets */, 346E917A1C29D42800D3620B /* LaunchScreen.storyboard */, 346E917D1C29D42800D3620B /* Info.plist */, + 06462428205EB35400072191 /* Example-iOS_ObjC.entitlements */, ); path = Source; sourceTree = ""; @@ -135,6 +198,8 @@ C4C31DB4A4928F246AA03805 /* Pods-Example.release.xcconfig */, 0D29B2A58C931A5D41332144 /* Pods-Example-iOS_ObjC.debug.xcconfig */, ECBCCC4A1A779C83C72044F2 /* Pods-Example-iOS_ObjC.release.xcconfig */, + 86C7660572AE6FF7A4D1592A /* Pods-Example-iOS_ObjC_Extension.debug.xcconfig */, + 3A18DF082AC2FA0980C9DE57 /* Pods-Example-iOS_ObjC_Extension.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -142,6 +207,24 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 06D4812C2055C3D400D9DC32 /* Example-iOS_ObjC_Extension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 06D4813D2055C3D400D9DC32 /* Build configuration list for PBXNativeTarget "Example-iOS_ObjC_Extension" */; + buildPhases = ( + 836219F293F319703A16E68D /* [CP] Check Pods Manifest.lock */, + 06D481292055C3D400D9DC32 /* Sources */, + 06D4812A2055C3D400D9DC32 /* Frameworks */, + 06D4812B2055C3D400D9DC32 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Example-iOS_ObjC_Extension"; + productName = "Example-iOS_ObjC_Extension"; + productReference = 06D4812D2055C3D400D9DC32 /* Example-iOS_ObjC_Extension.appex */; + productType = "com.apple.product-type.app-extension"; + }; 341310A61E6DEF7000D5DEE5 /* AppAuthExample-iOS_ObjCTests */ = { isa = PBXNativeTarget; buildConfigurationList = 341310AE1E6DEF7000D5DEE5 /* Build configuration list for PBXNativeTarget "AppAuthExample-iOS_ObjCTests" */; @@ -168,12 +251,12 @@ 346E91651C29D42800D3620B /* Sources */, 346E91661C29D42800D3620B /* Frameworks */, 346E91671C29D42800D3620B /* Resources */, - 0B0B46F67786AB6E322D5F2B /* [CP] Embed Pods Frameworks */, - 3CB1FD4B438DD277394F39A7 /* [CP] Copy Pods Resources */, + 06D4813E2055C3D400D9DC32 /* Embed App Extensions */, ); buildRules = ( ); dependencies = ( + 06D481392055C3D400D9DC32 /* PBXTargetDependency */, ); name = "Example-iOS_ObjC"; productName = Example; @@ -189,6 +272,15 @@ LastUpgradeCheck = 0720; ORGANIZATIONNAME = "William Denniss"; TargetAttributes = { + 06D4812C2055C3D400D9DC32 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; + }; + }; 341310A61E6DEF7000D5DEE5 = { CreatedOnToolsVersion = 8.2.1; ProvisioningStyle = Automatic; @@ -196,6 +288,11 @@ }; 346E91681C29D42800D3620B = { CreatedOnToolsVersion = 7.2; + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; + }; }; }; }; @@ -214,11 +311,20 @@ targets = ( 346E91681C29D42800D3620B /* Example-iOS_ObjC */, 341310A61E6DEF7000D5DEE5 /* AppAuthExample-iOS_ObjCTests */, + 06D4812C2055C3D400D9DC32 /* Example-iOS_ObjC_Extension */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 06D4812B2055C3D400D9DC32 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 06D481362055C3D400D9DC32 /* MainInterface.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 341310A51E6DEF7000D5DEE5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -239,34 +345,22 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 0B0B46F67786AB6E322D5F2B /* [CP] Embed Pods Frameworks */ = { + 836219F293F319703A16E68D /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example-iOS_ObjC/Pods-Example-iOS_ObjC-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 3CB1FD4B438DD277394F39A7 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Example-iOS_ObjC_Extension-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example-iOS_ObjC/Pods-Example-iOS_ObjC-resources.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; C4DC5E3A0D4C7419380FA8C2 /* [CP] Check Pods Manifest.lock */ = { @@ -275,18 +369,29 @@ files = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Example-iOS_ObjC-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 06D481292055C3D400D9DC32 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 06D481332055C3D400D9DC32 /* TodayViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 341310A31E6DEF7000D5DEE5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -308,6 +413,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 06D481392055C3D400D9DC32 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 06D4812C2055C3D400D9DC32 /* Example-iOS_ObjC_Extension */; + targetProxy = 06D481382055C3D400D9DC32 /* PBXContainerItemProxy */; + }; 341310AD1E6DEF7000D5DEE5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 346E91681C29D42800D3620B /* Example-iOS_ObjC */; @@ -316,6 +426,14 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ + 06D481342055C3D400D9DC32 /* MainInterface.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 06D481352055C3D400D9DC32 /* Base */, + ); + name = MainInterface.storyboard; + sourceTree = ""; + }; 346E917A1C29D42800D3620B /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -327,6 +445,70 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 06D4813B2055C3D400D9DC32 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 86C7660572AE6FF7A4D1592A /* Pods-Example-iOS_ObjC_Extension.debug.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = "Example-iOS_ObjC_Extension/Example-iOS_ObjC_Extension.entitlements"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = "Example-iOS_ObjC_Extension/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "net.openid.appauth.Example.Example-iOS-ObjC-Extension"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 06D4813C2055C3D400D9DC32 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3A18DF082AC2FA0980C9DE57 /* Pods-Example-iOS_ObjC_Extension.release.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = "Example-iOS_ObjC_Extension/Example-iOS_ObjC_Extension.entitlements"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = "Example-iOS_ObjC_Extension/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "net.openid.appauth.Example.Example-iOS-ObjC-Extension"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; 341310AF1E6DEF7000D5DEE5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -456,6 +638,9 @@ baseConfigurationReference = 0D29B2A58C931A5D41332144 /* Pods-Example-iOS_ObjC.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = "Source/Example-iOS_ObjC.entitlements"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Source/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -469,6 +654,9 @@ baseConfigurationReference = ECBCCC4A1A779C83C72044F2 /* Pods-Example-iOS_ObjC.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = "Source/Example-iOS_ObjC.entitlements"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Source/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -480,6 +668,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 06D4813D2055C3D400D9DC32 /* Build configuration list for PBXNativeTarget "Example-iOS_ObjC_Extension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 06D4813B2055C3D400D9DC32 /* Debug */, + 06D4813C2055C3D400D9DC32 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 341310AE1E6DEF7000D5DEE5 /* Build configuration list for PBXNativeTarget "AppAuthExample-iOS_ObjCTests" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Examples/Example-iOS_ObjC/Example-iOS_ObjC.xcodeproj/xcshareddata/xcschemes/Example-iOS_ObjC_Extension.xcscheme b/Examples/Example-iOS_ObjC/Example-iOS_ObjC.xcodeproj/xcshareddata/xcschemes/Example-iOS_ObjC_Extension.xcscheme new file mode 100644 index 000000000..7a9720c27 --- /dev/null +++ b/Examples/Example-iOS_ObjC/Example-iOS_ObjC.xcodeproj/xcshareddata/xcschemes/Example-iOS_ObjC_Extension.xcscheme @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/Base.lproj/MainInterface.storyboard b/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/Base.lproj/MainInterface.storyboard new file mode 100644 index 000000000..67a53a714 --- /dev/null +++ b/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/Base.lproj/MainInterface.storyboard @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/Example-iOS_ObjC_Extension.entitlements b/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/Example-iOS_ObjC_Extension.entitlements new file mode 100644 index 000000000..c250a2746 --- /dev/null +++ b/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/Example-iOS_ObjC_Extension.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.net.openid.appauth.Example + + + diff --git a/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/Info.plist b/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/Info.plist new file mode 100644 index 000000000..8839cbabf --- /dev/null +++ b/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/Info.plist @@ -0,0 +1,31 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Example-iOS_ObjC_Extension + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionMainStoryboard + MainInterface + NSExtensionPointIdentifier + com.apple.widget-extension + + + diff --git a/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/TodayViewController.h b/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/TodayViewController.h new file mode 100644 index 000000000..73d2d5e3a --- /dev/null +++ b/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/TodayViewController.h @@ -0,0 +1,23 @@ +/*! @file TodayViewController.h + @brief AppAuth iOS SDK Example + @copyright + Copyright 2015 Google Inc. All Rights Reserved. + @copydetails + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +@interface TodayViewController : UIViewController + +@end diff --git a/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/TodayViewController.m b/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/TodayViewController.m new file mode 100644 index 000000000..1bfbd96ed --- /dev/null +++ b/Examples/Example-iOS_ObjC/Example-iOS_ObjC_Extension/TodayViewController.m @@ -0,0 +1,222 @@ +/*! @file TodayViewController.m + @brief AppAuth iOS SDK Example + @copyright + Copyright 2015 Google Inc. All Rights Reserved. + @copydetails + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "TodayViewController.h" +#import +#import + +static NSString *const kAppAuthExampleAuthStateKey = @"authState"; + +@interface TodayViewController () + +@property(nonatomic, readonly, nullable) OIDAuthState *authState; +@property (weak, nonatomic) IBOutlet UITextView *logTextView; + +@end + +@implementation TodayViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + if (@available(iOS 10, *)) { + [self.extensionContext setWidgetLargestAvailableDisplayMode:NCWidgetDisplayModeExpanded]; + } else { + self.preferredContentSize = CGSizeMake(0, 400.0); + } + + [self loadState]; +} + +- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode + withMaximumSize:(CGSize)maxSize NS_AVAILABLE_IOS(10.0) { + + if (activeDisplayMode == NCWidgetDisplayModeExpanded) { + self.preferredContentSize = CGSizeMake(maxSize.width, 400.0); + } else if (activeDisplayMode == NCWidgetDisplayModeCompact) { + self.preferredContentSize = maxSize; + } +} + +- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler { + // Perform any setup necessary in order to update the view. + + // If an error is encountered, use NCUpdateResultFailed + // If there's no update required, use NCUpdateResultNoData + // If there's an update, use NCUpdateResultNewData + + completionHandler(NCUpdateResultNewData); +} + +/*! @brief Loads the @c OIDAuthState from @c NSUSerDefaults. + */ +- (void)loadState { + // loads OIDAuthState from NSUSerDefaults + NSUserDefaults* userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.net.openid.appauth.Example"]; + NSData *archivedAuthState = [userDefaults objectForKey:kAppAuthExampleAuthStateKey]; + OIDAuthState *authState = [NSKeyedUnarchiver unarchiveObjectWithData:archivedAuthState]; + [self setAuthState:authState]; +} + +/*! @brief Saves the @c OIDAuthState to @c NSUSerDefaults. + */ +- (void)saveState { + // for production usage consider using the OS Keychain instead + NSUserDefaults* userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.net.openid.appauth.Example"]; + NSData *archivedAuthState = [NSKeyedArchiver archivedDataWithRootObject:_authState]; + [userDefaults setObject:archivedAuthState + forKey:kAppAuthExampleAuthStateKey]; + [userDefaults synchronize]; +} + +- (void)setAuthState:(nullable OIDAuthState *)authState { + if (_authState == authState) { + return; + } + _authState = authState; + _authState.stateChangeDelegate = self; + [self stateChanged]; +} + +- (void)stateChanged { + [self saveState]; +} + +- (void)didChangeState:(OIDAuthState *)state { + [self stateChanged]; +} + +- (IBAction)getUserInfo:(UIButton *)sender { + NSURL *userinfoEndpoint = + _authState.lastAuthorizationResponse.request.configuration.discoveryDocument.userinfoEndpoint; + if (!userinfoEndpoint) { + [self logMessage:@"Userinfo endpoint not declared in discovery document"]; + return; + } + NSString *currentAccessToken = _authState.lastTokenResponse.accessToken; + + [self logMessage:@"Performing userinfo request"]; + + [_authState performActionWithFreshTokens:^(NSString *_Nonnull accessToken, + NSString *_Nonnull idToken, + NSError *_Nullable error) { + if (error) { + [self logMessage:@"Error fetching fresh tokens: %@", [error localizedDescription]]; + return; + } + + // log whether a token refresh occurred + if (![currentAccessToken isEqual:accessToken]) { + [self logMessage:@"Access token was refreshed automatically (%@ to %@)", + currentAccessToken, + accessToken]; + } else { + [self logMessage:@"Access token was fresh and not updated [%@]", accessToken]; + } + + // creates request to the userinfo endpoint, with access token in the Authorization header + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:userinfoEndpoint]; + NSString *authorizationHeaderValue = [NSString stringWithFormat:@"Bearer %@", accessToken]; + [request addValue:authorizationHeaderValue forHTTPHeaderField:@"Authorization"]; + + NSURLSessionConfiguration *configuration = + [NSURLSessionConfiguration defaultSessionConfiguration]; + NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration + delegate:nil + delegateQueue:nil]; + + // performs HTTP request + NSURLSessionDataTask *postDataTask = + [session dataTaskWithRequest:request + completionHandler:^(NSData *_Nullable data, + NSURLResponse *_Nullable response, + NSError *_Nullable error) { + dispatch_async(dispatch_get_main_queue(), ^() { + if (error) { + [self logMessage:@"HTTP request failed %@", error]; + return; + } + if (![response isKindOfClass:[NSHTTPURLResponse class]]) { + [self logMessage:@"Non-HTTP response"]; + return; + } + + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + id jsonDictionaryOrArray = + [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]; + + if (httpResponse.statusCode != 200) { + // server replied with an error + NSString *responseText = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + if (httpResponse.statusCode == 401) { + // "401 Unauthorized" generally indicates there is an issue with the authorization + // grant. Puts OIDAuthState into an error state. + NSError *oauthError = + [OIDErrorUtilities resourceServerAuthorizationErrorWithCode:0 + errorResponse:jsonDictionaryOrArray + underlyingError:error]; + [_authState updateWithAuthorizationError:oauthError]; + // log error + [self logMessage:@"Authorization Error (%@). Response: %@", oauthError, responseText]; + } else { + [self logMessage:@"HTTP: %d. Response: %@", + (int)httpResponse.statusCode, + responseText]; + } + return; + } + + // success response + [self logMessage:@"Success: %@", jsonDictionaryOrArray]; + }); + }]; + + [postDataTask resume]; + }]; +} + +/*! @brief Logs a message to stdout and the textfield. + @param format The format string and arguments. + */ +- (void)logMessage:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2) { + // gets message as string + va_list argp; + va_start(argp, format); + NSString *log = [[NSString alloc] initWithFormat:format arguments:argp]; + va_end(argp); + + // outputs to stdout + NSLog(@"%@", log); + + // appends to output log + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.dateFormat = @"hh:mm:ss"; + NSString *dateString = [dateFormatter stringFromDate:[NSDate date]]; + _logTextView.text = [NSString stringWithFormat:@"%@%@%@: %@", + _logTextView.text, + ([_logTextView.text length] > 0) ? @"\n" : @"", + dateString, + log]; +} + +- (IBAction)clearLogTextView:(UIButton *)sender { + _logTextView.text = @""; +} + +@end diff --git a/Examples/Example-iOS_ObjC/Podfile b/Examples/Example-iOS_ObjC/Podfile index 4d6ab0f6f..a4354d010 100644 --- a/Examples/Example-iOS_ObjC/Podfile +++ b/Examples/Example-iOS_ObjC/Podfile @@ -1,7 +1,13 @@ -target 'Example-iOS_ObjC' do - platform :ios, '9.0' +platform :ios, '9.0' +target 'Example-iOS_ObjC' do # AppAuth Pod # In production, just use `pod 'AppAuth'` without the path reference. pod 'AppAuth', :path => '../../' end + +target 'Example-iOS_ObjC_Extension' do + # AppAuth/Core Pod + # In production, just use `pod 'AppAuth/Core'` without the path reference. + pod 'AppAuth/Core', :path => '../../' +end diff --git a/Examples/Example-iOS_ObjC/Source/AppAuthExampleViewController.m b/Examples/Example-iOS_ObjC/Source/AppAuthExampleViewController.m index 86a32445e..2c3ebe03e 100644 --- a/Examples/Example-iOS_ObjC/Source/AppAuthExampleViewController.m +++ b/Examples/Example-iOS_ObjC/Source/AppAuthExampleViewController.m @@ -104,18 +104,19 @@ - (void)verifyConfig { */ - (void)saveState { // for production usage consider using the OS Keychain instead - NSData *archivedAuthState = [ NSKeyedArchiver archivedDataWithRootObject:_authState]; - [[NSUserDefaults standardUserDefaults] setObject:archivedAuthState - forKey:kAppAuthExampleAuthStateKey]; - [[NSUserDefaults standardUserDefaults] synchronize]; + NSUserDefaults* userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.net.openid.appauth.Example"]; + NSData *archivedAuthState = [NSKeyedArchiver archivedDataWithRootObject:_authState]; + [userDefaults setObject:archivedAuthState + forKey:kAppAuthExampleAuthStateKey]; + [userDefaults synchronize]; } /*! @brief Loads the @c OIDAuthState from @c NSUSerDefaults. */ - (void)loadState { // loads OIDAuthState from NSUSerDefaults - NSData *archivedAuthState = - [[NSUserDefaults standardUserDefaults] objectForKey:kAppAuthExampleAuthStateKey]; + NSUserDefaults* userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.net.openid.appauth.Example"]; + NSData *archivedAuthState = [userDefaults objectForKey:kAppAuthExampleAuthStateKey]; OIDAuthState *authState = [NSKeyedUnarchiver unarchiveObjectWithData:archivedAuthState]; [self setAuthState:authState]; } diff --git a/Examples/Example-iOS_ObjC/Source/Example-iOS_ObjC.entitlements b/Examples/Example-iOS_ObjC/Source/Example-iOS_ObjC.entitlements new file mode 100644 index 000000000..c250a2746 --- /dev/null +++ b/Examples/Example-iOS_ObjC/Source/Example-iOS_ObjC.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.net.openid.appauth.Example + + + diff --git a/Examples/Example-iOS_Swift-Carthage/Example.xcodeproj/project.pbxproj b/Examples/Example-iOS_Swift-Carthage/Example.xcodeproj/project.pbxproj index 825c2a30f..33f25f87b 100644 --- a/Examples/Example-iOS_Swift-Carthage/Example.xcodeproj/project.pbxproj +++ b/Examples/Example-iOS_Swift-Carthage/Example.xcodeproj/project.pbxproj @@ -7,6 +7,11 @@ objects = { /* Begin PBXBuildFile section */ + 06375C8821A4E50E00338E3F /* AppAuthCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06375C8721A4E50E00338E3F /* AppAuthCore.framework */; }; + 0646249B205F026300072191 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0646249A205F026300072191 /* NotificationCenter.framework */; }; + 0646249E205F026300072191 /* TodayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0646249D205F026300072191 /* TodayViewController.swift */; }; + 064624A1205F026300072191 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0646249F205F026300072191 /* MainInterface.storyboard */; }; + 064624A5205F026300072191 /* Example_Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 06462499205F026300072191 /* Example_Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 9F265BD11F9AC69300DC14BF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9F265BC91F9AC69300DC14BF /* Assets.xcassets */; }; 9F265BD31F9AC69300DC14BF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9F265BCB1F9AC69300DC14BF /* LaunchScreen.storyboard */; }; 9F265BD41F9AC69300DC14BF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9F265BCD1F9AC69300DC14BF /* Main.storyboard */; }; @@ -15,7 +20,39 @@ 9FD378231FB7C6F800436204 /* AppAuthExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FD378221FB7C6F800436204 /* AppAuthExampleViewController.swift */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 064624A3205F026300072191 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 9F265B8F1F9AC5D600DC14BF /* Project object */; + proxyType = 1; + remoteGlobalIDString = 06462498205F026300072191; + remoteInfo = Example_Extension; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 064624A9205F026300072191 /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 064624A5205F026300072191 /* Example_Extension.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ + 06375C8721A4E50E00338E3F /* AppAuthCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppAuthCore.framework; path = Carthage/Build/iOS/AppAuthCore.framework; sourceTree = ""; }; + 06462499205F026300072191 /* Example_Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Example_Extension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 0646249A205F026300072191 /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; }; + 0646249D205F026300072191 /* TodayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayViewController.swift; sourceTree = ""; }; + 064624A0205F026300072191 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; + 064624A2205F026300072191 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 064624AD205F034A00072191 /* Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Example.entitlements; sourceTree = ""; }; + 064624AE205F035D00072191 /* Example_Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Example_Extension.entitlements; sourceTree = ""; }; 9F265B971F9AC5D600DC14BF /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 9F265BC91F9AC69300DC14BF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 9F265BCC1F9AC69300DC14BF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -27,6 +64,15 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 06462496205F026300072191 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 06375C8821A4E50E00338E3F /* AppAuthCore.framework in Frameworks */, + 0646249B205F026300072191 /* NotificationCenter.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 9F265B941F9AC5D600DC14BF /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -38,10 +84,22 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 0646249C205F026300072191 /* Example_Extension */ = { + isa = PBXGroup; + children = ( + 0646249D205F026300072191 /* TodayViewController.swift */, + 0646249F205F026300072191 /* MainInterface.storyboard */, + 064624A2205F026300072191 /* Info.plist */, + 064624AE205F035D00072191 /* Example_Extension.entitlements */, + ); + path = Example_Extension; + sourceTree = ""; + }; 9F265B8E1F9AC5D600DC14BF = { isa = PBXGroup; children = ( 9F265BC81F9AC69300DC14BF /* Source */, + 0646249C205F026300072191 /* Example_Extension */, 9F265BD81F9AE4CA00DC14BF /* Frameworks */, 9F265B981F9AC5D600DC14BF /* Products */, ); @@ -51,6 +109,7 @@ isa = PBXGroup; children = ( 9F265B971F9AC5D600DC14BF /* Example.app */, + 06462499205F026300072191 /* Example_Extension.appex */, ); name = Products; sourceTree = ""; @@ -64,6 +123,7 @@ 9F265BCD1F9AC69300DC14BF /* Main.storyboard */, 9F265BC91F9AC69300DC14BF /* Assets.xcassets */, 9F265BD01F9AC69300DC14BF /* Info.plist */, + 064624AD205F034A00072191 /* Example.entitlements */, ); path = Source; sourceTree = ""; @@ -71,7 +131,9 @@ 9F265BD81F9AE4CA00DC14BF /* Frameworks */ = { isa = PBXGroup; children = ( + 06375C8721A4E50E00338E3F /* AppAuthCore.framework */, 9F265BD91F9AE50400DC14BF /* AppAuth.framework */, + 0646249A205F026300072191 /* NotificationCenter.framework */, ); name = Frameworks; sourceTree = ""; @@ -79,6 +141,24 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 06462498205F026300072191 /* Example_Extension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 064624A8205F026300072191 /* Build configuration list for PBXNativeTarget "Example_Extension" */; + buildPhases = ( + 06462495205F026300072191 /* Sources */, + 06462496205F026300072191 /* Frameworks */, + 06462497205F026300072191 /* Resources */, + 06375C8921A4E56B00338E3F /* Carthage */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Example_Extension; + productName = Example_Extension; + productReference = 06462499205F026300072191 /* Example_Extension.appex */; + productType = "com.apple.product-type.app-extension"; + }; 9F265B961F9AC5D600DC14BF /* Example */ = { isa = PBXNativeTarget; buildConfigurationList = 9F265BBF1F9AC5D600DC14BF /* Build configuration list for PBXNativeTarget "Example" */; @@ -86,11 +166,13 @@ 9F265B931F9AC5D600DC14BF /* Sources */, 9F265B941F9AC5D600DC14BF /* Frameworks */, 9F265B951F9AC5D600DC14BF /* Resources */, - 9F265BDB1F9AE52C00DC14BF /* ShellScript */, + 9F265BDB1F9AE52C00DC14BF /* Carthage */, + 064624A9205F026300072191 /* Embed App Extensions */, ); buildRules = ( ); dependencies = ( + 064624A4205F026300072191 /* PBXTargetDependency */, ); name = Example; productName = Example; @@ -103,13 +185,27 @@ 9F265B8F1F9AC5D600DC14BF /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0900; + LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 0900; ORGANIZATIONNAME = "Google Inc."; TargetAttributes = { + 06462498205F026300072191 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; + }; + }; 9F265B961F9AC5D600DC14BF = { CreatedOnToolsVersion = 9.0.1; ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; + }; }; }; }; @@ -127,11 +223,20 @@ projectRoot = ""; targets = ( 9F265B961F9AC5D600DC14BF /* Example */, + 06462498205F026300072191 /* Example_Extension */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 06462497205F026300072191 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 064624A1205F026300072191 /* MainInterface.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 9F265B951F9AC5D600DC14BF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -145,7 +250,26 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 9F265BDB1F9AE52C00DC14BF /* ShellScript */ = { + 06375C8921A4E56B00338E3F /* Carthage */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/iOS/AppAuth.framework", + ); + name = Carthage; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks\n"; + }; + 9F265BDB1F9AE52C00DC14BF /* Carthage */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -153,15 +277,24 @@ inputPaths = ( "$(SRCROOT)/Carthage/Build/iOS/AppAuth.framework", ); + name = Carthage; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks"; + shellScript = "/usr/local/bin/carthage copy-frameworks\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 06462495205F026300072191 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0646249E205F026300072191 /* TodayViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 9F265B931F9AC5D600DC14BF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -173,7 +306,23 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 064624A4205F026300072191 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 06462498205F026300072191 /* Example_Extension */; + targetProxy = 064624A3205F026300072191 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ + 0646249F205F026300072191 /* MainInterface.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 064624A0205F026300072191 /* Base */, + ); + name = MainInterface.storyboard; + sourceTree = ""; + }; 9F265BCB1F9AC69300DC14BF /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -193,6 +342,48 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 064624A6205F026300072191 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = Example_Extension/Example_Extension.entitlements; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); + INFOPLIST_FILE = Example_Extension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "net.openid.appauth.Example.Example-Extension"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 064624A7205F026300072191 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = Example_Extension/Example_Extension.entitlements; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); + INFOPLIST_FILE = Example_Extension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "net.openid.appauth.Example.Example-Extension"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; 9F265BBD1F9AC5D600DC14BF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -303,8 +494,11 @@ 9F265BC01F9AC5D600DC14BF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Source/Example.entitlements; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", @@ -322,8 +516,11 @@ 9F265BC11F9AC5D600DC14BF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Source/Example.entitlements; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", @@ -341,6 +538,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 064624A8205F026300072191 /* Build configuration list for PBXNativeTarget "Example_Extension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 064624A6205F026300072191 /* Debug */, + 064624A7205F026300072191 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 9F265B921F9AC5D600DC14BF /* Build configuration list for PBXProject "Example" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Examples/Example-iOS_Swift-Carthage/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme b/Examples/Example-iOS_Swift-Carthage/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme new file mode 100644 index 000000000..7ffcb4c0f --- /dev/null +++ b/Examples/Example-iOS_Swift-Carthage/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Example-iOS_Swift-Carthage/Example.xcodeproj/xcshareddata/xcschemes/Example_Extension.xcscheme b/Examples/Example-iOS_Swift-Carthage/Example.xcodeproj/xcshareddata/xcschemes/Example_Extension.xcscheme new file mode 100644 index 000000000..719ebd973 --- /dev/null +++ b/Examples/Example-iOS_Swift-Carthage/Example.xcodeproj/xcshareddata/xcschemes/Example_Extension.xcscheme @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Example-iOS_Swift-Carthage/Example_Extension/Base.lproj/MainInterface.storyboard b/Examples/Example-iOS_Swift-Carthage/Example_Extension/Base.lproj/MainInterface.storyboard new file mode 100644 index 000000000..170af8176 --- /dev/null +++ b/Examples/Example-iOS_Swift-Carthage/Example_Extension/Base.lproj/MainInterface.storyboard @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Example-iOS_Swift-Carthage/Example_Extension/Example_Extension.entitlements b/Examples/Example-iOS_Swift-Carthage/Example_Extension/Example_Extension.entitlements new file mode 100644 index 000000000..c250a2746 --- /dev/null +++ b/Examples/Example-iOS_Swift-Carthage/Example_Extension/Example_Extension.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.net.openid.appauth.Example + + + diff --git a/Examples/Example-iOS_Swift-Carthage/Example_Extension/Info.plist b/Examples/Example-iOS_Swift-Carthage/Example_Extension/Info.plist new file mode 100644 index 000000000..6ea3c3dc6 --- /dev/null +++ b/Examples/Example-iOS_Swift-Carthage/Example_Extension/Info.plist @@ -0,0 +1,31 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Example_Extension + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionMainStoryboard + MainInterface + NSExtensionPointIdentifier + com.apple.widget-extension + + + diff --git a/Examples/Example-iOS_Swift-Carthage/Example_Extension/TodayViewController.swift b/Examples/Example-iOS_Swift-Carthage/Example_Extension/TodayViewController.swift new file mode 100644 index 000000000..fc663d1bd --- /dev/null +++ b/Examples/Example-iOS_Swift-Carthage/Example_Extension/TodayViewController.swift @@ -0,0 +1,224 @@ +// +// TodayViewController.swift +// +// Copyright (c) 2017 The AppAuth Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit +import NotificationCenter +import AppAuthCore + +/** + NSCoding key for the authState property. + */ +let kAppAuthExampleAuthStateKey: String = "authState"; + +class TodayViewController: UIViewController, NCWidgetProviding { + + @IBOutlet private weak var logTextView: UITextView! + + private var authState: OIDAuthState? + + override func viewDidLoad() { + super.viewDidLoad() + + if #available(iOS 10.0, *) { + self.extensionContext?.widgetLargestAvailableDisplayMode = .expanded + } else { + self.preferredContentSize = CGSize(width: 0, height: 400.0) + } + + self.loadState() + } + + @available(iOSApplicationExtension 10.0, *) + func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize) { + if activeDisplayMode == .expanded { + preferredContentSize = CGSize(width: maxSize.width, height: 400.0) + } else if activeDisplayMode == .compact { + preferredContentSize = maxSize + } + } + + func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) { + // Perform any setup necessary in order to update the view. + + // If an error is encountered, use NCUpdateResult.Failed + // If there's no update required, use NCUpdateResult.NoData + // If there's an update, use NCUpdateResult.NewData + + completionHandler(NCUpdateResult.newData) + } + + @IBAction func userinfo(_ sender: UIButton) { + + guard let userinfoEndpoint = self.authState?.lastAuthorizationResponse.request.configuration.discoveryDocument?.userinfoEndpoint else { + self.logMessage("Userinfo endpoint not declared in discovery document") + return + } + + self.logMessage("Performing userinfo request") + + let currentAccessToken: String? = self.authState?.lastTokenResponse?.accessToken + + self.authState?.performAction() { (accessToken, idTOken, error) in + + if error != nil { + self.logMessage("Error fetching fresh tokens: \(error?.localizedDescription ?? "ERROR")") + return + } + + guard let accessToken = accessToken else { + self.logMessage("Error getting accessToken") + return + } + + if currentAccessToken != accessToken { + self.logMessage("Access token was refreshed automatically (\(currentAccessToken ?? "CURRENT_ACCESS_TOKEN") to \(accessToken))") + } else { + self.logMessage("Access token was fresh and not updated \(accessToken)") + } + + var urlRequest = URLRequest(url: userinfoEndpoint) + urlRequest.allHTTPHeaderFields = ["Authorization":"Bearer \(accessToken)"] + + let task = URLSession.shared.dataTask(with: urlRequest) { data, response, error in + + DispatchQueue.main.async { + + guard error == nil else { + self.logMessage("HTTP request failed \(error?.localizedDescription ?? "ERROR")") + return + } + + guard let response = response as? HTTPURLResponse else { + self.logMessage("Non-HTTP response") + return + } + + guard let data = data else { + self.logMessage("HTTP response data is empty") + return + } + + var json: [AnyHashable: Any]? + + do { + json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] + } catch { + self.logMessage("JSON Serialization Error") + } + + if response.statusCode != 200 { + // server replied with an error + let responseText: String? = String(data: data, encoding: String.Encoding.utf8) + + if response.statusCode == 401 { + // "401 Unauthorized" generally indicates there is an issue with the authorization + // grant. Puts OIDAuthState into an error state. + let oauthError = OIDErrorUtilities.resourceServerAuthorizationError(withCode: 0, + errorResponse: json, + underlyingError: error) + self.authState?.update(withAuthorizationError: oauthError) + self.logMessage("Authorization Error (\(oauthError)). Response: \(responseText ?? "RESPONSE_TEXT")") + } else { + self.logMessage("HTTP: \(response.statusCode), Response: \(responseText ?? "RESPONSE_TEXT")") + } + + return + } + + if let json = json { + self.logMessage("Success: \(json)") + } + } + } + + task.resume() + } + } + + @IBAction func clearLogTextView(_ sender: UIButton) { + self.logTextView.text = "" + } +} + +//MARK: OIDAuthState Delegate +extension TodayViewController: OIDAuthStateChangeDelegate { + + func didChange(_ state: OIDAuthState) { + self.stateChanged() + } +} + +//MARK: Helper Methods +extension TodayViewController { + + func saveState() { + + var data: Data? = nil + + if let authState = self.authState { + data = NSKeyedArchiver.archivedData(withRootObject: authState) + } + + if let userDefaults = UserDefaults(suiteName: "group.net.openid.appauth.Example") { + userDefaults.set(data, forKey: kAppAuthExampleAuthStateKey) + userDefaults.synchronize() + } + } + + func loadState() { + guard let data = UserDefaults(suiteName: "group.net.openid.appauth.Example")?.object(forKey: kAppAuthExampleAuthStateKey) as? Data else { + return + } + + if let authState = NSKeyedUnarchiver.unarchiveObject(with: data) as? OIDAuthState { + self.setAuthState(authState) + } + } + + func setAuthState(_ authState: OIDAuthState?) { + if (self.authState == authState) { + return; + } + self.authState = authState; + self.authState?.stateChangeDelegate = self; + self.stateChanged() + } + + func stateChanged() { + self.saveState() + } + + func logMessage(_ message: String?) { + + guard let message = message else { + return + } + + print(message); + + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "hh:mm:ss"; + let dateString = dateFormatter.string(from: Date()) + + // appends to output log + DispatchQueue.main.async { + let logText = "\(self.logTextView.text ?? "")\n\(dateString): \(message)" + self.logTextView.text = logText + } + } +} diff --git a/Examples/Example-iOS_Swift-Carthage/Source/AppAuthExampleViewController.swift b/Examples/Example-iOS_Swift-Carthage/Source/AppAuthExampleViewController.swift index fe9c27242..f70540472 100644 --- a/Examples/Example-iOS_Swift-Carthage/Source/AppAuthExampleViewController.swift +++ b/Examples/Example-iOS_Swift-Carthage/Source/AppAuthExampleViewController.swift @@ -463,13 +463,15 @@ extension AppAuthExampleViewController { if let authState = self.authState { data = NSKeyedArchiver.archivedData(withRootObject: authState) } - - UserDefaults.standard.set(data, forKey: kAppAuthExampleAuthStateKey) - UserDefaults.standard.synchronize() + + if let userDefaults = UserDefaults(suiteName: "group.net.openid.appauth.Example") { + userDefaults.set(data, forKey: kAppAuthExampleAuthStateKey) + userDefaults.synchronize() + } } func loadState() { - guard let data = UserDefaults.standard.object(forKey: kAppAuthExampleAuthStateKey) as? Data else { + guard let data = UserDefaults(suiteName: "group.net.openid.appauth.Example")?.object(forKey: kAppAuthExampleAuthStateKey) as? Data else { return } diff --git a/Examples/Example-iOS_Swift-Carthage/Source/Example.entitlements b/Examples/Example-iOS_Swift-Carthage/Source/Example.entitlements new file mode 100644 index 000000000..c250a2746 --- /dev/null +++ b/Examples/Example-iOS_Swift-Carthage/Source/Example.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.net.openid.appauth.Example + + + diff --git a/Examples/Example-tvOS/Example-tvOS/AppAuthTVExampleViewController.m b/Examples/Example-tvOS/Example-tvOS/AppAuthTVExampleViewController.m index c65ee4e0d..3d461619d 100644 --- a/Examples/Example-tvOS/Example-tvOS/AppAuthTVExampleViewController.m +++ b/Examples/Example-tvOS/Example-tvOS/AppAuthTVExampleViewController.m @@ -22,7 +22,7 @@ #import /*! @brief Indicates whether YES to discover endpoints from @c kIssuer or NO to use the - @c kTVAuthorizationEndpoint, @c kTokenEndpoint, and @c kUserInfoEndpoint values defined + @c kDeviceAuthorizationEndpoint, @c kTokenEndpoint, and @c kUserInfoEndpoint values defined below. */ static BOOL const shouldDiscoverEndpoints = YES; @@ -41,7 +41,7 @@ /*! @brief Device authorization endpoint. */ -static NSString *const kTVAuthorizationEndpoint = @"https://www.example.com/device"; +static NSString *const kDeviceAuthorizationEndpoint = @"https://www.example.com/device"; /*! @brief Token endpoint. */ @@ -99,8 +99,8 @@ - (void)verifyConfig { "Instructions: " "https://github.com/openid/AppAuth-iOS/blob/master/Examples/Example-tvOS/README.md"); } else { - NSAssert(![kTVAuthorizationEndpoint isEqualToString:@"https://www.example.com/device"], - @"Update kTVAuthorizationEndpoint with your own TV authorization endpoint. " + NSAssert(![kDeviceAuthorizationEndpoint isEqualToString:@"https://www.example.com/device"], + @"Update kDeviceAuthorizationEndpoint with your own device authorization endpoint. " "Instructions: " "https://github.com/openid/AppAuth-iOS/blob/master/Examples/Example-tvOS/README.md"); @@ -155,12 +155,12 @@ - (IBAction)signin:(id)sender { [self performAuthorizationWithConfiguration:configuration]; }]; } else { - NSURL *TVAuthorizationEndpoint = [NSURL URLWithString:kTVAuthorizationEndpoint]; + NSURL *deviceAuthorizationEndpoint = [NSURL URLWithString:kDeviceAuthorizationEndpoint]; NSURL *tokenEndpoint = [NSURL URLWithString:kTokenEndpoint]; - OIDTVServiceConfiguration *configuration = - [[OIDTVServiceConfiguration alloc] initWithTVAuthorizationEndpoint:TVAuthorizationEndpoint - tokenEndpoint:tokenEndpoint]; + OIDTVServiceConfiguration *configuration = [[OIDTVServiceConfiguration alloc] + initWithDeviceAuthorizationEndpoint:deviceAuthorizationEndpoint + tokenEndpoint:tokenEndpoint]; // Perform authorization flow [self performAuthorizationWithConfiguration:configuration]; diff --git a/Examples/Example-tvOS/README.md b/Examples/Example-tvOS/README.md new file mode 100644 index 000000000..4787247b6 --- /dev/null +++ b/Examples/Example-tvOS/README.md @@ -0,0 +1,64 @@ +# Example Project + +## Setup & Open the Project + +1. In the `Example-tvOS` folder, run the following command to install the AppAuth pod with the TV +subspec. + +``` +pod install +``` + +2. Open the `Example-tvOS.xcworkspace` workspace. + +``` +open Example-tvOS.xcworkspace +``` + +This workspace is configured to include AppAuth via CocoaPods. You can also include AppAuthTV using +Carthage or Swift Package Manager, please see the main [README](../../README.md) for instructions. + +## Configuration + +The example doesn't work out of the box; you need to configure it with your own client and IdP details. + +### Information You'll Need + +* Client ID +* Client Secret (optional) + +If you are choosing to automatically discover endpoints: + +* Issuer URL + +If you are choosing to manually specify endpoints: + +* Device Authorization Endpoint +* Token Endpoint +* User Info Endpoint + +How to get this information varies by IdP, but we have +[instructions](../README.md#openid-certified-providers) for some OpenID Certified providers. + +### Configure the Example + +#### In the file `AppAuthTVExampleViewController.m` + +1. Update `kClientID` with your new client ID. +2. Update `kClientSecret` with your client ID's secret, or set to `""` if not using. + +If you are choosing to automatically discover endpoints, also: + +1. Update `kIssuer` with the issuer URL. +2. Set `shouldDiscoverEndpoints` to `YES` + +If you are choosing to manually specify endpoints, also: + +1. Set `shouldDiscoverEndpoints` to `NO` +2. Update `kDeviceAuthorizationEndpoint` with the device authorization endpoint. +3. Update `kTokenEndpoint` with the token endpoint. +4. Update `kUserInfoEndpoint` with the token endpoint. + +### Running the Example + +Now your example should be ready to run. diff --git a/Examples/README-Google.md b/Examples/README-Google.md index 5a9c3f720..5b572b60b 100644 --- a/Examples/README-Google.md +++ b/Examples/README-Google.md @@ -21,7 +21,6 @@ Then, setup the example with your configuration: | Client ID | The value named `Client ID` in the console, has the format `IDENTIFIER.apps.googleusercontent.com`.| | Client Secret | Google's iOS clients do not have a secret.| | Redirect URI | The value for `iOS URL scheme` wil be the scheme of your redirect URI. This is the Client ID in reverse domain name notation, e.g. ` com.googleusercontent.apps.IDENTIFIER`. To construct the redirect URI, add your own path component. E.g. ` com.googleusercontent.apps.IDENTIFIER:/oauth2redirect/google`. Note that there is only a single slash (`/`) after the scheme.| -| ## macOS @@ -36,3 +35,14 @@ Then, setup the example with your configuration: | Client Secret | The value named `Client secret` in the console.| | Redirect URI | For macOS, you can use either the loopback interface (where AppAuth will generate the redirect URI for you), or a custom scheme. To create a custom scheme redirect URI, reverse the client id to get the URI scheme, for example ` com.googleusercontent.apps.IDENTIFIER` and, add your own path component. E.g. `com.googleusercontent.apps.IDENTIFIER:/oauth2redirect/google`. Note that there is only a single slash (`/`) after the scheme.| +## tvOS + +Select "TVs and Limited Input devices" as the application type. + +Then, setup the example with your configuration. + +| Configuration | Description | +|---------------------------|------------------| +| Issuer | `https://accounts.google.com` | +| Client ID | The value named `Client ID` in the console, has the format `IDENTIFIER.apps.googleusercontent.com`.| +| Client Secret | The value named `Client secret` in the console.| diff --git a/Examples/README.md b/Examples/README.md index 2361d3d49..820c0d5bb 100644 --- a/Examples/README.md +++ b/Examples/README.md @@ -11,6 +11,7 @@ Each example has docs on how to configure: * [Example for iOS (Objective-C)](Example-iOS_ObjC/README.md) * [Example for iOS w/ Carthage (Objective-C)](Example-iOS_ObjC-Carthage/README.md) * [Example for macOS](Example-macOS/README.md) +* [Example for tvOS](Example-tvOS/README.md) To get the Issuer, Client ID, and Redirect URI, for your particular IdP, you may view the IdP-specific information in the next section. diff --git a/README.md b/README.md index 50ffc204a..051223462 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![Pod Platform](https://img.shields.io/cocoapods/p/AppAuth.svg?style=flat)](https://cocoapods.org/pods/AppAuth) [![Catalyst compatible](https://img.shields.io/badge/Catalyst-compatible-brightgreen.svg?style=flat)](https://developer.apple.com/documentation/xcode/creating_a_mac_version_of_your_ipad_app) -AppAuth for iOS and macOS is a client SDK for communicating with +AppAuth for iOS and macOS, and tvOS is a client SDK for communicating with [OAuth 2.0](https://tools.ietf.org/html/rfc6749) and [OpenID Connect](http://openid.net/specs/openid-connect-core-1_0.html) providers. It strives to @@ -30,6 +30,9 @@ custom URI scheme redirects are used. The library is friendly to other extensions (standard or otherwise), with the ability to handle additional params in all protocol requests and responses. +For tvOS, AppAuth implements [OAuth 2.0 Device Authorization Grant +](https://tools.ietf.org/html/rfc8628) to allow for tvOS sign-ins through a secondary device. + ## Specification ### iOS @@ -70,6 +73,16 @@ either through custom URI schemes, or loopback HTTP redirects. Authorization servers that assume all clients are web-based, or require clients to maintain confidentiality of the client secrets may not work well. +### tvOS + +#### Supported Versions + +AppAuth supports tvOS 9.0 and above. Please note that while it is possible to run the standard AppAuth library on tvOS, the documentation below describes implementing [OAuth 2.0 Device Authorization Grant](https://tools.ietf.org/html/rfc8628) (AppAuthTV). + +#### Authorization Server Requirements + +AppAuthTV is designed for servers that support the device authorization flow as documented in [RFC 8628](https://tools.ietf.org/html/rfc8628). + ## Try Want to try out AppAuth? Just run: @@ -84,6 +97,20 @@ client info to try the demo). AppAuth supports four options for dependency management. +### CocoaPods + +With [CocoaPods](https://guides.cocoapods.org/using/getting-started.html), +add the following line to your `Podfile`: + + pod 'AppAuth' + +Then, run `pod install`. + +**tvOS:** Use the `TV` subspec: + + pod 'AppAuth/TV' + + ### Swift Package Manager With [Swift Package Manager](https://swift.org/package-manager), @@ -95,14 +122,7 @@ dependencies: [ ] ``` -### CocoaPods - -With [CocoaPods](https://guides.cocoapods.org/using/getting-started.html), -add the following line to your `Podfile`: - - pod 'AppAuth' - -Then, run `pod install`. +**tvOS:** Use the `AppAuthTV` target. ### Carthage @@ -113,6 +133,8 @@ line to your `Cartfile`: Then, run `carthage bootstrap`. +**tvOS:** Use the `AppAuthTV` framework. + ### Static Library You can also use AppAuth as a static library. This requires linking the library @@ -125,6 +147,8 @@ Linked Framework and Libraries" section of your target). 4. Add `AppAuth-iOS/Source` to your search paths of your target ("Build Settings -> "Header Search Paths"). +*Note: There is no static library for AppAuthTV.* + ## Auth Flow AppAuth supports both manual interaction with the authorization server @@ -166,6 +190,24 @@ let configuration = OIDServiceConfiguration(authorizationEndpoint: authorization // perform the auth request... ``` +**tvOS** + +Objective-C +```objc +NSURL *deviceAuthorizationEndpoint = + [NSURL URLWithString:@"https://oauth2.googleapis.com/device/code"]; +NSURL *tokenEndpoint = + [NSURL URLWithString:@"https://www.googleapis.com/oauth2/v4/token"]; + +OIDTVServiceConfiguration *configuration = + [[OIDTVServiceConfiguration alloc] + initWithDeviceAuthorizationEndpoint:deviceAuthorizationEndpoint + tokenEndpoint:tokenEndpoint]; + +// perform the auth request... +``` + + Or through discovery: Objective-C @@ -201,6 +243,26 @@ OIDAuthorizationService.discoverConfiguration(forIssuer: issuer) { configuration } ``` +**tvOS** + +Objective-C +```objc +NSURL *issuer = [NSURL URLWithString:@"https://accounts.google.com"]; + +[OIDTVAuthorizationService discoverServiceConfigurationForIssuer:issuer + completion:^(OIDTVServiceConfiguration *_Nullable configuration, + NSError *_Nullable error) { + + if (!configuration) { + NSLog(@"Error retrieving discovery document: %@", + [error localizedDescription]); + return; + } + + // perform the auth request... +}]; +``` + ### Authorizing – iOS First, you need to have a property in your `UIApplicationDelegate` @@ -428,6 +490,63 @@ _redirectHTTPHandler.currentAuthorizationFlow = }]; ``` + +### Authorizing – tvOS + +Ensure that your main class is a delegate of `OIDAuthStateChangeDelegate`, `OIDAuthStateErrorDelegate`, implement the corresponding methods, and include the following property and instance variable: + +Objective-C +```objc +// property of the containing class +@property(nonatomic, strong, nullable) OIDAuthState *authState; + +// instance variable of the containing class +OIDTVAuthorizationCancelBlock _cancelBlock; +``` + +Then, build and perform the authorization request. + +Objective-C +```objc +// builds authentication request +__weak __typeof(self) weakSelf = self; + +OIDTVAuthorizationRequest *request = + [[OIDTVAuthorizationRequest alloc] initWithConfiguration:configuration + clientId:kClientID + clientSecret:kClientSecret + scopes:@[ OIDScopeOpenID, OIDScopeProfile ] + additionalParameters:nil]; + +// performs authentication request +OIDTVAuthorizationInitialization initBlock = + ^(OIDTVAuthorizationResponse *_Nullable response, NSError *_Nullable error) { + if (response) { + // process authorization response + NSLog(@"Got authorization response: %@", response); + } else { + // handle initialization error + NSLog(@"Error: %@", error); + } + }; + +OIDTVAuthorizationCompletion completionBlock = + ^(OIDAuthState *_Nullable authState, NSError *_Nullable error) { + weakSelf.signInView.hidden = YES; + if (authState) { + NSLog(@"Token response: %@", authState.lastTokenResponse); + [weakSelf setAuthState:authState]; + } else { + NSLog(@"Error: %@", error); + [weakSelf setAuthState:nil]; + } + }; + +_cancelBlock = [OIDTVAuthorizationService authorizeTVRequest:request + initialization:initBlock + completion:completionBlock]; +``` + ### Making API Calls AppAuth gives you the raw token information, if you need it. However, we @@ -470,7 +589,7 @@ self.authState?.performAction() { (accessToken, idToken, error) in } ``` -### Custom User-Agents +### Custom User-Agents (iOS and macOS) Each OAuth flow involves presenting an external user-agent to the user, that allows them to interact with the OAuth authorization server. Typical examples @@ -522,7 +641,7 @@ Include the `EnterpriseUserAgent` subspec alongside any pods/subspecs you were a Make sure to import `AppAuthEnterpriseUserAgent.h` in addition to `AppAuth.h` if you are using the full `AppAuth` functionality. ##### Carthage -Use the `AppAuthEnterpriseUserAgent` Framework, which includes all the headers of the `AppAuth` framework. +Use the `AppAuthEnterpriseUserAgent` framework, which includes all the headers of the `AppAuth` framework. Make sure to import ``. This includes all the files included by AppAuth/AppAuthCore, so only this import is necessary. ##### Swift Package Manager @@ -616,4 +735,4 @@ Browse the [API documentation](http://openid.github.io/AppAuth-iOS/docs/latest/a ## Included Samples -Sample apps that explore core AppAuth features are available for iOS and macOS; follow the instructions in [Examples/README.md](Examples/README.md) to get started. +Sample apps that explore core AppAuth features are available for iOS, macOS and tvOS; follow the instructions in [Examples/README.md](Examples/README.md) to get started. diff --git a/Source/AppAuthTV/OIDTVAuthorizationRequest.m b/Source/AppAuthTV/OIDTVAuthorizationRequest.m index 5d085beb2..da524d388 100644 --- a/Source/AppAuthTV/OIDTVAuthorizationRequest.m +++ b/Source/AppAuthTV/OIDTVAuthorizationRequest.m @@ -105,7 +105,7 @@ - (NSURLRequest *)URLRequest { OIDTVServiceConfiguration *tvConfiguration = (OIDTVServiceConfiguration *)self.configuration; NSMutableURLRequest *URLRequest = - [[NSURLRequest requestWithURL:tvConfiguration.TVAuthorizationEndpoint] mutableCopy]; + [[NSURLRequest requestWithURL:tvConfiguration.deviceAuthorizationEndpoint] mutableCopy]; URLRequest.HTTPMethod = kHTTPPost; [URLRequest setValue:kHTTPContentTypeHeaderValue forHTTPHeaderField:kHTTPContentTypeHeaderKey]; NSString *bodyString = [query URLEncodedParameters]; diff --git a/Source/AppAuthTV/OIDTVServiceConfiguration.h b/Source/AppAuthTV/OIDTVServiceConfiguration.h index bdedcdd10..2afea6cac 100644 --- a/Source/AppAuthTV/OIDTVServiceConfiguration.h +++ b/Source/AppAuthTV/OIDTVServiceConfiguration.h @@ -24,19 +24,19 @@ NS_ASSUME_NONNULL_BEGIN */ @interface OIDTVServiceConfiguration : OIDServiceConfiguration -/*! @brief The TV authorization endpoint URI. +/*! @brief The device authorization endpoint URI. */ -@property(nonatomic, readonly) NSURL *TVAuthorizationEndpoint; +@property(nonatomic, readonly) NSURL *deviceAuthorizationEndpoint; /*! @internal @brief Unavailable. Please use - @c initWithTVAuthorizationEndpoint:tokenEndpoint: + @c initWithDeviceAuthorizationEndpoint:tokenEndpoint: */ - (instancetype)init NS_UNAVAILABLE; /*! @internal @brief Unavailable. Please use - @c initWithTVAuthorizationEndpoint:tokenEndpoint: + @c initWithDeviceAuthorizationEndpoint:tokenEndpoint: */ - (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint tokenEndpoint:(NSURL *)tokenEndpoint NS_UNAVAILABLE; @@ -49,11 +49,12 @@ NS_ASSUME_NONNULL_BEGIN NS_DESIGNATED_INITIALIZER; /*! @brief Designated initializer. - @param TVAuthorizationEndpoint The TV authorization endpoint URI. + @param deviceAuthorizationEndpoint The device authorization endpoint URI. @param tokenEndpoint The token exchange and refresh endpoint URI. */ -- (instancetype)initWithTVAuthorizationEndpoint:(NSURL *)TVAuthorizationEndpoint - tokenEndpoint:(NSURL *)tokenEndpoint NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithDeviceAuthorizationEndpoint:(NSURL *)deviceAuthorizationEndpoint + tokenEndpoint:(NSURL *)tokenEndpoint + NS_DESIGNATED_INITIALIZER; @end diff --git a/Source/AppAuthTV/OIDTVServiceConfiguration.m b/Source/AppAuthTV/OIDTVServiceConfiguration.m index c20883d18..202aa9104 100644 --- a/Source/AppAuthTV/OIDTVServiceConfiguration.m +++ b/Source/AppAuthTV/OIDTVServiceConfiguration.m @@ -21,9 +21,9 @@ #import "OIDDefines.h" #import "OIDServiceDiscovery.h" -/*! @brief The key for the @c TVAuthorizationEndpoint property. +/*! @brief The key for the @c deviceAuthorizationEndpoint property. */ -static NSString *const kTVAuthorizationEndpointKey = @"TVAuthorizationEndpoint"; +static NSString *const kDeviceAuthorizationEndpointKey = @"deviceAuthorizationEndpoint"; NS_ASSUME_NONNULL_BEGIN @@ -39,11 +39,11 @@ - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIAL @implementation OIDTVServiceConfiguration - (instancetype)init - OID_UNAVAILABLE_USE_INITIALIZER(@selector(initWithTVAuthorizationEndpoint:tokenEndpoint:)) + OID_UNAVAILABLE_USE_INITIALIZER(@selector(initWithDeviceAuthorizationEndpoint:tokenEndpoint:)) - (instancetype)initWithAuthorizationEndpoint:(NSURL *)authorizationEndpoint tokenEndpoint:(NSURL *)tokenEndpoint - OID_UNAVAILABLE_USE_INITIALIZER(@selector(initWithTVAuthorizationEndpoint:tokenEndpoint:)) + OID_UNAVAILABLE_USE_INITIALIZER(@selector(initWithDeviceAuthorizationEndpoint:tokenEndpoint:)) - (instancetype)initWithDiscoveryDocument:(OIDServiceDiscovery *)discoveryDocument { self = [super initWithDiscoveryDocument:discoveryDocument]; @@ -53,18 +53,18 @@ - (instancetype)initWithDiscoveryDocument:(OIDServiceDiscovery *)discoveryDocume NSLog(@"Warning: Discovery document used to initialize %@ " @"does not contain device authorization endpoint.", self); } else { - _TVAuthorizationEndpoint = [discoveryDocument.deviceAuthorizationEndpoint copy]; + _deviceAuthorizationEndpoint = [discoveryDocument.deviceAuthorizationEndpoint copy]; } } return self; } -- (instancetype)initWithTVAuthorizationEndpoint:(NSURL *)TVAuthorizationEndpoint - tokenEndpoint:(NSURL *)tokenEndpoint { +- (instancetype)initWithDeviceAuthorizationEndpoint:(NSURL *)deviceAuthorizationEndpoint + tokenEndpoint:(NSURL *)tokenEndpoint { self = [super initWithAuthorizationEndpoint:[[NSURL alloc] initWithString:@""] tokenEndpoint:tokenEndpoint]; if (self) { - _TVAuthorizationEndpoint = [TVAuthorizationEndpoint copy]; + _deviceAuthorizationEndpoint = [deviceAuthorizationEndpoint copy]; } return self; } @@ -78,25 +78,25 @@ + (BOOL)supportsSecureCoding { - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { - NSURL *TVAuthorizationEndpoint = [aDecoder decodeObjectOfClass:[NSURL class] - forKey:kTVAuthorizationEndpointKey]; - _TVAuthorizationEndpoint = TVAuthorizationEndpoint; + NSURL *deviceAuthorizationEndpoint = + [aDecoder decodeObjectOfClass:[NSURL class] forKey:kDeviceAuthorizationEndpointKey]; + _deviceAuthorizationEndpoint = deviceAuthorizationEndpoint; } return self; } - (void)encodeWithCoder:(NSCoder *)aCoder { [super encodeWithCoder:aCoder]; - [aCoder encodeObject:_TVAuthorizationEndpoint forKey:kTVAuthorizationEndpointKey]; + [aCoder encodeObject:_deviceAuthorizationEndpoint forKey:kDeviceAuthorizationEndpointKey]; } #pragma mark - description - (NSString *)description { - return [NSString stringWithFormat:@"<%@: %p, TVAuthorizationEndpoint: %@ tokenEndpoint: %@>", + return [NSString stringWithFormat:@"<%@: %p, deviceAuthorizationEndpoint: %@ tokenEndpoint: %@>", NSStringFromClass([self class]), (void *)self, - _TVAuthorizationEndpoint, + _deviceAuthorizationEndpoint, self.tokenEndpoint]; } diff --git a/UnitTests/AppAuthTV/OIDTVAuthorizationRequestTests.h b/UnitTests/AppAuthTV/OIDTVAuthorizationRequestTests.h index 4a2fb49b0..d4198a448 100644 --- a/UnitTests/AppAuthTV/OIDTVAuthorizationRequestTests.h +++ b/UnitTests/AppAuthTV/OIDTVAuthorizationRequestTests.h @@ -33,14 +33,14 @@ NS_ASSUME_NONNULL_BEGIN - (void)testInitializer; /*! @brief Tests the @c NSCopying implementation by round-tripping an instance through the copying - * process and checking to make sure the source and destination both contain the - * @c TVAuthorizationEndpoint + * process and checking to make sure the source and destination both contain the + * @c deviceAuthorizationEndpoint */ - (void)testCopying; /*! @brief Tests the @c NSSecureCoding implementation by round-tripping an instance through the - * coding process and checking to make sure the source and destination both contain the - * @c TVAuthorizationEndpoint + * coding process and checking to make sure the source and destination both contain the + * @c deviceAuthorizationEndpoint */ - (void)testSecureCoding; diff --git a/UnitTests/AppAuthTV/OIDTVAuthorizationRequestTests.m b/UnitTests/AppAuthTV/OIDTVAuthorizationRequestTests.m index b86869c34..7b1d19c95 100644 --- a/UnitTests/AppAuthTV/OIDTVAuthorizationRequestTests.m +++ b/UnitTests/AppAuthTV/OIDTVAuthorizationRequestTests.m @@ -32,9 +32,9 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wgnu" -/*! @brief Test value for the @c TVAuthorizationEndpoint property. +/*! @brief Test value for the @c deviceAuthorizationEndpoint property. */ -static NSString *const kTestTVAuthorizationEndpoint = @"https://www.example.com/device/code"; +static NSString *const kTestDeviceAuthorizationEndpoint = @"https://www.example.com/device/code"; /*! @brief Test value for the @c tokenEndpoint property. */ @@ -89,10 +89,10 @@ @implementation OIDTVAuthorizationRequestTests - (OIDTVServiceConfiguration *)testServiceConfiguration { NSURL *tokenEndpoint = [NSURL URLWithString:kTestTokenEndpoint]; - NSURL *TVAuthorizationEndpoint = [NSURL URLWithString:kTestTVAuthorizationEndpoint]; + NSURL *deviceAuthorizationEndpoint = [NSURL URLWithString:kTestDeviceAuthorizationEndpoint]; OIDTVServiceConfiguration *configuration = - [[OIDTVServiceConfiguration alloc] initWithTVAuthorizationEndpoint:TVAuthorizationEndpoint + [[OIDTVServiceConfiguration alloc] initWithDeviceAuthorizationEndpoint:deviceAuthorizationEndpoint tokenEndpoint:tokenEndpoint]; return configuration; } @@ -131,8 +131,8 @@ - (void)testInitializer { scopes:testScopes additionalParameters:testAdditionalParameters]; - NSURL *authRequestTVAuthorizationEndpoint = - ((OIDTVServiceConfiguration *)authRequest.configuration).TVAuthorizationEndpoint; + NSURL *authRequestDeviceAuthorizationEndpoint = + ((OIDTVServiceConfiguration *)authRequest.configuration).deviceAuthorizationEndpoint; XCTAssertEqualObjects(authRequest.clientID, kTestClientID); XCTAssertEqualObjects(authRequest.clientSecret, kTestClientSecret); @@ -140,13 +140,13 @@ - (void)testInitializer { XCTAssertEqualObjects(authRequest.additionalParameters, testAdditionalParameters); XCTAssertEqualObjects(authRequest.responseType, OIDResponseTypeCode); XCTAssertEqualObjects(authRequest.redirectURL, [[NSURL alloc] initWithString:@""]); - XCTAssertEqualObjects(authRequestTVAuthorizationEndpoint, - serviceConfiguration.TVAuthorizationEndpoint); + XCTAssertEqualObjects(authRequestDeviceAuthorizationEndpoint, + serviceConfiguration.deviceAuthorizationEndpoint); } /*! @brief Tests the @c NSCopying implementation by round-tripping an instance through the copying - * process and checking to make sure the source and destination both contain the - * @c TVAuthorizationEndpoint + * process and checking to make sure the source and destination both contain the + * @c deviceAuthorizationEndpoint */ - (void)testCopying { OIDTVServiceConfiguration *serviceConfiguration = [self testServiceConfiguration]; @@ -159,16 +159,16 @@ - (void)testCopying { additionalParameters:nil]; OIDTVAuthorizationRequest *authRequestCopy = [authRequest copy]; - NSURL *authRequestCopyTVAuthorizationEndpoint = - ((OIDTVServiceConfiguration *)authRequestCopy.configuration).TVAuthorizationEndpoint; + NSURL *authRequestCopyDeviceAuthorizationEndpoint = + ((OIDTVServiceConfiguration *)authRequestCopy.configuration).deviceAuthorizationEndpoint; - XCTAssertEqualObjects(authRequestCopyTVAuthorizationEndpoint, - serviceConfiguration.TVAuthorizationEndpoint); + XCTAssertEqualObjects(authRequestCopyDeviceAuthorizationEndpoint, + serviceConfiguration.deviceAuthorizationEndpoint); } /*! @brief Tests the @c NSSecureCoding implementation by round-tripping an instance through the - * coding process and checking to make sure the source and destination both contain the - * @c TVAuthorizationEndpoint + * coding process and checking to make sure the source and destination both contain the + * @c deviceAuthorizationEndpoint */ - (void)testSecureCoding { OIDTVServiceConfiguration *serviceConfiguration = [self testServiceConfiguration]; @@ -183,11 +183,11 @@ - (void)testSecureCoding { NSData *data = [NSKeyedArchiver archivedDataWithRootObject:authRequest]; OIDTVAuthorizationRequest *authRequestCopy = [NSKeyedUnarchiver unarchiveObjectWithData:data]; - NSURL *authRequestCopyTVAuthorizationEndpoint = - ((OIDTVServiceConfiguration *)authRequestCopy.configuration).TVAuthorizationEndpoint; + NSURL *authRequestCopyDeviceAuthorizationEndpoint = + ((OIDTVServiceConfiguration *)authRequestCopy.configuration).deviceAuthorizationEndpoint; - XCTAssertEqualObjects(authRequestCopyTVAuthorizationEndpoint, - serviceConfiguration.TVAuthorizationEndpoint); + XCTAssertEqualObjects(authRequestCopyDeviceAuthorizationEndpoint, + serviceConfiguration.deviceAuthorizationEndpoint); } /*! @brief Tests the @c URLRequest method on a request with no scopes or additional parameters @@ -207,7 +207,7 @@ - (void)testURLRequestBasicClientAuth { XCTAssertEqualObjects(URLRequest.HTTPMethod, kHTTPPost); XCTAssertEqualObjects([URLRequest valueForHTTPHeaderField:kHTTPContentTypeHeaderKey], kHTTPContentTypeHeaderValue); - XCTAssertEqualObjects(URLRequest.URL, serviceConfiguration.TVAuthorizationEndpoint); + XCTAssertEqualObjects(URLRequest.URL, serviceConfiguration.deviceAuthorizationEndpoint); NSDictionary *bodyParameters = [self bodyParametersFromURLRequest:URLRequest]; @@ -238,7 +238,7 @@ - (void)testURLRequestScopes { XCTAssertEqualObjects([URLRequest HTTPMethod], kHTTPPost); XCTAssertEqualObjects([URLRequest valueForHTTPHeaderField:kHTTPContentTypeHeaderKey], kHTTPContentTypeHeaderValue); - XCTAssertEqualObjects(URLRequest.URL, serviceConfiguration.TVAuthorizationEndpoint); + XCTAssertEqualObjects(URLRequest.URL, serviceConfiguration.deviceAuthorizationEndpoint); NSDictionary *bodyParameters = [self bodyParametersFromURLRequest:URLRequest]; @@ -269,7 +269,7 @@ - (void)testURLRequestAdditionalParams { XCTAssertEqualObjects([URLRequest HTTPMethod], kHTTPPost); XCTAssertEqualObjects([URLRequest valueForHTTPHeaderField:kHTTPContentTypeHeaderKey], kHTTPContentTypeHeaderValue); - XCTAssertEqualObjects(URLRequest.URL, serviceConfiguration.TVAuthorizationEndpoint); + XCTAssertEqualObjects(URLRequest.URL, serviceConfiguration.deviceAuthorizationEndpoint); NSDictionary *bodyParameters = [self bodyParametersFromURLRequest:URLRequest]; diff --git a/UnitTests/AppAuthTV/OIDTVAuthorizationResponseTests.m b/UnitTests/AppAuthTV/OIDTVAuthorizationResponseTests.m index 00612fd8f..555f6e177 100644 --- a/UnitTests/AppAuthTV/OIDTVAuthorizationResponseTests.m +++ b/UnitTests/AppAuthTV/OIDTVAuthorizationResponseTests.m @@ -29,9 +29,9 @@ #import "Source/AppAuthTV/OIDTVTokenRequest.h" #endif -/*! @brief Test value for the @c TVAuthorizationEndpoint property. +/*! @brief Test value for the @c deviceAuthorizationEndpoint property. */ -static NSString *const kTestTVAuthorizationEndpoint = @"https://www.example.com/device/code"; +static NSString *const kTestDeviceAuthorizationEndpoint = @"https://www.example.com/device/code"; /*! @brief Test value for the @c tokenEndpoint property. */ @@ -110,10 +110,10 @@ @implementation OIDTVAuthorizationResponseTests - (OIDTVServiceConfiguration *)testServiceConfiguration { NSURL *tokenEndpoint = [NSURL URLWithString:kTestTokenEndpoint]; - NSURL *TVAuthorizationEndpoint = [NSURL URLWithString:kTestTVAuthorizationEndpoint]; + NSURL *deviceAuthorizationEndpoint = [NSURL URLWithString:kTestDeviceAuthorizationEndpoint]; OIDTVServiceConfiguration *configuration = - [[OIDTVServiceConfiguration alloc] initWithTVAuthorizationEndpoint:TVAuthorizationEndpoint + [[OIDTVServiceConfiguration alloc] initWithDeviceAuthorizationEndpoint:deviceAuthorizationEndpoint tokenEndpoint:tokenEndpoint]; return configuration; } diff --git a/UnitTests/AppAuthTV/OIDTVTokenRequestTests.m b/UnitTests/AppAuthTV/OIDTVTokenRequestTests.m index eecb48d35..cf0bf4963 100644 --- a/UnitTests/AppAuthTV/OIDTVTokenRequestTests.m +++ b/UnitTests/AppAuthTV/OIDTVTokenRequestTests.m @@ -33,9 +33,9 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wgnu" -/*! @brief Test value for the @c TVAuthorizationEndpoint property. +/*! @brief Test value for the @c deviceAuthorizationEndpoint property. */ -static NSString *const kTestTVAuthorizationEndpoint = +static NSString *const kTestDeviceAuthorizationEndpoint = @"https://www.example.com/device/code"; /*! @brief Test value for the @c tokenEndpoint property. @@ -106,11 +106,11 @@ @implementation OIDTVTokenRequestTests - (OIDTVServiceConfiguration *)testServiceConfiguration { NSURL *tokenEndpoint = [NSURL URLWithString:kTestTokenEndpoint]; - NSURL *TVAuthorizationEndpoint = [NSURL URLWithString:kTestTVAuthorizationEndpoint]; + NSURL *deviceAuthorizationEndpoint = [NSURL URLWithString:kTestDeviceAuthorizationEndpoint]; - OIDTVServiceConfiguration *configuration = - [[OIDTVServiceConfiguration alloc] initWithTVAuthorizationEndpoint:TVAuthorizationEndpoint - tokenEndpoint:tokenEndpoint]; + OIDTVServiceConfiguration *configuration = [[OIDTVServiceConfiguration alloc] + initWithDeviceAuthorizationEndpoint:deviceAuthorizationEndpoint + tokenEndpoint:tokenEndpoint]; return configuration; } @@ -128,11 +128,11 @@ - (OIDTVTokenRequest *)testTokenRequest { */ - (void)testInitializer { OIDTVTokenRequest *request = [self testTokenRequest]; - NSURL *requestTVAuthorizationEndpoint = - ((OIDTVServiceConfiguration *)request.configuration).TVAuthorizationEndpoint; - - XCTAssertEqualObjects(requestTVAuthorizationEndpoint, - [self testServiceConfiguration].TVAuthorizationEndpoint); + NSURL *requestDeviceAuthorizationEndpoint = + ((OIDTVServiceConfiguration *)request.configuration).deviceAuthorizationEndpoint; + + XCTAssertEqualObjects(requestDeviceAuthorizationEndpoint, + [self testServiceConfiguration].deviceAuthorizationEndpoint); XCTAssertEqualObjects(request.deviceCode, kDeviceCodeValue); XCTAssertEqualObjects(request.grantType, kOIDTVDeviceTokenGrantType); XCTAssertEqualObjects(request.clientID, kTestClientID);