Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Agios 193 #1

Merged
merged 2 commits into from Sep 16, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 16 additions & 4 deletions AeroGearOAuth2.xcodeproj/project.pbxproj
Expand Up @@ -8,10 +8,13 @@

/* Begin PBXBuildFile section */
48070BF819B07AA000FCE5FA /* ConfigTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48070BF719B07AA000FCE5FA /* ConfigTest.swift */; };
4814EF4B19C1C0FA008BAC4D /* TrustedPersistantOAuth2Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4814EF4919C1C0FA008BAC4D /* TrustedPersistantOAuth2Session.swift */; };
4814EF4C19C1C0FA008BAC4D /* UntrustedMemoryOAuth2Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4814EF4A19C1C0FA008BAC4D /* UntrustedMemoryOAuth2Session.swift */; };
4814EF4E19C1C10C008BAC4D /* FacebookOAuth2Module.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4814EF4D19C1C10C008BAC4D /* FacebookOAuth2Module.swift */; };
4833046819AF1635002F8DA9 /* AeroGearOAuth2.h in Headers */ = {isa = PBXBuildFile; fileRef = 4833046719AF1635002F8DA9 /* AeroGearOAuth2.h */; settings = {ATTRIBUTES = (Public, ); }; };
4833047219AF1635002F8DA9 /* AeroGearOAuth2Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4833047119AF1635002F8DA9 /* AeroGearOAuth2Tests.swift */; };
483304A019AF327D002F8DA9 /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4833049F19AF327D002F8DA9 /* AccountManager.swift */; };
483304A519AF44DF002F8DA9 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = 483304A419AF44DF002F8DA9 /* Config.swift */; };
48C94D8019C1F0970000ABBB /* OAuth2ModuleTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48C94D7F19C1F0970000ABBB /* OAuth2ModuleTest.swift */; };
48CD52D719B0C1CB008D0694 /* OAuth2Module.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CD52D619B0C1CB008D0694 /* OAuth2Module.swift */; };
48CD52DD19B0C22A008D0694 /* OAuth2Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CD52DC19B0C22A008D0694 /* OAuth2Session.swift */; };
48CD52DF19B0CB5A008D0694 /* Oauth2SessionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CD52DE19B0CB5A008D0694 /* Oauth2SessionTest.swift */; };
Expand Down Expand Up @@ -50,16 +53,19 @@

