- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gsaslclient_native.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 // gsaslclient_native.cpp
19 //
20
21 #include "gdef.h"
22 #include "gnet.h"
23 #include "gauth.h"
24 #include "gsaslclient.h"
25 #include "gmd5.h"
26 #include "gstr.h"
27 #include "gdebug.h"
28 #include <algorithm> // set_intersection
29 #include <set>
30
31 namespace
32 {
33 const char * login_challenge_1 = "Username:" ;
34 const char * login_challenge_2 = "Password:" ;
35 }
36
40 class GAuth::SaslClientImp
41 {
42 public:
43 const SaslClient::Secrets & m_secrets ;
44 explicit SaslClientImp( const SaslClient::Secrets & ) ;
45 static std::string clientResponse( const std::string & secret ,
46 const std::string & challenge , bool cram , bool & error ) ;
47 static std::string digest( const std::string & secret , const std::string & challenge ) ;
48 static std::string cramDigest( const std::string & secret , const std::string & challenge ) ;
49 } ;
50
51 // ===
52
53 GAuth::SaslClientImp::SaslClientImp( const SaslClient::Secrets & secrets ) :
54 m_secrets(secrets)
55 {
56 }
57
58 std::string GAuth::SaslClientImp::clientResponse( const std::string & secret ,
59 const std::string & challenge , bool cram , bool & error )
60 {
61 try
62 {
63 G_DEBUG( "GAuth::SaslClientImp::clientResponse: challenge=\"" << challenge << "\"" ) ;
64 return cram ? cramDigest(secret,challenge) : digest(secret,challenge) ;
65 }
66 catch( std::exception & e )
67 {
68 std::string what = e.what() ;
69 G_DEBUG( "GAuth::SaslClient: " << what ) ;
70 error = true ;
71 }
72 return std::string() ;
73 }
74
75 std::string GAuth::SaslClientImp::cramDigest( const std::string & secret , const std::string & challenge )
76 {
77 return G::Md5::printable(G::Md5::hmac(secret,challenge,G::Md5::Masked())) ;
78 }
79
80 std::string GAuth::SaslClientImp::digest( const std::string & secret , const std::string & challenge )
81 {
82 return G::Md5::printable(G::Md5::digest(challenge,secret)) ;
83 }
84
85 // ===
86
87 GAuth::SaslClient::SaslClient( const SaslClient::Secrets & secrets , const std::string & server_name ) :
88 m_imp(new SaslClientImp(secrets) )
89 {
90 G_IGNORE_PARAMETER(std::string,server_name) ;
91 G_DEBUG( "GAuth::SaslClient::ctor: server-name=\"" << server_name << "\", active=" << active() ) ;
92 }
93
94 GAuth::SaslClient::~SaslClient()
95 {
96 delete m_imp ;
97 }
98
99 bool GAuth::SaslClient::active() const
100 {
101 return m_imp->m_secrets.valid() ;
102 }
103
104 std::string GAuth::SaslClient::initial_response( const std::string & mechanism , bool & done ,
105 bool & error , bool & sensitive ) const
106 {
107 done = false ;
108 error = false ;
109 sensitive = false ;
110
111 std::string auth("AUTH") ;
112 std::string sep(" ") ;
113
114 std::string rsp ;
115 if( mechanism == "XOAUTH2" )
116 {
117 std::string secret = m_imp->m_secrets.secret(mechanism) ;
118 rsp = auth + sep + mechanism + sep + secret ;
119 error = secret.empty() ;
120 done = true ;
121 sensitive = true ;
122 }
123 else
124 {
125 rsp = auth + sep + mechanism ;
126 }
127
128 return rsp ;
129 }
130
131 std::string GAuth::SaslClient::response( const std::string & mechanism , const std::string & challenge ,
132 bool & done , bool & error , bool & sensitive ) const
133 {
134 done = false ;
135 error = false ;
136 sensitive = false ;
137
138 std::string rsp ;
139 if( mechanism == "CRAM-MD5" || mechanism == "APOP" )
140 {
141 const bool cram = mechanism == "CRAM-MD5" ;
142 std::string id = m_imp->m_secrets.id(mechanism) ;
143 std::string secret = m_imp->m_secrets.secret(mechanism) ;
144 error = id.empty() || secret.empty() ;
145 if( !error )
146 rsp = id + " " + SaslClientImp::clientResponse( secret , challenge , cram , error ) ;
147
148 done = true ;
149 }
150 else if( mechanism == "PLAIN" )
151 {
152 std::string sep( 1U , '\0' ) ;
153 std::string id = m_imp->m_secrets.id(mechanism) ;
154 std::string secret = m_imp->m_secrets.secret(mechanism) ;
155 rsp = sep + id + sep + secret ;
156 error = id.empty() || secret.empty() ;
157 done = true ;
158 sensitive = true ;
159 }
160 else if( mechanism == "LOGIN" )
161 {
162 if( challenge == login_challenge_1 )
163 {
164 rsp = m_imp->m_secrets.id(mechanism) ;
165 error = rsp.empty() ;
166 done = false ;
167 }
168 else if( challenge == login_challenge_2 )
169 {
170 rsp = m_imp->m_secrets.secret(mechanism) ;
171 error = rsp.empty() ;
172 done = true ;
173 sensitive = true ;
174 }
175 else
176 {
177 error = true ;
178 }
179 }
180 else
181 {
182 error = true ;
183 }
184
185 if( error )
186 {
187 G_WARNING( "GAuth::SaslClient: invalid challenge" ) ;
188 done = true ;
189 }
190
191 return rsp ;
192 }
193
194 std::string GAuth::SaslClient::preferred( const G::Strings & mechanism_list ) const
195 {
196 G_DEBUG( "GAuth::SaslClient::preferred: server's mechanisms: [" << G::Str::join(mechanism_list,",") << "]" ) ;
197
198 // short-circuit if no secrets
199 //
200 if( !active() )
201 return std::string() ;
202
203 const std::string login( "LOGIN" ) ;
204 const std::string plain( "PLAIN" ) ;
205 const std::string xoauth2( "XOAUTH2" ) ;
206 const std::string cram( "CRAM-MD5" ) ;
207
208 // create a them set
209 std::set<std::string> them ;
210 for( G::Strings::const_iterator p = mechanism_list.begin() ; p != mechanism_list.end() ; ++p )
211 them.insert( G::Str::upper(*p) ) ;
212
213 // create an us set
214 std::set<std::string> us ;
215 if( !m_imp->m_secrets.id(login).empty() ) us.insert(login) ;
216 if( !m_imp->m_secrets.id(plain).empty() ) us.insert(plain) ;
217 if( !m_imp->m_secrets.id(xoauth2).empty() ) us.insert(xoauth2) ;
218 if( !m_imp->m_secrets.id(cram).empty() ) us.insert(cram) ;
219
220 // get the intersection
221 std::set<std::string> both ;
222 std::set_intersection( them.begin() , them.end() , us.begin() , us.end() , std::inserter(both,both.end()) ) ;
223
224 // preferred order: cram, xoauth2, plain, login
225 std::string m ;
226 if( m.empty() && both.find(cram) != both.end() ) m = cram ;
227 if( m.empty() && both.find(xoauth2) != both.end() ) m = xoauth2 ;
228 if( m.empty() && both.find(plain) != both.end() ) m = plain ;
229 if( m.empty() && both.find(login) != both.end() ) m = login ;
230 G_DEBUG( "GAuth::SaslClient::preferred: we prefer \"" << m << "\"" ) ;
231
232 return m ;
233 }
234
235 // ==
236
237 GAuth::SaslClient::Secrets::~Secrets()
238 {
239 }
240
G::Md5::Masked
An overload discriminator for G::Md5::hmac()
Definition: gmd5.h:43
GAuth::SaslClient::preferred
std::string preferred(const G::Strings &mechanisms) const
Returns the name of the preferred mechanism taken from the given set.
Definition: gsaslclient_native.cpp:194
GAuth::SaslClientImp::digest
static std::string digest(const std::string &secret, const std::string &challenge)
Definition: gsaslclient_native.cpp:80
GAuth::SaslClient::response
std::string response(const std::string &mechanism, const std::string &challenge, bool &done, bool &error, bool &sensitive) const
Returns a response to the given challenge.
Definition: gsaslclient_native.cpp:131
gsaslclient.h
gmd5.h
G::Strings
std::list< std::string > Strings
A std::list of std::strings.
Definition: gstrings.h:39
GAuth::SaslClientImp::SaslClientImp
SaslClientImp(const SaslClient::Secrets &)
Definition: gsaslclient_native.cpp:53
GAuth::SaslClient::SaslClient
SaslClient(const Secrets &secrets, const std::string &server_name)
Constructor. The secrets reference is kept.
Definition: gsaslclient_native.cpp:87
GAuth::SaslClient::active
bool active() const
Returns true if the constructor's secrets object is valid.
Definition: gsaslclient_native.cpp:99
G::Md5::hmac
static std::string hmac(const std::string &key, const std::string &input)
Computes a Hashed Message Authentication Code using MD5 as the hash function.
Definition: gmd5_native.cpp:167
GAuth::SaslClientImp
A private pimple-pattern implementation class used by GAuth::SaslClient.
Definition: gsaslclient_native.cpp:40
gstr.h
gauth.h
GAuth::SaslClient::Secrets
An interface used by GAuth::SaslClient to obtain authentication secrets.
Definition: gsaslclient.h:52
GAuth::SaslClientImp::cramDigest
static std::string cramDigest(const std::string &secret, const std::string &challenge)
Definition: gsaslclient_native.cpp:75
G::Str::upper
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
G_DEBUG
#define G_DEBUG(expr)
Definition: glog.h:95
G::Md5::digest
static std::string digest(const std::string &input)
Creates an MD5 digest.
Definition: gmd5_native.cpp:173
GAuth::SaslClientImp::m_secrets
const SaslClient::Secrets & m_secrets
Definition: gsaslclient_native.cpp:43
GAuth::SaslClient::Secrets::~Secrets
virtual ~Secrets()
Definition: gsaslclient_native.cpp:237
GAuth::SaslClientImp::clientResponse
static std::string clientResponse(const std::string &secret, const std::string &challenge, bool cram, bool &error)
Definition: gsaslclient_native.cpp:58
GAuth::SaslClient::~SaslClient
~SaslClient()
Destructor.
Definition: gsaslclient_native.cpp:94
GAuth::SaslClient::initial_response
std::string initial_response(const std::string &mechanism, bool &done, bool &error, bool &sensitive) const
Returns an initial_response for authentication.
Definition: gsaslclient_native.cpp:104
G::Str::join
static std::string join(const Strings &strings, const std::string &sep)
Concatenates a set of strings.
Definition: gstr.cpp:799
G::Md5::printable
static std::string printable(const std::string &input)
Converts a binary string into a printable form, using a lowercase hexadecimal encoding.
Definition: gmd5_native.cpp:193
G_WARNING
#define G_WARNING(expr)
Definition: glog.h:107
gdebug.h