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