6a5dac3f6165dcf4b0421bb659fe9579599b2220
[atutor.git] / mods / atsocial_iphone_app / OAuth / OAMutableURLRequest.m
1 //
2 //  OAMutableURLRequest.m
3 //  OAuthConsumer
4 //
5 //  Created by Jon Crosby on 10/19/07.
6 //  Copyright 2007 Kaboomerang LLC. All rights reserved.
7 //  Modified by Cassie Doll on 02/02/09
8 //
9 //  Permission is hereby granted, free of charge, to any person obtaining a copy
10 //  of this software and associated documentation files (the "Software"), to deal
11 //  in the Software without restriction, including without limitation the rights
12 //  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 //  copies of the Software, and to permit persons to whom the Software is
14 //  furnished to do so, subject to the following conditions:
15 //
16 //  The above copyright notice and this permission notice shall be included in
17 //  all copies or substantial portions of the Software.
18 //
19 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 //  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 //  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 //  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 //  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 //  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 //  THE SOFTWARE.
26
27
28 #import "OAMutableURLRequest.h"
29 #import "OAConsumer.h"
30 #import "OAToken.h"
31 #import "OAHMAC_SHA1SignatureProvider.h"
32 #import "OARequestParameter.h"
33
34 @interface OAMutableURLRequest ()
35 @property (nonatomic, retain) id<OASignatureProviding> signatureProvider;
36 - (NSString *)_generateTimestamp;
37 - (NSString *)_generateNonce;
38 - (NSString *)_signatureBaseString;
39 - (void)_putParametersInRequest;
40 - (NSString *)_getNormalizedRequestParameters;
41 @end
42
43 @implementation OAMutableURLRequest
44 @synthesize signatureProvider;
45 @synthesize signature, nonce, parameters;
46
47 #pragma mark init
48
49 - (id)initWithURL:(NSURL *)aUrl consumer:(OAConsumer *)aConsumer token:(OAToken *)aToken {     
50   return [self initWithURL:aUrl parameters:nil consumer:aConsumer token:aToken];
51 }
52
53 - (id)initWithURL:(NSURL *)aUrl parameters:(NSArray *)extraParameters
54          consumer:(OAConsumer *)aConsumer token:(OAToken *)aToken {     
55   return [self initWithURL:aUrl parameters:extraParameters consumer:aConsumer token:aToken realm:nil 
56          signatureProvider:nil nonce:[self _generateNonce] timestamp:[self _generateTimestamp]];
57 }
58
59 - (id)initWithURL:(NSURL *)aUrl consumer:(OAConsumer *)aConsumer token:(OAToken *)aToken
60             realm:(NSString *)aRealm signatureProvider:(id<OASignatureProviding, NSObject>)aProvider {     
61   return [self initWithURL:aUrl parameters:nil consumer:aConsumer token:aToken realm:aRealm 
62          signatureProvider:aProvider nonce:[self _generateNonce] timestamp:[self _generateTimestamp]];
63 }
64
65 // Setting a timestamp and nonce to known
66 // values can be helpful for testing
67 - (id)initWithURL:(NSURL *)aUrl
68        parameters:(NSArray *)extraParameters
69          consumer:(OAConsumer *)aConsumer
70             token:(OAToken *)aToken
71             realm:(NSString *)aRealm
72 signatureProvider:(id<OASignatureProviding, NSObject>)aProvider
73             nonce:(NSString *)aNonce
74         timestamp:(NSString *)aTimestamp {
75   if (self = [super initWithURL:aUrl
76                     cachePolicy:NSURLRequestReloadIgnoringCacheData
77                 timeoutInterval:20.0]) {    
78     consumer = [aConsumer retain];
79     
80     // empty token for Unauthorized Request Token transaction
81     if (aToken == nil) {
82       token = nil;
83     } else {
84       token = [aToken retain];
85     }
86     
87     if (aRealm == nil) {
88       realm = @"";
89     } else {
90       realm = [aRealm retain];
91     }
92     
93     // default to HMAC-SHA1
94     if (aProvider == nil) {
95       self.signatureProvider = [[[OAHMAC_SHA1SignatureProvider alloc] init] autorelease];
96     } else { 
97       self.signatureProvider = aProvider;
98     }
99     
100     timestamp = [aTimestamp retain];
101     nonce = [aNonce retain];
102     
103     if (extraParameters) {
104       self.parameters = [NSMutableArray arrayWithArray:extraParameters];
105     } else {
106       self.parameters = [NSMutableArray arrayWithCapacity:7];
107     }
108   }
109   return self;
110 }
111
112 - (void)dealloc {
113   [consumer release];
114   [token release];
115   [realm release];
116   [signatureProvider release];
117   [timestamp release];
118   [nonce release];
119   [parameters release];
120   [super dealloc];
121 }
122
123 #pragma mark -
124 #pragma mark Public
125
126 - (void)prepare {
127   // Add in all of the oauth parameters
128   [parameters addObject:[OARequestParameter requestParameterWithName:@"oauth_consumer_key" value:consumer.key]];
129   [parameters addObject:[OARequestParameter requestParameterWithName:@"oauth_signature_method" value:[signatureProvider name]]];
130   [parameters addObject:[OARequestParameter requestParameterWithName:@"oauth_timestamp" value:timestamp]];
131   [parameters addObject:[OARequestParameter requestParameterWithName:@"oauth_nonce" value:nonce]];
132   [parameters addObject:[OARequestParameter requestParameterWithName:@"oauth_version" value:@"1.0"]];
133   
134   if (token) {
135     [parameters addObject:[OARequestParameter requestParameterWithName:@"oauth_token" value:token.key]];
136   }
137   
138   // TODO: if later RSA-SHA1 support is added then a little code redesign is needed
139   NSString *baseString = [self _signatureBaseString];
140   NSString *secret = [NSString stringWithFormat:@"%@&%@",
141                       [consumer.secret URLEncodedString],
142                       token ? [token.secret URLEncodedString] : @""];
143   
144   NSLog(@"Base string: %@ and secret: %@", baseString, secret);
145   signature = [signatureProvider signClearText:baseString
146                                     withSecret:secret];
147   
148   [parameters addObject:[OARequestParameter requestParameterWithName:@"oauth_signature" value:signature]];
149   [self _putParametersInRequest];
150 }
151
152 #pragma mark -
153 #pragma mark Private
154
155 - (NSString *)_generateTimestamp {
156   return [NSString stringWithFormat:@"%d", time(NULL)];
157 }
158
159 - (NSString *)_generateNonce {
160   CFUUIDRef theUUID = CFUUIDCreate(NULL);
161   CFStringRef string = CFUUIDCreateString(NULL, theUUID);
162   NSMakeCollectable(theUUID);
163   return [(NSString *)string autorelease];
164 }
165
166 - (NSString *)_signatureBaseString {
167   return [NSString stringWithFormat:@"%@&%@&%@",
168           [self HTTPMethod],
169           [[[self URL] absoluteString] URLEncodedString],
170           [[self _getNormalizedRequestParameters] URLEncodedString]];
171 }
172
173 - (void)_putParametersInRequest {  
174   NSString *normalizedRequestParameters = [self _getNormalizedRequestParameters];
175   
176   if ([[self HTTPMethod] isEqualToString:@"GET"] || [[self HTTPMethod] isEqualToString:@"DELETE"]) {
177     [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", [[self URL] absoluteString], normalizedRequestParameters]]];
178     
179   } else {
180     // POST, PUT
181     NSData *postData = [normalizedRequestParameters dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
182     [self setHTTPBody:postData];
183     [self setValue:[NSString stringWithFormat:@"%d", [postData length]] forHTTPHeaderField:@"Content-Length"];
184     [self setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
185     
186     NSString *oauthToken = @"";
187     if (token) {
188       oauthToken = [NSString stringWithFormat:@"oauth_token=\"%@\", ", [token.key URLEncodedString]];
189     }
190     
191     NSString *oauthHeader = [NSString stringWithFormat:@"OAuth realm=\"%@\" oauth_consumer_key=\"%@\", %@oauth_signature_method=\"%@\", oauth_signature=\"%@\", oauth_timestamp=\"%@\", oauth_nonce=\"%@\", oauth_version=\"1.0\"",
192                              [realm URLEncodedString],
193                              [consumer.key URLEncodedString],
194                              oauthToken,
195                              [[signatureProvider name] URLEncodedString],
196                              [signature URLEncodedString],
197                              timestamp,
198                              nonce];
199     
200     [self setValue:oauthHeader forHTTPHeaderField:@"Authorization"];
201     [oauthToken release];
202     [oauthHeader release];
203   }
204 }
205
206 - (NSString *)_getNormalizedRequestParameters {
207   NSMutableArray *parameterPairs = [NSMutableArray arrayWithCapacity:([parameters count])];
208   
209   for (OARequestParameter *param in parameters) {
210     [parameterPairs addObject:[param URLEncodedNameValuePair]];
211   }
212   
213   NSArray* sortedPairs = [parameterPairs sortedArrayUsingSelector:@selector(compare:)];
214   return [sortedPairs componentsJoinedByString:@"&"];
215 }
216
217
218 @end