38class GAuth::SaslClientImp
41 using Response = SaslClient::Response ;
42 SaslClientImp(
const SaslClientSecrets & ,
const std::string & ) ;
46 Response initialResponse(
G::string_view selector , std::size_t )
const ;
49 std::string mechanism()
const ;
50 std::string id()
const ;
51 std::string info()
const ;
52 static bool match(
const G::StringArray & mechanisms ,
const std::string & ) ;
55 const SaslClientSecrets & m_secrets ;
56 std::string m_config ;
58 mutable std::string m_info ;
59 mutable std::string m_id ;
66G::string_view GAuth::SaslClientImp::login_challenge_1 {
"Username:" , 9U } ;
67G::string_view GAuth::SaslClientImp::login_challenge_2 {
"Password:" , 9U } ;
71GAuth::SaslClientImp::SaslClientImp(
const SaslClientSecrets & secrets ,
72 const std::string & sasl_client_config ) :
74 m_config(sasl_client_config) ,
89 if( m_secrets.clientSecret(
"plain",selector).valid() )
91 our_list = Cram::hashTypes(
"CRAM-" ,
false ) ;
95 our_list = Cram::hashTypes(
"CRAM-" ,
true ) ;
96 for(
auto p = our_list.begin() ; p != our_list.end() ; )
98 std::string type = (*p).substr( 5U ) ;
99 if( m_secrets.clientSecret(type,selector).valid() )
102 p = our_list.erase( p ) ;
105 if( m_secrets.clientSecret(
"oauth",selector).valid() )
107 our_list.push_back(
"XOAUTH2" ) ;
109 if( m_secrets.clientSecret(
"plain",selector).valid() )
111 our_list.push_back( PLAIN ) ;
112 our_list.push_back( LOGIN ) ;
116 if( !m_config.empty() )
127 m_mechanisms.clear() ;
128 for(
auto & our_mechanism : our_list )
130 if( match(server_mechanisms,our_mechanism) )
132 m_mechanisms.push_back( our_mechanism ) ;
136 G_DEBUG(
"GAuth::SaslClientImp::mechanism: server mechanisms: [" <<
G::Str::join(
",",server_mechanisms) <<
"]" ) ;
137 G_DEBUG(
"GAuth::SaslClientImp::mechanism: our mechanisms: [" <<
G::Str::join(
",",our_list) <<
"]" ) ;
138 G_DEBUG(
"GAuth::SaslClientImp::mechanism: usable mechanisms: [" <<
G::Str::join(
",",m_mechanisms) <<
"]" ) ;
140 return m_mechanisms.empty() ? std::string() : m_mechanisms.at(0U) ;
143bool GAuth::SaslClientImp::next()
145 if( !m_mechanisms.empty() )
146 m_mechanisms.erase( m_mechanisms.begin() ) ;
147 return !m_mechanisms.empty() ;
150std::string GAuth::SaslClientImp::mechanism()
const
152 return m_mechanisms.empty() ? std::string() : m_mechanisms.at(0U) ;
161 if( m_mechanisms.empty() || m_mechanisms[0U].find(
"CRAM-") == 0U )
164 const std::string & m = m_mechanisms[0] ;
165 Response rsp = response( m , m ==
"LOGIN" ? login_challenge_1 :
G::string_view() , selector ) ;
166 if( rsp.error || rsp.data.size() > limit )
176 rsp.sensitive = true ;
180 Secret secret = Secret::none() ;
181 if( mechanism.find(
"CRAM-") == 0U )
184 secret = m_secrets.clientSecret( hash_type , selector ) ;
185 if( !secret.valid() )
186 secret = m_secrets.clientSecret(
"plain" , selector ) ;
187 rsp.data = Cram::response( hash_type ,
true , secret , challenge , secret.id() ) ;
188 rsp.error = rsp.data.empty() ;
191 else if( mechanism ==
"APOP"_sv )
193 secret = m_secrets.clientSecret(
"MD5"_sv , selector ) ;
194 rsp.data = Cram::response(
"MD5"_sv ,
false , secret , challenge , secret.id() ) ;
195 rsp.error = rsp.data.empty() ;
198 else if( mechanism == PLAIN )
200 secret = m_secrets.clientSecret(
"plain"_sv , selector ) ;
201 rsp.data = std::string(1U,
'\0').append(secret.id()).append(1U,
'\0').append(secret.secret()) ;
202 rsp.error = !secret.valid() ;
205 else if( mechanism == LOGIN && challenge == login_challenge_1 )
207 secret = m_secrets.clientSecret(
"plain"_sv , selector ) ;
208 rsp.data = secret.id() ;
209 rsp.error = !secret.valid() ;
211 rsp.sensitive = false ;
213 else if( mechanism == LOGIN && challenge == login_challenge_2 )
215 secret = m_secrets.clientSecret(
"plain"_sv , selector ) ;
216 rsp.data = secret.secret() ;
217 rsp.error = !secret.valid() ;
220 else if( mechanism ==
"XOAUTH2"_sv && challenge.empty() )
222 secret = m_secrets.clientSecret(
"oauth"_sv , selector ) ;
223 rsp.data = secret.secret() ;
224 rsp.error = !secret.valid() ;
227 else if( mechanism ==
"XOAUTH2"_sv )
229 secret = m_secrets.clientSecret(
"oauth"_sv , selector ) ;
233 rsp.sensitive = false ;
239 .assign(
"using mechanism [")
242 .append(secret.info()) ;
249std::string GAuth::SaslClientImp::id()
const
254std::string GAuth::SaslClientImp::info()
const
259bool GAuth::SaslClientImp::validSelector(
G::string_view selector )
const
261 return m_secrets.validSelector( selector ) ;
264bool GAuth::SaslClientImp::mustAuthenticate(
G::string_view selector )
const
266 return m_secrets.mustAuthenticate( selector ) ;
269bool GAuth::SaslClientImp::match(
const G::StringArray & mechanisms ,
const std::string & mechanism )
271 return std::find(mechanisms.begin(),mechanisms.end(),mechanism) != mechanisms.end() ;
277 m_imp(
std::make_unique<SaslClientImp>(secrets,config))
286 return m_imp->validSelector( selector ) ;
291 return m_imp->mustAuthenticate( selector ) ;
297 return m_imp->response( mechanism , challenge , selector ) ;
302 return m_imp->initialResponse( selector , limit ) ;
307 return m_imp->mechanism( server_mechanisms , selector ) ;
312 return m_imp->next() ;
318 if( s.empty() )
return s ;
319 return m_imp->next() ? mechanism() : std::string() ;
325 return m_imp->mechanism() ;
335 return m_imp->info() ;
An interface used by GAuth::SaslClient to obtain a client id and its authentication secret.
std::string id() const
Returns the authentication id, valid after the last response().
Response response(G::string_view mechanism, G::string_view challenge, G::string_view selector) const
Returns a response to the given challenge.
Response initialResponse(G::string_view selector, std::size_t limit=0U) const
Returns an optional initial response.
bool mustAuthenticate(G::string_view selector) const
Returns true if authentication is required.
SaslClient(const SaslClientSecrets &secrets, const std::string &config)
Constructor. The secrets reference is kept.
bool next()
Moves to the next preferred mechanism.
std::string info() const
Returns logging and diagnostic information, valid after the last response().
std::string mechanism() const
Returns the name of the current mechanism once next() has returned true.
bool validSelector(G::string_view selector) const
Returns true if the selector is valid.
static void splitIntoTokens(const std::string &in, StringArray &out, string_view ws, char esc='\0')
Splits the string into 'ws'-delimited tokens.
static std::string join(string_view sep, const StringArray &strings)
Concatenates an array of strings with separators.
static std::string lower(string_view)
Returns a copy of 's' in which all seven-bit upper-case characters have been replaced by lower-case c...
static std::string upper(string_view)
Returns a copy of 's' in which all seven-bit lower-case characters have been replaced by upper-case c...
A class like c++17's std::string_view.
An interface to an underlying TLS library.
std::string headMatchResidue(const StringArray &list, string_view head)
Returns the unmatched part of the first string in the array that has the given start.
void keepMatch(StringArray &list, const StringArray &allow_list, Ignore=Ignore::Nothing)
Removes items in the list that do not match any entry in the allow list.
bool imatch(const StringArray &, const std::string &)
Returns true if any string in the array matches the given string, ignoring case.
void removeMatch(StringArray &list, const StringArray &deny_list, Ignore=Ignore::Nothing)
Removes items in the list that match an entry in the deny list.
std::vector< std::string > StringArray
A std::vector of std::strings.
Result structure returned from GAuth::SaslClient::response.