44 std::string mechanisms(
const std::string & )
const ;
45 bool init(
const std::string & mechanism ) ;
46 std::string mechanism()
const ;
47 std::string initialChallenge()
const ;
48 std::string apply(
const std::string & response ,
bool & done ) ;
50 bool trustedCore(
const std::string & ,
const GNet::Address & )
const ;
52 std::string id()
const ;
53 bool authenticated()
const ;
60 std::string m_mechanism ;
61 std::string m_challenge ;
62 bool m_authenticated ;
64 std::string m_trustee ;
65 static const char * login_challenge_1 ;
66 static const char * login_challenge_2 ;
69const char * GAuth::SaslServerBasicImp::login_challenge_1 =
"Username:" ;
70const char * GAuth::SaslServerBasicImp::login_challenge_2 =
"Password:" ;
74GAuth::SaslServerBasicImp::SaslServerBasicImp(
const SaslServerSecrets & secrets ,
const std::string & sasl_server_config ,
bool allow_apop ) :
75 m_allow_apop(allow_apop) ,
78 m_authenticated(false)
81 m_mechanisms.push_back(
"PLAIN" ) ;
82 m_mechanisms.push_back(
"LOGIN" ) ;
84 m_mechanisms.push_back(
"XOAUTH2" ) ;
87 if( !sasl_server_config.empty() )
92 m_mechanisms.erase(
G::Str::keepMatch( m_mechanisms.begin() , m_mechanisms.end() , whitelist ,
true ) , m_mechanisms.end() ) ;
93 m_mechanisms.erase(
G::Str::removeMatch( m_mechanisms.begin() , m_mechanisms.end() , blacklist ,
true ) , m_mechanisms.end() ) ;
94 if( m_mechanisms.empty() )
95 throw SaslServerBasic::NoMechanisms() ;
99std::string GAuth::SaslServerBasicImp::mechanisms(
const std::string & sep )
const
104bool GAuth::SaslServerBasicImp::init(
const std::string & mechanism_in )
106 m_first_apply = true ;
107 m_authenticated = false ;
110 m_challenge.erase() ;
111 m_mechanism.erase() ;
114 if( m_allow_apop && mechanism ==
"APOP" )
116 m_mechanism = mechanism ;
120 else if( std::find(m_mechanisms.begin(),m_mechanisms.end(),mechanism) == m_mechanisms.end() )
122 G_DEBUG(
"GAuth::SaslServerBasicImp::init: requested mechanism [" << mechanism <<
"] is not in our list" ) ;
125 else if( mechanism.find(
"CRAM-") == 0U )
127 m_mechanism = mechanism ;
133 m_mechanism = mechanism ;
138std::string GAuth::SaslServerBasicImp::initialChallenge()
const
141 if( m_mechanism ==
"PLAIN" )
142 return std::string() ;
143 else if( m_mechanism ==
"XOAUTH2" )
144 return std::string() ;
145 else if( m_mechanism ==
"LOGIN" )
146 return login_challenge_1 ;
151std::string GAuth::SaslServerBasicImp::apply(
const std::string & response ,
bool & done )
153 G_DEBUG(
"GAuth::SaslServerBasic::apply: response: \"" <<
G::Str::printable(response) <<
"\"" ) ;
155 bool first_apply = m_first_apply ;
156 m_first_apply = false ;
161 std::string next_challenge ;
163 if( m_mechanism.find(
"CRAM-") == 0U || m_mechanism ==
"APOP" )
169 if( m_mechanism ==
"APOP" )
171 secret = m_secrets.serverSecret(
"plain" ,
id ) ;
175 std::string hash_type = m_mechanism.substr(5U) ;
176 secret = m_secrets.serverSecret( hash_type ,
id ) ;
177 if( !secret.valid() )
178 secret = m_secrets.serverSecret(
"plain" ,
id ) ;
181 if( !secret.valid() )
183 m_authenticated = false ;
189 m_mechanism ==
"APOP" ?
190 Cram::validate(
"MD5" ,
false , secret , m_challenge , response ) :
191 Cram::validate( m_mechanism.substr(5U) , true , secret , m_challenge , response ) ;
195 else if( m_mechanism ==
"PLAIN" )
198 std::string sep( 1U ,
'\0' ) ;
199 std::string id_pwd_in =
G::Str::tail( response , sep ) ;
202 secret = m_secrets.serverSecret(
"plain" ,
id ) ;
204 m_authenticated = secret.valid() && !
id.empty() && !pwd_in.empty() && pwd_in == secret.key() ;
208 else if( m_mechanism ==
"XOAUTH2" && first_apply )
213 m_authenticated = true ;
218 next_challenge =
"not authenticated, send empty response" ;
222 else if( m_mechanism ==
"XOAUTH2" )
224 m_authenticated = false ;
227 else if( first_apply )
230 G_ASSERT( m_mechanism ==
"LOGIN" ) ;
231 id = m_id = response ;
233 next_challenge = login_challenge_2 ;
237 G_ASSERT( m_mechanism ==
"LOGIN" ) ;
239 secret = m_secrets.serverSecret(
"plain" , m_id ) ;
240 m_authenticated = secret.valid() && !response.empty() && response == secret.key() ;
246 std::ostringstream ss ;
248 << (m_authenticated?
"successful":
"failed") <<
" authentication of remote client using mechanism ["
249 <<
G::Str::lower(m_mechanism) <<
"] and " << secret.info(
id) ;
250 if( m_authenticated )
251 G_LOG(
"GAuth::SaslServerBasicImp::apply: " << ss.str() ) ;
253 G_WARNING(
"GAuth::SaslServerBasicImp::apply: " << ss.str() ) ;
256 return next_challenge ;
259bool GAuth::SaslServerBasicImp::trusted(
const GNet::Address & address )
const
261 G_DEBUG(
"GAuth::SaslServerBasicImp::trusted: \"" << address.
hostPartString() <<
"\"" ) ;
263 return std::any_of( wildcards.cbegin() , wildcards.cend() ,
264 [&](
const std::string &wca){return trustedCore(wca,address);} ) ;
267bool GAuth::SaslServerBasicImp::trustedCore(
const std::string & address_wildcard ,
const GNet::Address & address )
const
269 G_DEBUG(
"GAuth::SaslServerBasicImp::trustedCore: \"" << address_wildcard <<
"\", \"" << address.
hostPartString() <<
"\"" ) ;
270 std::pair<std::string,std::string> pair = m_secrets.serverTrust( address_wildcard ) ;
271 std::string & trustee = pair.first ;
272 if( !trustee.empty() )
274 G_LOG(
"GAuth::SaslServer::trusted: trusting [" << address.
hostPartString() <<
"]: "
275 <<
"matched [" << address_wildcard <<
"] from " << pair.second ) ;
276 const_cast<SaslServerBasicImp*
>(
this)->m_trustee = trustee ;
285bool GAuth::SaslServerBasicImp::active()
const
287 return m_secrets.valid() ;
290std::string GAuth::SaslServerBasicImp::mechanism()
const
295std::string GAuth::SaslServerBasicImp::id()
const
297 return m_authenticated ? m_id : m_trustee ;
300bool GAuth::SaslServerBasicImp::authenticated()
const
302 return m_authenticated ;
312GAuth::SaslServerBasic::~SaslServerBasic()
315std::string GAuth::SaslServerBasic::mechanisms(
char c )
const
317 return m_imp->mechanisms( std::string(1U,c) ) ;
320std::string GAuth::SaslServerBasic::mechanism()
const
322 return m_imp->mechanism() ;
325bool GAuth::SaslServerBasic::trusted(
const GNet::Address & address )
const
327 return m_imp->trusted( address ) ;
330bool GAuth::SaslServerBasic::active()
const
332 return m_imp->active() ;
335bool GAuth::SaslServerBasic::init(
const std::string & mechanism )
337 return m_imp->init( mechanism ) ;
340bool GAuth::SaslServerBasic::mustChallenge()
const
343 return m !=
"PLAIN" && m !=
"LOGIN" && m !=
"XOAUTH2" ;
346std::string GAuth::SaslServerBasic::initialChallenge()
const
348 return m_imp->initialChallenge() ;
351std::string GAuth::SaslServerBasic::apply(
const std::string & response ,
bool & done )
353 return m_imp->apply( response , done ) ;
356bool GAuth::SaslServerBasic::authenticated()
const
358 return m_imp->authenticated() ;
361std::string GAuth::SaslServerBasic::id()
const
366bool GAuth::SaslServerBasic::requiresEncryption()
const
static std::string challenge(unsigned int random)
Returns a challenge string that incorporates the given random number and the current time.
static std::string id(const std::string &response)
Returns the leading id part of the response.
static bool validate(const std::string &hash_type, bool hmac, const Secret &secret, const std::string &challenge, const std::string &response)
Validates the response with respect to the original challenge.
static G::StringArray hashTypes(const std::string &prefix=std::string(), bool require_state=false)
Returns a list of supported hash types, such as "MD5" and "SHA1", ordered with the strongest first.
A private pimple-pattern implementation class used by GAuth::SaslServerBasic.
SaslServerBasic(const SaslServerSecrets &, const std::string &config, bool allow_apop)
Constructor.
An interface used by GAuth::SaslServer to obtain authentication secrets.
static Secret none()
Factory function that returns a secret that is not valid() and has an empty id().
The GNet::Address class encapsulates a TCP/UDP transport address.
G::StringArray wildcards() const
Returns an ordered list of wildcard strings that match this address.
std::string hostPartString(bool raw=false) const
Returns a string which represents the network address.
static std::string join(const std::string &sep, const StringArray &strings)
Concatenates an array of strings with separators.
static std::string tail(const std::string &in, std::size_t pos, const std::string &default_=std::string())
Returns the last part of the string after the given position.
static void splitIntoTokens(const std::string &in, StringArray &out, string_view ws, char esc='\0')
Splits the string into 'ws'-delimited tokens.
static StringArray::iterator removeMatch(StringArray::iterator begin, StringArray::iterator end, const StringArray &match_list, bool ignore_case=false)
Removes items in the begin/end list that match one of the elements in the match-list (blocklist).
static std::string upper(const std::string &s)
Returns a copy of 's' in which all Latin-1 lower-case characters have been replaced by upper-case cha...
static std::string printable(const std::string &in, char escape='\\')
Returns a printable representation of the given input string, using chacter code ranges 0x20 to 0x7e ...
static std::string headMatchResidue(const StringArray &in, const std::string &head)
Returns the unmatched part of the first string in the array that has the given start.
static std::string head(const std::string &in, std::size_t pos, const std::string &default_=std::string())
Returns the first part of the string up to just before the given position.
static StringArray::iterator keepMatch(StringArray::iterator begin, StringArray::iterator end, const StringArray &match_list, bool ignore_case=false)
Removes items in the begin/end list that do not match any of the elements in the match-list (whitelis...
static std::string lower(const std::string &s)
Returns a copy of 's' in which all Latin-1 upper-case characters have been replaced by lower-case cha...
static bool enabled() noexcept
Returns true if test features are enabled.
std::vector< std::string > StringArray
A std::vector of std::strings.