Imported Upstream version 15.0.0
[platform/upstream/libzypp.git] / zypp / media / CredentialManager.cc
index 8202e14..4ff8dc1 100644 (file)
@@ -6,12 +6,13 @@
 |                         /_____||_| |_| |_|                           |
 |                                                                      |
 \---------------------------------------------------------------------*/
-/** \file zypp/media/CredentialManager.h
+/** \file zypp/media/CredentialManager.cc
  *
  */
 #include <iostream>
 #include <fstream>
 
+#include "zypp/ZConfig.h"
 #include "zypp/base/Function.h"
 #include "zypp/base/Logger.h"
 #include "zypp/base/Easy.h"
 
 #include "zypp/media/CredentialManager.h"
 
-#define CUSTOM_CREDENTIALS_FILE_DIR "/etc/zypp/credentials.d"
-#define GLOBAL_CREDENTIALS_FILE "/etc/zypp/credentials.cat" 
-#define USER_CREDENTIALS_FILE   ".zypp/credentials.cat"
+#define USER_CREDENTIALS_FILE ".zypp/credentials.cat"
 
 using namespace std;
 
 //////////////////////////////////////////////////////////////////////
-namespace zypp 
+namespace zypp
 { ////////////////////////////////////////////////////////////////////
   //////////////////////////////////////////////////////////////////////
   namespace media
   { ////////////////////////////////////////////////////////////////////
 
+  //////////////////////////////////////////////////////////////////////
+  //
+  // CLASS NAME : AuthDataComparator
+  //
+  //////////////////////////////////////////////////////////////////////
+
+  bool
+  AuthDataComparator::operator()(
+      const AuthData_Ptr & lhs, const AuthData_Ptr & rhs)
+  {
+    static const url::ViewOption vopt =
+        url::ViewOption::DEFAULTS
+        - url::ViewOption::WITH_USERNAME
+        - url::ViewOption::WITH_PASSWORD
+        - url::ViewOption::WITH_QUERY_STR;
+
+    if (lhs->username() != rhs->username())
+      return true;
+
+    if (lhs->url().asString(vopt) != rhs->url().asString(vopt))
+      return true;
+
+    return false;
+  }
 
   //////////////////////////////////////////////////////////////////////
   //
-  // CLASS NAME : CredManagerOptions 
+  // CLASS NAME : CredManagerOptions
   //
   //////////////////////////////////////////////////////////////////////
 
   CredManagerOptions::CredManagerOptions(const Pathname & rootdir)
-    : globalCredFilePath(rootdir / GLOBAL_CREDENTIALS_FILE)
-    , customCredFileDir(rootdir / CUSTOM_CREDENTIALS_FILE_DIR)
+    : globalCredFilePath(rootdir / ZConfig::instance().credentialsGlobalFile())
+    , customCredFileDir(rootdir / ZConfig::instance().credentialsGlobalDir())
   {
     char * homedir = getenv("HOME");
     if (homedir)
@@ -53,7 +76,7 @@ namespace zypp
 
   //////////////////////////////////////////////////////////////////////
   //
-  // CLASS NAME : CredentialManager::Impl 
+  // CLASS NAME : CredentialManager::Impl
   //
   struct CredentialManager::Impl
   {
@@ -61,7 +84,7 @@ namespace zypp
 
     ~Impl()
     {}
-    
+
     void init_globalCredentials();
     void init_userCredentials();
 
@@ -78,18 +101,23 @@ namespace zypp
     CredentialSet _credsGlobal;
     CredentialSet _credsUser;
     CredentialSet _credsTmp;
+
+    bool _globalDirty;
+    bool _userDirty;
   };
   //////////////////////////////////////////////////////////////////////
 
 
   //////////////////////////////////////////////////////////////////////
   //
-  // CLASS NAME : CredentialManager::Impl 
+  // CLASS NAME : CredentialManager::Impl
   //
   //////////////////////////////////////////////////////////////////////
 
   CredentialManager::Impl::Impl(const CredManagerOptions & options)
     : _options(options)
+    , _globalDirty(false)
+    , _userDirty(false)
   {
     init_globalCredentials();
     init_userCredentials();
@@ -134,7 +162,7 @@ namespace zypp
           bind(&Impl::processCredentials, this, _1));
     }
     else
-      DBG << "user cred file does not exist";
+      DBG << "user cred file does not exist" << endl;
 
     _credsUser = _credsTmp; _credsTmp.clear();
     DBG << "Got " << _credsUser.size() << " user records." << endl;
@@ -152,12 +180,17 @@ namespace zypp
                              const Url & url,
                              url::ViewOption vopt)
   {
+    const string & username = url.getUsername();
     for(CredentialManager::CredentialIterator it = set.begin(); it != set.end(); ++it)
     {
-      if (url.asString(vopt) == (*it)->url().asString(vopt))
-        return *it;
+      // this ignores url params - not sure if it is good or bad...
+      if (url.asString(vopt).find((*it)->url().asString(vopt)) == 0)
+      {
+        if (username.empty() || username == (*it)->username())
+          return *it;
+      }
     }
-    
+
     return AuthData_Ptr();
   }
 
@@ -170,10 +203,11 @@ namespace zypp
     // default url::ViewOption will take care of that.
     // operator==(Url,Url) compares the whole Url
 
-    // if the wanted URL does not contain username, ignore that, too
     url::ViewOption vopt;
-//    if (url.getUsername().empty())
-      vopt = vopt - url::ViewOption::WITH_USERNAME;
+    vopt = vopt
+      - url::ViewOption::WITH_USERNAME
+      - url::ViewOption::WITH_PASSWORD
+      - url::ViewOption::WITH_QUERY_STR;
 
     // search in global credentials
     result = findIn(_credsGlobal, url, vopt);
@@ -194,14 +228,14 @@ namespace zypp
   AuthData_Ptr CredentialManager::Impl::getCredFromFile(const Pathname & file)
   {
     AuthData_Ptr result;
-    
+
     Pathname credfile;
     if (file.absolute())
       // get from that file
       credfile = file;
     else
-      // get from /etc/zypp/credentials.d
-      credfile = _options.customCredFileDir / file;
+      // get from /etc/zypp/credentials.d, delete the leading path
+      credfile = _options.customCredFileDir / file.basename();
 
     CredentialFileReader(credfile, bind(&Impl::processCredentials, this, _1));
     if (_credsTmp.empty())
@@ -252,7 +286,7 @@ namespace zypp
 
   //////////////////////////////////////////////////////////////////////
   //
-  // CLASS NAME : CredentialManager 
+  // CLASS NAME : CredentialManager
   //
   //////////////////////////////////////////////////////////////////////
 
@@ -262,39 +296,91 @@ namespace zypp
 
 
   AuthData_Ptr CredentialManager::getCred(const Url & url)
-  { return _pimpl->getCred(url); }
+  {
+    string credfile = url.getQueryParam("credentials");
+    if (credfile.empty())
+      return _pimpl->getCred(url);
+    return _pimpl->getCredFromFile(credfile);
+  }
 
 
   AuthData_Ptr CredentialManager::getCredFromFile(const Pathname & file)
   { return _pimpl->getCredFromFile(file); }
 
 
-  void CredentialManager::save(const AuthData & cred, bool global)
-  { global ? saveInGlobal(cred) : saveInUser(cred); }
+  void CredentialManager::addCred(const AuthData & cred)
+  {
+    Pathname credfile = cred.url().getQueryParam("credentials");
+    if (credfile.empty())
+      //! \todo ask user where to store these creds. saving to user creds for now
+      addUserCred(cred);
+    else
+      saveInFile(cred, credfile);
+  }
 
 
-  void CredentialManager::saveInGlobal(const AuthData & cred)
+  void CredentialManager::addGlobalCred(const AuthData & cred)
   {
     AuthData_Ptr c_ptr;
     c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
-    _pimpl->_credsGlobal.insert(c_ptr); //! \todo avoid adding duplicates
-    _pimpl->saveGlobalCredentials();
+    pair<CredentialIterator, bool> ret = _pimpl->_credsGlobal.insert(c_ptr);
+    if (ret.second)
+      _pimpl->_globalDirty = true;
+    else if ((*ret.first)->password() != cred.password())
+    {
+      _pimpl->_credsGlobal.erase(ret.first);
+      _pimpl->_credsGlobal.insert(c_ptr);
+      _pimpl->_globalDirty = true;
+    }
   }
 
 
-  void CredentialManager::saveInUser(const AuthData & cred)
+  void CredentialManager::addUserCred(const AuthData & cred)
   {
     AuthData_Ptr c_ptr;
     c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
-    _pimpl->_credsUser.insert(c_ptr); //! \todo avoid adding duplicates
-    _pimpl->saveUserCredentials();
+    pair<CredentialIterator, bool> ret = _pimpl->_credsUser.insert(c_ptr);
+    if (ret.second)
+      _pimpl->_userDirty = true;
+    else if ((*ret.first)->password() != cred.password())
+    {
+      _pimpl->_credsUser.erase(ret.first);
+      _pimpl->_credsUser.insert(c_ptr);
+      _pimpl->_userDirty = true;
+    }
+  }
+
+
+  void CredentialManager::save()
+  {
+    if (_pimpl->_globalDirty)
+      _pimpl->saveGlobalCredentials();
+    if (_pimpl->_userDirty)
+      _pimpl->saveUserCredentials();
+    _pimpl->_globalDirty = false;
+    _pimpl->_userDirty = false;
+  }
+
+
+  void CredentialManager::saveInGlobal(const AuthData & cred)
+  {
+    addGlobalCred(cred);
+    save();
+  }
+
+
+  void CredentialManager::saveInUser(const AuthData & cred)
+  {
+    addUserCred(cred);
+    save();
   }
 
 
-  void CredentialManager::saveIn(const AuthData & cred, const Pathname & credFile)
+  void CredentialManager::saveInFile(const AuthData & cred, const Pathname & credFile)
   {
     AuthData_Ptr c_ptr;
     c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
+    c_ptr->setUrl(Url()); // don't save url in custom creds file
     CredentialManager::CredentialSet creds;
     creds.insert(c_ptr);