SyncConfig: implement "id" handling for reading and writing credentials

save/checkPassword both know how to handle the "id" provider now.
This commit is contained in:
Patrick Ohly 2013-07-26 16:19:40 +02:00
parent efd6b2aebf
commit 1ab5aeac8d
2 changed files with 157 additions and 68 deletions

View file

@ -1370,6 +1370,12 @@ public:
PasswordConfigProperty::checkPassword(ui, config, syncPropUsername, sourceName);
}
virtual void savePassword(UserInterface &ui,
SyncConfig &config,
const std::string &sourceName = "") const {
PasswordConfigProperty::savePassword(ui, config, syncPropUsername, sourceName);
}
ConfigPasswordKey getPasswordKey(const string &descr,
const string &serverName,
FilterConfigNode &globalConfigNode,
@ -1460,6 +1466,11 @@ public:
PasswordConfigProperty::checkPassword(ui, config, syncPropProxyUsername, sourceName);
}
}
virtual void savePassword(UserInterface &ui,
SyncConfig &config,
const std::string &sourceName = std::string()) const {
PasswordConfigProperty::savePassword(ui, config, syncPropProxyUsername, sourceName);
}
virtual ConfigPasswordKey getPasswordKey(const std::string &descr,
const std::string &serverName,
FilterConfigNode &globalConfigNode,
@ -1977,59 +1988,88 @@ void PasswordConfigProperty::checkPassword(UserInterface &ui,
if (!sourceName.empty()) {
sourceConfigNode = config.getSyncSourceNodes(sourceName).getNode(*this);
}
InitStateString username = usernameProperty.getProperty(sourceConfigNode ? *sourceConfigNode : *globalConfigNode);
FilterConfigNode &configNode = sourceConfigNode ? *sourceConfigNode : *globalConfigNode;
InitStateString username = usernameProperty.getProperty(configNode);
SE_LOG_DEBUG(NULL, "checking password property '%s' in config '%s' with user identity '%s'",
getMainName().c_str(),
serverName.c_str(),
username.c_str());
UserIdentity identity(UserIdentity::fromString(username));
InitStateString passwordToSave;
InitStateString usernameToSave;
if (identity.m_provider == USER_IDENTITY_SYNC_CONFIG) {
// TODO: Actual username/password are stored in a different config. Go find it...
return;
}
if (identity.m_provider != USER_IDENTITY_PLAIN_TEXT) {
const std::string &credConfigName = identity.m_identity;
SE_LOG_INFO(NULL, "using %s/%s from config '%s' as credentials for %s%s%s",
syncPropUsername.getMainName().c_str(),
syncPropPassword.getMainName().c_str(),
credConfigName.c_str(),
serverName.c_str(),
sourceName.empty() ? "" : "/",
sourceName.c_str());
// Actual username/password are stored in a different config. Go find it...
SyncConfig::Layout layout = config.getLayout();
if (layout != SyncConfig::SHARED_LAYOUT) {
SE_THROW(StringPrintf("%s = %s: only supported in configs using the current config storage, please migrate config %s",
usernameProperty.getMainName().c_str(),
username.c_str(),
config.getConfigName().c_str()));
}
boost::shared_ptr<SyncConfig> credConfig(new SyncConfig(credConfigName));
if (!credConfig->exists()) {
SE_THROW(StringPrintf("%s = %s: config '%s' not found, cannot look up credentials",
usernameProperty.getMainName().c_str(),
username.c_str(),
credConfigName.c_str()));
}
syncPropPassword.checkPassword(ui, *credConfig);
// Always store the new values.
passwordToSave = InitStateString(credConfig->getSyncPassword(), true);
usernameToSave = InitStateString(credConfig->getSyncUser().toString(), true);
} else if (identity.m_provider != USER_IDENTITY_PLAIN_TEXT) {
// Can some provider give us the plain text password? Not at the moment,
// so we've got nothing to do here.
return;
}
// Default, internal password handling.
string password, passwordSave;
/* if no source config node, then it should only be password in the global config node */
if(sourceConfigNode.get() == NULL) {
password = getProperty(*globalConfigNode);
} else {
password = getProperty(*sourceConfigNode);
// Default, internal password handling.
InitStateString password = getProperty(configNode);
string descr = getDescr(serverName,*globalConfigNode,sourceName,sourceConfigNode);
if (password == "-") {
ConfigPasswordKey key = getPasswordKey(descr,serverName,*globalConfigNode,sourceName,sourceConfigNode);
std::string uiPassword = ui.askPassword(getMainName(),descr, key);
// Empty means "no response". askPassword() pre-dates the
// InitStateString class, and probably should be changed
// to use it to avoid this kind of ambiguity, but for now
// keep this semantic. Therefore don't use the result if
// empty.
if (!uiPassword.empty()) {
passwordToSave = uiPassword;
}
} else if(boost::starts_with(password, "${") &&
boost::ends_with(password, "}")) {
string envname = password.substr(2, password.size() - 3);
const char *envval = getenv(envname.c_str());
if (!envval) {
SyncContext::throwError(string("the environment variable '") +
envname +
"' for the '" +
descr +
"' password is not set");
} else {
passwordToSave = envval;
}
}
}
string descr = getDescr(serverName,*globalConfigNode,sourceName,sourceConfigNode);
if (password == "-") {
ConfigPasswordKey key = getPasswordKey(descr,serverName,*globalConfigNode,sourceName,sourceConfigNode);
passwordSave = ui.askPassword(getMainName(),descr, key);
} else if(boost::starts_with(password, "${") &&
boost::ends_with(password, "}")) {
string envname = password.substr(2, password.size() - 3);
const char *envval = getenv(envname.c_str());
if (!envval) {
SyncContext::throwError(string("the environment variable '") +
envname +
"' for the '" +
descr +
"' password is not set");
} else {
passwordSave = envval;
}
// If we found a password, then set it in the config node
// temporarily. That way, all following "get password" calls will
// be able to return it without having to make all callers away of
// password handling.
if (passwordToSave.wasSet()) {
configNode.addFilter(getMainName(), InitStateString(passwordToSave, true));
}
/* If password is from ui or environment variable, set them in the config node on fly
* Previous impl use temp string to store them, this is not good for expansion in the backend */
if(!passwordSave.empty()) {
if(sourceConfigNode.get() == NULL) {
globalConfigNode->addFilter(getMainName(), InitStateString(passwordSave, true));
} else {
sourceConfigNode->addFilter(getMainName(), InitStateString(passwordSave, true));
}
if (usernameToSave.wasSet()) {
configNode.addFilter(usernameProperty.getMainName(), InitStateString(usernameToSave, true));
}
}
@ -2043,6 +2083,7 @@ std::string PasswordConfigProperty::getUsername(const ConfigProperty &usernamePr
void PasswordConfigProperty::savePassword(UserInterface &ui,
SyncConfig &config,
const ConfigProperty &usernameProperty,
const std::string &sourceName) const
{
std::string serverName = config.getConfigName();
@ -2051,34 +2092,72 @@ void PasswordConfigProperty::savePassword(UserInterface &ui,
if (!sourceName.empty()) {
sourceConfigNode = config.getSyncSourceNodes(sourceName).getNode(*this);
}
FilterConfigNode &configNode = sourceConfigNode ? *sourceConfigNode : *globalConfigNode;
// TODO: support identities
InitStateString username = usernameProperty.getProperty(configNode);
SE_LOG_DEBUG(NULL, "saving password property '%s' in config '%s' with user identity '%s'",
getMainName().c_str(),
serverName.c_str(),
username.c_str());
UserIdentity identity(UserIdentity::fromString(username));
/** here we don't invoke askPassword for this function has different logic from it */
string password;
if(sourceConfigNode.get() == NULL) {
password = getProperty(*globalConfigNode);
} else {
password = getProperty(*sourceConfigNode);
}
/** if it has been stored or it has no value, do nothing */
if(password == "-" || password == "") {
return;
} else if(boost::starts_with(password, "${") &&
boost::ends_with(password, "}")) {
/** we delay this calculation of environment variable for
* it might be changed in the sync time. */
return;
}
string descr = getDescr(serverName,*globalConfigNode,sourceName,sourceConfigNode);
ConfigPasswordKey key = getPasswordKey(descr,serverName,*globalConfigNode,sourceName,sourceConfigNode);
if(ui.savePassword(getMainName(), password, key)) {
string value = "-";
if(sourceConfigNode.get() == NULL) {
setProperty(*globalConfigNode, value);
} else {
setProperty(*sourceConfigNode,value);
// In checkPassword() we retrieve from background storage and store as temporary value.
// Here we use the temporary value and move it in the background storage.
InitStateString password = getProperty(configNode);
bool updatePassword = false;
InitStateString passwordToSave;
if (identity.m_provider == USER_IDENTITY_SYNC_CONFIG) {
// Store in the other config and unset it here.
updatePassword = true;
const std::string &credConfigName = identity.m_identity;
SE_LOG_INFO(NULL, "setting %s in config '%s' as part of credentials for %s%s%s",
syncPropPassword.getMainName().c_str(),
credConfigName.c_str(),
serverName.c_str(),
sourceName.empty() ? "" : "/",
sourceName.c_str());
// Actual username/password are stored in a different config. Go find it...
SyncConfig::Layout layout = config.getLayout();
if (layout != SyncConfig::SHARED_LAYOUT) {
SE_THROW(StringPrintf("%s = %s: only supported in configs using the current config storage, please migrate config %s",
usernameProperty.getMainName().c_str(),
username.c_str(),
config.getConfigName().c_str()));
}
boost::shared_ptr<SyncConfig> credConfig(new SyncConfig(credConfigName));
if (!credConfig->exists()) {
SE_THROW(StringPrintf("%s = %s: config '%s' not found, cannot look up credentials",
usernameProperty.getMainName().c_str(),
username.c_str(),
credConfigName.c_str()));
}
credConfig->setSyncPassword(password, false);
syncPropPassword.savePassword(ui, *credConfig);
} else if (identity.m_provider != USER_IDENTITY_PLAIN_TEXT) {
// Cannot store passwords in providers.
if (password.wasSet() && !password.empty()) {
SE_THROW(StringPrintf("setting property '%s' not supported for provider '%s' from property '%s'",
getMainName().c_str(),
identity.m_provider.c_str(),
usernameProperty.getMainName().c_str()));
}
} else {
if (password == "-" || password == "" ||
(boost::starts_with(password, "${") && boost::ends_with(password, "}"))) {
// Nothing to do, leave it as is.
} else {
string descr = getDescr(serverName,*globalConfigNode,sourceName,sourceConfigNode);
ConfigPasswordKey key = getPasswordKey(descr,serverName,*globalConfigNode,sourceName,sourceConfigNode);
if (ui.savePassword(getMainName(), password, key)) {
passwordToSave = "-";
updatePassword = true;
}
}
}
if (updatePassword) {
setProperty(configNode, passwordToSave);
}
}
@ -2728,6 +2807,11 @@ public:
const std::string &sourceName) const {
PasswordConfigProperty::checkPassword(ui, config, sourcePropUser, sourceName);
}
virtual void savePassword(UserInterface &ui,
SyncConfig &config,
const std::string &sourceName) const {
PasswordConfigProperty::savePassword(ui, config, sourcePropUser, sourceName);
}
virtual ConfigPasswordKey getPasswordKey(const std::string &descr,
const std::string &serverName,

View file

@ -742,12 +742,12 @@ class PasswordConfigProperty : public ConfigProperty {
const std::string &sourceName = std::string()) const = 0;
/**
* It firstly check password and then invoke ui's savePassword
* function to save the password if necessary
* Move password to storage. Accessed via base ConfigProperty
* class, must be implemented in derived classes.
*/
virtual void savePassword(UserInterface &ui,
SyncConfig &config,
const std::string &sourceName = std::string()) const;
const std::string &sourceName = std::string()) const = 0;
protected:
@ -760,6 +760,11 @@ class PasswordConfigProperty : public ConfigProperty {
const ConfigProperty &usernameProperty,
const std::string &sourceName = std::string()) const;
void savePassword(UserInterface &ui,
SyncConfig &config,
const ConfigProperty &usernameProperty,
const std::string &sourceName = std::string()) const;
/**
* Get password lookup key for storing or retrieving passwords.
*