diff --git a/AFOAuth2Manager.xcodeproj/project.pbxproj b/AFOAuth2Manager.xcodeproj/project.pbxproj index 1b886788..69fb6de5 100644 --- a/AFOAuth2Manager.xcodeproj/project.pbxproj +++ b/AFOAuth2Manager.xcodeproj/project.pbxproj @@ -7,31 +7,69 @@ objects = { /* Begin PBXBuildFile section */ - 2934F28E1C15D9BE008B8AE4 /* AFOAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 2934F28C1C15D9BE008B8AE4 /* AFOAuthCredential.h */; }; + 2934F28E1C15D9BE008B8AE4 /* AFOAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 2934F28C1C15D9BE008B8AE4 /* AFOAuthCredential.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2934F28F1C15D9BE008B8AE4 /* AFOAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 2934F28D1C15D9BE008B8AE4 /* AFOAuthCredential.m */; }; - 29490FD51BE11C5100893BE1 /* AFHTTPRequestSerializer+OAuth2.h in Headers */ = {isa = PBXBuildFile; fileRef = 29490FD11BE11C5100893BE1 /* AFHTTPRequestSerializer+OAuth2.h */; }; - 29490FD71BE11C5100893BE1 /* AFOAuth2Manager.h in Headers */ = {isa = PBXBuildFile; fileRef = 29490FD31BE11C5100893BE1 /* AFOAuth2Manager.h */; }; + 2934F2D01C15F374008B8AE4 /* AFOAuth2Manager.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29490FC51BE11BD700893BE1 /* AFOAuth2Manager.framework */; }; + 2934F2D71C15F3C6008B8AE4 /* AFNetworking.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 29490FDC1BE11CBB00893BE1 /* AFNetworking.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 2934F2D81C15F3CD008B8AE4 /* AFNetworking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29490FDC1BE11CBB00893BE1 /* AFNetworking.framework */; }; + 2934F2DA1C15F44E008B8AE4 /* AFOAuthManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2934F2D91C15F44E008B8AE4 /* AFOAuthManagerTests.m */; }; + 2934F2DC1C15FE8C008B8AE4 /* AFOAuthCredentialTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2934F2DB1C15FE8C008B8AE4 /* AFOAuthCredentialTests.m */; }; + 29490FD51BE11C5100893BE1 /* AFHTTPRequestSerializer+OAuth2.h in Headers */ = {isa = PBXBuildFile; fileRef = 29490FD11BE11C5100893BE1 /* AFHTTPRequestSerializer+OAuth2.h */; settings = {ATTRIBUTES = (Public, ); }; }; 29490FDD1BE11CBB00893BE1 /* AFNetworking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29490FDC1BE11CBB00893BE1 /* AFNetworking.framework */; }; - 29490FE01BE11D1000893BE1 /* AFOAuth2SessionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 29490FDE1BE11D1000893BE1 /* AFOAuth2SessionManager.h */; }; - 29490FE11BE11D1000893BE1 /* AFOAuth2SessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 29490FDF1BE11D1000893BE1 /* AFOAuth2SessionManager.m */; }; + 29490FE01BE11D1000893BE1 /* AFOAuth2Manager.h in Headers */ = {isa = PBXBuildFile; fileRef = 29490FDE1BE11D1000893BE1 /* AFOAuth2Manager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 29490FE11BE11D1000893BE1 /* AFOAuth2Manager.m in Sources */ = {isa = PBXBuildFile; fileRef = 29490FDF1BE11D1000893BE1 /* AFOAuth2Manager.m */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 2934F2D11C15F374008B8AE4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29490FBC1BE11BD700893BE1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 29490FC41BE11BD700893BE1; + remoteInfo = "AFOAuth2Manager iOS"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 2934F2D61C15F3BD008B8AE4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 2934F2D71C15F3C6008B8AE4 /* AFNetworking.framework in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 2934F28C1C15D9BE008B8AE4 /* AFOAuthCredential.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFOAuthCredential.h; sourceTree = ""; }; 2934F28D1C15D9BE008B8AE4 /* AFOAuthCredential.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFOAuthCredential.m; sourceTree = ""; }; + 2934F2CB1C15F373008B8AE4 /* AFOAuth2Manager iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "AFOAuth2Manager iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2934F2CF1C15F374008B8AE4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 2934F2D91C15F44E008B8AE4 /* AFOAuthManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFOAuthManagerTests.m; sourceTree = ""; }; + 2934F2DB1C15FE8C008B8AE4 /* AFOAuthCredentialTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFOAuthCredentialTests.m; sourceTree = ""; }; 29490FC51BE11BD700893BE1 /* AFOAuth2Manager.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AFOAuth2Manager.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 29490FD11BE11C5100893BE1 /* AFHTTPRequestSerializer+OAuth2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AFHTTPRequestSerializer+OAuth2.h"; sourceTree = ""; }; 29490FD21BE11C5100893BE1 /* AFHTTPRequestSerializer+OAuth2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "AFHTTPRequestSerializer+OAuth2.m"; sourceTree = ""; }; - 29490FD31BE11C5100893BE1 /* AFOAuth2Manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFOAuth2Manager.h; sourceTree = ""; }; - 29490FD41BE11C5100893BE1 /* AFOAuth2Manager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFOAuth2Manager.m; sourceTree = ""; }; 29490FDA1BE11C5C00893BE1 /* AFOAuth2Manager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AFOAuth2Manager.h; sourceTree = ""; }; 29490FDB1BE11C5C00893BE1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 29490FDC1BE11CBB00893BE1 /* AFNetworking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AFNetworking.framework; path = Carthage/Build/iOS/AFNetworking.framework; sourceTree = ""; }; - 29490FDE1BE11D1000893BE1 /* AFOAuth2SessionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFOAuth2SessionManager.h; sourceTree = ""; }; - 29490FDF1BE11D1000893BE1 /* AFOAuth2SessionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFOAuth2SessionManager.m; sourceTree = ""; }; + 29490FDE1BE11D1000893BE1 /* AFOAuth2Manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFOAuth2Manager.h; sourceTree = ""; }; + 29490FDF1BE11D1000893BE1 /* AFOAuth2Manager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFOAuth2Manager.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 2934F2C81C15F373008B8AE4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2934F2D01C15F374008B8AE4 /* AFOAuth2Manager.framework in Frameworks */, + 2934F2D81C15F3CD008B8AE4 /* AFNetworking.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 29490FC11BE11BD700893BE1 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -43,12 +81,23 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 2934F2CC1C15F374008B8AE4 /* Tests */ = { + isa = PBXGroup; + children = ( + 2934F2CF1C15F374008B8AE4 /* Info.plist */, + 2934F2D91C15F44E008B8AE4 /* AFOAuthManagerTests.m */, + 2934F2DB1C15FE8C008B8AE4 /* AFOAuthCredentialTests.m */, + ); + path = Tests; + sourceTree = ""; + }; 29490FBB1BE11BD700893BE1 = { isa = PBXGroup; children = ( 29490FDC1BE11CBB00893BE1 /* AFNetworking.framework */, 29490FD01BE11C5100893BE1 /* AFOAuth2Manager */, 29490FD91BE11C5C00893BE1 /* Resources */, + 2934F2CC1C15F374008B8AE4 /* Tests */, 29490FC61BE11BD700893BE1 /* Products */, ); sourceTree = ""; @@ -57,6 +106,7 @@ isa = PBXGroup; children = ( 29490FC51BE11BD700893BE1 /* AFOAuth2Manager.framework */, + 2934F2CB1C15F373008B8AE4 /* AFOAuth2Manager iOS Tests.xctest */, ); name = Products; sourceTree = ""; @@ -66,10 +116,8 @@ children = ( 29490FD11BE11C5100893BE1 /* AFHTTPRequestSerializer+OAuth2.h */, 29490FD21BE11C5100893BE1 /* AFHTTPRequestSerializer+OAuth2.m */, - 29490FD31BE11C5100893BE1 /* AFOAuth2Manager.h */, - 29490FD41BE11C5100893BE1 /* AFOAuth2Manager.m */, - 29490FDE1BE11D1000893BE1 /* AFOAuth2SessionManager.h */, - 29490FDF1BE11D1000893BE1 /* AFOAuth2SessionManager.m */, + 29490FDE1BE11D1000893BE1 /* AFOAuth2Manager.h */, + 29490FDF1BE11D1000893BE1 /* AFOAuth2Manager.m */, 2934F28C1C15D9BE008B8AE4 /* AFOAuthCredential.h */, 2934F28D1C15D9BE008B8AE4 /* AFOAuthCredential.m */, ); @@ -93,8 +141,7 @@ buildActionMask = 2147483647; files = ( 2934F28E1C15D9BE008B8AE4 /* AFOAuthCredential.h in Headers */, - 29490FE01BE11D1000893BE1 /* AFOAuth2SessionManager.h in Headers */, - 29490FD71BE11C5100893BE1 /* AFOAuth2Manager.h in Headers */, + 29490FE01BE11D1000893BE1 /* AFOAuth2Manager.h in Headers */, 29490FD51BE11C5100893BE1 /* AFHTTPRequestSerializer+OAuth2.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -102,6 +149,25 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 2934F2CA1C15F373008B8AE4 /* AFOAuth2Manager iOS Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2934F2D51C15F374008B8AE4 /* Build configuration list for PBXNativeTarget "AFOAuth2Manager iOS Tests" */; + buildPhases = ( + 2934F2C71C15F373008B8AE4 /* Sources */, + 2934F2C81C15F373008B8AE4 /* Frameworks */, + 2934F2C91C15F373008B8AE4 /* Resources */, + 2934F2D61C15F3BD008B8AE4 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 2934F2D21C15F374008B8AE4 /* PBXTargetDependency */, + ); + name = "AFOAuth2Manager iOS Tests"; + productName = "AFOAuth2Manager iOS Tests"; + productReference = 2934F2CB1C15F373008B8AE4 /* AFOAuth2Manager iOS Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 29490FC41BE11BD700893BE1 /* AFOAuth2Manager iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 29490FCD1BE11BD700893BE1 /* Build configuration list for PBXNativeTarget "AFOAuth2Manager iOS" */; @@ -129,6 +195,9 @@ LastUpgradeCheck = 0710; ORGANIZATIONNAME = Alamofire; TargetAttributes = { + 2934F2CA1C15F373008B8AE4 = { + CreatedOnToolsVersion = 7.1.1; + }; 29490FC41BE11BD700893BE1 = { CreatedOnToolsVersion = 7.1; }; @@ -147,11 +216,19 @@ projectRoot = ""; targets = ( 29490FC41BE11BD700893BE1 /* AFOAuth2Manager iOS */, + 2934F2CA1C15F373008B8AE4 /* AFOAuth2Manager iOS Tests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 2934F2C91C15F373008B8AE4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 29490FC31BE11BD700893BE1 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -162,18 +239,63 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 2934F2C71C15F373008B8AE4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2934F2DA1C15F44E008B8AE4 /* AFOAuthManagerTests.m in Sources */, + 2934F2DC1C15FE8C008B8AE4 /* AFOAuthCredentialTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 29490FC01BE11BD700893BE1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 29490FE11BE11D1000893BE1 /* AFOAuth2SessionManager.m in Sources */, + 29490FE11BE11D1000893BE1 /* AFOAuth2Manager.m in Sources */, 2934F28F1C15D9BE008B8AE4 /* AFOAuthCredential.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 2934F2D21C15F374008B8AE4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 29490FC41BE11BD700893BE1 /* AFOAuth2Manager iOS */; + targetProxy = 2934F2D11C15F374008B8AE4 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ + 2934F2D31C15F374008B8AE4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.alamofire.AFOAuth2Manager-iOS-Tests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 2934F2D41C15F374008B8AE4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.alamofire.AFOAuth2Manager-iOS-Tests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; 29490FCB1BE11BD700893BE1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -305,6 +427,14 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 2934F2D51C15F374008B8AE4 /* Build configuration list for PBXNativeTarget "AFOAuth2Manager iOS Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2934F2D31C15F374008B8AE4 /* Debug */, + 2934F2D41C15F374008B8AE4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; 29490FBF1BE11BD700893BE1 /* Build configuration list for PBXProject "AFOAuth2Manager" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/AFOAuth2Manager.xcodeproj/xcshareddata/xcschemes/AFOAuth2Manager iOS.xcscheme b/AFOAuth2Manager.xcodeproj/xcshareddata/xcschemes/AFOAuth2Manager iOS.xcscheme index 7cbe5d50..aeb40149 100644 --- a/AFOAuth2Manager.xcodeproj/xcshareddata/xcschemes/AFOAuth2Manager iOS.xcscheme +++ b/AFOAuth2Manager.xcodeproj/xcshareddata/xcschemes/AFOAuth2Manager iOS.xcscheme @@ -26,9 +26,29 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> + + + + + + + + diff --git a/AFOAuth2Manager/AFOAuth2Manager.h b/AFOAuth2Manager/AFOAuth2Manager.h index f7f325a6..66517596 100644 --- a/AFOAuth2Manager/AFOAuth2Manager.h +++ b/AFOAuth2Manager/AFOAuth2Manager.h @@ -18,22 +18,15 @@ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import - -#import +// THE SOFTWARE +#import @class AFOAuthCredential; +@import AFNetworking; -/** - `AFOAuth2Manager` encapsulates common patterns to authenticate against a resource server conforming to the behavior outlined in the OAuth 2.0 specification. - - In your application, it is recommended that you use `AFOAuth2Manager` exclusively to get an authorization token, which is then passed to another `AFHTTPClient` subclass. +NS_ASSUME_NONNULL_BEGIN - @see RFC 6749 The OAuth 2.0 Authorization Framework: http://tools.ietf.org/html/rfc6749 - */ -@interface AFOAuth2Manager : AFHTTPRequestOperationManager +@interface AFOAuth2Manager : AFHTTPSessionManager ///------------------------------------------ /// @name Accessing OAuth 2 Client Properties @@ -55,7 +48,7 @@ @property (nonatomic, assign) BOOL useHTTPBasicAuthentication; ///------------------------------------------------ -/// @name Creating and Initializing OAuth 2 Clients +/// @name Creating and Initializing OAuth 2 Managers ///------------------------------------------------ /** @@ -65,16 +58,21 @@ @param clientID The client identifier issued by the authorization server, uniquely representing the registration information provided by the client. This argument must not be `nil`. @param secret The client secret. - @return The newly-initialized OAuth 2 client + @return The newly-initialized OAuth 2 manager */ -+ (instancetype)clientWithBaseURL:(NSURL *)url - clientID:(NSString *)clientID - secret:(NSString *)secret; ++ (instancetype)managerWithBaseURL:(NSURL *)url + clientID:(NSString *)clientID + secret:(NSString *)secret; + ++ (instancetype)managerWithBaseURL:(NSURL *)url + sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration + clientID:(NSString *)clientID + secret:(NSString *)secret; /** Initializes an `AFOAuth2Manager` object with the specified base URL, client identifier, and secret. The communication to to the server will use HTTP basic auth by default (use `-(id)initWithBaseURL:clientID:secret:withBasicAuth:` to change this). - @param url The base URL for the HTTP client. This argument must not be `nil`. + @param url The base URL for the HTTP manager. This argument must not be `nil`. @param clientID The client identifier issued by the authorization server, uniquely representing the registration information provided by the client. This argument must not be `nil`. @param secret The client secret. @@ -84,12 +82,17 @@ clientID:(NSString *)clientID secret:(NSString *)secret; +- (id)initWithBaseURL:(NSURL *)url + sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration + clientID:(NSString *)clientID + secret:(NSString *)secret; + ///--------------------- /// @name Authenticating ///--------------------- /** - Creates and enqueues an `AFHTTPRequestOperation` to authenticate against the server using a specified username and password, with a designated scope. + Creates and enqueues an `NSURLSessionTask` to authenticate against the server using a specified username and password, with a designated scope. @param URLString The URL string used to create the request URL. @param username The username used for authentication @@ -98,199 +101,64 @@ @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server. @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server. */ -- (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLString - username:(NSString *)username - password:(NSString *)password - scope:(NSString *)scope - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure; +- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString + username:(NSString *)username + password:(NSString *)password + scope:(nullable NSString *)scope + success:(void (^)(AFOAuthCredential *credential))success + failure:(void (^)(NSError *error))failure; /** - Creates and enqueues an `AFHTTPRequestOperation` to authenticate against the server with a designated scope. + Creates and enqueues an `NSURLSessionTask` to authenticate against the server with a designated scope. @param URLString The URL string used to create the request URL. @param scope The authorization scope @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server. @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server. */ -- (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLString - scope:(NSString *)scope - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure; +- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString + scope:(nullable NSString *)scope + success:(void (^)(AFOAuthCredential *credential))success + failure:(void (^)(NSError *error))failure; /** - Creates and enqueues an `AFHTTPRequestOperation` to authenticate against the server using the specified refresh token. - + Creates and enqueues an `NSURLSessionTask` to authenticate against the server using the specified refresh token. @param URLString The URL string used to create the request URL. @param refreshToken The OAuth refresh token @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server. @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server. */ -- (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLString - refreshToken:(NSString *)refreshToken - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure; +- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString + refreshToken:(NSString *)refreshToken + success:(void (^)(AFOAuthCredential *credential))success + failure:(void (^)(NSError *error))failure; /** - Creates and enqueues an `AFHTTPRequestOperation` to authenticate against the server with an authorization code, redirecting to a specified URI upon successful authentication. - + Creates and enqueues an `NSURLSessionTask` to authenticate against the server with an authorization code, redirecting to a specified URI upon successful authentication. @param URLString The URL string used to create the request URL. @param code The authorization code @param uri The URI to redirect to after successful authentication @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server. @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server. */ -- (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLString - code:(NSString *)code - redirectURI:(NSString *)uri - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure; +- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString + code:(NSString *)code + redirectURI:(NSString *)uri + success:(void (^)(AFOAuthCredential *credential))success + failure:(void (^)(NSError *error))failure; /** - Creates and enqueues an `AFHTTPRequestOperation` to authenticate against the server with the specified parameters. + Creates and enqueues an `NSURLSessionTask` to authenticate against the server with the specified parameters. @param URLString The URL string used to create the request URL. @param parameters The parameters to be encoded and set in the request HTTP body. @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server. @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server. */ -- (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLString - parameters:(NSDictionary *)parameters - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure; - -@end - -#pragma mark - - -/** - `AFOAuthCredential` models the credentials returned from an OAuth server, storing the token type, access & refresh tokens, and whether the token is expired. - - OAuth credentials can be stored in the user's keychain, and retrieved on subsequent launches. - */ -@interface AFOAuthCredential : NSObject - -///-------------------------------------- -/// @name Accessing Credential Properties -///-------------------------------------- - -/** - The OAuth access token. - */ -@property (readonly, nonatomic, copy) NSString *accessToken; - -/** - The OAuth token type (e.g. "bearer"). - */ -@property (readonly, nonatomic, copy) NSString *tokenType; - -/** - The OAuth refresh token. - */ -@property (readonly, nonatomic, copy) NSString *refreshToken; - -/** - Whether the OAuth credentials are expired. - */ -@property (readonly, nonatomic, assign, getter = isExpired) BOOL expired; - -///-------------------------------------------- -/// @name Creating and Initializing Credentials -///-------------------------------------------- - -/** - Create an OAuth credential from a token string, with a specified type. - - @param token The OAuth token string. - @param type The OAuth token type. - */ -+ (instancetype)credentialWithOAuthToken:(NSString *)token - tokenType:(NSString *)type; - -/** - Initialize an OAuth credential from a token string, with a specified type. - - @param token The OAuth token string. - @param type The OAuth token type. - */ -- (id)initWithOAuthToken:(NSString *)token - tokenType:(NSString *)type; - -///---------------------------- -/// @name Setting Refresh Token -///---------------------------- - -/** - Set the credential refresh token, without a specific expiration - - @param refreshToken The OAuth refresh token. - */ -- (void)setRefreshToken:(NSString *)refreshToken; - - -/** - Set the expiration on the access token. If no expiration is given by the OAuth2 provider, - you may pass in [NSDate distantFuture] - - @param expiration The expiration of the access token. This must not be `nil`. - */ -- (void)setExpiration:(NSDate *)expiration; - -/** - Set the credential refresh token, with a specified expiration. - - @param refreshToken The OAuth refresh token. - @param expiration The expiration of the access token. This must not be `nil`. - */ -- (void)setRefreshToken:(NSString *)refreshToken - expiration:(NSDate *)expiration; - -///----------------------------------------- -/// @name Storing and Retrieving Credentials -///----------------------------------------- - -/** - Stores the specified OAuth credential for a given web service identifier in the Keychain. - with the default Keychain Accessibilty of kSecAttrAccessibleWhenUnlocked. - - @param credential The OAuth credential to be stored. - @param identifier The service identifier associated with the specified credential. - - @return Whether or not the credential was stored in the keychain. - */ -+ (BOOL)storeCredential:(AFOAuthCredential *)credential - withIdentifier:(NSString *)identifier; - -/** - Stores the specified OAuth token for a given web service identifier in the Keychain. - - @param credential The OAuth credential to be stored. - @param identifier The service identifier associated with the specified token. - @param securityAccessibility The Keychain security accessibility to store the credential with. - - @return Whether or not the credential was stored in the keychain. - */ -+ (BOOL)storeCredential:(AFOAuthCredential *)credential - withIdentifier:(NSString *)identifier - withAccessibility:(id)securityAccessibility; - -/** - Retrieves the OAuth credential stored with the specified service identifier from the Keychain. - - @param identifier The service identifier associated with the specified credential. - - @return The retrieved OAuth credential. - */ -+ (AFOAuthCredential *)retrieveCredentialWithIdentifier:(NSString *)identifier; - -/** - Deletes the OAuth credential stored with the specified service identifier from the Keychain. - - @param identifier The service identifier associated with the specified credential. - - @return Whether or not the credential was deleted from the keychain. - */ -+ (BOOL)deleteCredentialWithIdentifier:(NSString *)identifier; +- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString + parameters:(NSDictionary *)parameters + success:(void (^)(AFOAuthCredential *credential))success + failure:(void (^)(NSError *error))failure; @end @@ -300,15 +168,10 @@ /** ## Error Domains - The following error domain is predefined. - - `NSString * const AFOAuth2ErrorDomain` - ## OAuth Grant Types - OAuth 2.0 provides several grant types, covering several different use cases. The following grant type string constants are provided: - `kAFOAuthCodeGrantType`: "authorization_code" `kAFOAuthClientCredentialsGrantType`: "client_credentials" `kAFOAuthPasswordCredentialsGrantType`: "password" @@ -323,3 +186,5 @@ extern NSString * const kAFOAuthRefreshGrantType; @compatibility_alias AFOAuth2Client AFOAuth2Manager; @compatibility_alias AFOAuth2RequestOperationManager AFOAuth2Manager; + +NS_ASSUME_NONNULL_END diff --git a/AFOAuth2Manager/AFOAuth2Manager.m b/AFOAuth2Manager/AFOAuth2Manager.m index 13424444..88d83f11 100644 --- a/AFOAuth2Manager/AFOAuth2Manager.m +++ b/AFOAuth2Manager/AFOAuth2Manager.m @@ -18,30 +18,17 @@ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import +// THE SOFTWARE #import "AFOAuth2Manager.h" +#import "AFOAuthCredential.h" -NSString * const AFOAuth2ErrorDomain = @"com.alamofire.networking.oauth2.error"; - -NSString * const kAFOAuthCodeGrantType = @"authorization_code"; NSString * const kAFOAuthClientCredentialsGrantType = @"client_credentials"; NSString * const kAFOAuthPasswordCredentialsGrantType = @"password"; +NSString * const kAFOAuthCodeGrantType = @"authorization_code"; NSString * const kAFOAuthRefreshGrantType = @"refresh_token"; -NSString * const kAFOAuth2CredentialServiceName = @"AFOAuthCredentialService"; - -static NSDictionary * AFKeychainQueryDictionaryWithIdentifier(NSString *identifier) { - NSCParameterAssert(identifier); - - return @{ - (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, - (__bridge id)kSecAttrService: kAFOAuth2CredentialServiceName, - (__bridge id)kSecAttrAccount: identifier - }; -} +NSString * const AFOAuth2ErrorDomain = @"com.alamofire.networking.oauth2.error"; // See: http://tools.ietf.org/html/rfc6749#section-5.2 static NSError * AFErrorFromRFC6749Section5_2Error(id object) { @@ -79,42 +66,54 @@ return [NSError errorWithDomain:AFOAuth2ErrorDomain code:-1 userInfo:mutableUserInfo]; } -#pragma mark - - -@interface AFOAuth2Manager () +@interface AFOAuth2Manager() @property (readwrite, nonatomic, copy) NSString *serviceProviderIdentifier; @property (readwrite, nonatomic, copy) NSString *clientID; @property (readwrite, nonatomic, copy) NSString *secret; + @end @implementation AFOAuth2Manager -+ (instancetype)clientWithBaseURL:(NSURL *)url - clientID:(NSString *)clientID - secret:(NSString *)secret -{ - return [[self alloc] initWithBaseURL:url clientID:clientID secret:secret]; ++ (instancetype) managerWithBaseURL:(NSURL *)url + clientID:(NSString *)clientID + secret:(NSString *)secret { + return [self managerWithBaseURL:url sessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] clientID:clientID secret:secret]; +} + ++ (instancetype) managerWithBaseURL:(NSURL *)url + sessionConfiguration:(NSURLSessionConfiguration *)configuration + clientID:(NSString *)clientID + secret:(NSString *)secret { + return [[self alloc] initWithBaseURL:url sessionConfiguration:configuration clientID:clientID secret:secret]; } - (id)initWithBaseURL:(NSURL *)url clientID:(NSString *)clientID - secret:(NSString *)secret -{ + secret:(NSString *)secret { + return [self initWithBaseURL:url sessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] clientID:clientID secret:secret]; +} + +- (id)initWithBaseURL:(NSURL *)url + sessionConfiguration:(NSURLSessionConfiguration *)configuration + clientID:(NSString *)clientID + secret:(NSString *)secret { + NSParameterAssert(url); NSParameterAssert(clientID); + NSParameterAssert(secret); - self = [super initWithBaseURL:url]; + self = [super initWithBaseURL:url sessionConfiguration:configuration]; if (!self) { return nil; } - + self.serviceProviderIdentifier = [self.baseURL host]; self.clientID = clientID; self.secret = secret; - self.useHTTPBasicAuthentication = YES; [self.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"]; - + return self; } @@ -138,64 +137,65 @@ - (void)setSecret:(NSString *)secret { _secret = secret; } -#pragma mark - +#pragma mark - -- (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLString - username:(NSString *)username - password:(NSString *)password - scope:(NSString *)scope - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure -{ +- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString + username:(NSString *)username + password:(NSString *)password + scope:(NSString *)scope + success:(void (^)(AFOAuthCredential * _Nonnull))success + failure:(void (^)(NSError * _Nonnull))failure { NSParameterAssert(username); NSParameterAssert(password); - NSParameterAssert(scope); - NSDictionary *parameters = @{ - @"grant_type": kAFOAuthPasswordCredentialsGrantType, - @"username": username, - @"password": password, - @"scope": scope - }; + NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; + [parameters setValue:kAFOAuthPasswordCredentialsGrantType forKey:@"grant_type"]; + [parameters setValue:username forKey:@"username"]; + [parameters setValue:password forKey:@"password"]; + + if (scope) { + [parameters setValue:scope forKey:@"scope"]; + } return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure]; } -- (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLString - scope:(NSString *)scope - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure -{ - NSParameterAssert(scope); +- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString + scope:(NSString *)scope + success:(void (^)(AFOAuthCredential * _Nonnull))success + failure:(void (^)(NSError * _Nonnull))failure { - NSDictionary *parameters = @{ - @"grant_type": kAFOAuthClientCredentialsGrantType, - @"scope": scope - }; + NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; + [parameters setValue:kAFOAuthClientCredentialsGrantType forKey:@"grant_type"]; + + if (scope) { + [parameters setValue:scope forKey:@"scope"]; + } return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure]; } -- (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLString - refreshToken:(NSString *)refreshToken - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure + +- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString + refreshToken:(NSString *)refreshToken + success:(void (^)(AFOAuthCredential *credential))success + failure:(void (^)(NSError *error))failure { NSParameterAssert(refreshToken); NSDictionary *parameters = @{ @"grant_type": kAFOAuthRefreshGrantType, @"refresh_token": refreshToken - }; + }; return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure]; } -- (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLString - code:(NSString *)code - redirectURI:(NSString *)uri - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure +- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString + code:(NSString *)code + redirectURI:(NSString *)uri + success:(void (^)(AFOAuthCredential *credential))success + failure:(void (^)(NSError *error))failure { NSParameterAssert(code); NSParameterAssert(uri); @@ -204,15 +204,15 @@ - (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLS @"grant_type": kAFOAuthCodeGrantType, @"code": code, @"redirect_uri": uri - }; + }; return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure]; } -- (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLString - parameters:(NSDictionary *)parameters - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure +- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString + parameters:(NSDictionary *)parameters + success:(void (^)(AFOAuthCredential *credential))success + failure:(void (^)(NSError *error))failure { NSMutableDictionary *mutableParameters = [NSMutableDictionary dictionaryWithDictionary:parameters]; if (!self.useHTTPBasicAuthentication) { @@ -221,12 +221,12 @@ - (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLS } parameters = [NSDictionary dictionaryWithDictionary:mutableParameters]; - AFHTTPRequestOperation *requestOperation = [self POST:URLString parameters:parameters success:^(__unused AFHTTPRequestOperation *operation, id responseObject) { + NSURLSessionTask *task; + task = [self POST:URLString parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { if (!responseObject) { if (failure) { failure(nil); } - return; } @@ -234,8 +234,6 @@ - (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLS if (failure) { failure(AFErrorFromRFC6749Section5_2Error(responseObject)); } - - return; } NSString *refreshToken = [responseObject valueForKey:@"refresh_token"]; @@ -264,167 +262,14 @@ - (AFHTTPRequestOperation *)authenticateUsingOAuthWithURLString:(NSString *)URLS if (success) { success(credential); } - } failure:^(__unused AFHTTPRequestOperation *operation, NSError *error) { + + } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { if (failure) { failure(error); } }]; - - return requestOperation; -} - -@end - -#pragma mark - - -@interface AFOAuthCredential () -@property (readwrite, nonatomic, copy) NSString *accessToken; -@property (readwrite, nonatomic, copy) NSString *tokenType; -@property (readwrite, nonatomic, copy) NSString *refreshToken; -@property (readwrite, nonatomic, copy) NSDate *expiration; -@end - -@implementation AFOAuthCredential -@dynamic expired; - -#pragma mark - - -+ (instancetype)credentialWithOAuthToken:(NSString *)token - tokenType:(NSString *)type -{ - return [[self alloc] initWithOAuthToken:token tokenType:type]; -} - -- (id)initWithOAuthToken:(NSString *)token - tokenType:(NSString *)type -{ - self = [super init]; - if (!self) { - return nil; - } - - self.accessToken = token; - self.tokenType = type; - - return self; -} - -- (NSString *)description { - return [NSString stringWithFormat:@"<%@ accessToken:\"%@\" tokenType:\"%@\" refreshToken:\"%@\" expiration:\"%@\">", [self class], self.accessToken, self.tokenType, self.refreshToken, self.expiration]; -} - -- (void)setRefreshToken:(NSString *)refreshToken -{ - _refreshToken = refreshToken; -} - -- (void)setExpiration:(NSDate *)expiration -{ - _expiration = expiration; -} - -- (void)setRefreshToken:(NSString *)refreshToken - expiration:(NSDate *)expiration -{ - NSParameterAssert(refreshToken); - NSParameterAssert(expiration); - - self.refreshToken = refreshToken; - self.expiration = expiration; -} - -- (BOOL)isExpired { - return [self.expiration compare:[NSDate date]] == NSOrderedAscending; -} - -#pragma mark Keychain - -+ (BOOL)storeCredential:(AFOAuthCredential *)credential - withIdentifier:(NSString *)identifier -{ - id securityAccessibility = nil; -#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 43000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wtautological-compare" - if (&kSecAttrAccessibleWhenUnlocked != NULL) { - securityAccessibility = (__bridge id)kSecAttrAccessibleWhenUnlocked; - } -#pragma clang diagnostic pop -#endif - - return [[self class] storeCredential:credential withIdentifier:identifier withAccessibility:securityAccessibility]; -} - -+ (BOOL)storeCredential:(AFOAuthCredential *)credential - withIdentifier:(NSString *)identifier - withAccessibility:(id)securityAccessibility -{ - NSMutableDictionary *queryDictionary = [AFKeychainQueryDictionaryWithIdentifier(identifier) mutableCopy]; - - if (!credential) { - return [self deleteCredentialWithIdentifier:identifier]; - } - - NSMutableDictionary *updateDictionary = [NSMutableDictionary dictionary]; - updateDictionary[(__bridge id)kSecValueData] = [NSKeyedArchiver archivedDataWithRootObject:credential]; - - if (securityAccessibility) { - updateDictionary[(__bridge id)kSecAttrAccessible] = securityAccessibility; - } - - OSStatus status; - BOOL exists = ([self retrieveCredentialWithIdentifier:identifier] != nil); - - if (exists) { - status = SecItemUpdate((__bridge CFDictionaryRef)queryDictionary, (__bridge CFDictionaryRef)updateDictionary); - } else { - [queryDictionary addEntriesFromDictionary:updateDictionary]; - status = SecItemAdd((__bridge CFDictionaryRef)queryDictionary, NULL); - } - - return (status == errSecSuccess); -} - -+ (BOOL)deleteCredentialWithIdentifier:(NSString *)identifier { - NSMutableDictionary *queryDictionary = [AFKeychainQueryDictionaryWithIdentifier(identifier) mutableCopy]; - - OSStatus status = SecItemDelete((__bridge CFDictionaryRef)queryDictionary); - - return (status == errSecSuccess); -} - -+ (AFOAuthCredential *)retrieveCredentialWithIdentifier:(NSString *)identifier { - NSMutableDictionary *queryDictionary = [AFKeychainQueryDictionaryWithIdentifier(identifier) mutableCopy]; - queryDictionary[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue; - queryDictionary[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne; - - CFDataRef result = nil; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)queryDictionary, (CFTypeRef *)&result); - - if (status != errSecSuccess) { - return nil; - } - - return [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)result]; -} - -#pragma mark - NSCoding - -- (id)initWithCoder:(NSCoder *)decoder { - self = [super init]; - self.accessToken = [decoder decodeObjectForKey:NSStringFromSelector(@selector(accessToken))]; - self.tokenType = [decoder decodeObjectForKey:NSStringFromSelector(@selector(tokenType))]; - self.refreshToken = [decoder decodeObjectForKey:NSStringFromSelector(@selector(refreshToken))]; - self.expiration = [decoder decodeObjectForKey:NSStringFromSelector(@selector(expiration))]; - - return self; -} -- (void)encodeWithCoder:(NSCoder *)encoder { - [encoder encodeObject:self.accessToken forKey:NSStringFromSelector(@selector(accessToken))]; - [encoder encodeObject:self.tokenType forKey:NSStringFromSelector(@selector(tokenType))]; - [encoder encodeObject:self.refreshToken forKey:NSStringFromSelector(@selector(refreshToken))]; - [encoder encodeObject:self.expiration forKey:NSStringFromSelector(@selector(expiration))]; + return task; } @end diff --git a/AFOAuth2Manager/AFOAuth2SessionManager.h b/AFOAuth2Manager/AFOAuth2SessionManager.h deleted file mode 100644 index 1b84814c..00000000 --- a/AFOAuth2Manager/AFOAuth2SessionManager.h +++ /dev/null @@ -1,139 +0,0 @@ -// AFOAuth2SessionManager.h -// -// Copyright (c) 2012-2014 AFNetworking (http://afnetworking.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE - -#import -@class AFOAuthCredential; -@import AFNetworking; - -NS_ASSUME_NONNULL_BEGIN - -@interface AFOAuth2SessionManager : AFHTTPSessionManager - -///------------------------------------------ -/// @name Accessing OAuth 2 Client Properties -///------------------------------------------ - -/** - The service provider identifier used to store and retrieve OAuth credentials by `AFOAuthCredential`. Equivalent to the hostname of the client `baseURL`. - */ -@property (readonly, nonatomic, copy) NSString *serviceProviderIdentifier; - -/** - The client identifier issued by the authorization server, uniquely representing the registration information provided by the client. - */ -@property (readonly, nonatomic, copy) NSString *clientID; - -/** - Whether to encode client credentials in a Base64-encoded HTTP `Authorization` header, as opposed to the request body. Defaults to `YES`. - */ -@property (nonatomic, assign) BOOL useHTTPBasicAuthentication; - -///------------------------------------------------ -/// @name Creating and Initializing OAuth 2 Managers -///------------------------------------------------ - -/** - Creates and initializes an `AFOAuth2SessionManager` object with the specified base URL, client identifier, and secret. - - @param url The base URL for the HTTP client. This argument must not be `nil`. - @param clientID The client identifier issued by the authorization server, uniquely representing the registration information provided by the client. This argument must not be `nil`. - @param secret The client secret. - - @return The newly-initialized OAuth 2 manager - */ -+ (instancetype)managerWithBaseURL:(NSURL *)url - clientID:(NSString *)clientID - secret:(NSString *)secret; - -+ (instancetype)managerWithBaseURL:(NSURL *)url - sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration - clientID:(NSString *)clientID - secret:(NSString *)secret; - -/** - Initializes an `AFOAuth2SessionManager` object with the specified base URL, client identifier, and secret. The communication to to the server will use HTTP basic auth by default (use `-(id)initWithBaseURL:clientID:secret:withBasicAuth:` to change this). - - @param url The base URL for the HTTP manager. This argument must not be `nil`. - @param clientID The client identifier issued by the authorization server, uniquely representing the registration information provided by the client. This argument must not be `nil`. - @param secret The client secret. - - @return The newly-initialized OAuth 2 client - */ -- (id)initWithBaseURL:(NSURL *)url - clientID:(NSString *)clientID - secret:(NSString *)secret; - -- (id)initWithBaseURL:(NSURL *)url - sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration - clientID:(NSString *)clientID - secret:(NSString *)secret; - -///--------------------- -/// @name Authenticating -///--------------------- - -/** - Creates and enqueues an `NSURLSessionTask` to authenticate against the server using a specified username and password, with a designated scope. - - @param URLString The URL string used to create the request URL. - @param username The username used for authentication - @param password The password used for authentication - @param scope The authorization scope - @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server. - @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server. - */ -- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString - username:(NSString *)username - password:(NSString *)password - scope:(NSString *)scope - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure; - -/** - Creates and enqueues an `NSURLSessionTask` to authenticate against the server with a designated scope. - - @param URLString The URL string used to create the request URL. - @param scope The authorization scope - @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server. - @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server. - */ -- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString - scope:(NSString *)scope - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure; - -/** - Creates and enqueues an `NSURLSessionTask` to authenticate against the server with the specified parameters. - - @param URLString The URL string used to create the request URL. - @param parameters The parameters to be encoded and set in the request HTTP body. - @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server. - @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server. - */ -- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString - parameters:(NSDictionary *)parameters - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AFOAuth2Manager/AFOAuth2SessionManager.m b/AFOAuth2Manager/AFOAuth2SessionManager.m deleted file mode 100644 index af8c2013..00000000 --- a/AFOAuth2Manager/AFOAuth2SessionManager.m +++ /dev/null @@ -1,273 +0,0 @@ -// AFOAuth2SessionManager.m -// -// Copyright (c) 2012-2014 AFNetworking (http://afnetworking.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE - -#import "AFOAuth2SessionManager.h" -#import "AFOAuthCredential.h" - -NSString * const kAFOAuthClientCredentialsGrantType = @"client_credentials"; -NSString * const kAFOAuthPasswordCredentialsGrantType = @"password"; -NSString * const kAFOAuthCodeGrantType = @"authorization_code"; -NSString * const kAFOAuthRefreshGrantType = @"refresh_token"; - -NSString * const AFOAuth2ErrorDomain = @"com.alamofire.networking.oauth2.error"; - -// See: http://tools.ietf.org/html/rfc6749#section-5.2 -static NSError * AFErrorFromRFC6749Section5_2Error(id object) { - if (![object valueForKey:@"error"] || [[object valueForKey:@"error"] isEqual:[NSNull null]]) { - return nil; - } - - NSMutableDictionary *mutableUserInfo = [NSMutableDictionary dictionary]; - - NSString *description = nil; - if ([object valueForKey:@"error_description"]) { - description = [object valueForKey:@"error_description"]; - } else { - if ([[object valueForKey:@"error"] isEqualToString:@"invalid_request"]) { - description = NSLocalizedStringFromTable(@"The request is missing a required parameter, includes an unsupported parameter value (other than grant type), repeats a parameter, includes multiple credentials, utilizes more than one mechanism for authenticating the client, or is otherwise malformed.", @"AFOAuth2Manager", @"invalid_request"); - } else if ([[object valueForKey:@"error"] isEqualToString:@"invalid_client"]) { - description = NSLocalizedStringFromTable(@"Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The authorization server MAY return an HTTP 401 (Unauthorized) status code to indicate which HTTP authentication schemes are supported. If the client attempted to authenticate via the \"Authorization\" request header field, the authorization server MUST respond with an HTTP 401 (Unauthorized) status code and include the \"WWW-Authenticate\" response header field matching the authentication scheme used by the client.", @"AFOAuth2Manager", @"invalid_request"); - } else if ([[object valueForKey:@"error"] isEqualToString:@"invalid_grant"]) { - description = NSLocalizedStringFromTable(@"The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.", @"AFOAuth2Manager", @"invalid_request"); - } else if ([[object valueForKey:@"error"] isEqualToString:@"unauthorized_client"]) { - description = NSLocalizedStringFromTable(@"The authenticated client is not authorized to use this authorization grant type.", @"AFOAuth2Manager", @"invalid_request"); - } else if ([[object valueForKey:@"error"] isEqualToString:@"unsupported_grant_type"]) { - description = NSLocalizedStringFromTable(@"The authorization grant type is not supported by the authorization server.", @"AFOAuth2Manager", @"invalid_request"); - } - } - - if (description) { - mutableUserInfo[NSLocalizedDescriptionKey] = description; - } - - if ([object valueForKey:@"error_uri"]) { - mutableUserInfo[NSLocalizedRecoverySuggestionErrorKey] = [object valueForKey:@"error_uri"]; - } - - return [NSError errorWithDomain:AFOAuth2ErrorDomain code:-1 userInfo:mutableUserInfo]; -} - -@interface AFOAuth2SessionManager() -@property (readwrite, nonatomic, copy) NSString *serviceProviderIdentifier; -@property (readwrite, nonatomic, copy) NSString *clientID; -@property (readwrite, nonatomic, copy) NSString *secret; - -@end - -@implementation AFOAuth2SessionManager - -+ (instancetype) managerWithBaseURL:(NSURL *)url - clientID:(NSString *)clientID - secret:(NSString *)secret { - return [self managerWithBaseURL:url sessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] clientID:clientID secret:secret]; -} - -+ (instancetype) managerWithBaseURL:(NSURL *)url - sessionConfiguration:(NSURLSessionConfiguration *)configuration - clientID:(NSString *)clientID - secret:(NSString *)secret { - return [[self alloc] initWithBaseURL:url sessionConfiguration:configuration clientID:clientID secret:secret]; -} - -- (id)initWithBaseURL:(NSURL *)url - clientID:(NSString *)clientID - secret:(NSString *)secret { - return [self initWithBaseURL:url sessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] clientID:clientID secret:secret]; -} - -- (id)initWithBaseURL:(NSURL *)url - sessionConfiguration:(NSURLSessionConfiguration *)configuration - clientID:(NSString *)clientID - secret:(NSString *)secret { - NSParameterAssert(url); - NSParameterAssert(clientID); - NSParameterAssert(secret); - - self = [super initWithBaseURL:url sessionConfiguration:configuration]; - if (!self) { - return nil; - } - - self.serviceProviderIdentifier = [self.baseURL host]; - self.clientID = clientID; - self.secret = secret; - self.useHTTPBasicAuthentication = YES; - - [self.requestSerializer setValue:@"application/json" forKey:@"Accept"]; - - return self; -} - -#pragma mark - - -- (void)setUseHTTPBasicAuthentication:(BOOL)useHTTPBasicAuthentication { - _useHTTPBasicAuthentication = useHTTPBasicAuthentication; - - if (self.useHTTPBasicAuthentication) { - [self.requestSerializer setAuthorizationHeaderFieldWithUsername:self.clientID password:self.secret]; - } else { - [self.requestSerializer setValue:nil forHTTPHeaderField:@"Authorization"]; - } -} - -- (void)setSecret:(NSString *)secret { - if (!secret) { - secret = @""; - } - - _secret = secret; -} - -#pragma mark - - -- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString - username:(NSString *)username - password:(NSString *)password - scope:(NSString *)scope - success:(void (^)(AFOAuthCredential * _Nonnull))success - failure:(void (^)(NSError * _Nonnull))failure { - NSParameterAssert(username); - NSParameterAssert(password); - NSParameterAssert(scope); - - NSDictionary *parameters = @{ - @"grant_type": kAFOAuthPasswordCredentialsGrantType, - @"username": username, - @"password": password, - @"scope": scope - }; - - return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure]; -} - -- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString - scope:(NSString *)scope - success:(void (^)(AFOAuthCredential * _Nonnull))success - failure:(void (^)(NSError * _Nonnull))failure { - NSParameterAssert(scope); - - NSDictionary *parameters = @{ - @"grant_type": kAFOAuthClientCredentialsGrantType, - @"scope": scope - }; - - return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure]; -} - - -- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString - refreshToken:(NSString *)refreshToken - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure -{ - NSParameterAssert(refreshToken); - - NSDictionary *parameters = @{ - @"grant_type": kAFOAuthRefreshGrantType, - @"refresh_token": refreshToken - }; - - return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure]; -} - -- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString - code:(NSString *)code - redirectURI:(NSString *)uri - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure -{ - NSParameterAssert(code); - NSParameterAssert(uri); - - NSDictionary *parameters = @{ - @"grant_type": kAFOAuthCodeGrantType, - @"code": code, - @"redirect_uri": uri - }; - - return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure]; -} - -- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString - parameters:(NSDictionary *)parameters - success:(void (^)(AFOAuthCredential *credential))success - failure:(void (^)(NSError *error))failure -{ - NSMutableDictionary *mutableParameters = [NSMutableDictionary dictionaryWithDictionary:parameters]; - if (!self.useHTTPBasicAuthentication) { - mutableParameters[@"client_id"] = self.clientID; - mutableParameters[@"client_secret"] = self.secret; - } - parameters = [NSDictionary dictionaryWithDictionary:mutableParameters]; - - NSURLSessionTask *task; - task = [self POST:URLString parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { - if (!responseObject) { - if (failure) { - failure(nil); - } - return; - } - - if ([responseObject valueForKey:@"error"]) { - if (failure) { - failure(AFErrorFromRFC6749Section5_2Error(responseObject)); - } - } - - NSString *refreshToken = [responseObject valueForKey:@"refresh_token"]; - if (!refreshToken || [refreshToken isEqual:[NSNull null]]) { - refreshToken = [parameters valueForKey:@"refresh_token"]; - } - - AFOAuthCredential *credential = [AFOAuthCredential credentialWithOAuthToken:[responseObject valueForKey:@"access_token"] tokenType:[responseObject valueForKey:@"token_type"]]; - - - if (refreshToken) { // refreshToken is optional in the OAuth2 spec - [credential setRefreshToken:refreshToken]; - } - - // Expiration is optional, but recommended in the OAuth2 spec. It not provide, assume distantFuture === never expires - NSDate *expireDate = [NSDate distantFuture]; - id expiresIn = [responseObject valueForKey:@"expires_in"]; - if (expiresIn && ![expiresIn isEqual:[NSNull null]]) { - expireDate = [NSDate dateWithTimeIntervalSinceNow:[expiresIn doubleValue]]; - } - - if (expireDate) { - [credential setExpiration:expireDate]; - } - - if (success) { - success(credential); - } - - } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { - if (failure) { - failure(error); - } - }]; - - return task; -} - -@end diff --git a/AFOAuth2Manager/AFOAuthCredential.h b/AFOAuth2Manager/AFOAuthCredential.h index 354c38d1..be97d5f4 100644 --- a/AFOAuth2Manager/AFOAuthCredential.h +++ b/AFOAuth2Manager/AFOAuthCredential.h @@ -22,6 +22,8 @@ #import +NS_ASSUME_NONNULL_BEGIN + /** `AFOAuthCredential` models the credentials returned from an OAuth server, storing the token type, access & refresh tokens, and whether the token is expired. @@ -140,7 +142,7 @@ @return The retrieved OAuth credential. */ -+ (AFOAuthCredential *)retrieveCredentialWithIdentifier:(NSString *)identifier; ++ (nullable AFOAuthCredential *)retrieveCredentialWithIdentifier:(NSString *)identifier; /** Deletes the OAuth credential stored with the specified service identifier from the Keychain. @@ -152,3 +154,5 @@ + (BOOL)deleteCredentialWithIdentifier:(NSString *)identifier; @end + +NS_ASSUME_NONNULL_END diff --git a/AFOAuth2Manager/AFOAuthCredential.m b/AFOAuth2Manager/AFOAuthCredential.m index 4e3ab116..ce6ceeeb 100644 --- a/AFOAuth2Manager/AFOAuthCredential.m +++ b/AFOAuth2Manager/AFOAuthCredential.m @@ -119,10 +119,6 @@ + (BOOL)storeCredential:(AFOAuthCredential *)credential { NSMutableDictionary *queryDictionary = [AFKeychainQueryDictionaryWithIdentifier(identifier) mutableCopy]; - if (!credential) { - return [self deleteCredentialWithIdentifier:identifier]; - } - NSMutableDictionary *updateDictionary = [NSMutableDictionary dictionary]; updateDictionary[(__bridge id)kSecValueData] = [NSKeyedArchiver archivedDataWithRootObject:credential]; diff --git a/Resources/AFOAuth2Manager.h b/Resources/AFOAuth2Manager.h index 27543ce5..42ee4385 100644 --- a/Resources/AFOAuth2Manager.h +++ b/Resources/AFOAuth2Manager.h @@ -15,5 +15,7 @@ FOUNDATION_EXPORT double AFOAuth2ManagerVersionNumber; FOUNDATION_EXPORT const unsigned char AFOAuth2ManagerVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import - +#import +#import +#import diff --git a/Tests/AFOAuthCredentialTests.m b/Tests/AFOAuthCredentialTests.m new file mode 100644 index 00000000..33d37781 --- /dev/null +++ b/Tests/AFOAuthCredentialTests.m @@ -0,0 +1,52 @@ +// +// AFOAuthCredentialTests.m +// AFOAuth2Manager +// +// Created by Kevin Harwood on 12/7/15. +// Copyright © 2015 Alamofire. All rights reserved. +// + +#import +#import "AFOAuthCredential.h" + +@interface AFOAuthCredentialTests : XCTestCase + +@end + +@implementation AFOAuthCredentialTests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testCredentialExpiration { + AFOAuthCredential *credential = [[AFOAuthCredential alloc] initWithOAuthToken:@"token" tokenType:@"Bearer"]; + [credential setExpiration:[NSDate distantPast]]; + XCTAssertTrue(credential.expired); + + [credential setRefreshToken:@"refresh" expiration:[NSDate distantFuture]]; + XCTAssertFalse(credential.expired); +} + +- (void)testCredentialStorage { + AFOAuthCredential *credential = [[AFOAuthCredential alloc] initWithOAuthToken:@"token" tokenType:@"Bearer"]; + NSString *identifier = [[NSUUID UUID] UUIDString]; + XCTAssertTrue([AFOAuthCredential storeCredential:credential withIdentifier:identifier]); + + [credential setRefreshToken:@"updated_token" expiration:[NSDate distantFuture]]; + XCTAssertTrue([AFOAuthCredential storeCredential:credential withIdentifier:identifier]); + + AFOAuthCredential *retrievedCred = [AFOAuthCredential retrieveCredentialWithIdentifier:identifier]; + XCTAssertNotNil(retrievedCred); + + XCTAssertTrue([retrievedCred.refreshToken isEqualToString:credential.refreshToken]); + + XCTAssertTrue([AFOAuthCredential deleteCredentialWithIdentifier:identifier]); +} +@end diff --git a/Tests/AFOAuthManagerTests.m b/Tests/AFOAuthManagerTests.m new file mode 100644 index 00000000..c8236262 --- /dev/null +++ b/Tests/AFOAuthManagerTests.m @@ -0,0 +1,73 @@ +// AFOAuthManagerTests.m +// +// Copyright (c) 2012-2014 AFNetworking (http://afnetworking.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFOAuthCredential.h" +#import "AFOAuth2Manager.h" + +@interface AFOAuthManagerTests : XCTestCase + +@property (nonatomic, strong) NSURL *baseURL; + +@end + +@implementation AFOAuthManagerTests + +- (void)setUp { + + //Demo OAuth2 App: http://brentertainment.com/oauth2/ + self.baseURL = [NSURL URLWithString:@"http://brentertainment.com/oauth2/"]; + [super setUp]; +} + +- (void)tearDown { + [super tearDown]; +} + +- (void)testUserCredentialsSucceedsWithNoBasicAuthentication { + AFOAuth2Manager *manager = [[AFOAuth2Manager alloc] initWithBaseURL:self.baseURL + clientID:@"demoapp" + secret:@"demopass"]; + manager.useHTTPBasicAuthentication = NO; + + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; + + [manager + authenticateUsingOAuthWithURLString:@"lockdin/token" + username:@"demouser" + password:@"testpass" + scope:nil + success:^(AFOAuthCredential * _Nonnull credential) { + XCTAssertNotNil(credential); + XCTAssertNotNil(credential.accessToken); + XCTAssertTrue([credential.tokenType isEqualToString:@"Bearer"]); + XCTAssertNotNil(credential.refreshToken); + [expectation fulfill]; + } + failure:^(NSError * _Nonnull error) { + XCTFail(@"Request should succeed"); + }]; + + [self waitForExpectationsWithTimeout:10.0 handler:nil]; +} + +@end diff --git a/Tests/Info.plist b/Tests/Info.plist new file mode 100644 index 00000000..ba72822e --- /dev/null +++ b/Tests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + +