Imported Upstream version 15.22.0 00/94700/1
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 1 Nov 2016 02:09:15 +0000 (11:09 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 1 Nov 2016 02:09:16 +0000 (11:09 +0900)
Change-Id: I1c89e244d7676f14da8169007309f605498649d7
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
VERSION.cmake
libzypp.spec.cmake
package/libzypp.changes
zypp/RepoInfo.cc
zypp/RepoInfo.h
zypp/RepoManager.cc
zypp/media/CredentialFileReader.cc
zypp/media/CredentialFileReader.h
zypp/media/CredentialManager.cc
zypp/media/MediaUserAuth.cc

index 109e747..e67c39b 100644 (file)
@@ -60,9 +60,9 @@
 #
 SET(LIBZYPP_MAJOR "15")
 SET(LIBZYPP_COMPATMINOR "19")
-SET(LIBZYPP_MINOR "21")
-SET(LIBZYPP_PATCH "7")
+SET(LIBZYPP_MINOR "22")
+SET(LIBZYPP_PATCH "0")
 #
-# LAST RELEASED: 15.21.7 (19)
+# LAST RELEASED: 15.22.0 (19)
 # (The number in parenthesis is LIBZYPP_COMPATMINOR)
 #=======
index 56ac03a..6006700 100644 (file)
@@ -242,6 +242,7 @@ mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/services.d
 mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/systemCheck.d
 mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/vendors.d
 mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/multiversion.d
+mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/credentials.d
 mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp
 mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins
 mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins/appdata
@@ -339,6 +340,7 @@ rm -rf "$RPM_BUILD_ROOT"
 %dir               %{_sysconfdir}/zypp/systemCheck.d
 %dir               %{_sysconfdir}/zypp/vendors.d
 %dir               %{_sysconfdir}/zypp/multiversion.d
+%dir               %{_sysconfdir}/zypp/credentials.d
 %config(noreplace) %{_sysconfdir}/zypp/zypp.conf
 %config(noreplace) %{_sysconfdir}/zypp/systemCheck
 %config(noreplace) %{_sysconfdir}/logrotate.d/zypp-history.lr
index fe72097..f1f57fe 100644 (file)
@@ -1,4 +1,15 @@
 -------------------------------------------------------------------
+Mon Apr 25 14:59:41 CEST 2016 - ma@suse.de
+
+- Fix credential file parser losing entries with known URL but
+  different user name (bsc#933760)
+- RepoManager: allow extraction of multiple baseurls for service
+  repos (bsc#964932)
+- addRepository: fix to use the correct history file for logging
+- specfile: add /etc/zypp/credentials.d to the file list
+- version 15.22.0 (19)
+
+-------------------------------------------------------------------
 Mon Apr 18 15:03:13 CEST 2016 - ma@suse.de
 
 - RepoindexFileReader: fix service metadata TTL default value (bsc#967828)
index 8d35fba..6ac2015 100644 (file)
@@ -347,6 +347,9 @@ namespace zypp
     _pimpl->baseUrls().raw().push_back( url_r );
   }
 
+  void RepoInfo::setBaseUrls( url_set urls )
+  { _pimpl->baseUrls().raw().swap( urls ); }
+
   void RepoInfo::setPath( const Pathname &path )
   { _pimpl->path = path; }
 
index e2b0bc2..075df3c 100644 (file)
@@ -159,6 +159,10 @@ namespace zypp
        * Clears current base URL list and adds \a url.
        */
       void setBaseUrl( const Url &url );
+      /**
+       * Clears current base URL list and adds an \ref url_set.
+       */
+      void setBaseUrls( url_set urls );
 
       /**
        * \short Repository path
index f83e403..b830e85 100644 (file)
@@ -64,6 +64,76 @@ namespace zypp
   ///////////////////////////////////////////////////////////////////
   namespace
   {
+    ///////////////////////////////////////////////////////////////////
+    /// \class UrlCredentialExtractor
+    /// \brief Extract credentials in \ref Url authority and store them via \ref CredentialManager.
+    ///
+    /// Lazy init CredentialManager and save collected credentials when
+    /// going out of scope.
+    ///
+    /// Methods return whether a password has been collected/extracted.
+    ///
+    /// \code
+    /// UrlCredentialExtractor( "/rootdir" ).collect( oneUrlOrUrlContainer );
+    /// \endcode
+    /// \code
+    /// {
+    ///   UrlCredentialExtractor extractCredentials;
+    ///   extractCredentials.collect( oneUrlOrUrlContainer );
+    ///   extractCredentials.extract( oneMoreUrlOrUrlContainer );
+    ///   ....
+    /// }
+    /// \endcode
+    ///
+    class UrlCredentialExtractor
+    {
+    public:
+      UrlCredentialExtractor( Pathname & root_r )
+      : _root( root_r )
+      {}
+
+      ~UrlCredentialExtractor()
+      { if ( _cmPtr ) _cmPtr->save(); }
+
+      /** Remember credentials stored in URL authority leaving the password in \a url_r. */
+      bool collect( const Url & url_r )
+      {
+       bool ret = url_r.hasCredentialsInAuthority();
+       if ( ret )
+       {
+         if ( !_cmPtr ) _cmPtr.reset( new media::CredentialManager( _root ) );
+         _cmPtr->addUserCred( url_r );
+       }
+       return ret;
+      }
+      /** \overload operating on Url container */
+      template<class TContainer>
+      bool collect( const TContainer & urls_r )
+      {        bool ret = false; for ( const Url & url : urls_r ) { if ( collect( url ) && !ret ) ret = true; } return ret; }
+
+      /** Remember credentials stored in URL authority stripping the passowrd from \a url_r. */
+      bool extract( Url & url_r )
+      {
+       bool ret = collect( url_r );
+       if ( ret )
+         url_r.setPassword( std::string() );
+       return ret;
+      }
+      /** \overload operating on Url container */
+      template<class TContainer>
+      bool extract( TContainer & urls_r )
+      {        bool ret = false; for ( Url & url : urls_r ) { if ( extract( url ) && !ret ) ret = true; } return ret; }
+
+    private:
+      const Pathname & _root;
+      scoped_ptr<media::CredentialManager> _cmPtr;
+    };
+  } // namespace
+  ///////////////////////////////////////////////////////////////////
+
+  ///////////////////////////////////////////////////////////////////
+  namespace
+  {
     /** Simple media mounter to access non-downloading URLs e.g. for non-local plaindir repos.
      * \ingroup g_RAII
      */
@@ -1596,26 +1666,9 @@ namespace zypp
     progress.set(90);
 
     // check for credentials in Urls
-    bool havePasswords = false;
-    for_( urlit, tosave.baseUrlsBegin(), tosave.baseUrlsEnd() )
-      if ( urlit->hasCredentialsInAuthority() )
-      {
-        havePasswords = true;
-        break;
-      }
-    // save the credentials
-    if ( havePasswords )
-    {
-      media::CredentialManager cm(
-          media::CredManagerOptions(_options.rootDir) );
-
-      for_(urlit, tosave.baseUrlsBegin(), tosave.baseUrlsEnd())
-        if (urlit->hasCredentialsInAuthority())
-          //! \todo use a method calling UI callbacks to ask where to save creds?
-          cm.saveInUser(media::AuthData(*urlit));
-    }
+    UrlCredentialExtractor( _options.rootDir ).collect( tosave.baseUrls() );
 
-    HistoryLog().addRepository(tosave);
+    HistoryLog(_options.rootDir).addRepository(tosave);
 
     progress.toMax();
     MIL << "done" << endl;
@@ -1823,6 +1876,8 @@ namespace zypp
       newinfo.setFilepath(toedit.filepath());
       reposManip().erase(toedit);
       reposManip().insert(newinfo);
+      // check for credentials in Urls
+      UrlCredentialExtractor( _options.rootDir ).collect( newinfo.baseUrls() );
       HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo);
       MIL << "repo " << alias << " modified" << endl;
     }
