From 9acfd11de7f811862eb51e27e05a883870df134f Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Fri, 12 Dec 2014 15:40:47 +0200 Subject: [PATCH 5/7] signon-accounts: implement getCredentials Use the information contained in the AgAuthData object to decide which authentication method is being used. Move the common authentication code into a private authenticate() method. [PO: fixed g_variant_builder_end() mem leak] [PO: avoid issue found via cppcheck: returning std::string::c_str() in a method returning a std::string forces a string copy, which is inefficient.] [PO: UiPolicy was not set because of an invalid g_variant_builder_add() "sv" parameter.] --- src/backends/signon/signon-accounts.cpp | 91 +++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 21 deletions(-) diff --git a/src/backends/signon/signon-accounts.cpp b/src/backends/signon/signon-accounts.cpp index 33d02c0..d8f67dc 100644 --- a/src/backends/signon/signon-accounts.cpp +++ b/src/backends/signon/signon-accounts.cpp @@ -65,6 +65,7 @@ class SignonAuthProvider : public AuthProvider SignonAuthSessionCXX m_authSession; AgAuthDataCXX m_authData; std::string m_accessToken; + Credentials m_credentials; bool m_invalidateCache; public: @@ -75,9 +76,51 @@ public: m_invalidateCache(false) {} - virtual bool methodIsSupported(AuthMethod method) const { return method == AUTH_METHOD_OAUTH2; } + virtual bool methodIsSupported(AuthMethod method) const { + // Unless the method name is "password", let's assume it's OAuth; + // note that we don't explicitly check if the method name is a + // OAuth one, because gSSO and UOA use different method names for + // their OAuth implementations + AuthMethod ourMethod = + (strcmp(ag_auth_data_get_method(m_authData), "password") == 0) ? + AUTH_METHOD_CREDENTIALS : AUTH_METHOD_OAUTH2; + return method == ourMethod; + } + + virtual Credentials getCredentials() { + SE_LOG_DEBUG(NULL, "retrieving password"); + + if (!m_credentials.m_password.empty() && !m_invalidateCache) { + return m_credentials; + } + + GVariantBuilder builder; + g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); + if (m_invalidateCache) { + // Request the user's password + g_variant_builder_add(&builder, "{sv}", "UiPolicy", + g_variant_new_uint32(SIGNON_POLICY_REQUEST_PASSWORD)); + } + GVariantCXX extraOptions(g_variant_take_ref(g_variant_builder_end(&builder)), TRANSFER_REF); - virtual Credentials getCredentials() { SE_THROW("only OAuth2 is supported"); } + GVariantCXX resultData = authenticate(extraOptions); + GVariantCXX usernameVar(g_variant_lookup_value(resultData, "UserName", G_VARIANT_TYPE_STRING), TRANSFER_REF); + GVariantCXX passwordVar(g_variant_lookup_value(resultData, "Secret", G_VARIANT_TYPE_STRING), TRANSFER_REF); + if (!usernameVar || !passwordVar) { + SE_THROW("Username or password missing"); + } + Credentials credentials; + credentials.m_username = g_variant_get_string(usernameVar, NULL); + credentials.m_password = g_variant_get_string(passwordVar, NULL); + if (credentials.m_password.empty()) { + SE_THROW("Got an empty password"); + } else if (m_invalidateCache && + credentials.m_password == m_credentials.m_password) { + SE_THROW("Got the same invalid credentials"); + } + m_credentials = credentials; + return m_credentials; + } virtual std::string getOAuth2Bearer(const PasswordUpdateCallback &passwordUpdateCallback) { @@ -96,6 +139,27 @@ public: } GVariantCXX extraOptions(g_variant_take_ref(g_variant_builder_end(&builder)), TRANSFER_REF); + GVariantCXX resultData = authenticate(extraOptions); + GVariantCXX tokenVar(g_variant_lookup_value(resultData, "AccessToken", G_VARIANT_TYPE_STRING), TRANSFER_REF); + if (!tokenVar) { + SE_THROW("no AccessToken in OAuth2 response"); + } + std::string newToken = g_variant_get_string(tokenVar, NULL); + if (newToken.empty()) { + SE_THROW("AccessToken did not contain a string value"); + } else if (m_invalidateCache && newToken == m_accessToken) { + SE_THROW("Got the same invalid AccessToken"); + } + m_accessToken = newToken; + return m_accessToken; + } + + virtual void invalidateCachedSecrets() { m_invalidateCache = true; } + + virtual std::string getUsername() const { return ""; } + +private: + GVariantCXX authenticate(GVariant *extraOptions) { // We get assigned a plain pointer to an instance that we'll own, // so we have to use the "steal" variant to enable that assignment. GVariantStealCXX resultData; @@ -103,7 +167,7 @@ public: GVariantCXX sessionData(ag_auth_data_get_login_parameters(m_authData, extraOptions), TRANSFER_REF); const char *mechanism = ag_auth_data_get_mechanism(m_authData); PlainGStr buffer(g_variant_print(sessionData, true)); - SE_LOG_DEBUG(NULL, "asking for OAuth2 token with method %s, mechanism %s and parameters %s", + SE_LOG_DEBUG(NULL, "asking for authentication with method %s, mechanism %s and parameters %s", signon_auth_session_get_method(m_authSession), mechanism, buffer.get()); @@ -112,31 +176,16 @@ public: SYNCEVO_GLIB_CALL_SYNC(resultData, gerror, signon_auth_session_process_async, m_authSession, sessionData, mechanism, NULL); buffer.reset(resultData ? g_variant_print(resultData, true) : NULL); - SE_LOG_DEBUG(NULL, "OAuth2 token result: %s, %s", + SE_LOG_DEBUG(NULL, "authentication result: %s, %s", buffer.get() ? buffer.get() : "<>", gerror ? gerror->message : "???"); if (!resultData || gerror) { SE_THROW_EXCEPTION_STATUS(StatusException, - StringPrintf("could not obtain OAuth2 token: %s", gerror ? gerror->message : "???"), + StringPrintf("could not authenticate: %s", gerror ? gerror->message : "???"), STATUS_FORBIDDEN); } - GVariantCXX tokenVar(g_variant_lookup_value(resultData, "AccessToken", G_VARIANT_TYPE_STRING), TRANSFER_REF); - if (!tokenVar) { - SE_THROW("no AccessToken in OAuth2 response"); - } - std::string newToken = g_variant_get_string(tokenVar, NULL); - if (newToken.empty()) { - SE_THROW("AccessToken did not contain a string value"); - } else if (m_invalidateCache && newToken == m_accessToken) { - SE_THROW("Got the same invalid AccessToken"); - } - m_accessToken = newToken; - return m_accessToken; + return resultData; } - - virtual void invalidateCachedSecrets() { m_invalidateCache = true; } - - virtual std::string getUsername() const { return ""; } }; class StoreIdentityData -- 2.1.4