- Main Page
- Classes
- Files

- File List

# src/http_basic_auth.cpp

    00001 // ---------------------------------------------------------------------
    00002 // pion:  a Boost C++ framework for building lightweight HTTP interfaces
    00003 // ---------------------------------------------------------------------
    00004 // Copyright (C) 2007-2012 Cloudmeter, Inc.  (http://www.cloudmeter.com)
    00005 //
    00006 // Distributed under the Boost Software License, Version 1.0.
    00007 // See http://www.boost.org/LICENSE_1_0.txt
    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 {    // begin namespace pion
    00018 namespace http {    // begin namespace http
    00019
    00020
    00021 // static members of basic_auth
    00022
    00023 const unsigned int  basic_auth::CACHE_EXPIRATION = 300;  // 5 minutes
    00024
    00025
    00026 // basic_auth member functions
    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; // this request does not require authentication
    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         // expire cache
    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                 // ok - this is an old record.. expire it now
    00052                 m_user_cache.erase(i);
    00053             }
    00054         }
    00055         m_cache_cleanup_time = time_now;
    00056     }
    00057
    00058     // if we are here, we need to check if access authorized...
    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             // to do - use fast cache to match with active credentials
    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                 // we found the credentials in our cache...
    00068                 // we can approve authorization now!
    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                 // match username/password
    00079                 user_ptr user=m_user_manager->get_user(username, password);
    00080                 if (user) {
    00081                     // add user to the cache
    00082                     m_user_cache.insert(std::make_pair(credentials, std::make_pair(time_now, user)));
    00083                     // add user credentials to the request object
    00084                     http_request_ptr->set_user(user);
    00085                     return true;
    00086                 }
    00087             }
    00088         }
    00089     }
    00090
    00091     // user not found
    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     // find ':' symbol
    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     // authentication failed, send 401.....
    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 }   // end namespace http
    00157 }   // end namespace pion