@@ -1876,15 +1931,8 @@ namespace zypp
     saveService( toSave );
     _services.insert( toSave );
 
-    // check for credentials in Url (username:password, not ?credentials param)
-    if ( toSave.url().hasCredentialsInAuthority() )
-    {
-      media::CredentialManager cm(
-          media::CredManagerOptions(_options.rootDir) );
-
-      //! \todo use a method calling UI callbacks to ask where to save creds?
-      cm.saveInUser(media::AuthData(toSave.url()));
-    }
+    // check for credentials in Url
+    UrlCredentialExtractor( _options.rootDir ).collect( toSave.url() );
 
     MIL << "added service " << toSave.alias() << endl;
   }
@@ -2051,34 +2099,41 @@ namespace zypp
     {
       // First of all: Prepend service alias:
       it->setAlias( str::form( "%s:%s", service.alias().c_str(), it->alias().c_str() ) );
-      // set refrence to the parent service
+      // set reference to the parent service
       it->setService( service.alias() );
 
       // remember the new parsed repo state
       newRepoStates[it->alias()] = *it;
 
-      // if the repo url was not set by the repoindex parser, set service's url
-      Url url;
-      if ( it->baseUrlsEmpty() )
-        url = service.rawUrl();
-      else
+      // - If the repo url was not set by the repoindex parser, set service's url.
+      // - Libzypp currently has problem with separate url + path handling so just
+      //   append a path, if set, to the baseurls
+      // - Credentials in the url authority will be extracted later, either if the
+      //   repository is added or if we check for changed urls.
+      Pathname path;
+      if ( !it->path().empty() )
       {
-        // service repo can contain only one URL now, so no need to iterate.
-        url = it->rawUrl();    // raw!
+       if ( it->path() != "/" )
+         path = it->path();
+       it->setPath("");
       }
 
-      // libzypp currently has problem with separate url + path handling
-      // so just append the path to the baseurl
-      if ( !it->path().empty() )
+      if ( it->baseUrlsEmpty() )
       {
-        Pathname path(url.getPathName());
-        path /= it->path();
-        url.setPathName( path.asString() );
-        it->setPath("");
+       Url url( service.rawUrl() );
+       if ( !path.empty() )
+         url.setPathName( url.getPathName() / path );
+       it->setBaseUrl( std::move(url) );
+      }
+      else if ( !path.empty() )
+      {
+       RepoInfo::url_set urls( it->rawBaseUrls() );
+       for ( Url & url : urls )
+       {
+         url.setPathName( url.getPathName() / path );
+       }
+       it->setBaseUrls( std::move(urls) );
       }
-
-      // save the url
-      it->setBaseUrl( url );
     }
 
     ////////////////////////////////////////////////////////////////////////////
@@ -2114,7 +2169,8 @@ namespace zypp
     }
 
     ////////////////////////////////////////////////////////////////////////////
-    // create missing repositories and modify exising ones if needed...
+    // create missing repositories and modify existing ones if needed...
+    UrlCredentialExtractor urlCredentialExtractor( _options.rootDir ); // To collect any credentials stored in repo URLs
     for_( it, collector.repos.begin(), collector.repos.end() )
     {
       // User explicitly requested the repo being enabled?
@@ -2239,13 +2295,16 @@ namespace zypp
        }
 
         // changed url?
-        // service repo can contain only one URL now, so no need to iterate.
-        if ( oldRepo->rawUrl() != it->rawUrl() )
         {
-          DBG << "Service repo " << it->alias() << " gets new URL " << it->rawUrl() << endl;
-          oldRepo->setBaseUrl( it->rawUrl() );
-          oldRepoModified = true;
-        }
+         RepoInfo::url_set newUrls( it->rawBaseUrls() );
+         urlCredentialExtractor.extract( newUrls );    // Extract! to prevent passwds from disturbing the comparison below
+         if ( oldRepo->rawBaseUrls() != newUrls )
+         {
+           DBG << "Service repo " << it->alias() << " gets new URLs " << newUrls << endl;
+           oldRepo->setBaseUrls( std::move(newUrls) );
+           oldRepoModified = true;
+         }
+       }
 
         // changed gpg check settings?
        // ATM only plugin services can set GPG values.
@@ -2353,6 +2412,9 @@ namespace zypp
 
     _services.erase(oldAlias);
     _services.insert(service);
+    // check for credentials in Urls
+    UrlCredentialExtractor( _options.rootDir ).collect( service.url() );
+
 
     // changed properties affecting also repositories
     if ( oldAlias != service.alias()                   // changed alias
index 853a587..d6a07ea 100644 (file)
@@ -22,79 +22,123 @@ using std::endl;
 #undef ZYPP_BASE_LOGGER_LOGGROUP
 #define ZYPP_BASE_LOGGER_LOGGROUP "parser"
 
-
 ///////////////////////////////////////////////////////////////////
 namespace zypp
-{ /////////////////////////////////////////////////////////////////
+{
   ///////////////////////////////////////////////////////////////////
   namespace media
-  { /////////////////////////////////////////////////////////////////
-
-
-  //////////////////////////////////////////////////////////////////////
-  //
-  // CLASS NAME : CredentialFileReader
-  //
-  //////////////////////////////////////////////////////////////////////
-
-  CredentialFileReader::CredentialFileReader(
-      const Pathname & crfile,
-      const ProcessCredentials & callback)
   {
-    InputStream is(crfile);
-    parser::IniDict dict(is);
-    for (parser::IniDict::section_const_iterator its = dict.sectionsBegin();
-         its != dict.sectionsEnd();
-         ++its)
+    ///////////////////////////////////////////////////////////////////
+    namespace
     {
-      Url storedUrl;
-      if (!its->empty())
-      {
-        try { storedUrl = Url(*its); }
-        catch (const url::UrlException &)
-        {
-          ERR << "invalid URL '" << *its << "' in credentials in file: "
-              << crfile << endl;
-          continue;
-        }
-      }
-
-      AuthData_Ptr credentials;
-      credentials.reset(new AuthData());
-
-      // set url
-      if (storedUrl.isValid())
-        credentials->setUrl(storedUrl);
-
-      for (parser::IniDict::entry_const_iterator it = dict.entriesBegin(*its);
-           it != dict.entriesEnd(*its);
-           ++it)
+      // Looks like INI but allows multiple sections for the same URL
+      // but different user (in .cat files). So don't use an Ini
+      // Also support a global section without '[URL]' which is used
+      // in credential files.
+      // -------------------------------------
+      // username = emptyUSER
+      // password = emptyPASS
+      // -------------------------------------
+      // [http://server/tmp/sumafake222]
+      // username = USER
+      // password = PASS
+      //
+      // [http://server/tmp/sumafake222]
+      // username = USER2
+      // password = PASS
+      // -------------------------------------
+      struct CredentialFileReaderImpl : public parser::IniParser
       {
-        if (it->first == "username")
-          credentials->setUsername(it->second);
-        else if (it->first == "password")
-          credentials->setPassword(it->second);
-        else
-          ERR << "Unknown attribute in [" << crfile << "]: "
-              << it->second << " ignored" << endl;
-      }
-
-      if (credentials->valid())
-        callback(credentials);
-      else
-        ERR << "invalid credentials in file: " << crfile << endl;
-    } // sections
-  }
-
-
-  CredentialFileReader::~CredentialFileReader()
-  {}
-
-
-    /////////////////////////////////////////////////////////////////
-  } // media
+       typedef CredentialFileReader::ProcessCredentials ProcessCredentials;
+
+       struct StopParsing {};
+
+       CredentialFileReaderImpl( const Pathname & input_r, const ProcessCredentials & callback_r )
+       : _input( input_r )
+       , _callback( callback_r )
+       {
+         try
+         {
+           parse( input_r );
+         }
+         catch ( StopParsing )
+         { /* NO error but consumer aborted parsing */ }
+       }
+
+       // NO-OP; new sections are opened in consume()
+       virtual void beginParse()
+       { /*EMPTY*/ }
+
+       // start a new section [url]
+       virtual void consume( const std::string & section_r )
+       {
+         endParse();   // close any open section
+         _secret.reset( new AuthData );
+         try
+         {
+           _secret->setUrl( Url(section_r) );
+         }
+         catch ( const url::UrlException & )
+         {
+           ERR << "Ignore invalid URL '" << section_r << "' in file " << _input << endl;
+           _secret.reset();    // ignore this section
+         }
+       }
+
+       virtual void consume( const std::string & section_r, const std::string & key_r, const std::string & value_r )
+       {
+         if ( !_secret && section_r.empty() )
+           _secret.reset( new AuthData );      // a initial global section without [URL]
+
+         if ( _secret )
+         {
+           if ( key_r == "username" )
+             _secret->setUsername( value_r );
+           else if ( key_r == "password" )
+             _secret->setPassword( value_r );
+           else
+             WAR << "Ignore unknown attribute '" << key_r << "=" << value_r << "' in file " << _input << endl;
+         }
+         // else: ignored section due to wrong URL
+       }
+
+       // send any valid pending section
+       virtual void endParse()
+       {
+         if ( _secret )
+         {
+           if ( _secret->valid() )
+           {
+             if ( !_callback( _secret ) )
+               throw( StopParsing() );
+           }
+           else
+             ERR << "Ignore invalid credentials for URL '" << _secret->url() << "' in file " << _input << endl;
+         }
+       }
+
+      private:
+       const Pathname &                _input;
+       const ProcessCredentials &      _callback;
+       AuthData_Ptr                    _secret;
+      };
+    } // namespace
+    ///////////////////////////////////////////////////////////////////
+
+    //////////////////////////////////////////////////////////////////////
+    //
+    // CLASS NAME : CredentialFileReader
+    //
+    //////////////////////////////////////////////////////////////////////
+
+    CredentialFileReader::CredentialFileReader( const Pathname & crfile_r, const ProcessCredentials & callback_r )
+    { CredentialFileReaderImpl( crfile_r, callback_r ); }
+
+    CredentialFileReader::~CredentialFileReader()
+    {}
+
+  } // namespace media
   ///////////////////////////////////////////////////////////////////
