gsecretsfile.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 Graeme Walker <graeme_walker@users.sourceforge.net>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gsecretsfile.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gauth.h"
23 #include "gsecretsfile.h"
24 #include "gsecrets.h"
25 #include "groot.h"
26 #include "gxtext.h"
27 #include "gstr.h"
28 #include "gdatetime.h"
29 #include "gfile.h"
30 #include "gassert.h"
31 #include "gmemory.h"
32 #include <map>
33 #include <set>
34 #include <fstream>
35 #include <string>
36 #include <algorithm> // std::swap
37 #include <utility> // std::swap, std::pair
38 #include <sstream>
39 
40 GAuth::SecretsFile::SecretsFile( const G::Path & path , bool auto_ , const std::string & debug_name ,
41  const std::string & server_type ) :
42  m_path(path) ,
43  m_auto(auto_) ,
44  m_debug_name(debug_name) ,
45  m_server_type(server_type) ,
46  m_file_time(0) ,
47  m_check_time(G::DateTime::now())
48 {
49  m_server_type = m_server_type.empty() ? std::string("server") : m_server_type ;
50  G_DEBUG( "GAuth::Secrets: " << m_debug_name << ": \"" << path << "\"" ) ;
51  m_valid = ! path.str().empty() ;
52  if( m_valid )
53  read( path ) ;
54 }
55 
57 {
58  return m_valid ;
59 }
60 
61 void GAuth::SecretsFile::reread() const
62 {
63  (const_cast<SecretsFile*>(this))->reread(0) ;
64 }
65 
66 void GAuth::SecretsFile::reread( int )
67 {
68  if( m_auto )
69  {
71  G_DEBUG( "GAuth::SecretsFile::reread: file time checked at " << m_check_time << ": now " << now ) ;
72  if( now != m_check_time ) // at most once a second
73  {
74  m_check_time = now ;
75  G::DateTime::EpochTime t = readFileTime( m_path ) ;
76  G_DEBUG( "GAuth::SecretsFile::reread: current file time " << t << ": saved file time " << m_file_time ) ;
77  if( t != m_file_time )
78  {
79  G_LOG_S( "GAuth::Secrets: re-reading secrets file: " << m_path ) ;
80  read( m_path ) ;
81  }
82  }
83  }
84 }
85 
86 void GAuth::SecretsFile::read( const G::Path & path )
87 {
88  std::auto_ptr<std::ifstream> file ;
89  {
90  G::Root claim_root ;
91  file <<= new std::ifstream( path.str().c_str() ) ;
92  }
93  if( !file->good() )
94  {
95  std::ostringstream ss ;
96  ss << "reading \"" << path << "\" for " << m_debug_name << " secrets" ;
97  throw Secrets::OpenError( ss.str() ) ;
98  }
99  m_file_time = readFileTime( path ) ;
100 
101  m_map.clear() ;
102  m_set.clear() ;
103  unsigned int count = read( *file.get() ) ;
104  count++ ; // avoid 'unused' warning
105  G_DEBUG( "GAuth::SecretsFile::read: processed " << (count-1) << " records" ) ;
106 }
107 
108 G::DateTime::EpochTime GAuth::SecretsFile::readFileTime( const G::Path & path )
109 {
110  G::Root claim_root ;
111  return G::File::time( path ) ;
112 }
113 
114 unsigned int GAuth::SecretsFile::read( std::istream & file )
115 {
116  unsigned int count = 0U ;
117  for( unsigned int line_number = 1U ; file.good() ; ++line_number )
118  {
119  std::string line = G::Str::readLineFrom( file ) ;
120  if( !file )
121  break ;
122 
123  G::Str::trim( line , G::Str::ws() ) ;
124  if( !line.empty() && line.at(0U) != '#' )
125  {
126  G::StringArray word_array ;
127  G::Str::splitIntoTokens( line , word_array , " \t" ) ;
128  if( word_array.size() > 4U )
129  {
130  G_WARNING( "GAuth::SecretsFile::read: ignoring extra fields on line "
131  << line_number << " of secrets file" ) ;
132  }
133  if( word_array.size() >= 4U )
134  {
135  bool processed = process( word_array[0U] , word_array[1U] , word_array[2U] , word_array[3U] ) ;
136  G_DEBUG( "GAuth::SecretsFile::read: line #" << line_number << (processed?" used":" ignored") ) ;
137  if( processed )
138  count++ ;
139  }
140  else
141  {
142  G_WARNING( "GAuth::SecretsFile::read: ignoring line "
143  << line_number << " of secrets file: too few fields" ) ;
144  }
145  }
146  }
147  return count ;
148 }
149 
150 bool GAuth::SecretsFile::process( std::string side , std::string mechanism , std::string id , std::string secret )
151 {
152  G::Str::toUpper( mechanism ) ;
153  G::Str::toUpper( side ) ;
154 
155  // allow columns 1 and 2 to switch around
156  if( mechanism == G::Str::upper(m_server_type) || mechanism == "CLIENT" )
157  std::swap( mechanism , side ) ;
158 
159  if( side == G::Str::upper(m_server_type) )
160  {
161  // server-side
162  std::string key = mechanism + ":" + id ;
163  std::string value = secret ;
164  m_map.insert( std::make_pair(key,value) ) ;
165  m_set.insert( mechanism ) ;
166  return true ;
167  }
168  else if( side == "CLIENT" )
169  {
170  // client-side -- no userid in the key since only one secret
171  std::string key = mechanism + " client" ;
172  std::string value = id + " " + secret ;
173  m_map.insert( std::make_pair(key,value) ) ;
174  return true ;
175  }
176  else
177  {
178  return false ;
179  }
180 }
181 
183 {
184 }
185 
186 std::string GAuth::SecretsFile::id( const std::string & mechanism ) const
187 {
188  reread() ;
189  Map::const_iterator p = m_map.find( mechanism+" client" ) ;
190  std::string result ;
191  if( p != m_map.end() && (*p).second.find(" ") != std::string::npos )
192  result = G::Xtext::decode( (*p).second.substr(0U,(*p).second.find(" ")) ) ;
193  G_DEBUG( "GAuth::Secrets::id: " << m_debug_name << ": \"" << mechanism << "\"" ) ;
194  return result ;
195 }
196 
197 std::string GAuth::SecretsFile::secret( const std::string & mechanism ) const
198 {
199  reread() ;
200  Map::const_iterator p = m_map.find( mechanism+" client" ) ;
201  if( p == m_map.end() || (*p).second.find(" ") == std::string::npos )
202  return std::string() ;
203  else
204  return G::Xtext::decode( (*p).second.substr((*p).second.find(" ")+1U) ) ;
205 }
206 
207 std::string GAuth::SecretsFile::secret( const std::string & mechanism , const std::string & id ) const
208 {
209  reread() ;
210  Map::const_iterator p = m_map.find( mechanism+":"+G::Xtext::encode(id) ) ;
211  if( p == m_map.end() )
212  return std::string() ;
213  else
214  return G::Xtext::decode( (*p).second ) ;
215 }
216 
217 std::string GAuth::SecretsFile::path() const
218 {
219  return m_path.str() ;
220 }
221 
222 bool GAuth::SecretsFile::contains( const std::string & mechanism ) const
223 {
224  return m_set.find(mechanism) != m_set.end() ;
225 }
226 
std::string str() const
Returns the path string.
Definition: gpath.cpp:135
#define G_LOG_S(expr)
Definition: glog.h:103
static EpochTime now()
Returns the current epoch time.
Definition: gdatetime.cpp:34
std::time_t EpochTime
Definition: gdatetime.h:41
static std::string decode(const std::string &)
Decodes the given string.
Definition: gxtext.cpp:79
bool valid() const
static std::string encode(const std::string &)
Encodes the given string.
Definition: gxtext.cpp:58
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstrings.h:44
A class which acquires the process's special privileges on construction and releases them on destruct...
Definition: groot.h:49
static void splitIntoTokens(const std::string &in, Strings &out, const std::string &ws)
Splits the string into 'ws'-delimited tokens.
Definition: gstr.cpp:714
std::string secret(const std::string &mechanism) const
std::string id(const std::string &mechanism) const
static void trim(std::string &s, const std::string &ws)
Trims both ends of s, taking off any of the 'ws' characters.
Definition: gstr.cpp:133
bool contains(const std::string &mechanism) const
A implementation class used by GAuth::Secrets.
Definition: gsecretsfile.h:42
SecretsFile(const G::Path &path, bool auto_, const std::string &name, const std::string &type)
Low-level classes.
std::string path() const
static std::string upper(const std::string &s)
Returns a copy of 's' in which all lowercase characters have been replaced by uppercase characters...
Definition: gstr.cpp:426
static std::string readLineFrom(std::istream &stream, const std::string &eol=std::string())
Reads a line from the stream using the given line terminator.
Definition: gstr.cpp:536
#define G_DEBUG(expr)
Definition: glog.h:95
A Path object represents a file system path.
Definition: gpath.h:44
static time_type time(const Path &file)
Returns the file's timestamp.
Definition: gfile_unix.cpp:78
static std::string ws()
A convenience function returning standard whitespace characters.
Definition: gstr.cpp:829
#define G_WARNING(expr)
Definition: glog.h:107
static void toUpper(std::string &s)
Replaces all lowercase characters in string 's' by uppercase characters.
Definition: gstr.cpp:422