libzypp 17.28.8
CredentialManager.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12#include <iostream>
13#include <fstream>
14
15#include <zypp/ZConfig.h>
16#include <zypp/base/Function.h>
17#include <zypp/base/Logger.h>
18#include <zypp/base/Easy.h>
19#include <zypp/PathInfo.h>
20
24
25#include <boost/interprocess/sync/file_lock.hpp>
26#include <boost/interprocess/sync/scoped_lock.hpp>
27#include <boost/interprocess/sync/sharable_lock.hpp>
28
29namespace bpci = boost::interprocess;
30
31
32using std::endl;
33
34#define USER_CREDENTIALS_FILE ".zypp/credentials.cat"
35
37namespace zypp
38{
40 namespace media
41 {
42
44 //
45 // CLASS NAME : AuthDataComparator
46 //
48
49 bool AuthDataComparator::operator()( const AuthData_Ptr & lhs, const AuthData_Ptr & rhs ) const
50 {
55 // std::less semantic!
56 int cmp = lhs->url().asString(vopt).compare( rhs->url().asString(vopt) );
57 if ( ! cmp )
58 cmp = lhs->username().compare( rhs->username() );
59 return( cmp < 0 );
60 }
61
63 //
64 // CLASS NAME : CredManagerOptions
65 //
67
69 : globalCredFilePath(rootdir / ZConfig::instance().credentialsGlobalFile())
70 , customCredFileDir(rootdir / ZConfig::instance().credentialsGlobalDir())
71 {
72 char * homedir = getenv("HOME");
73 if (homedir)
74 userCredFilePath = rootdir / homedir / USER_CREDENTIALS_FILE;
75 }
76
77
79 //
80 // CLASS NAME : CredentialManager::Impl
81 //
83 {
84 Impl(const CredManagerOptions & options);
85
87 {}
88
91
93
94 AuthData_Ptr getCred(const Url & url) const;
98
99
101
105
108 };
110
111
113 //
114 // CLASS NAME : CredentialManager::Impl
115 //
117
119 : _options(options)
120 , _globalDirty(false)
121 , _userDirty(false)
122 {
125 }
126
127
129 {
130 if (_options.globalCredFilePath.empty())
131 DBG << "global cred file not known";
132 else if (PathInfo(_options.globalCredFilePath).isExist())
133 {
134 /* list<Pathname> entries;
135 if (filesystem::readdir(entries, _options.globalCredFilePath, false) != 0)
136 ZYPP_THROW(Exception("failed to read directory"));
137
138 for_(it, entries.begin(), entries.end())*/
139
140 CredentialFileReader(_options.globalCredFilePath,
141 bind(&Impl::processCredentials, this, _1));
142 }
143 else
144 DBG << "global cred file does not exist";
145
146 _credsGlobal = _credsTmp; _credsTmp.clear();
147 DBG << "Got " << _credsGlobal.size() << " global records." << endl;
148 }
149
150
152 {
153 if (_options.userCredFilePath.empty())
154 DBG << "user cred file not known";
155 else if (PathInfo(_options.userCredFilePath).isExist())
156 {
157 /* list<Pathname> entries;
158 if (filesystem::readdir(entries, _options.userCredFilePath, false ) != 0)
159 ZYPP_THROW(Exception("failed to read directory"));
160
161 for_(it, entries.begin(), entries.end())*/
162 CredentialFileReader(_options.userCredFilePath,
163 bind(&Impl::processCredentials, this, _1));
164 }
165 else
166 DBG << "user cred file does not exist" << endl;
167
168 _credsUser = _credsTmp; _credsTmp.clear();
169 DBG << "Got " << _credsUser.size() << " user records." << endl;
170 }
171
172
174 {
175 _credsTmp.insert(cred);
176 return true;
177 }
178
179
181 const Url & url,
182 url::ViewOption vopt)
183 {
184 const std::string & username = url.getUsername();
185 for( CredentialManager::CredentialIterator it = set.begin(); it != set.end(); ++it )
186 {
187 if ( !(*it)->url().isValid() )
188 continue;
189
190 // this ignores url params - not sure if it is good or bad...
191 if ( url.asString(vopt).find((*it)->url().asString(vopt)) == 0 )
192 {
193 if ( username.empty() || username == (*it)->username() )
194 return *it;
195 }
196 }
197
198 return AuthData_Ptr();
199 }
200
201
203 {
204 AuthData_Ptr result;
205
206 // compare the urls via asString(), but ignore password
207 // default url::ViewOption will take care of that.
208 // operator==(Url,Url) compares the whole Url
209
210 url::ViewOption vopt;
211 vopt = vopt
215
216 // search in global credentials
217 result = findIn(_credsGlobal, url, vopt);
218
219 // search in home credentials
220 if (!result)
221 result = findIn(_credsUser, url, vopt);
222
223 if (result)
224 DBG << "Found credentials for '" << url << "':" << endl << *result;
225 else
226 DBG << "No credentials for '" << url << "'" << endl;
227
228 return result;
229 }
230
231
233 {
234 AuthData_Ptr result;
235
236 Pathname credfile;
237 if (file.absolute())
238 // get from that file
239 credfile = file;
240 else
241 // get from /etc/zypp/credentials.d, delete the leading path
242 credfile = _options.customCredFileDir / file.basename();
243
244 // make sure only our thread accesses the file
245 bpci::file_lock lockFile ( credfile.c_str() );
246 bpci::scoped_lock lock( lockFile );
247
248 CredentialFileReader(credfile, bind(&Impl::processCredentials, this, _1));
249 if (_credsTmp.empty())
250 WAR << file << " does not contain valid credentials or is not readable." << endl;
251 else
252 {
253 result = *_credsTmp.begin();
254 _credsTmp.clear();
255 }
256
257 return result;
258 }
259
262 const Pathname & file,
263 const mode_t mode)
264 {
265 int ret = 0;
267
268 std::ofstream fs(file.c_str());
269 if (!fs)
270 ret = 1;
271
272 // make sure only our thread accesses the file
273 bpci::file_lock lockFile ( file.c_str() );
274 bpci::scoped_lock lock( lockFile );
275
276
277 for_(it, creds.begin(), creds.end())
278 {
279 (*it)->dumpAsIniOn(fs);
280 (*it)->setLastDatabaseUpdate( time( nullptr ) );
281 fs << endl;
282 }
283 fs.close();
284
285 filesystem::chmod(file, mode);
286
287 return ret;
288 }
289
291 {
292 save_creds_in_file(_credsGlobal, _options.globalCredFilePath, 0640);
293 }
294
296 {
297 save_creds_in_file(_credsUser, _options.userCredFilePath, 0600);
298 }
299
300
302 //
303 // CLASS NAME : CredentialManager
304 //
306
308 : _pimpl(new Impl(opts))
309 {}
310
311
313 {
314 std::string credfile = url.getQueryParam("credentials");
315 if (credfile.empty())
316 return _pimpl->getCred(url);
317 return _pimpl->getCredFromFile(credfile);
318 }
319
320
322 { return _pimpl->getCredFromFile(file); }
323
324
326 {
327 if ( !cred.url().isValid() )
328 ZYPP_THROW( MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) );
329
330 Pathname credfile = cred.url().getQueryParam("credentials");
331 if (credfile.empty())
333 addUserCred(cred);
334 else
335 saveInFile(cred, credfile);
336 }
337
338
340 {
341 if ( !cred.url().isValid() )
342 ZYPP_THROW( MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) );
343
344 AuthData_Ptr c_ptr;
345 c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
346 std::pair<CredentialIterator, bool> ret = _pimpl->_credsGlobal.insert(c_ptr);
347 if (ret.second)
348 _pimpl->_globalDirty = true;
349 else if ((*ret.first)->password() != cred.password())
350 {
351 _pimpl->_credsGlobal.erase(ret.first);
352 _pimpl->_credsGlobal.insert(c_ptr);
353 _pimpl->_globalDirty = true;
354 }
355 }
356
357
359 {
360 if ( !cred.url().isValid() )
361 ZYPP_THROW( MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) );
362
363 AuthData_Ptr c_ptr;
364 c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
365 std::pair<CredentialIterator, bool> ret = _pimpl->_credsUser.insert(c_ptr);
366 if (ret.second)
367 _pimpl->_userDirty = true;
368 else if ((*ret.first)->password() != cred.password())
369 {
370 _pimpl->_credsUser.erase(ret.first);
371 _pimpl->_credsUser.insert(c_ptr);
372 _pimpl->_userDirty = true;
373 }
374 }
375
376
378 {
379 if (_pimpl->_globalDirty)
380 _pimpl->saveGlobalCredentials();
381 if (_pimpl->_userDirty)
382 _pimpl->saveUserCredentials();
383 _pimpl->_globalDirty = false;
384 _pimpl->_userDirty = false;
385 }
386
387
389 {
390 addGlobalCred(cred);
391 save();
392 }
393
394
396 {
397 addUserCred(cred);
398 save();
399 }
400
401
402 void CredentialManager::saveInFile(const AuthData & cred, const Pathname & credFile)
403 {
404 AuthData_Ptr c_ptr;
405 c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
406 c_ptr->setUrl(Url()); // don't save url in custom creds file
408 creds.insert(c_ptr);
409
410 int ret;
411 if (credFile.absolute())
412 ret = save_creds_in_file(creds, credFile, 0640);
413 else
414 ret = save_creds_in_file(
415 creds, _pimpl->_options.customCredFileDir / credFile, 0600);
416
417 if (!ret)
418 {
420 ERR << "error saving the credentials" << endl;
421 }
422 }
423
424
426 {
427 if (global)
428 {
429 if (!filesystem::unlink(_pimpl->_options.globalCredFilePath))
430 ERR << "could not delete user credentials file "
431 << _pimpl->_options.globalCredFilePath << endl;
432 _pimpl->_credsUser.clear();
433 }
434 else
435 {
436 if (!filesystem::unlink(_pimpl->_options.userCredFilePath))
437 ERR << "could not delete global credentials file"
438 << _pimpl->_options.userCredFilePath << endl;
439 _pimpl->_credsGlobal.clear();
440 }
441 }
442
443
445 { return _pimpl->_credsGlobal.begin(); }
446
448 { return _pimpl->_credsGlobal.end(); }
449
451 { return _pimpl->_credsGlobal.size(); }
452
454 { return _pimpl->_credsGlobal.empty(); }
455
456
458 { return _pimpl->_credsUser.begin(); }
459
461 { return _pimpl->_credsUser.end(); }
462
464 { return _pimpl->_credsUser.size(); }
465
467 { return _pimpl->_credsUser.empty(); }
468
469
471 } // media
474} // zypp
#define USER_CREDENTIALS_FILE
Url manipulation class.
Definition: Url.h:92
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:497
std::string getUsername(EEncoding eflag=zypp::url::E_DECODED) const
Returns the username from the URL authority.
Definition: Url.cc:572
std::string getQueryParam(const std::string &param, EEncoding eflag=zypp::url::E_DECODED) const
Return the value for the specified query parameter.
Definition: Url.cc:660
bool isValid() const
Verifies the Url.
Definition: Url.cc:489
Interim helper class to collect global options and settings.
Definition: ZConfig.h:62
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:281
Pathname dirname() const
Return all but the last component od this path.
Definition: Pathname.h:124
bool absolute() const
Test for an absolute path.
Definition: Pathname.h:116
const char * c_str() const
String representation.
Definition: Pathname.h:110
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:128
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
Class for handling media authentication data.
Definition: MediaUserAuth.h:31
std::string password() const
Definition: MediaUserAuth.h:57
Parse credentials files and catalogs.
CredentialSize credsUserSize() const
void save()
Saves any unsaved credentials added via addUserCred() or addGlobalCred() methods.
AuthData_Ptr getCredFromFile(const Pathname &file)
Read credentials from a file.
CredentialIterator credsGlobalBegin() const
CredentialIterator credsUserBegin() const
std::set< AuthData_Ptr, AuthDataComparator > CredentialSet
CredentialSet::const_iterator CredentialIterator
void saveInUser(const AuthData &cred)
Saves given cred to user's credentials file.
AuthData_Ptr getCred(const Url &url)
Get credentials for the specified url.
void addUserCred(const AuthData &cred)
Add new user credentials.
void saveInFile(const AuthData &, const Pathname &credFile)
Saves given cred to user specified credentials file.
CredentialIterator credsGlobalEnd() const
CredentialIterator credsUserEnd() const
CredentialSize credsGlobalSize() const
void addCred(const AuthData &cred)
Add new credentials with user callbacks.
void addGlobalCred(const AuthData &cred)
Add new global credentials.
CredentialSet::size_type CredentialSize
void saveInGlobal(const AuthData &cred)
Saves given cred to global credentials file.
void clearAll(bool global=false)
Remove all global or user credentials from memory and disk.
CredentialManager(const CredManagerOptions &opts=CredManagerOptions())
int chmod(const Pathname &path, mode_t mode)
Like 'chmod'.
Definition: PathInfo.cc:1092
int unlink(const Pathname &path)
Like 'unlink'.
Definition: PathInfo.cc:700
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition: PathInfo.cc:319
static AuthData_Ptr findIn(const CredentialManager::CredentialSet &set, const Url &url, url::ViewOption vopt)
static int save_creds_in_file(const CredentialManager::CredentialSet creds, const Pathname &file, const mode_t mode)
shared_ptr< AuthData > AuthData_Ptr
Definition: MediaUserAuth.h:77
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
bool operator()(const AuthData_Ptr &lhs, const AuthData_Ptr &rhs) const
CredManagerOptions(const Pathname &rootdir="")
Impl(const CredManagerOptions &options)
AuthData_Ptr getCred(const Url &url) const
bool processCredentials(AuthData_Ptr &cred)
AuthData_Ptr getCredFromFile(const Pathname &file)
Url::asString() view options.
Definition: UrlBase.h:40
static const ViewOption WITH_PASSWORD
Option to include password in the URL string.
Definition: UrlBase.h:67
static const ViewOption DEFAULTS
Default combination of view options.
Definition: UrlBase.h:177
static const ViewOption WITH_USERNAME
Option to include username in the URL string.
Definition: UrlBase.h:58
static const ViewOption WITH_QUERY_STR
Option to include query string in the URL string.
Definition: UrlBase.h:101
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:392
#define DBG
Definition: Logger.h:95
#define ERR
Definition: Logger.h:98
#define WAR
Definition: Logger.h:97