-  /////////////////////////////////////////////////////////////////
-} // zypp
+} // namespace zypp
 ///////////////////////////////////////////////////////////////////
 
index fba8e60..f9a3574 100644 (file)
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
-{ /////////////////////////////////////////////////////////////////
+{
   ///////////////////////////////////////////////////////////////////
   namespace media
-  { /////////////////////////////////////////////////////////////////
-
-
-  //////////////////////////////////////////////////////////////////////
-  //
-  // CLASS NAME : CredentialFileReader 
-  //
-  class CredentialFileReader
   {
-  public:
-    /**
-      * Callback definition.
-      * First parameter is the \ref Url with which the credentials are
-      * associated, the second are the credentials.
-      *
-      * Return false from the callback to get a \ref AbortRequestException
-      * to be thrown and the processing to be cancelled.
-      */
-    typedef function<bool(AuthData_Ptr &)> ProcessCredentials;
-
-    CredentialFileReader(const Pathname & crfile,
-                         const ProcessCredentials & callback);
-    ~CredentialFileReader();
-  private:
-    ProcessCredentials _callback;
-  };
-  //////////////////////////////////////////////////////////////////////
-
-
-    /////////////////////////////////////////////////////////////////
-  } // media
+    //////////////////////////////////////////////////////////////////////
+    /// \class CredentialFileReader
+    /// \brief Parse credentials files and catalogs
+    class CredentialFileReader
+    {
+    public:
+      /** Callback invoked for each entry found in the file.
+       * Return \c false to abort parsing.
+       */
+      typedef function<bool(AuthData_Ptr &)> ProcessCredentials;
+
+      CredentialFileReader( const Pathname & crfile_r, const ProcessCredentials & callback_r );
+      ~CredentialFileReader();
+    private:
+      ProcessCredentials _callback;
+    };
+    //////////////////////////////////////////////////////////////////////
+
+  } // namespace media
   ///////////////////////////////////////////////////////////////////
-  /////////////////////////////////////////////////////////////////
-} // zypp
+} // namespace zypp
 ///////////////////////////////////////////////////////////////////
 
 #endif /* ZYPP_MEDIA_CREDENTIALFILEREADER_H */
index 4ff8dc1..9e52d2e 100644 (file)
@@ -39,23 +39,17 @@ namespace zypp
   //
   //////////////////////////////////////////////////////////////////////
 
-  bool
-  AuthDataComparator::operator()(
-      const AuthData_Ptr & lhs, const AuthData_Ptr & rhs)
+  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;
+    static const url::ViewOption vopt = url::ViewOption::DEFAULTS
+                                     - url::ViewOption::WITH_USERNAME
+                                     - url::ViewOption::WITH_PASSWORD
+                                     - url::ViewOption::WITH_QUERY_STR;
+    // std::less semantic!
+    int cmp = lhs->url().asString(vopt).compare( rhs->url().asString(vopt) );
+    if ( ! cmp )
+      cmp = lhs->username().compare( rhs->username() );
+    return( cmp < 0 );
   }
 
   //////////////////////////////////////////////////////////////////////
index 047f303..d84c89c 100644 (file)
@@ -41,9 +41,12 @@ bool AuthData::valid() const
 
 std::ostream & AuthData::dumpOn( std::ostream & str ) const
 {
+  if (_url.isValid())
+    str << "[" << _url.asString( url::ViewOptions() - url::ViewOptions::WITH_USERNAME - url::ViewOptions::WITH_PASSWORD ) << "]" << endl;
+  else
+    str << "[<no-url>]" << endl;
   str << "username: '" << _username << "'" << std::endl
-      << "password: " << (_password.empty() ? "<empty>" : "<non-empty>")
-      << std::endl;
+      << "password: " << (_password.empty() ? "<empty>" : "<non-empty>");
   return str;
 }
 
@@ -83,8 +86,8 @@ bool CurlAuthData::valid() const
 
 std::ostream & CurlAuthData::dumpOn( std::ostream & str ) const
 {
-  AuthData::dumpOn(str) << " auth_type: " << _auth_type_str
-    << " (" << _auth_type << ")" << std::endl;
+  AuthData::dumpOn(str) << endl
+  << " auth_type: " << _auth_type_str << " (" << _auth_type << ")";
   return str;
 }