/* Begin PBXFileReference section */
48070BF719B07AA000FCE5FA /* ConfigTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigTest.swift; sourceTree = "<group>"; };
4814EF4919C1C0FA008BAC4D /* TrustedPersistantOAuth2Session.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrustedPersistantOAuth2Session.swift; sourceTree = "<group>"; };
4814EF4A19C1C0FA008BAC4D /* UntrustedMemoryOAuth2Session.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UntrustedMemoryOAuth2Session.swift; sourceTree = "<group>"; };
4814EF4D19C1C10C008BAC4D /* FacebookOAuth2Module.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FacebookOAuth2Module.swift; sourceTree = "<group>"; };
4833046219AF1635002F8DA9 /* AeroGearOAuth2.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AeroGearOAuth2.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4833046619AF1635002F8DA9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4833046719AF1635002F8DA9 /* AeroGearOAuth2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AeroGearOAuth2.h; sourceTree = "<group>"; };
4833046D19AF1635002F8DA9 /* AeroGearOAuth2Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AeroGearOAuth2Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
4833047019AF1635002F8DA9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4833047119AF1635002F8DA9 /* AeroGearOAuth2Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AeroGearOAuth2Tests.swift; sourceTree = "<group>"; };
4833047B19AF28AD002F8DA9 /* AGURLSessionStubs.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AGURLSessionStubs.xcodeproj; path = "aerogear-ios-httpstub/AGURLSessionStubs.xcodeproj"; sourceTree = SOURCE_ROOT; };
4833048419AF28D9002F8DA9 /* AeroGearHttp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AeroGearHttp.xcodeproj; path = "aerogear-ios-http/AeroGearHttp.xcodeproj"; sourceTree = SOURCE_ROOT; };
4833049F19AF327D002F8DA9 /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = "<group>"; };
483304A419AF44DF002F8DA9 /* Config.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = "<group>"; };
48C94D7F19C1F0970000ABBB /* OAuth2ModuleTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OAuth2ModuleTest.swift; sourceTree = "<group>"; };
48CD52D619B0C1CB008D0694 /* OAuth2Module.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OAuth2Module.swift; sourceTree = "<group>"; };
48CD52DC19B0C22A008D0694 /* OAuth2Session.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OAuth2Session.swift; sourceTree = "<group>"; };
48CD52DE19B0CB5A008D0694 /* Oauth2SessionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Oauth2SessionTest.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -110,6 +116,9 @@
483304A419AF44DF002F8DA9 /* Config.swift */,
48CD52D619B0C1CB008D0694 /* OAuth2Module.swift */,
48CD52DC19B0C22A008D0694 /* OAuth2Session.swift */,
4814EF4919C1C0FA008BAC4D /* TrustedPersistantOAuth2Session.swift */,
4814EF4A19C1C0FA008BAC4D /* UntrustedMemoryOAuth2Session.swift */,
4814EF4D19C1C10C008BAC4D /* FacebookOAuth2Module.swift */,
);
path = AeroGearOAuth2;
sourceTree = "<group>";
Expand All @@ -128,7 +137,7 @@
children = (
48070BF719B07AA000FCE5FA /* ConfigTest.swift */,
48CD52DE19B0CB5A008D0694 /* Oauth2SessionTest.swift */,
4833047119AF1635002F8DA9 /* AeroGearOAuth2Tests.swift */,
48C94D7F19C1F0970000ABBB /* OAuth2ModuleTest.swift */,
4833046F19AF1635002F8DA9 /* Supporting Files */,
);
path = AeroGearOAuth2Tests;
Expand Down Expand Up @@ -311,16 +320,19 @@
483304A019AF327D002F8DA9 /* AccountManager.swift in Sources */,
48CD52DD19B0C22A008D0694 /* OAuth2Session.swift in Sources */,
48CD52D719B0C1CB008D0694 /* OAuth2Module.swift in Sources */,
4814EF4B19C1C0FA008BAC4D /* TrustedPersistantOAuth2Session.swift in Sources */,
4814EF4E19C1C10C008BAC4D /* FacebookOAuth2Module.swift in Sources */,
483304A519AF44DF002F8DA9 /* Config.swift in Sources */,
4814EF4C19C1C0FA008BAC4D /* UntrustedMemoryOAuth2Session.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
4833046919AF1635002F8DA9 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
48C94D8019C1F0970000ABBB /* OAuth2ModuleTest.swift in Sources */,
48CD52DF19B0CB5A008D0694 /* Oauth2SessionTest.swift in Sources */,
4833047219AF1635002F8DA9 /* AeroGearOAuth2Tests.swift in Sources */,
48070BF819B07AA000FCE5FA /* ConfigTest.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
84 changes: 83 additions & 1 deletion AeroGearOAuth2/AccountManager.swift
Expand Up @@ -17,6 +17,88 @@

import Foundation

public class FacebookConfig: Config {
public init(clientId: String, clientSecret: String, scopes: [String], accountId: String? = nil) {
super.init(base: "",
authzEndpoint: "https://www.facebook.com/dialog/oauth",
redirectURL: "fb\(clientId)://authorize/",
accessTokenEndpoint: "https://graph.facebook.com/oauth/access_token",
clientId: clientId,
clientSecret: clientSecret,
revokeTokenEndpoint: "https://www.facebook.com/me/permissions",
scopes: scopes,
accountId: accountId)
}
}

public class GoogleConfig: Config {
public init(clientId: String, scopes: [String], accountId: String? = nil) {
let bundleString = NSBundle.mainBundle().bundleIdentifier!
super.init(base: "https://accounts.google.com",
authzEndpoint: "o/oauth2/auth",
redirectURL: "\(bundleString):/oauth2Callback",
accessTokenEndpoint: "o/oauth2/token",
clientId: clientId,
revokeTokenEndpoint: "rest/revoke",
scopes: scopes,
accountId: accountId)
}
}

public class AccountManager {
public init() {}

var modules: [String: OAuth2Module]

init() {
self.modules = [String: OAuth2Module]()
}

public class var sharedInstance: AccountManager {
struct Singleton {
static let instance = AccountManager()
}
return Singleton.instance
}

public class func addAccount(config: Config, moduleClass: OAuth2Module.Type) -> OAuth2Module {
var myModule:OAuth2Module
myModule = moduleClass(config: config)
// TODO check accountId is unique in modules list
sharedInstance.modules[myModule.oauth2Session.accountId] = myModule
return myModule
}

public class func removeAccount(name: String, config: Config, moduleClass: OAuth2Module.Type) -> OAuth2Module? {
return sharedInstance.modules.removeValueForKey(name)
}

public class func getAccountByName(name: String) -> OAuth2Module? {
return sharedInstance.modules[name]
}

public class func getAccountsByClienId(clientId: String) -> [OAuth2Module] {
let modules: [OAuth2Module] = [OAuth2Module](sharedInstance.modules.values)
return modules.filter {$0.config.clientId == clientId }
}

public class func getAccountByConfig(config: Config) -> OAuth2Module? {
if config.accountId != nil {
return sharedInstance.modules[config.accountId!]
} else {
let modules = getAccountsByClienId(config.clientId)
if modules.count > 0 {
return modules[0]
} else {
return nil
}
}
}

public class func addFacebookAccount(config: FacebookConfig) -> FacebookOAuth2Module {
return addAccount(config, moduleClass: FacebookOAuth2Module.self) as FacebookOAuth2Module
}

public class func addGoogleAccount(config: GoogleConfig) -> OAuth2Module {
return addAccount(config, moduleClass: OAuth2Module.self)
}
}
2 changes: 1 addition & 1 deletion AeroGearOAuth2/Config.swift
Expand Up @@ -17,7 +17,7 @@

import Foundation

public struct Config {
public class Config {
/**
* Applies the baseURL to the configuration.
*/
Expand Down
7 changes: 4 additions & 3 deletions AeroGearOAuth2/FacebookOAuth2Module.swift
Expand Up @@ -16,11 +16,12 @@
*/

