00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <boost/algorithm/string.hpp>
00011 #include <pion/net/HTTPBasicAuth.hpp>
00012 #include <pion/net/HTTPResponseWriter.hpp>
00013 #include <pion/net/HTTPServer.hpp>
00014
00015
00016 namespace pion {
00017 namespace net {
00018
00019
00020
00021
00022 const unsigned int HTTPBasicAuth::CACHE_EXPIRATION = 300;
00023
00024
00025
00026
00027 HTTPBasicAuth::HTTPBasicAuth(PionUserManagerPtr userManager, const std::string& realm)
00028 : HTTPAuth(userManager), m_realm(realm),
00029 m_cache_cleanup_time(boost::posix_time::second_clock::universal_time())
00030 {
00031 setLogger(PION_GET_LOGGER("pion.net.HTTPBasicAuth"));
00032 }
00033
00034 bool HTTPBasicAuth::handleRequest(HTTPRequestPtr& request, TCPConnectionPtr& tcp_conn)
00035 {
00036 if (!needAuthentication(request)) {
00037 return true;
00038 }
00039
00040 PionDateTime time_now(boost::posix_time::second_clock::universal_time());
00041 if (time_now > m_cache_cleanup_time + boost::posix_time::seconds(CACHE_EXPIRATION)) {
00042
00043 boost::mutex::scoped_lock cache_lock(m_cache_mutex);
00044 PionUserCache::iterator i;
00045 PionUserCache::iterator next=m_user_cache.begin();
00046 while (next!=m_user_cache.end()) {
00047 i=next;
00048 ++next;
00049 if (time_now > i->second.first + boost::posix_time::seconds(CACHE_EXPIRATION)) {
00050
00051 m_user_cache.erase(i);
00052 }
00053 }
00054 m_cache_cleanup_time = time_now;
00055 }
00056
00057
00058 std::string authorization = request->getHeader(HTTPTypes::HEADER_AUTHORIZATION);
00059 if (!authorization.empty()) {
00060 std::string credentials;
00061 if (parseAuthorization(authorization, credentials)) {
00062
00063 boost::mutex::scoped_lock cache_lock(m_cache_mutex);
00064 PionUserCache::iterator user_cache_ptr=m_user_cache.find(credentials);
00065 if (user_cache_ptr!=m_user_cache.end()) {
00066
00067
00068 request->setUser(user_cache_ptr->second.second);
00069 user_cache_ptr->second.first = time_now;
00070 return true;
00071 }
00072
00073 std::string username;
00074 std::string password;
00075
00076 if (parseCredentials(credentials, username, password)) {
00077
00078 PionUserPtr user=m_user_manager->getUser(username, password);
00079 if (user) {
00080
00081 m_user_cache.insert(std::make_pair(credentials, std::make_pair(time_now, user)));
00082
00083 request->setUser(user);
00084 return true;
00085 }
00086 }
00087 }
00088 }
00089
00090
00091 handleUnauthorized(request, tcp_conn);
00092 return false;
00093 }
00094
00095 void HTTPBasicAuth::setOption(const std::string& name, const std::string& value)
00096 {
00097 if (name=="realm")
00098 m_realm = value;
00099 else
00100 throw UnknownOptionException(name);
00101 }
00102
00103 bool HTTPBasicAuth::parseAuthorization(const std::string& authorization, std::string &credentials)
00104 {
00105 if (!boost::algorithm::starts_with(authorization, "Basic "))
00106 return false;
00107 credentials = authorization.substr(6);
00108 if (credentials.empty())
00109 return false;
00110 return true;
00111 }
00112
00113 bool HTTPBasicAuth::parseCredentials(const std::string &credentials,
00114 std::string &username, std::string &password)
00115 {
00116 std::string user_password;
00117
00118 if (! HTTPTypes::base64_decode(credentials, user_password))
00119 return false;
00120
00121
00122 std::string::size_type i = user_password.find(':');
00123 if (i==0 || i==std::string::npos)
00124 return false;
00125
00126 username = user_password.substr(0, i);
00127 password = user_password.substr(i+1);
00128
00129 return true;
00130 }
00131
00132 void HTTPBasicAuth::handleUnauthorized(HTTPRequestPtr& http_request,
00133 TCPConnectionPtr& tcp_conn)
00134 {
00135
00136 static const std::string CONTENT =
00137 " <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\""
00138 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">"
00139 "<HTML>"
00140 "<HEAD>"
00141 "<TITLE>Error</TITLE>"
00142 "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=ISO-8859-1\">"
00143 "</HEAD>"
00144 "<BODY><H1>401 Unauthorized.</H1></BODY>"
00145 "</HTML> ";
00146 HTTPResponseWriterPtr writer(HTTPResponseWriter::create(tcp_conn, *http_request,
00147 boost::bind(&TCPConnection::finish, tcp_conn)));
00148 writer->getResponse().setStatusCode(HTTPTypes::RESPONSE_CODE_UNAUTHORIZED);
00149 writer->getResponse().setStatusMessage(HTTPTypes::RESPONSE_MESSAGE_UNAUTHORIZED);
00150 writer->getResponse().addHeader("WWW-Authenticate", "Basic realm=\"" + m_realm + "\"");
00151 writer->writeNoCopy(CONTENT);
00152 writer->send();
00153 }
00154
00155 }
00156 }