BBGMultiAccountManager
|
00001 /* Copyright (c) 2011 Google Inc. 00002 * 00003 * Licensed under the Apache License, Version 2.0 (the "License"); 00004 * you may not use this file except in compliance with the License. 00005 * You may obtain a copy of the License at 00006 * 00007 * http://www.apache.org/licenses/LICENSE-2.0 00008 * 00009 * Unless required by applicable law or agreed to in writing, software 00010 * distributed under the License is distributed on an "AS IS" BASIS, 00011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 * See the License for the specific language governing permissions and 00013 * limitations under the License. 00014 */ 00015 00016 #if GTM_INCLUDE_OAUTH2 || !GDATA_REQUIRE_SERVICE_INCLUDES 00017 00018 // This class implements the OAuth 2 protocol for authorizing requests. 00019 // http://tools.ietf.org/html/draft-ietf-oauth-v2 00020 00021 #import <Foundation/Foundation.h> 00022 00023 // GTMHTTPFetcher.h brings in GTLDefines/GDataDefines 00024 #import "GTMHTTPFetcher.h" 00025 00026 #undef _EXTERN 00027 #undef _INITIALIZE_AS 00028 #ifdef GTMOAUTH2AUTHENTICATION_DEFINE_GLOBALS 00029 #define _EXTERN 00030 #define _INITIALIZE_AS(x) =x 00031 #else 00032 #if defined(__cplusplus) 00033 #define _EXTERN extern "C" 00034 #else 00035 #define _EXTERN extern 00036 #endif 00037 #define _INITIALIZE_AS(x) 00038 #endif 00039 00040 // Until all OAuth 2 providers are up to the same spec, we'll provide a crude 00041 // way here to override the "Bearer" string in the Authorization header 00042 #ifndef GTM_OAUTH2_BEARER 00043 #define GTM_OAUTH2_BEARER "Bearer" 00044 #endif 00045 00046 // Service provider name allows stored authorization to be associated with 00047 // the authorizing service 00048 _EXTERN NSString* const kGTMOAuth2ServiceProviderGoogle _INITIALIZE_AS(@"Google"); 00049 00050 // 00051 // GTMOAuth2SignIn constants, included here for use by clients 00052 // 00053 _EXTERN NSString* const kGTMOAuth2ErrorDomain _INITIALIZE_AS(@"com.google.GTMOAuth2"); 00054 00055 // Error userInfo keys 00056 _EXTERN NSString* const kGTMOAuth2ErrorMessageKey _INITIALIZE_AS(@"error"); 00057 _EXTERN NSString* const kGTMOAuth2ErrorRequestKey _INITIALIZE_AS(@"request"); 00058 _EXTERN NSString* const kGTMOAuth2ErrorJSONKey _INITIALIZE_AS(@"json"); 00059 00060 enum { 00061 // Error code indicating that the window was prematurely closed 00062 kGTMOAuth2ErrorWindowClosed = -1000, 00063 kGTMOAuth2ErrorAuthorizationFailed = -1001, 00064 kGTMOAuth2ErrorTokenExpired = -1002, 00065 kGTMOAuth2ErrorTokenUnavailable = -1003, 00066 kGTMOAuth2ErrorUnauthorizableRequest = -1004 00067 }; 00068 00069 00070 // Notifications for token fetches 00071 _EXTERN NSString* const kGTMOAuth2FetchStarted _INITIALIZE_AS(@"kGTMOAuth2FetchStarted"); 00072 _EXTERN NSString* const kGTMOAuth2FetchStopped _INITIALIZE_AS(@"kGTMOAuth2FetchStopped"); 00073 00074 _EXTERN NSString* const kGTMOAuth2FetcherKey _INITIALIZE_AS(@"fetcher"); 00075 _EXTERN NSString* const kGTMOAuth2FetchTypeKey _INITIALIZE_AS(@"FetchType"); 00076 _EXTERN NSString* const kGTMOAuth2FetchTypeToken _INITIALIZE_AS(@"token"); 00077 _EXTERN NSString* const kGTMOAuth2FetchTypeRefresh _INITIALIZE_AS(@"refresh"); 00078 _EXTERN NSString* const kGTMOAuth2FetchTypeAssertion _INITIALIZE_AS(@"assertion"); 00079 _EXTERN NSString* const kGTMOAuth2FetchTypeUserInfo _INITIALIZE_AS(@"userInfo"); 00080 00081 // Token-issuance errors 00082 _EXTERN NSString* const kGTMOAuth2ErrorKey _INITIALIZE_AS(@"error"); 00083 00084 _EXTERN NSString* const kGTMOAuth2ErrorInvalidRequest _INITIALIZE_AS(@"invalid_request"); 00085 _EXTERN NSString* const kGTMOAuth2ErrorInvalidClient _INITIALIZE_AS(@"invalid_client"); 00086 _EXTERN NSString* const kGTMOAuth2ErrorInvalidGrant _INITIALIZE_AS(@"invalid_grant"); 00087 _EXTERN NSString* const kGTMOAuth2ErrorUnauthorizedClient _INITIALIZE_AS(@"unauthorized_client"); 00088 _EXTERN NSString* const kGTMOAuth2ErrorUnsupportedGrantType _INITIALIZE_AS(@"unsupported_grant_type"); 00089 _EXTERN NSString* const kGTMOAuth2ErrorInvalidScope _INITIALIZE_AS(@"invalid_scope"); 00090 00091 // Notification that sign-in has completed, and token fetches will begin (useful 00092 // for displaying interstitial messages after the window has closed) 00093 _EXTERN NSString* const kGTMOAuth2UserSignedIn _INITIALIZE_AS(@"kGTMOAuth2UserSignedIn"); 00094 00095 // Notification for token changes 00096 _EXTERN NSString* const kGTMOAuth2AccessTokenRefreshed _INITIALIZE_AS(@"kGTMOAuth2AccessTokenRefreshed"); 00097 _EXTERN NSString* const kGTMOAuth2RefreshTokenChanged _INITIALIZE_AS(@"kGTMOAuth2RefreshTokenChanged"); 00098 00099 // Notification for WebView loading 00100 _EXTERN NSString* const kGTMOAuth2WebViewStartedLoading _INITIALIZE_AS(@"kGTMOAuth2WebViewStartedLoading"); 00101 _EXTERN NSString* const kGTMOAuth2WebViewStoppedLoading _INITIALIZE_AS(@"kGTMOAuth2WebViewStoppedLoading"); 00102 _EXTERN NSString* const kGTMOAuth2WebViewKey _INITIALIZE_AS(@"kGTMOAuth2WebViewKey"); 00103 _EXTERN NSString* const kGTMOAuth2WebViewStopKindKey _INITIALIZE_AS(@"kGTMOAuth2WebViewStopKindKey"); 00104 _EXTERN NSString* const kGTMOAuth2WebViewFinished _INITIALIZE_AS(@"finished"); 00105 _EXTERN NSString* const kGTMOAuth2WebViewFailed _INITIALIZE_AS(@"failed"); 00106 _EXTERN NSString* const kGTMOAuth2WebViewCancelled _INITIALIZE_AS(@"cancelled"); 00107 00108 // Notification for network loss during html sign-in display 00109 _EXTERN NSString* const kGTMOAuth2NetworkLost _INITIALIZE_AS(@"kGTMOAuthNetworkLost"); 00110 _EXTERN NSString* const kGTMOAuth2NetworkFound _INITIALIZE_AS(@"kGTMOAuthNetworkFound"); 00111 00112 @interface GTMOAuth2Authentication : NSObject <GTMFetcherAuthorizationProtocol> { 00113 @private 00114 NSString *clientID_; 00115 NSString *clientSecret_; 00116 NSString *redirectURI_; 00117 NSMutableDictionary *parameters_; 00118 00119 // authorization parameters 00120 NSURL *tokenURL_; 00121 NSDate *expirationDate_; 00122 00123 NSDictionary *additionalTokenRequestParameters_; 00124 00125 // queue of requests for authorization waiting for a valid access token 00126 GTMHTTPFetcher *refreshFetcher_; 00127 NSMutableArray *authorizationQueue_; 00128 00129 id <GTMHTTPFetcherServiceProtocol> fetcherService_; // WEAK 00130 00131 Class parserClass_; 00132 00133 BOOL shouldAuthorizeAllRequests_; 00134 00135 // arbitrary data retained for the user 00136 id userData_; 00137 NSMutableDictionary *properties_; 00138 } 00139 00140 // OAuth2 standard protocol parameters 00141 // 00142 // These should be the plain strings; any needed escaping will be provided by 00143 // the library. 00144 00145 // Request properties 00146 @property (copy) NSString *clientID; 00147 @property (copy) NSString *clientSecret; 00148 @property (copy) NSString *redirectURI; 00149 @property (retain) NSString *scope; 00150 @property (retain) NSString *tokenType; 00151 @property (retain) NSString *assertion; 00152 00153 // Apps may optionally add parameters here to be provided to the token 00154 // endpoint on token requests and refreshes 00155 @property (retain) NSDictionary *additionalTokenRequestParameters; 00156 00157 // Response properties 00158 @property (retain) NSMutableDictionary *parameters; 00159 00160 @property (retain) NSString *accessToken; 00161 @property (retain) NSString *refreshToken; 00162 @property (retain) NSNumber *expiresIn; 00163 @property (retain) NSString *code; 00164 @property (retain) NSString *errorString; 00165 00166 // URL for obtaining access tokens 00167 @property (copy) NSURL *tokenURL; 00168 00169 // Calculated expiration date (expiresIn seconds added to the 00170 // time the access token was received.) 00171 @property (copy) NSDate *expirationDate; 00172 00173 // Service identifier, like "Google"; not used for authentication 00174 // 00175 // The provider name is just for allowing stored authorization to be associated 00176 // with the authorizing service. 00177 @property (copy) NSString *serviceProvider; 00178 00179 // User email and verified status; not used for authentication 00180 // 00181 // The verified string can be checked with -boolValue. If the result is false, 00182 // then the email address is listed with the account on the server, but the 00183 // address has not been confirmed as belonging to the owner of the account. 00184 @property (retain) NSString *userEmail; 00185 @property (retain) NSString *userEmailIsVerified; 00186 00187 // Property indicating if this auth has a refresh token so is suitable for 00188 // authorizing a request. This does not guarantee that the token is valid. 00189 @property (readonly) BOOL canAuthorize; 00190 00191 // Property indicating if this object will authorize plain http request 00192 // (as well as any non-https requests.) Default is NO, only requests with the 00193 // scheme https are authorized, since security may be compromised if tokens 00194 // are sent over the wire using an unencrypted protocol like http. 00195 @property (assign) BOOL shouldAuthorizeAllRequests; 00196 00197 // userData is retained for the convenience of the caller 00198 @property (retain) id userData; 00199 00200 // Stored property values are retained for the convenience of the caller 00201 @property (retain) NSDictionary *properties; 00202 00203 // Property for the optional fetcher service instance to be used to create 00204 // fetchers 00205 // 00206 // Fetcher service objects retain authorizations, so this is weak to avoid 00207 // circular retains. 00208 @property (assign) id <GTMHTTPFetcherServiceProtocol> fetcherService; // WEAK 00209 00210 // Alternative JSON parsing class; this should implement the 00211 // GTMOAuth2ParserClass informal protocol. If this property is 00212 // not set, the class SBJSON must be available in the runtime. 00213 @property (assign) Class parserClass; 00214 00215 // Convenience method for creating an authentication object 00216 + (id)authenticationWithServiceProvider:(NSString *)serviceProvider 00217 tokenURL:(NSURL *)tokenURL 00218 redirectURI:(NSString *)redirectURI 00219 clientID:(NSString *)clientID 00220 clientSecret:(NSString *)clientSecret; 00221 00222 // Clear out any authentication values, prepare for a new request fetch 00223 - (void)reset; 00224 00225 // Main authorization entry points 00226 // 00227 // These will refresh the access token, if necessary, add the access token to 00228 // the request, then invoke the callback. 00229 // 00230 // The request argument may be nil to just force a refresh of the access token, 00231 // if needed. 00232 // 00233 // NOTE: To avoid accidental leaks of bearer tokens, the request must 00234 // be for a URL with the scheme https unless the shouldAuthorizeAllRequests 00235 // property is set. 00236 00237 // The finish selector should have a signature matching 00238 // - (void)authentication:(GTMOAuth2Authentication *)auth 00239 // request:(NSMutableURLRequest *)request 00240 // finishedWithError:(NSError *)error; 00241 00242 - (void)authorizeRequest:(NSMutableURLRequest *)request 00243 delegate:(id)delegate 00244 didFinishSelector:(SEL)sel; 00245 00246 #if NS_BLOCKS_AVAILABLE 00247 - (void)authorizeRequest:(NSMutableURLRequest *)request 00248 completionHandler:(void (^)(NSError *error))handler; 00249 #endif 00250 00251 // Synchronous entry point; authorizing this way cannot refresh an expired 00252 // access token 00253 - (BOOL)authorizeRequest:(NSMutableURLRequest *)request; 00254 00255 // If the authentication is waiting for a refresh to complete, spin the run 00256 // loop, discarding events, until the fetch has completed 00257 // 00258 // This is only for use in testing or in tools without a user interface. 00259 - (void)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds; 00260 00261 00263 // 00264 // Internal properties and methods for use by GTMOAuth2SignIn 00265 // 00266 00267 // Pending fetcher to get a new access token, if any 00268 @property (retain) GTMHTTPFetcher *refreshFetcher; 00269 00270 // Check if a request is queued up to be authorized 00271 - (BOOL)isAuthorizingRequest:(NSURLRequest *)request; 00272 00273 // Check if a request appears to be authorized 00274 - (BOOL)isAuthorizedRequest:(NSURLRequest *)request; 00275 00276 // Stop any pending refresh fetch 00277 - (void)stopAuthorization; 00278 00279 // OAuth fetch user-agent header value 00280 - (NSString *)userAgent; 00281 00282 // Parse and set token and token secret from response data 00283 - (void)setKeysForResponseString:(NSString *)str; 00284 - (void)setKeysForResponseDictionary:(NSDictionary *)dict; 00285 00286 // Persistent token string for keychain storage 00287 // 00288 // We'll use the format "refresh_token=foo&serviceProvider=bar" so we can 00289 // easily alter what portions of the auth data are stored 00290 // 00291 // Use these methods for serialization 00292 - (NSString *)persistenceResponseString; 00293 - (void)setKeysForPersistenceResponseString:(NSString *)str; 00294 00295 // method to begin fetching an access token, used by the sign-in object 00296 - (GTMHTTPFetcher *)beginTokenFetchWithDelegate:(id)delegate 00297 didFinishSelector:(SEL)finishedSel; 00298 00299 // Entry point to post a notification about a fetcher currently used for 00300 // obtaining or refreshing a token; the sign-in object will also use this 00301 // to indicate when the user's email address is being fetched. 00302 // 00303 // Fetch type constants are above under "notifications for token fetches" 00304 - (void)notifyFetchIsRunning:(BOOL)isStarting 00305 fetcher:(GTMHTTPFetcher *)fetcher 00306 type:(NSString *)fetchType; 00307 00308 // Arbitrary key-value properties retained for the user 00309 - (void)setProperty:(id)obj forKey:(NSString *)key; 00310 - (id)propertyForKey:(NSString *)key; 00311 00312 // 00313 // Utilities 00314 // 00315 00316 + (NSString *)encodedOAuthValueForString:(NSString *)str; 00317 00318 + (NSString *)encodedQueryParametersForDictionary:(NSDictionary *)dict; 00319 00320 + (NSDictionary *)dictionaryWithResponseString:(NSString *)responseStr; 00321 00322 + (NSString *)scopeWithStrings:(NSString *)firsStr, ... NS_REQUIRES_NIL_TERMINATION; 00323 @end 00324 00325 #endif // GTM_INCLUDE_OAUTH2 || !GDATA_REQUIRE_SERVICE_INCLUDES