|
1 /* |
|
2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 #include <e32std.h> |
|
25 #include "wsovisecurityhandler.h" |
|
26 #include "wsovicons.h" |
|
27 #include "wsovihandlercontext.h" |
|
28 #include "senlogger.h" |
|
29 #include "wsovimessagecontext.h" |
|
30 #include <SenTransportProperties.h> |
|
31 #include <SenHttpTransportProperties.h> |
|
32 |
|
33 #include "wsoviutils.h" |
|
34 #include "sencryptoutils.h" |
|
35 |
|
36 |
|
37 using namespace OAuth; |
|
38 namespace |
|
39 { |
|
40 const TInt KSHA1OutputSize = 20;// see http://en.wikipedia.org/wiki/SHA_hash_functions |
|
41 } |
|
42 // Create instance of concrete ECOM interface implementation |
|
43 CWSOviSecurityHandler* CWSOviSecurityHandler::NewL( |
|
44 MSenHandlerContext* aHandlerCtx) |
|
45 { |
|
46 |
|
47 CWSOviSecurityHandler* self = |
|
48 new (ELeave) CWSOviSecurityHandler(*aHandlerCtx); |
|
49 return self; |
|
50 } |
|
51 |
|
52 // Constructor |
|
53 CWSOviSecurityHandler::CWSOviSecurityHandler(MSenHandlerContext& aCtx): |
|
54 CSenMessageHandler(aCtx), iDiff(0) |
|
55 { |
|
56 } |
|
57 |
|
58 // Destructor |
|
59 CWSOviSecurityHandler::~CWSOviSecurityHandler() |
|
60 { |
|
61 TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler::~CWSOviSecurityHandler()"))); |
|
62 } |
|
63 |
|
64 TInt CWSOviSecurityHandler::InvokeL(MSenMessageContext& aCtx) |
|
65 { |
|
66 TInt error(KErrNone); |
|
67 TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler::InvokeL(MSenMessageContext& aCtx)"))); |
|
68 CSenTransportProperties* tp = ((CWSOviMessageContext&)aCtx).TP(); |
|
69 const TInt* servertime = ((CWSOviMessageContext&)aCtx).GetIntL(WSOviContextKeys::KRetryNeeded); |
|
70 const TDesC8* bodyMessage = ((CWSOviMessageContext&)aCtx).GetDesC8L(WSOviContextKeys::KMessageBody); |
|
71 |
|
72 |
|
73 TPtrC8 oldValue; |
|
74 if (!tp) return KErrNotFound; |
|
75 error = tp->PropertyL(KAuthHttpHeader, oldValue); |
|
76 if (error) return error;//device handler missed |
|
77 |
|
78 |
|
79 TPtrC8 consumerKey; |
|
80 error = tp->PropertyL(KNCIMConsumerKeyId, consumerKey); |
|
81 |
|
82 TPtrC8 consumerSecret; |
|
83 error = tp->PropertyL(KNCIMConsumerSecret, consumerSecret); |
|
84 |
|
85 TBool needSecurity(ETrue); |
|
86 error = tp->BoolPropertyL(KNeedSecurity,needSecurity); |
|
87 |
|
88 |
|
89 const TDesC8* endpoint = ((CWSOviMessageContext&)aCtx).GetDesC8L(KEndpointKey); |
|
90 if (!endpoint) |
|
91 { |
|
92 endpoint = &KParValRealm(); |
|
93 } |
|
94 |
|
95 CSenHttpTransportProperties::TSenHttpMethod httpMethod; |
|
96 error = ((CSenHttpTransportProperties*)tp)->HttpMethodL(httpMethod); |
|
97 if (error) |
|
98 { |
|
99 httpMethod = CSenHttpTransportProperties::ESenHttpPost; |
|
100 } |
|
101 //====================NAuth message encoding + signing (algorithm) |
|
102 |
|
103 //____1____ generate random(NONCE) |
|
104 |
|
105 HBufC8* nonce(SenCryptoUtils::GetRandomNonceL()); |
|
106 TLSLOG_FORMAT((KSenCoreServiceManagerLogChannelBase , KMinLogLevel,_L("CWSOviSecurityHandler:: ____1____ generate random(NONCE %S)"), nonce)); |
|
107 |
|
108 |
|
109 //____2____ generate timestamp |
|
110 TTime time; |
|
111 time.UniversalTime(); |
|
112 if (servertime && *servertime > 0/*&& iDiff==0*/) |
|
113 { |
|
114 TTimeIntervalMinutes minutes(*servertime); |
|
115 iDiff = time-minutes; |
|
116 ((CWSOviMessageContext&)aCtx).Update(WSOviContextKeys::KRetryNeeded, 0); |
|
117 } |
|
118 time -= TTimeIntervalMicroSeconds(iDiff.Int64()); |
|
119 HBufC8* timestamp = SenCryptoUtils::GetTimestampL(time); |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 TLSLOG_FORMAT((KSenCoreServiceManagerLogChannelBase , KMinLogLevel,_L("CWSOviSecurityHandler:: ____2____ generate (timestamp %S)"), timestamp)); |
|
127 |
|
128 //____3____ create request without signature |
|
129 |
|
130 const TDesC8* token = aCtx.GetDesC8L(WSOviContextKeys::KToken()); |
|
131 TPtrC8 clearToken = KNullDesC8(); |
|
132 TInt tokenLength(0); |
|
133 if (token && needSecurity) |
|
134 { |
|
135 TInt left = token->Locate('>') + 1; |
|
136 TInt right = token->LocateReverse('<'); |
|
137 clearToken.Set(token->Mid(left, right - left)); |
|
138 tokenLength = clearToken.Length(); |
|
139 tokenLength += KParToken().Length(); |
|
140 tokenLength += KEqual().Length() + KQtMark().Length() + |
|
141 KQtMark().Length() + KComma().Length(); |
|
142 } |
|
143 |
|
144 RBuf8 newValue; |
|
145 newValue.Create(oldValue.Length() + |
|
146 KComma().Length() + |
|
147 |
|
148 KParSignMethod().Length() + |
|
149 KEqual().Length() + KQtMark().Length() + |
|
150 KParValHMACSHA().Length() + |
|
151 KQtMark().Length() + KComma().Length() + |
|
152 |
|
153 KParTimestamp().Length() + |
|
154 KEqual().Length() + KQtMark().Length() + |
|
155 timestamp->Length() + |
|
156 KQtMark().Length() + KComma().Length() + |
|
157 |
|
158 KParNonce().Length() + |
|
159 KEqual().Length() + KQtMark().Length() + |
|
160 nonce->Length() + |
|
161 KQtMark().Length() + KComma().Length() + |
|
162 |
|
163 tokenLength + |
|
164 |
|
165 KParSignature().Length() + |
|
166 KEqual().Length() + KQtMark().Length() + |
|
167 KSHA1OutputSize*3 + |
|
168 KParSignature().Length() |
|
169 |
|
170 ); |
|
171 CleanupClosePushL(newValue); |
|
172 |
|
173 TPtrC8 country; |
|
174 tp->PropertyL(KNCIMCountry(), country); |
|
175 |
|
176 RMapDescriptors& headerProperties = ((CWSOviMessageContext&)aCtx).OAuthProperies(); |
|
177 HBufC8* property = KParValHMACSHA().AllocL(); |
|
178 headerProperties.Insert(&KParSignMethod, property); |
|
179 headerProperties.Insert(&KParTimestamp, timestamp); |
|
180 headerProperties.Insert(&KParNonce, nonce); |
|
181 if (country.Length()) |
|
182 { |
|
183 headerProperties.Insert(&KNCIMCountry, country.AllocL()); |
|
184 } |
|
185 headerProperties.Insert(&KParConsumerKey, consumerKey.AllocL()); |
|
186 if (token && needSecurity) |
|
187 { |
|
188 headerProperties.Insert(&KParToken, clearToken.AllocL()); |
|
189 } |
|
190 |
|
191 newValue.Append(oldValue); |
|
192 newValue.Append(KComma()); |
|
193 |
|
194 |
|
195 |
|
196 newValue.Append(KParSignMethod()); |
|
197 newValue.Append(KEqual()); |
|
198 newValue.Append(KQtMark()); |
|
199 newValue.Append(KParValHMACSHA); |
|
200 newValue.Append(KQtMark()); |
|
201 newValue.Append(KComma()); |
|
202 |
|
203 |
|
204 newValue.Append(KParTimestamp()); |
|
205 newValue.Append(KEqual()); |
|
206 newValue.Append(KQtMark()); |
|
207 newValue.Append(*timestamp); |
|
208 newValue.Append(KQtMark()); |
|
209 newValue.Append(KComma()); |
|
210 |
|
211 |
|
212 newValue.Append(KParNonce()); |
|
213 newValue.Append(KEqual()); |
|
214 newValue.Append(KQtMark()); |
|
215 newValue.Append(*nonce); |
|
216 newValue.Append(KQtMark()); |
|
217 newValue.Append(KComma()); |
|
218 |
|
219 if (token && needSecurity) |
|
220 { |
|
221 newValue.Append(KParToken()); |
|
222 newValue.Append(KEqual()); |
|
223 newValue.Append(KQtMark()); |
|
224 newValue.Append(clearToken); |
|
225 newValue.Append(KQtMark()); |
|
226 newValue.Append(KComma()); |
|
227 } |
|
228 |
|
229 TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler:: ____3____ create request without signature"))); |
|
230 |
|
231 //____4____ normalize request |
|
232 |
|
233 HBufC8* body = NULL; |
|
234 if (bodyMessage) |
|
235 { |
|
236 HBufC8* bodyEncoded = CWSOviUtils::EncodeCharsLC(*bodyMessage); |
|
237 body = HBufC8::NewL(OAuth::KXmlContentEqual().Length()+bodyEncoded->Length()); |
|
238 body->Des().Append(OAuth::KXmlContentEqual()); |
|
239 body->Des().Append(*bodyEncoded); |
|
240 CleanupStack::PopAndDestroy(bodyEncoded); |
|
241 CleanupStack::PushL(body); |
|
242 } |
|
243 |
|
244 TInt length=0; |
|
245 if (body) |
|
246 { |
|
247 length+=body->Length(); |
|
248 length+=KAmpMark().Length(); |
|
249 } |
|
250 for(TInt i=0; i<headerProperties.Count(); i++) |
|
251 { |
|
252 length+=(*headerProperties.KeyAt(i)).Length(); |
|
253 length+=(*headerProperties.ValueAt(i)).Length(); |
|
254 length+=KEqual().Length(); |
|
255 if(i) |
|
256 length+=KAmpMark().Length(); |
|
257 } |
|
258 |
|
259 RBuf8 headerToNormalize; |
|
260 CleanupClosePushL(headerToNormalize); |
|
261 headerToNormalize.Create(length); |
|
262 if (body) |
|
263 { |
|
264 headerToNormalize.Append(*body); |
|
265 headerToNormalize.Append(KAmpMark()); |
|
266 } |
|
267 for(TInt i=0; i<headerProperties.Count(); i++) |
|
268 { |
|
269 headerToNormalize.Append(*headerProperties.KeyAt(i)); |
|
270 headerToNormalize.Append(KEqual()); |
|
271 headerToNormalize.Append(*headerProperties.ValueAt(i)); |
|
272 if(i<headerProperties.Count()-1) |
|
273 headerToNormalize.Append(KAmpMark()); |
|
274 } |
|
275 TLSLOG_ALL(KSenCoreServiceManagerLogChannelBase , KMinLogLevel, headerToNormalize); |
|
276 |
|
277 HBufC8* strToSign = NULL; |
|
278 if (httpMethod == CSenHttpTransportProperties::ESenHttpPost) |
|
279 { |
|
280 strToSign = CWSOviUtils::NormalizeStringLC( KParHttpMethodPost, *endpoint/*KParValRealm*/, headerToNormalize ); |
|
281 } |
|
282 else if (httpMethod == CSenHttpTransportProperties::ESenHttpGet) |
|
283 { |
|
284 strToSign = CWSOviUtils::NormalizeStringLC( KParHttpMethodGet, *endpoint/*KParValRealm*/, headerToNormalize ); |
|
285 } |
|
286 else if(httpMethod == CSenHttpTransportProperties::ESenHttpPut) |
|
287 { |
|
288 strToSign = CWSOviUtils::NormalizeStringLC( KParHttpMethodPut, *endpoint/*KParValRealm*/, headerToNormalize ); |
|
289 } |
|
290 else if(httpMethod == CSenHttpTransportProperties::ESenHttpDelete) |
|
291 { |
|
292 strToSign = CWSOviUtils::NormalizeStringLC( KParHttpMethodDelete, *endpoint/*KParValRealm*/, headerToNormalize ); |
|
293 } |
|
294 #ifdef _SENDEBUG |
|
295 |
|
296 TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler:: ____4____ normalize request"))); |
|
297 if(strToSign) |
|
298 { |
|
299 TLSLOG_ALL(KSenCoreServiceManagerLogChannelBase , KMinLogLevel, *strToSign); |
|
300 } |
|
301 #endif // _SENDEBUG |
|
302 |
|
303 //____5____ calculate hash |
|
304 |
|
305 CSHA1* sha1 = CSHA1::NewL(); |
|
306 CleanupStack::PushL(sha1); |
|
307 |
|
308 TBuf8<KSHA1OutputSize> hash; |
|
309 hash.Copy(sha1->Final(*strToSign)); |
|
310 |
|
311 TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler:: ____5____ calculate hash & Key"))); |
|
312 TLSLOG_ALL(KSenCoreServiceManagerLogChannelBase , KMinLogLevel, hash); |
|
313 |
|
314 //____6____ sign (with HC client secret) |
|
315 |
|
316 |
|
317 /* |
|
318 See http://oauth.net/core/1.0/#anchor16 |
|
319 "...key is the concatenated values (each first encoded per Parameter Encoding (Parameter Encoding)) |
|
320 of the Consumer Secret and Token Secret, separated by an ‘&’ character (ASCII code 38) even if empty..." |
|
321 */ |
|
322 |
|
323 const TDesC8* tokenSecretCtx = aCtx.GetDesC8L(WSOviContextKeys::KTokenSecret()); |
|
324 HBufC8* tokenSecret = NULL; |
|
325 if (tokenSecretCtx && needSecurity) |
|
326 { |
|
327 tokenSecret = CWSOviUtils::EncodeCharsLC(*tokenSecretCtx); |
|
328 } |
|
329 HBufC8* encodedConsumerSecret = CWSOviUtils::EncodeCharsLC(consumerSecret); |
|
330 RBuf8 key; |
|
331 CleanupClosePushL(key); |
|
332 if (tokenSecret && needSecurity) |
|
333 { |
|
334 key.Create(KAmpMark().Length() + |
|
335 encodedConsumerSecret->Length() + |
|
336 tokenSecret->Length() ); |
|
337 } |
|
338 else |
|
339 { |
|
340 key.Create(KAmpMark().Length() + |
|
341 encodedConsumerSecret->Length()); |
|
342 } |
|
343 |
|
344 key.Append(*encodedConsumerSecret); |
|
345 key.Append(KAmpMark()); |
|
346 if (tokenSecret && needSecurity) |
|
347 { |
|
348 key.Append(*tokenSecret); |
|
349 } |
|
350 TLSLOG_ALL(KSenCoreServiceManagerLogChannelBase , KMinLogLevel, key); |
|
351 //CleanupStack::PopAndDestroy(encodedSignatureSecret); |
|
352 CHMAC* hmac = CHMAC::NewL(key, sha1);//sha1 is consumed |
|
353 |
|
354 CleanupStack::PopAndDestroy(&key); |
|
355 CleanupStack::PopAndDestroy(encodedConsumerSecret); |
|
356 if (tokenSecretCtx && needSecurity) |
|
357 { |
|
358 CleanupStack::PopAndDestroy(tokenSecret); |
|
359 } |
|
360 CleanupStack::Pop(sha1); |
|
361 CleanupStack::PushL(hmac); |
|
362 TPtrC8 signatureValue = hmac->Final(*strToSign); //(hash); |
|
363 |
|
364 |
|
365 |
|
366 TLSLOG_FORMAT((KSenCoreServiceManagerLogChannelBase , KMinLogLevel,_L("CWSOviSecurityHandler:: ____6____ sign (with HC client secret %S)"), &signatureValue)); |
|
367 //____7____ append signature to http header |
|
368 |
|
369 newValue.Append(KParSignature()); |
|
370 newValue.Append(KEqual()); |
|
371 newValue.Append(KQtMark()); |
|
372 HBufC8* base64Signature = SenCryptoUtils::EncodeBase64L(signatureValue); |
|
373 CleanupStack::PopAndDestroy(hmac); |
|
374 CleanupStack::PushL(base64Signature); |
|
375 |
|
376 //____8____ URL-encoded |
|
377 HBufC8* encodedSignature = CWSOviUtils::EncodeCharsLC(*base64Signature); |
|
378 |
|
379 newValue.Append(*encodedSignature); |
|
380 newValue.Append(KQtMark()); |
|
381 |
|
382 |
|
383 |
|
384 tp->SetPropertyL(KAuthHttpHeader, newValue, KHttpHeaderType); |
|
385 |
|
386 |
|
387 CleanupStack::PopAndDestroy(encodedSignature); |
|
388 CleanupStack::PopAndDestroy(base64Signature); |
|
389 CleanupStack::PopAndDestroy(strToSign); |
|
390 CleanupStack::PopAndDestroy(&headerToNormalize); |
|
391 if (body) |
|
392 { |
|
393 CleanupStack::PopAndDestroy(body); |
|
394 } |
|
395 CleanupStack::PopAndDestroy(&newValue); |
|
396 TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler:: ____7____ append signature to http header"))); |
|
397 |
|
398 //msg context keeps same tp, so we dont have to update msg context |
|
399 return KErrNone; |
|
400 } |
|
401 |
|
402 |
|
403 SenHandler::THandlerDirection CWSOviSecurityHandler::Direction() const |
|
404 { |
|
405 TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler::Direction()"))); |
|
406 return SenHandler::EOutgoing; |
|
407 }; |
|
408 SenHandler::THandlerPhase CWSOviSecurityHandler::Phase() |
|
409 { |
|
410 TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler::Phase()"))); |
|
411 return SenHandler::EMessage; |
|
412 }; |
|
413 TInt CWSOviSecurityHandler::InitL(MSenHandlerContext& /*aCtx*/) |
|
414 { |
|
415 return KErrNone; |
|
416 } |
|
417 // END OF FILE |
|
418 |