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.]
This commit is contained in:
Alberto Mardegan 2014-12-12 15:40:47 +02:00 committed by Patrick Ohly
parent c58ed9ff59
commit 9acfd11de7
1 changed files with 75 additions and 26 deletions

View File

@ -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_THROW("only OAuth2 is supported"); }
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);
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,30 +139,7 @@ public:
}
GVariantCXX extraOptions(g_variant_take_ref(g_variant_builder_end(&builder)), TRANSFER_REF);
// 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;
GErrorCXX gerror;
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",
signon_auth_session_get_method(m_authSession),
mechanism,
buffer.get());
#define signon_auth_session_process_async_finish signon_auth_session_process_finish
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",
buffer.get() ? buffer.get() : "<<null>>",
gerror ? gerror->message : "???");
if (!resultData || gerror) {
SE_THROW_EXCEPTION_STATUS(StatusException,
StringPrintf("could not obtain OAuth2 token: %s", gerror ? gerror->message : "???"),
STATUS_FORBIDDEN);
}
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");
@ -137,6 +157,35 @@ public:
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;
GErrorCXX gerror;
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 authentication with method %s, mechanism %s and parameters %s",
signon_auth_session_get_method(m_authSession),
mechanism,
buffer.get());
#define signon_auth_session_process_async_finish signon_auth_session_process_finish
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, "authentication result: %s, %s",
buffer.get() ? buffer.get() : "<<null>>",
gerror ? gerror->message : "???");
if (!resultData || gerror) {
SE_THROW_EXCEPTION_STATUS(StatusException,
StringPrintf("could not authenticate: %s", gerror ? gerror->message : "???"),
STATUS_FORBIDDEN);
}
return resultData;
}
};
class StoreIdentityData