· 7 years ago · May 23, 2018, 08:20 PM
1//
2// FROAuthRequest.m
3// kroonjuwelen
4//
5// Created by Jonathan Dalrymple on 12/04/2010.
6// Copyright 2010 Float:Right. All rights reserved.
7//
8
9#import "FROAuthRequest.h"
10
11@interface FROAuthRequest(private)
12
13- (void) prepare;
14- (NSString *)signatureBaseString;
15- (NSString*) signatureBaseStringForURL:(NSURL*) pURL
16 withMethod:(NSString*) method
17 withParams:(NSDictionary*) dictionary;
18- (NSString *)timestamp;
19- (NSString *)nonce;
20
21@end
22
23@interface ASIFormDataRequest(private)
24
25-(id) postData;
26
27@end
28
29@implementation FROAuthRequest
30
31@synthesize token = _token;
32@synthesize consumer = _consumer;
33@synthesize signatureProvider = _signatureProvider;
34
35#pragma mark -
36#pragma mark Factory Methods
37+(id) requestWithURL: (NSURL *)newURL
38 consumer: (OAConsumer*) consumer
39 token: (OAToken*) token
40 realm: (NSString*) realm
41 signatureProvider: (id<OASignatureProviding>) provider
42{
43 return [[[FROAuthRequest alloc] initWithURL: newURL
44 consumer: consumer
45 token: token
46 realm: realm
47 signatureProvider: provider
48 ] autorelease];
49}
50
51
52#pragma mark -
53#pragma mark Init Methods
54-(id) initWithURL: (NSURL *)newURL
55 consumer: (OAConsumer*) consumer
56 token: (OAToken*) token
57 realm: (NSString*) realm
58 signatureProvider: (id<OASignatureProviding>) provider
59{
60
61 if( self = [super initWithURL: newURL] ){
62
63 //Alter this after the request has been created;
64 //[self setRequestMethod:@"POST"];
65
66 [self setConsumer: consumer];
67
68
69 if( token == nil ){
70 self.token = [[OAToken alloc] init];
71 }
72 else{
73 self.token = token;
74 }
75
76 _realm = realm ? [realm retain] : @"";
77
78 if( provider == nil ){
79
80 self.signatureProvider = [[OAHMAC_SHA1SignatureProvider alloc] init];
81 }
82 else{
83 self.signatureProvider = provider;
84 }
85
86 _nonce = nil;
87
88 _timestamp = nil;
89
90 }
91
92 return self;
93
94}
95
96
97#pragma mark -
98#pragma mark Start Methods
99//Overload start ASync
100-(void) startAsynchronous{
101
102 [self prepare];
103
104 [super startAsynchronous];
105
106}
107
108-(void) startSynchronous{
109
110 [self prepare];
111
112 [super startSynchronous];
113}
114
115
116#pragma mark -
117#pragma mark Overloaded ASIFormDataRequest
118- (void)buildPostBody
119{
120 //If we want to do anything other than GET, build a body
121 if(![[self requestMethod] isEqualToString:@"GET"]){
122 [super buildPostBody];
123 }
124
125}
126
127/*
128
129
130- (void)requestFinished{
131
132 NSLog(@"[FROAuthRequest] Request Finished");
133
134
135 [super requestFinished];
136}
137*/
138- (void)requestFailed:(FROAuthRequest *) pRequest{
139#if DEBUG
140 NSLog(@"[FROAuthRequest requestFailed] %@", [pRequest error]);
141#endif
142 //[super requestFinished];
143}
144
145
146//-**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-
147// OAuth Methods
148//-**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-
149#pragma mark -
150#pragma mark Request Token
151+(OAToken*) _requestTokenFromProvider:(NSURL*) requestURL
152 withConsumer:(OAConsumer*) pConsumer
153 forObject:(id) pDelegate
154{
155
156#if DEBUG
157 NSLog(@"[FROAuthRequest requestToken]");
158#endif
159 FROAuthRequest* tokenRequest;
160
161 tokenRequest = [FROAuthRequest requestWithURL: requestURL
162 consumer: pConsumer
163 token: nil
164 realm: nil
165 signatureProvider: nil
166 ];
167
168 [tokenRequest startSynchronous];
169
170 return [FROAuthRequest _didRequestToken: tokenRequest forObject:pDelegate];
171}
172
173/*
174 Request token callback
175 */
176+(OAToken*) _didRequestToken:(FROAuthRequest*) pRequest
177 forObject:pDelegate
178{
179
180 OAToken *tempToken;
181
182 //Parse out the token
183 if( [pRequest responseString] && [pRequest responseStatusCode] == 200 ){
184
185 tempToken = [[[OAToken alloc] initWithHTTPResponseBody: [pRequest responseString]] autorelease];
186#if DEBUG
187 NSLog(@"[FROAuthRequest didRequestToken] Found a response \r\n%@", [pRequest responseString]);
188
189 NSLog(@"[FROAuthRequest didRequestToken] New Request Token Created key:%@ secret:%@",tempToken.key,tempToken.secret);
190#endif
191 //Authenticate the token
192 if( [tempToken key] != nil){
193
194 if( pDelegate && [pDelegate respondsToSelector:@selector(authenticateToken:withProvider:)]){
195
196 [pDelegate performSelector:@selector( authenticateToken:withProvider:) withObject: tempToken withObject: [pRequest url]];
197 //[pDelegate authenticateToken: tempToken withProvider:[pRequest url]];
198
199 }
200
201 return tempToken;
202 }
203 }
204 else{
205
206 UIAlertView *alertView;
207
208 alertView = [[UIAlertView alloc] initWithTitle: NSLocalizedString(@"Could not connect",@"Could not connect")
209 message: NSLocalizedString(@"Could not to connect to the internet",@"Could not to connect to the internet")
210 delegate: nil
211 cancelButtonTitle: NSLocalizedString(@"ok",@"Ok")
212 otherButtonTitles: nil
213 ];
214
215 [alertView show];
216
217 [alertView release];
218#if DEBUG
219 NSLog(@"[FROAuthRequest didRequestToken] failed");
220#endif
221 }
222
223 //Notify the parent that we failed
224 //[[self delegate] performSelectorOnMainThread:[self didFailSelector] withObject:self waitUntilDone:[NSThread isMainThread]];
225
226 return nil;
227}
228
229
230#pragma mark -
231#pragma mark Authorize Token
232+(OAToken*) _accessTokenWithRequestToken:(OAToken*) pToken
233 fromProvider:(NSURL*) accessURL
234 forConsumer:(OAConsumer*) pConsumer
235 forObject:(id) pDelegate
236{
237
238#if DEBUG
239 NSLog(@"[FROAuthRequest authorizeToken]");
240#endif
241 FROAuthRequest* authorizeRequest;
242
243 //Append the pin to the token
244 //NSString *URLStr = [accessURL absoluteString];
245
246 //URLStr = [URLStr stringByAppendingString:[NSString stringWithFormat:@"?oauth_verifier=%s", pToken.pin]];
247
248 authorizeRequest = [FROAuthRequest requestWithURL: accessURL //[NSURL URLWithString:URLStr]
249 consumer: pConsumer
250 token: pToken
251 realm: nil
252 signatureProvider: nil
253 ];
254
255 //We are already operating on a seperate thread so using this should be fine
256 [authorizeRequest startSynchronous];
257
258 //This log can be split into callbacks
259 if( [authorizeRequest responseStatusCode] == 200 && [authorizeRequest responseString] ){
260#if DEBUG
261 NSLog(@"[FROAuthRequest] Created new Access Token! \r\n%@", [authorizeRequest responseString]);
262#endif
263 //Set the access token
264 return [[[OAToken alloc] initWithHTTPResponseBody:[authorizeRequest responseString]] autorelease];
265
266 }
267 else{
268#if DEBUG
269 NSLog(@"[FROAuthRequest] Failed to get Access Token!");
270#endif
271 return nil;
272 }
273}
274
275//Use xAuth to authorize a token
276+(OAToken*) _accessTokenFromProvider:(NSURL*) accessURL
277 WithUsername:(NSString*) pUsername
278 password:(NSString*) pPassword
279 andConsumer:(OAConsumer*) pConsumer
280{
281
282 FROAuthRequest *accessRequest;
283
284 //Insure that it SSL
285 if( ![[accessURL scheme] isEqualToString:@"https"] ){
286#if DEBUG
287 NSLog(@"Not SSL :%@",[accessURL scheme]);
288#endif
289 //return nil;
290 }
291
292 accessRequest = [FROAuthRequest requestWithURL: accessURL
293 consumer: pConsumer
294 token: nil
295 realm: nil
296 signatureProvider: nil
297 ];
298
299 [accessRequest setRequestMethod:@"POST"];
300
301 [accessRequest setPostValue:pUsername forKey:@"x_auth_username"];
302
303 [accessRequest setPostValue:pPassword forKey:@"x_auth_password"];
304
305 [accessRequest setPostValue:@"client_auth" forKey:@"x_auth_mode"];
306
307 [accessRequest startSynchronous];
308
309 if( [accessRequest responseStatusCode] == 200 && [accessRequest responseString] ){
310#if DEBUG
311 NSLog(@"[FROAuthRequest xAuthToken] Success \r\n%@", [accessRequest responseString]);
312#endif
313 return [[[OAToken alloc] initWithHTTPResponseBody:[accessRequest responseString]] autorelease];
314 }
315 else{
316
317 UIAlertView *alertView;
318
319 alertView = [[UIAlertView alloc] initWithTitle: @""
320 message: @"Couldn't find "
321 delegate: nil
322 cancelButtonTitle: nil
323 otherButtonTitles: nil
324 ];
325
326 [alertView show];
327
328 [alertView release];
329#if DEBUG
330 NSLog(@"[FROAuthRequest xAuthToken] Failure \r\n%@", [accessRequest error]);
331#endif
332 return nil;
333 }
334}
335
336//-**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-
337// Utilites
338//-**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-
339
340/*
341 URL encode a string
342 */
343- (NSString *) URLEncodedString: (NSString *) string {
344 CFStringRef preprocessedString = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef) string, CFSTR(""), kCFStringEncodingUTF8);
345 NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
346 preprocessedString,
347 NULL,
348 CFSTR("!*'();:@&=+$,/?%#[]"),
349 kCFStringEncodingUTF8);
350 [result autorelease];
351
352 //NSLog(@"RETAIN COUNT %d",CFGetRetainCount( preprocessedString));
353
354 if( preprocessedString != NULL ){
355 CFRelease(preprocessedString);
356 }
357
358 //Handle Spaces
359 result = [result stringByReplacingOccurrencesOfString:@"%20" withString:@"%2520"];
360
361 //Handle Hashes
362 result = [result stringByReplacingOccurrencesOfString:@"%23" withString:@"%2523"];
363
364 //Handle Colons
365 //result = [result stringByReplacingOccurrencesOfString:@"%3A" withString:@"%253A"];
366
367#if DEBUG
368 NSLog(@"String encoded \r\nin:%@ \r\nout:%@", string, result);
369#endif
370 return result;
371}
372
373//Create a url string
374- (NSString *)URLStringWithoutQueryFromURL: (NSURL *) pURL
375{
376 NSArray *parts = [[pURL absoluteString] componentsSeparatedByString:@"?"];
377 return [parts objectAtIndex:0];
378}
379
380/*
381 Generate a timestamp on demand
382 */
383- (NSString*)timestamp
384{
385 if(!_timestamp) {
386 _timestamp = [NSString stringWithFormat:@"%d", time(NULL)];
387 }
388
389 return _timestamp;
390}
391
392//Generate Nonce on demand
393- (NSString*)nonce
394{
395
396 if( !_nonce ){
397 CFUUIDRef theUUID = CFUUIDCreate(NULL);
398 CFStringRef string = CFUUIDCreateString(NULL, theUUID);
399 CFRelease(theUUID);
400
401 _nonce = (NSString *)string;
402 }
403
404 return _nonce;
405}
406
407//Create BaseString
408- (NSString *)signatureBaseString
409{
410
411 NSMutableDictionary *params;
412 NSString *queryStr;
413 //NSArray *queryParams;
414
415 params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
416 [[self consumer] key],
417 @"oauth_consumer_key",
418 [[self token] key] ? [[self token] key] : @"", //Stops nil from being entered and causing a failure
419 @"oauth_token",
420 [[self signatureProvider] name],
421 @"oauth_signature_method",
422 [self timestamp],
423 @"oauth_timestamp",
424 [self nonce],
425 @"oauth_nonce",
426 @"1.0",
427 @"oauth_version",
428 nil
429 ];
430
431 //Find out if the params to the query
432 if( queryStr = [[self url] query] ){
433 //Break the query up into pairs and add them to the dictionary
434 for( NSString *keyValPairStr in [queryStr componentsSeparatedByString:@"&"]){
435
436 //NSLog(@"KeyVal Pair %@", keyValPairStr );
437
438 NSArray *keyValPair = [keyValPairStr componentsSeparatedByString:@"="];
439
440 [params setObject: [keyValPair objectAtIndex:1] forKey: [keyValPair objectAtIndex:0]];
441 }
442
443 }
444
445 //If this is post request find out
446 if( [self isKindOfClass:[ASIFormDataRequest class]] && [self respondsToSelector:@selector(postData)]){
447
448 for( NSString *key in [self postData] ){
449
450 [params setValue:[[self postData] objectForKey:key] forKey:key];
451 }
452
453 }
454
455
456 return [self signatureBaseStringForURL: [self url]
457 withMethod: [self requestMethod]
458 withParams: (NSDictionary*)params
459 ];
460}
461
462//Create a signature base string
463-(NSString*) signatureBaseStringForURL:(NSURL*) pURL
464 withMethod:(NSString*) method
465 withParams:(NSDictionary*) dictionary{
466
467 NSMutableArray *pairs;
468 NSArray *sortedPairs;
469 NSString *key, *tmp;
470 NSString *baseString, *normalizedString;
471
472 if( [dictionary count] < 6 ){
473 @throw [NSException exceptionWithName:@"InvalidParameterCount"
474 reason:[NSString stringWithFormat:@"Passed Dictionary contains too few entries (6 Min vs %d found)", [dictionary count]]
475 userInfo:[NSDictionary dictionaryWithObjectsAndKeys: dictionary,@"dictionary",self,@"request",nil]];
476 }
477
478 pairs = [[NSMutableArray alloc] init];
479
480 for( key in dictionary ){
481
482 if( [[dictionary objectForKey:key] length] > 0){
483 tmp = [NSString stringWithFormat:@"%@=%@", key, [dictionary objectForKey:key] ];
484
485 tmp = [self URLEncodedString: tmp];
486
487 [pairs addObject:tmp];
488 }
489 else{
490 #if DEBUG
491 NSLog(@"[FRORequest signatureBaseString] %@ was nil, skipping", key);
492 #endif
493 }
494
495 }
496
497 sortedPairs = [pairs sortedArrayUsingSelector:@selector(compare:)];
498
499 normalizedString = [sortedPairs componentsJoinedByString:@"&"];
500
501 baseString = [NSString stringWithFormat:@"%@&%@&%@",
502 [method uppercaseString],
503 [self URLEncodedString:[self URLStringWithoutQueryFromURL:pURL]],
504 [self URLEncodedString: normalizedString]
505 ];
506
507 //Cleanup
508 [pairs release];
509#if DEBUG
510 NSLog(@"Basestring \r\n%@", baseString);
511#endif
512 return baseString;
513}
514
515//Add Auth header to this request
516- (void)prepare
517{
518 // sign
519 // Secrets must be urlencoded before concatenated with '&'
520 // TODO: if later RSA-SHA1 support is added then a little code redesign is needed
521 NSString *consumerSecret, *tokenSecret, *signature, *oauthToken, *oauthHeader;
522
523 consumerSecret = [self URLEncodedString: self.consumer.secret];
524
525 tokenSecret = [self URLEncodedString: self.token.secret];
526
527 signature = [self.signatureProvider signClearText:[self signatureBaseString]
528 withSecret:[NSString stringWithFormat:@"%@&%@", consumerSecret, tokenSecret]];
529
530 // set OAuth headers
531
532 if ([self.token.key isEqualToString:@""]){
533 oauthToken = @""; // not used on Request Token transactions
534 }
535 else{
536 oauthToken = [NSString stringWithFormat:@"oauth_token=\"%@\", ", [self URLEncodedString: self.token.key]];
537 }
538
539 oauthHeader = [NSString stringWithFormat:
540 @"OAuth realm=\"%@\", oauth_consumer_key=\"%@\", %@oauth_signature_method=\"%@\", oauth_signature=\"%@\", oauth_timestamp=\"%@\", oauth_nonce=\"%@\", oauth_version=\"1.0\"",
541 [self URLEncodedString: _realm],
542 [self URLEncodedString: [self.consumer key]],
543 oauthToken,
544 [self URLEncodedString: [self.signatureProvider name]],
545 [self URLEncodedString: signature],
546 [self timestamp],
547 [self nonce]
548 ];
549
550 if (self.token.pin.length) oauthHeader = [oauthHeader stringByAppendingFormat: @", oauth_verifier=\"%@\"", self.token.pin]; //added for the Twitter OAuth implementation
551#if DEBUG
552 NSLog(@"[FROAuthRequest prepare] \r\nAuthentication Header %@", oauthHeader);
553#endif
554 [self addRequestHeader:@"Authorization" value: oauthHeader];
555
556}
557
558#pragma mark -
559#pragma mark Dealloc
560-(void) dealloc{
561/*
562 [self.requestToken release];
563*/
564 [_realm release];
565
566 [_nonce release];
567
568 // Cause a crash if if a nil check is done
569 //[_timestamp release];
570
571 [_consumer release];
572
573 [self.signatureProvider release];
574
575 [self.token release];
576
577 [super dealloc];
578}
579
580@end