import Foundation
import AeroGearHttp

public class FacebookOAuth2Module: OAuth2Module {

override public init(config: Config, accountId: String) {
super.init(config: config, accountId: accountId)
required public init(config: Config, accountId: String, session: OAuth2Session) {
super.init(config: config, accountId: accountId, session: session)
self.httpAuthz = Http(url: config.base, sessionConfig: NSURLSessionConfiguration.defaultSessionConfiguration(), requestSerializer: JsonRequestSerializer(url: NSURL(string: config.base), headers: [String: String]()), responseSerializer: StringResponseSerializer())
}

Expand Down Expand Up @@ -52,7 +53,7 @@ public class FacebookOAuth2Module: OAuth2Module {
}
}
//println("access:\(accessToken!) expires:\(expiredIn!)")
self.oauth2Session.saveAccessToken(accessToken: accessToken, refreshToken: nil, expiration: expiredIn)
self.oauth2Session.saveAccessToken(accessToken, refreshToken: nil, expiration: expiredIn)
success(accessToken)
}
}, failure: {(error: NSError) -> () in
Expand Down
35 changes: 18 additions & 17 deletions AeroGearOAuth2/OAuth2Module.swift
Expand Up @@ -37,35 +37,36 @@ public class OAuth2Module {
let config: Config
var httpAuthz: Http

public lazy var http: Http = {
var headerFields: [String: String]?
if (self.isAuthorized()) {
headerFields = self.authorizationFields()
return Http(url: nil, sessionConfig: nil, headers: headerFields != nil ? headerFields! : [String: String]())
public var http: Http {
get {
var headerFields: [String: String]?
if (self.isAuthorized()) {
headerFields = self.authorizationFields()
return Http(url: nil, sessionConfig: nil, headers: headerFields != nil ? headerFields! : [String: String]())
}
return Http()
}

return Http()
}()
}
var oauth2Session: OAuth2Session
var applicationLaunchNotificationObserver: NSObjectProtocol?
var applicationDidBecomeActiveNotificationObserver: NSObjectProtocol?
var state: AuthorizationState

// used without AccountManager, default accountId, not really usefull
public convenience init(config: Config) {
// Default accountId, default to TrustedPersistantOAuth2Session
public required convenience init(config: Config) {
if (config.accountId != nil) {
self.init(config: config, accountId:config.accountId!)
self.init(config: config, accountId:config.accountId!, session: TrustedPersistantOAuth2Session(accountId: config.accountId!))
} else {
self.init(config: config, accountId:"ACCOUNT_FOR_CLIENTID_\(config.clientId)")
let accountId = "ACCOUNT_FOR_CLIENTID_\(config.clientId)"
self.init(config: config, accountId: accountId, session: TrustedPersistantOAuth2Session(accountId: accountId))
}
}

// used by AccountManager with a user given accountId
public init(config: Config, accountId: String) {
public required init(config: Config, accountId: String, session: OAuth2Session) {
self.config = config
// TODO use timeout config paramter
self.httpAuthz = Http(url: config.base, sessionConfig: NSURLSessionConfiguration.defaultSessionConfiguration())
self.oauth2Session = OAuth2Session(accountId:accountId)
self.oauth2Session = session
self.state = .AuthorizationStateUnknown
}

Expand Down Expand Up @@ -114,7 +115,7 @@ public class OAuth2Module {
let expiration = unwrappedResponse["expires_in"] as NSNumber
let exp: String = expiration.stringValue

self.oauth2Session.saveAccessToken(accessToken: accessToken, refreshToken: unwrappedRefreshToken, expiration: exp)
self.oauth2Session.saveAccessToken(accessToken, refreshToken: unwrappedRefreshToken, expiration: exp)
success(unwrappedResponse["access_token"]);
}
}, failure: { (error: NSError) -> Void in
Expand All @@ -139,7 +140,7 @@ public class OAuth2Module {
let expiration = unwrappedResponse["expires_in"] as NSNumber
let exp: String = expiration.stringValue

self.oauth2Session.saveAccessToken(accessToken: accessToken, refreshToken: refreshToken, expiration: exp)
self.oauth2Session.saveAccessToken(accessToken, refreshToken: refreshToken, expiration: exp)
success(accessToken)
}
}, failure: {(error: NSError) -> () in
Expand Down
38 changes: 8 additions & 30 deletions AeroGearOAuth2/OAuth2Session.swift
Expand Up @@ -16,58 +16,36 @@
*/
import Foundation

extension String {
var doubleValue: Double {
return (self as NSString).doubleValue
}
}

public class OAuth2Session {

public protocol OAuth2Session {
/**
* The account id.
*/
public let accountId: String
var accountId: String {get}

/**
* The access token which expires.
*/
var accessToken: String?
var accessToken: String? {get set}

/**
* The access token's expiration date.
*/
var accessTokenExpirationDate: NSDate?
var accessTokenExpirationDate: NSDate? {get set}

/**
* The refresh tokens. This toke does not expire and should be used to renew access token when expired.
*/
var refreshToken: String?
var refreshToken: String? {get set}

/**
* Check validity of accessToken. return true if still valid, false when expired.
*/
func tokenIsNotExpired() -> Bool {
return self.accessTokenExpirationDate?.timeIntervalSinceDate(NSDate()) > 0 ;
}
func tokenIsNotExpired() -> Bool

/**
* Save in memory tokens information. Saving tokens allow you to refresh accesstoken transparently for the user without prompting
* for grant access.
*/
func saveAccessToken(accessToken: String? = nil, refreshToken: String? = nil, expiration: String? = nil) {
self.accessToken = accessToken
self.refreshToken = refreshToken
let now = NSDate()
if let inter = expiration?.doubleValue {
self.accessTokenExpirationDate = now.dateByAddingTimeInterval(inter)
}
}

public init(accountId: String, accessToken: String? = nil, accessTokenExpirationDate: NSDate? = nil, refreshToken: String? = nil) {
self.accessToken = accessToken
self.accessTokenExpirationDate = accessTokenExpirationDate
self.refreshToken = refreshToken
self.accountId = accountId
}
func saveAccessToken()
func saveAccessToken(accessToken: String?, refreshToken: String?, expiration: String?)
}