--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/webservices/wsoviplugin/src/wsovisecurityhandler.cpp Thu Jan 07 16:19:19 2010 +0200
@@ -0,0 +1,418 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+
+
+
+
+
+#include <e32std.h>
+#include "wsovisecurityhandler.h"
+#include "wsovicons.h"
+#include "wsovihandlercontext.h"
+#include "senlogger.h"
+#include "wsovimessagecontext.h"
+#include <SenTransportProperties.h>
+#include <SenHttpTransportProperties.h>
+
+#include "wsoviutils.h"
+#include "sencryptoutils.h"
+
+
+using namespace OAuth;
+namespace
+ {
+ const TInt KSHA1OutputSize = 20;// see http://en.wikipedia.org/wiki/SHA_hash_functions
+ }
+// Create instance of concrete ECOM interface implementation
+CWSOviSecurityHandler* CWSOviSecurityHandler::NewL(
+ MSenHandlerContext* aHandlerCtx)
+ {
+
+ CWSOviSecurityHandler* self =
+ new (ELeave) CWSOviSecurityHandler(*aHandlerCtx);
+ return self;
+ }
+
+// Constructor
+CWSOviSecurityHandler::CWSOviSecurityHandler(MSenHandlerContext& aCtx):
+ CSenMessageHandler(aCtx), iDiff(0)
+ {
+ }
+
+// Destructor
+CWSOviSecurityHandler::~CWSOviSecurityHandler()
+ {
+ TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler::~CWSOviSecurityHandler()")));
+ }
+
+TInt CWSOviSecurityHandler::InvokeL(MSenMessageContext& aCtx)
+ {
+ TInt error(KErrNone);
+ TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler::InvokeL(MSenMessageContext& aCtx)")));
+ CSenTransportProperties* tp = ((CWSOviMessageContext&)aCtx).TP();
+ const TInt* servertime = ((CWSOviMessageContext&)aCtx).GetIntL(WSOviContextKeys::KRetryNeeded);
+ const TDesC8* bodyMessage = ((CWSOviMessageContext&)aCtx).GetDesC8L(WSOviContextKeys::KMessageBody);
+
+
+ TPtrC8 oldValue;
+ if (!tp) return KErrNotFound;
+ error = tp->PropertyL(KAuthHttpHeader, oldValue);
+ if (error) return error;//device handler missed
+
+
+ TPtrC8 consumerKey;
+ error = tp->PropertyL(KNCIMConsumerKeyId, consumerKey);
+
+ TPtrC8 consumerSecret;
+ error = tp->PropertyL(KNCIMConsumerSecret, consumerSecret);
+
+ TBool needSecurity(ETrue);
+ error = tp->BoolPropertyL(KNeedSecurity,needSecurity);
+
+
+ const TDesC8* endpoint = ((CWSOviMessageContext&)aCtx).GetDesC8L(KEndpointKey);
+ if (!endpoint)
+ {
+ endpoint = &KParValRealm();
+ }
+
+ CSenHttpTransportProperties::TSenHttpMethod httpMethod;
+ error = ((CSenHttpTransportProperties*)tp)->HttpMethodL(httpMethod);
+ if (error)
+ {
+ httpMethod = CSenHttpTransportProperties::ESenHttpPost;
+ }
+//====================NAuth message encoding + signing (algorithm)
+
+//____1____ generate random(NONCE)
+
+ HBufC8* nonce(SenCryptoUtils::GetRandomNonceL());
+ TLSLOG_FORMAT((KSenCoreServiceManagerLogChannelBase , KMinLogLevel,_L("CWSOviSecurityHandler:: ____1____ generate random(NONCE %S)"), nonce));
+
+
+//____2____ generate timestamp
+ TTime time;
+ time.UniversalTime();
+ if (servertime && *servertime > 0/*&& iDiff==0*/)
+ {
+ TTimeIntervalMinutes minutes(*servertime);
+ iDiff = time-minutes;
+ ((CWSOviMessageContext&)aCtx).Update(WSOviContextKeys::KRetryNeeded, 0);
+ }
+ time -= TTimeIntervalMicroSeconds(iDiff.Int64());
+ HBufC8* timestamp = SenCryptoUtils::GetTimestampL(time);
+
+
+
+
+
+
+ TLSLOG_FORMAT((KSenCoreServiceManagerLogChannelBase , KMinLogLevel,_L("CWSOviSecurityHandler:: ____2____ generate (timestamp %S)"), timestamp));
+
+//____3____ create request without signature
+
+ const TDesC8* token = aCtx.GetDesC8L(WSOviContextKeys::KToken());
+ TPtrC8 clearToken = KNullDesC8();
+ TInt tokenLength(0);
+ if (token && needSecurity)
+ {
+ TInt left = token->Locate('>') + 1;
+ TInt right = token->LocateReverse('<');
+ clearToken.Set(token->Mid(left, right - left));
+ tokenLength = clearToken.Length();
+ tokenLength += KParToken().Length();
+ tokenLength += KEqual().Length() + KQtMark().Length() +
+ KQtMark().Length() + KComma().Length();
+ }
+
+ RBuf8 newValue;
+ newValue.Create(oldValue.Length() +
+ KComma().Length() +
+
+ KParSignMethod().Length() +
+ KEqual().Length() + KQtMark().Length() +
+ KParValHMACSHA().Length() +
+ KQtMark().Length() + KComma().Length() +
+
+ KParTimestamp().Length() +
+ KEqual().Length() + KQtMark().Length() +
+ timestamp->Length() +
+ KQtMark().Length() + KComma().Length() +
+
+ KParNonce().Length() +
+ KEqual().Length() + KQtMark().Length() +
+ nonce->Length() +
+ KQtMark().Length() + KComma().Length() +
+
+ tokenLength +
+
+ KParSignature().Length() +
+ KEqual().Length() + KQtMark().Length() +
+ KSHA1OutputSize*3 +
+ KParSignature().Length()
+
+ );
+ CleanupClosePushL(newValue);
+
+ TPtrC8 country;
+ tp->PropertyL(KNCIMCountry(), country);
+
+ RMapDescriptors& headerProperties = ((CWSOviMessageContext&)aCtx).OAuthProperies();
+ HBufC8* property = KParValHMACSHA().AllocL();
+ headerProperties.Insert(&KParSignMethod, property);
+ headerProperties.Insert(&KParTimestamp, timestamp);
+ headerProperties.Insert(&KParNonce, nonce);
+ if (country.Length())
+ {
+ headerProperties.Insert(&KNCIMCountry, country.AllocL());
+ }
+ headerProperties.Insert(&KParConsumerKey, consumerKey.AllocL());
+ if (token && needSecurity)
+ {
+ headerProperties.Insert(&KParToken, clearToken.AllocL());
+ }
+
+ newValue.Append(oldValue);
+ newValue.Append(KComma());
+
+
+
+ newValue.Append(KParSignMethod());
+ newValue.Append(KEqual());
+ newValue.Append(KQtMark());
+ newValue.Append(KParValHMACSHA);
+ newValue.Append(KQtMark());
+ newValue.Append(KComma());
+
+
+ newValue.Append(KParTimestamp());
+ newValue.Append(KEqual());
+ newValue.Append(KQtMark());
+ newValue.Append(*timestamp);
+ newValue.Append(KQtMark());
+ newValue.Append(KComma());
+
+
+ newValue.Append(KParNonce());
+ newValue.Append(KEqual());
+ newValue.Append(KQtMark());
+ newValue.Append(*nonce);
+ newValue.Append(KQtMark());
+ newValue.Append(KComma());
+
+ if (token && needSecurity)
+ {
+ newValue.Append(KParToken());
+ newValue.Append(KEqual());
+ newValue.Append(KQtMark());
+ newValue.Append(clearToken);
+ newValue.Append(KQtMark());
+ newValue.Append(KComma());
+ }
+
+ TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler:: ____3____ create request without signature")));
+
+//____4____ normalize request
+
+ HBufC8* body = NULL;
+ if (bodyMessage)
+ {
+ HBufC8* bodyEncoded = CWSOviUtils::EncodeCharsLC(*bodyMessage);
+ body = HBufC8::NewL(OAuth::KXmlContentEqual().Length()+bodyEncoded->Length());
+ body->Des().Append(OAuth::KXmlContentEqual());
+ body->Des().Append(*bodyEncoded);
+ CleanupStack::PopAndDestroy(bodyEncoded);
+ CleanupStack::PushL(body);
+ }
+
+ TInt length=0;
+ if (body)
+ {
+ length+=body->Length();
+ length+=KAmpMark().Length();
+ }
+ for(TInt i=0; i<headerProperties.Count(); i++)
+ {
+ length+=(*headerProperties.KeyAt(i)).Length();
+ length+=(*headerProperties.ValueAt(i)).Length();
+ length+=KEqual().Length();
+ if(i)
+ length+=KAmpMark().Length();
+ }
+
+ RBuf8 headerToNormalize;
+ CleanupClosePushL(headerToNormalize);
+ headerToNormalize.Create(length);
+ if (body)
+ {
+ headerToNormalize.Append(*body);
+ headerToNormalize.Append(KAmpMark());
+ }
+ for(TInt i=0; i<headerProperties.Count(); i++)
+ {
+ headerToNormalize.Append(*headerProperties.KeyAt(i));
+ headerToNormalize.Append(KEqual());
+ headerToNormalize.Append(*headerProperties.ValueAt(i));
+ if(i<headerProperties.Count()-1)
+ headerToNormalize.Append(KAmpMark());
+ }
+ TLSLOG_ALL(KSenCoreServiceManagerLogChannelBase , KMinLogLevel, headerToNormalize);
+
+ HBufC8* strToSign = NULL;
+ if (httpMethod == CSenHttpTransportProperties::ESenHttpPost)
+ {
+ strToSign = CWSOviUtils::NormalizeStringLC( KParHttpMethodPost, *endpoint/*KParValRealm*/, headerToNormalize );
+ }
+ else if (httpMethod == CSenHttpTransportProperties::ESenHttpGet)
+ {
+ strToSign = CWSOviUtils::NormalizeStringLC( KParHttpMethodGet, *endpoint/*KParValRealm*/, headerToNormalize );
+ }
+ else if(httpMethod == CSenHttpTransportProperties::ESenHttpPut)
+ {
+ strToSign = CWSOviUtils::NormalizeStringLC( KParHttpMethodPut, *endpoint/*KParValRealm*/, headerToNormalize );
+ }
+ else if(httpMethod == CSenHttpTransportProperties::ESenHttpDelete)
+ {
+ strToSign = CWSOviUtils::NormalizeStringLC( KParHttpMethodDelete, *endpoint/*KParValRealm*/, headerToNormalize );
+ }
+#ifdef _SENDEBUG
+
+ TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler:: ____4____ normalize request")));
+ if(strToSign)
+ {
+ TLSLOG_ALL(KSenCoreServiceManagerLogChannelBase , KMinLogLevel, *strToSign);
+ }
+#endif // _SENDEBUG
+
+//____5____ calculate hash
+
+ CSHA1* sha1 = CSHA1::NewL();
+ CleanupStack::PushL(sha1);
+
+ TBuf8<KSHA1OutputSize> hash;
+ hash.Copy(sha1->Final(*strToSign));
+
+ TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler:: ____5____ calculate hash & Key")));
+ TLSLOG_ALL(KSenCoreServiceManagerLogChannelBase , KMinLogLevel, hash);
+
+//____6____ sign (with HC client secret)
+
+
+ /*
+ See http://oauth.net/core/1.0/#anchor16
+ "...key is the concatenated values (each first encoded per Parameter Encoding (Parameter Encoding))
+ of the Consumer Secret and Token Secret, separated by an ‘&’ character (ASCII code 38) even if empty..."
+ */
+
+ const TDesC8* tokenSecretCtx = aCtx.GetDesC8L(WSOviContextKeys::KTokenSecret());
+ HBufC8* tokenSecret = NULL;
+ if (tokenSecretCtx && needSecurity)
+ {
+ tokenSecret = CWSOviUtils::EncodeCharsLC(*tokenSecretCtx);
+ }
+ HBufC8* encodedConsumerSecret = CWSOviUtils::EncodeCharsLC(consumerSecret);
+ RBuf8 key;
+ CleanupClosePushL(key);
+ if (tokenSecret && needSecurity)
+ {
+ key.Create(KAmpMark().Length() +
+ encodedConsumerSecret->Length() +
+ tokenSecret->Length() );
+ }
+ else
+ {
+ key.Create(KAmpMark().Length() +
+ encodedConsumerSecret->Length());
+ }
+
+ key.Append(*encodedConsumerSecret);
+ key.Append(KAmpMark());
+ if (tokenSecret && needSecurity)
+ {
+ key.Append(*tokenSecret);
+ }
+ TLSLOG_ALL(KSenCoreServiceManagerLogChannelBase , KMinLogLevel, key);
+ //CleanupStack::PopAndDestroy(encodedSignatureSecret);
+ CHMAC* hmac = CHMAC::NewL(key, sha1);//sha1 is consumed
+
+ CleanupStack::PopAndDestroy(&key);
+ CleanupStack::PopAndDestroy(encodedConsumerSecret);
+ if (tokenSecretCtx && needSecurity)
+ {
+ CleanupStack::PopAndDestroy(tokenSecret);
+ }
+ CleanupStack::Pop(sha1);
+ CleanupStack::PushL(hmac);
+ TPtrC8 signatureValue = hmac->Final(*strToSign); //(hash);
+
+
+
+ TLSLOG_FORMAT((KSenCoreServiceManagerLogChannelBase , KMinLogLevel,_L("CWSOviSecurityHandler:: ____6____ sign (with HC client secret %S)"), &signatureValue));
+//____7____ append signature to http header
+
+ newValue.Append(KParSignature());
+ newValue.Append(KEqual());
+ newValue.Append(KQtMark());
+ HBufC8* base64Signature = SenCryptoUtils::EncodeBase64L(signatureValue);
+ CleanupStack::PopAndDestroy(hmac);
+ CleanupStack::PushL(base64Signature);
+
+//____8____ URL-encoded
+ HBufC8* encodedSignature = CWSOviUtils::EncodeCharsLC(*base64Signature);
+
+ newValue.Append(*encodedSignature);
+ newValue.Append(KQtMark());
+
+
+
+ tp->SetPropertyL(KAuthHttpHeader, newValue, KHttpHeaderType);
+
+
+ CleanupStack::PopAndDestroy(encodedSignature);
+ CleanupStack::PopAndDestroy(base64Signature);
+ CleanupStack::PopAndDestroy(strToSign);
+ CleanupStack::PopAndDestroy(&headerToNormalize);
+ if (body)
+ {
+ CleanupStack::PopAndDestroy(body);
+ }
+ CleanupStack::PopAndDestroy(&newValue);
+ TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler:: ____7____ append signature to http header")));
+
+ //msg context keeps same tp, so we dont have to update msg context
+ return KErrNone;
+ }
+
+
+SenHandler::THandlerDirection CWSOviSecurityHandler::Direction() const
+ {
+ TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler::Direction()")));
+ return SenHandler::EOutgoing;
+ };
+SenHandler::THandlerPhase CWSOviSecurityHandler::Phase()
+ {
+ TLSLOG(KSenCoreServiceManagerLogChannelBase , KMinLogLevel,(_L("CWSOviSecurityHandler::Phase()")));
+ return SenHandler::EMessage;
+ };
+TInt CWSOviSecurityHandler::InitL(MSenHandlerContext& /*aCtx*/)
+ {
+ return KErrNone;
+ }
+// END OF FILE
+