diff options
author | Monroe Linden <monroe@lindenlab.com> | 2010-03-31 13:53:40 -0700 |
---|---|---|
committer | Monroe Linden <monroe@lindenlab.com> | 2010-03-31 13:53:40 -0700 |
commit | 5c190996222ce2cf14997e16e16beb110173c0a2 (patch) | |
tree | 65e8f0c71de7b8cf9283bdae14036d1693f14563 /indra | |
parent | e504f895135eec69d9ec5ee31cdefc2ced145631 (diff) |
Enable OpenID auth in the embedded webkit browser.
Extract openid_url and openid_token tokens from the login response in process_login_success_response() and send them to LLViewerMedia if they're present.
Added LLViewerMedia::openIDSetup() to receive openid_url and openid_token, and added code to LLViewerMedia to do a POST with LLHTTPClient, retrieve the resulting cookie, and push it into the central cookie store. Also made sure the OpenID cookie gets re-added when the cookie store is cleared.
Added LLPluginCookieStore::setCookiesFromHost() to properly add a cookie that may not have a domain set. Made LLPluginCookieStore::Cookie::parse() add missing domain and path fields to cookies as necessary.
Fixed an issue where carriage returns in the string passed to LLPluginCookieStore::setCookies() or LLPluginCookieStore::setCookiesFromHost() would cause a parse failure.
Reviewed by gino and callum at http://codereview.lindenlab.com/1254001
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llplugin/llplugincookiestore.cpp | 73 | ||||
-rw-r--r-- | indra/llplugin/llplugincookiestore.h | 9 | ||||
-rw-r--r-- | indra/newview/llstartup.cpp | 7 | ||||
-rw-r--r-- | indra/newview/llviewermedia.cpp | 99 | ||||
-rw-r--r-- | indra/newview/llviewermedia.h | 8 |
5 files changed, 184 insertions, 12 deletions
diff --git a/indra/llplugin/llplugincookiestore.cpp b/indra/llplugin/llplugincookiestore.cpp index 1964b8d789..92ee24e1d5 100644 --- a/indra/llplugin/llplugincookiestore.cpp +++ b/indra/llplugin/llplugincookiestore.cpp @@ -62,11 +62,11 @@ LLPluginCookieStore::Cookie::Cookie(const std::string &s, std::string::size_type { } -LLPluginCookieStore::Cookie *LLPluginCookieStore::Cookie::createFromString(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end) +LLPluginCookieStore::Cookie *LLPluginCookieStore::Cookie::createFromString(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, const std::string &host) { Cookie *result = new Cookie(s, cookie_start, cookie_end); - if(!result->parse()) + if(!result->parse(host)) { delete result; result = NULL; @@ -92,7 +92,7 @@ std::string LLPluginCookieStore::Cookie::getKey() const return result; } -bool LLPluginCookieStore::Cookie::parse() +bool LLPluginCookieStore::Cookie::parse(const std::string &host) { bool first_field = true; @@ -248,7 +248,50 @@ bool LLPluginCookieStore::Cookie::parse() // The cookie MUST have a name if(mNameEnd <= mNameStart) return false; + + // If the cookie doesn't have a domain, add the current host as the domain. + if(mDomainEnd <= mDomainStart) + { + if(host.empty()) + { + // no domain and no current host -- this is a parse failure. + return false; + } + + // Figure out whether this cookie ended with a ";" or not... + std::string::size_type last_char = mCookie.find_last_not_of(" "); + if((last_char != std::string::npos) && (mCookie[last_char] != ';')) + { + mCookie += ";"; + } + + mCookie += " domain="; + mDomainStart = mCookie.size(); + mCookie += host; + mDomainEnd = mCookie.size(); + + lldebugs << "added domain (" << mDomainStart << " to " << mDomainEnd << "), new cookie is: " << mCookie << llendl; + } + + // If the cookie doesn't have a path, add "/". + if(mPathEnd <= mPathStart) + { + // Figure out whether this cookie ended with a ";" or not... + std::string::size_type last_char = mCookie.find_last_not_of(" "); + if((last_char != std::string::npos) && (mCookie[last_char] != ';')) + { + mCookie += ";"; + } + + mCookie += " path="; + mPathStart = mCookie.size(); + mCookie += "/"; + mPathEnd = mCookie.size(); + lldebugs << "added path (" << mPathStart << " to " << mPathEnd << "), new cookie is: " << mCookie << llendl; + } + + return true; } @@ -409,13 +452,29 @@ void LLPluginCookieStore::setCookies(const std::string &cookies, bool mark_chang while(start != std::string::npos) { - std::string::size_type end = cookies.find('\n', start); + std::string::size_type end = cookies.find_first_of("\r\n", start); if(end > start) { // The line is non-empty. Try to create a cookie from it. setOneCookie(cookies, start, end, mark_changed); } - start = cookies.find_first_not_of("\n ", end); + start = cookies.find_first_not_of("\r\n ", end); + } +} + +void LLPluginCookieStore::setCookiesFromHost(const std::string &cookies, const std::string &host, bool mark_changed) +{ + std::string::size_type start = 0; + + while(start != std::string::npos) + { + std::string::size_type end = cookies.find_first_of("\r\n", start); + if(end > start) + { + // The line is non-empty. Try to create a cookie from it. + setOneCookie(cookies, start, end, mark_changed, host); + } + start = cookies.find_first_not_of("\r\n ", end); } } @@ -502,9 +561,9 @@ std::string LLPluginCookieStore::unquoteString(const std::string &s) // When deleting with mark_changed set to true, this replaces the existing cookie in the list with an entry that's marked both dead and changed. // Some time later when writeChangedCookies() is called with clear_changed set to true, the dead cookie is deleted from the list after being returned, so that the // delete operation (in the form of the expired cookie) is passed along. -void LLPluginCookieStore::setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed) +void LLPluginCookieStore::setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed, const std::string &host) { - Cookie *cookie = Cookie::createFromString(s, cookie_start, cookie_end); + Cookie *cookie = Cookie::createFromString(s, cookie_start, cookie_end, host); if(cookie) { lldebugs << "setting cookie: " << cookie->getCookie() << llendl; diff --git a/indra/llplugin/llplugincookiestore.h b/indra/llplugin/llplugincookiestore.h index 5250f008b6..a93f0c14f0 100644 --- a/indra/llplugin/llplugincookiestore.h +++ b/indra/llplugin/llplugincookiestore.h @@ -66,18 +66,21 @@ public: void setCookies(const std::string &cookies, bool mark_changed = true); void readCookies(std::istream& s, bool mark_changed = true); + // sets one or more cookies (without reinitializing anything), supplying a hostname the cookies came from -- use when setting a cookie manually + void setCookiesFromHost(const std::string &cookies, const std::string &host, bool mark_changed = true); + // quote or unquote a string as per the definition of 'quoted-string' in rfc2616 static std::string quoteString(const std::string &s); static std::string unquoteString(const std::string &s); private: - void setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed); + void setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed, const std::string &host = LLStringUtil::null); class Cookie { public: - static Cookie *createFromString(const std::string &s, std::string::size_type cookie_start = 0, std::string::size_type cookie_end = std::string::npos); + static Cookie *createFromString(const std::string &s, std::string::size_type cookie_start = 0, std::string::size_type cookie_end = std::string::npos, const std::string &host = LLStringUtil::null); // Construct a string from the cookie that uniquely represents it, to be used as a key in a std::map. std::string getKey() const; @@ -95,7 +98,7 @@ private: private: Cookie(const std::string &s, std::string::size_type cookie_start = 0, std::string::size_type cookie_end = std::string::npos); - bool parse(); + bool parse(const std::string &host); std::string::size_type findFieldEnd(std::string::size_type start = 0, std::string::size_type end = std::string::npos); bool matchName(std::string::size_type start, std::string::size_type end, const char *name); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 1a1dffe85c..b5a73a3143 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3087,6 +3087,13 @@ bool process_login_success_response() } } + // Start the process of fetching the OpenID session cookie for this user login + std::string openid_url = response["openid_url"]; + if(!openid_url.empty()) + { + std::string openid_token = response["openid_token"]; + LLViewerMedia::openIDSetup(openid_url, openid_token); + } bool success = false; // JC: gesture loading done below, when we have an asset system diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 6f0d9cdd95..d9fabc7d64 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -257,7 +257,43 @@ public: LLViewerMediaImpl *mMediaImpl; bool mInitialized; }; + +class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLViewerMediaOpenIDResponder); +public: + LLViewerMediaOpenIDResponder( ) + { + } + + ~LLViewerMediaOpenIDResponder() + { + } + + /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + LL_DEBUGS("MediaAuth") << content << LL_ENDL; + std::string cookie = content["set-cookie"].asString(); + + LLViewerMedia::openIDCookieResponse(cookie); + } + + /* virtual */ void completedRaw( + U32 status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + // This is just here to disable the default behavior (attempting to parse the response as llsd). + // We don't care about the content of the response, only the set-cookie header. + } + +}; + LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; +LLURL LLViewerMedia::sOpenIDURL; +std::string LLViewerMedia::sOpenIDCookie; static LLViewerMedia::impl_list sViewerMediaImplList; static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap; static LLTimer sMediaCreateTimer; @@ -1067,7 +1103,8 @@ void LLViewerMedia::clearAllCookies() } } - + // If we have an OpenID cookie, re-add it to the cookie store. + setOpenIDCookie(); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1168,7 +1205,9 @@ void LLViewerMedia::loadCookieFile() pimpl->mMediaSource->clear_cookies(); } } - + + // If we have an OpenID cookie, re-add it to the cookie store. + setOpenIDCookie(); } @@ -1241,6 +1280,62 @@ void LLViewerMedia::removeCookie(const std::string &name, const std::string &dom } +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setOpenIDCookie() +{ + if(!sOpenIDCookie.empty()) + { + getCookieStore()->setCookiesFromHost(sOpenIDCookie, sOpenIDURL.mAuthority); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token) +{ + LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL; + + // post the token to the url + // the responder will need to extract the cookie(s). + + // Save the OpenID URL for later -- we may need the host when adding the cookie. + sOpenIDURL.init(openid_url.c_str()); + + // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. + sOpenIDCookie.clear(); + + LLSD headers = LLSD::emptyMap(); + // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header + headers["Accept"] = "*/*"; + // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" + headers["Content-Type"] = "application/x-www-form-urlencoded"; + + // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. + size_t size = openid_token.size(); + U8 *data = new U8[size]; + memcpy(data, openid_token.data(), size); + + LLHTTPClient::postRaw( + openid_url, + data, + size, + new LLViewerMediaOpenIDResponder(), + headers); + +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::openIDCookieResponse(const std::string &cookie) +{ + LL_DEBUGS("MediaAuth") << "Cookie received: \"" << cookie << "\"" << LL_ENDL; + + sOpenIDCookie += cookie; + + setOpenIDCookie(); +} + bool LLViewerMedia::hasInWorldMedia() { if (sInWorldMediaDisabled) return false; diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 10dacf9532..e829d7a5b4 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -44,6 +44,8 @@ #include "llpluginclassmedia.h" #include "v4color.h" +#include "llurl.h" + class LLViewerMediaImpl; class LLUUID; class LLViewerMediaTexture; @@ -152,11 +154,17 @@ public: static void addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path = std::string("/"), bool secure = false ); static void addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path = std::string("/"), bool secure = false ); static void removeCookie(const std::string &name, const std::string &domain, const std::string &path = std::string("/") ); + + static void openIDSetup(const std::string &openid_url, const std::string &openid_token); + static void openIDCookieResponse(const std::string &cookie); private: + static void setOpenIDCookie(); static void onTeleportFinished(); static LLPluginCookieStore *sCookieStore; + static LLURL sOpenIDURL; + static std::string sOpenIDCookie; }; // Implementation functions not exported into header file |