Esempio n. 1
0
bool HTTPBasicAuth::handleRequest(HTTPRequestPtr& request, TCPConnectionPtr& tcp_conn)
{
	if (!needAuthentication(request)) {
		return true; // this request does not require authentication
	}
	
	PionDateTime time_now(boost::posix_time::second_clock::universal_time());
	if (time_now > m_cache_cleanup_time + boost::posix_time::seconds(CACHE_EXPIRATION)) {
		// expire cache
		boost::mutex::scoped_lock cache_lock(m_cache_mutex);
		PionUserCache::iterator i;
		PionUserCache::iterator next=m_user_cache.begin();
		while (next!=m_user_cache.end()) {
			i=next;
			++next;
			if (time_now > i->second.first + boost::posix_time::seconds(CACHE_EXPIRATION)) {
				// ok - this is an old record.. expire it now
				m_user_cache.erase(i);
			}
		}
		m_cache_cleanup_time = time_now;
	}
	
	// if we are here, we need to check if access authorized...
	std::string authorization = request->getHeader(HTTPTypes::HEADER_AUTHORIZATION);
	if (!authorization.empty()) {
		std::string credentials;
		if (parseAuthorization(authorization, credentials)) {
			// to do - use fast cache to match with active credentials
			boost::mutex::scoped_lock cache_lock(m_cache_mutex);
			PionUserCache::iterator user_cache_ptr=m_user_cache.find(credentials);
			if (user_cache_ptr!=m_user_cache.end()) {
				// we found the credentials in our cache...
				// we can approve authorization now!
				request->setUser(user_cache_ptr->second.second);
				user_cache_ptr->second.first = time_now;
				return true;
			}
	
			std::string username;
			std::string password;
	
			if (parseCredentials(credentials, username, password)) {
				// match username/password
				PionUserPtr user=m_user_manager->getUser(username, password);
				if (user) {
					// add user to the cache
					m_user_cache.insert(std::make_pair(credentials, std::make_pair(time_now, user)));
					// add user credentials to the request object
					request->setUser(user);
					return true;
				}
			}
		}
	}

	// user not found
	handleUnauthorized(request, tcp_conn);
	return false;
}
Esempio n. 2
0
bool HTTPCookieAuth::handleRequest(HTTPRequestPtr& request, TCPConnectionPtr& tcp_conn)
{
	if (processLogin(request,tcp_conn)) {
		return false; // we processed login/logout request, no future processing for this request permitted
	}

	if (!needAuthentication(request)) {
		return true; // this request does not require authentication
	}

	// check if it is redirection page.. If yes, then do not test its credentials ( as used for login)
	if (!m_redirect.empty() && m_redirect==request->getResource()) {
		return true; // this request does not require authentication
	}
	
	// check cache for expiration
	PionDateTime time_now(boost::posix_time::second_clock::universal_time());
	expireCache(time_now);

	// if we are here, we need to check if access authorized...
	const std::string auth_cookie(request->getCookie(AUTH_COOKIE_NAME));
	if (! auth_cookie.empty()) {
		// check if this cookie is in user cache
		boost::mutex::scoped_lock cache_lock(m_cache_mutex);
		PionUserCache::iterator user_cache_itr=m_user_cache.find(auth_cookie);
		if (user_cache_itr != m_user_cache.end()) {
			// we find those credential in our cache...
			// we can approve authorization now!
			request->setUser(user_cache_itr->second.second);
			// and update cache timeout
			user_cache_itr->second.first = time_now;
			return true;
		}
	}

	// user not found
	handleUnauthorized(request,tcp_conn);
	return false;
}
Esempio n. 3
0
void HTTPServer::handleNotFoundRequest(HTTPRequestPtr& http_request,
									   TCPConnectionPtr& tcp_conn)
{
	static const std::string NOT_FOUND_HTML_START =
		"<html><head>\n"
		"<title>404 Not Found</title>\n"
		"</head><body>\n"
		"<h1>Not Found</h1>\n"
		"<p>The requested URL ";
	static const std::string NOT_FOUND_HTML_FINISH =
		" was not found on this server.</p>\n"
		"</body></html>\n";
	HTTPResponseWriterPtr writer(HTTPResponseWriter::create(tcp_conn, *http_request,
															boost::bind(&TCPConnection::finish, tcp_conn)));
	writer->getResponse().setStatusCode(HTTPTypes::RESPONSE_CODE_NOT_FOUND);
	writer->getResponse().setStatusMessage(HTTPTypes::RESPONSE_MESSAGE_NOT_FOUND);
	writer->writeNoCopy(NOT_FOUND_HTML_START);
	writer << http_request->getResource();
	writer->writeNoCopy(NOT_FOUND_HTML_FINISH);
	writer->send();
}
Esempio n. 4
0
void HTTPServer::handleRequest(HTTPRequestPtr& http_request,
							   TCPConnectionPtr& tcp_conn)
{
	if (! http_request->isValid()) {
		// the request is invalid or an error occured
		PION_LOG_INFO(m_logger, "Received an invalid HTTP request");
		m_bad_request_handler(http_request, tcp_conn);
		return;
	}
		
	PION_LOG_DEBUG(m_logger, "Received a valid HTTP request");

	// strip off trailing slash if the request has one
	std::string resource_requested(stripTrailingSlash(http_request->getResource()));

	// apply any redirection
	RedirectMap::const_iterator it = m_redirects.find(resource_requested);
	unsigned int num_redirects = 0;
	while (it != m_redirects.end()) {
		if (++num_redirects > MAX_REDIRECTS) {
			PION_LOG_ERROR(m_logger, "Maximum number of redirects (HTTPServer::MAX_REDIRECTS) exceeded for requested resource: " << http_request->getOriginalResource());
			m_server_error_handler(http_request, tcp_conn, "Maximum number of redirects (HTTPServer::MAX_REDIRECTS) exceeded for requested resource");
			return;
		}
		resource_requested = it->second;
		http_request->changeResource(resource_requested);
		it = m_redirects.find(resource_requested);
	}

	// if authentication activated, check current request
	if (m_auth) {
		// try to verify authentication
		if (! m_auth->handleRequest(http_request, tcp_conn)) {
			// the HTTP 401 message has already been sent by the authentication object
			PION_LOG_DEBUG(m_logger, "Authentication required for HTTP resource: "
				<< resource_requested);
			if (http_request->getResource() != http_request->getOriginalResource()) {
				PION_LOG_DEBUG(m_logger, "Original resource requested was: " << http_request->getOriginalResource());
			}
			return;
		}
	}
	
	// search for a handler matching the resource requested
	RequestHandler request_handler;
	if (findRequestHandler(resource_requested, request_handler)) {
		
		// try to handle the request
		try {
			request_handler(http_request, tcp_conn);
			PION_LOG_DEBUG(m_logger, "Found request handler for HTTP resource: "
						   << resource_requested);
			if (http_request->getResource() != http_request->getOriginalResource()) {
				PION_LOG_DEBUG(m_logger, "Original resource requested was: " << http_request->getOriginalResource());
			}
		} catch (HTTPResponseWriter::LostConnectionException& e) {
			// the connection was lost while or before sending the response
			PION_LOG_WARN(m_logger, "HTTP request handler: " << e.what());
			tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_CLOSE);	// make sure it will get closed
			tcp_conn->finish();
		} catch (std::bad_alloc&) {
			// propagate memory errors (FATAL)
			throw;
		} catch (std::exception& e) {
			// recover gracefully from other exceptions thrown request handlers
			PION_LOG_ERROR(m_logger, "HTTP request handler: " << e.what());
			m_server_error_handler(http_request, tcp_conn, e.what());
		}
		
	} else {
		
		// no web services found that could handle the request
		PION_LOG_INFO(m_logger, "No HTTP request handlers found for resource: "
					  << resource_requested);
		if (http_request->getResource() != http_request->getOriginalResource()) {
			PION_LOG_DEBUG(m_logger, "Original resource requested was: " << http_request->getOriginalResource());
		}
		m_not_found_handler(http_request, tcp_conn);
	}
}
Esempio n. 5
0
/// handles requests for EchoService
void EchoService::operator()(HTTPRequestPtr& request, TCPConnectionPtr& tcp_conn)
{
	// this web service uses static text to test the mixture of "copied" with
	// "static" (no-copy) text
	static const std::string REQUEST_ECHO_TEXT("[Request Echo]");
	static const std::string REQUEST_HEADERS_TEXT("[Request Headers]");
	static const std::string QUERY_PARAMS_TEXT("[Query Parameters]");
	static const std::string COOKIE_PARAMS_TEXT("[Cookie Parameters]");
	static const std::string POST_CONTENT_TEXT("[POST Content]");
	static const std::string USER_INFO_TEXT("[USER Info]");
	
	// Set Content-type to "text/plain" (plain ascii text)
	HTTPResponseWriterPtr writer(HTTPResponseWriter::create(tcp_conn, *request,
															boost::bind(&TCPConnection::finish, tcp_conn)));
	writer->getResponse().setContentType(HTTPTypes::CONTENT_TYPE_TEXT);
	
	// write request information
	writer->writeNoCopy(REQUEST_ECHO_TEXT);
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	writer
		<< "Request method: "
		<< request->getMethod()
		<< HTTPTypes::STRING_CRLF
		<< "Resource originally requested: "
		<< request->getOriginalResource()
		<< HTTPTypes::STRING_CRLF
		<< "Resource delivered: "
		<< request->getResource()
		<< HTTPTypes::STRING_CRLF
		<< "Query string: "
		<< request->getQueryString()
		<< HTTPTypes::STRING_CRLF
		<< "HTTP version: "
		<< request->getVersionMajor() << '.' << request->getVersionMinor()
		<< HTTPTypes::STRING_CRLF
		<< "Content length: "
		<< (unsigned long)request->getContentLength()
		<< HTTPTypes::STRING_CRLF
		<< HTTPTypes::STRING_CRLF;
			 
	// write request headers
	writer->writeNoCopy(REQUEST_HEADERS_TEXT);
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	std::for_each(request->getHeaders().begin(), request->getHeaders().end(),
				  boost::bind(&writeDictionaryTerm, writer, _1, false));
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);

	// write query parameters
	writer->writeNoCopy(QUERY_PARAMS_TEXT);
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	std::for_each(request->getQueryParams().begin(), request->getQueryParams().end(),
				  boost::bind(&writeDictionaryTerm, writer, _1, true));
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	
	// write cookie parameters
	writer->writeNoCopy(COOKIE_PARAMS_TEXT);
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	std::for_each(request->getCookieParams().begin(), request->getCookieParams().end(),
				  boost::bind(&writeDictionaryTerm, writer, _1, false));
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	
	// write POST content
	writer->writeNoCopy(POST_CONTENT_TEXT);
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	if (request->getContentLength() != 0) {
		writer->write(request->getContent(), request->getContentLength());
		writer->writeNoCopy(HTTPTypes::STRING_CRLF);
		writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	}
	
	// if authenticated, write user info
	PionUserPtr user = request->getUser();
	if (user) {
		writer->writeNoCopy(USER_INFO_TEXT);
		writer->writeNoCopy(HTTPTypes::STRING_CRLF);
		writer->writeNoCopy(HTTPTypes::STRING_CRLF);
		writer << "User authenticated, username: " << user->getUsername();
		writer->writeNoCopy(HTTPTypes::STRING_CRLF);
	}
    
	// send the writer
	writer->send();
}
Esempio n. 6
0
bool HTTPCookieAuth::processLogin(HTTPRequestPtr& http_request, TCPConnectionPtr& tcp_conn)
{
	// strip off trailing slash if the request has one
	std::string resource(HTTPServer::stripTrailingSlash(http_request->getResource()));

	if (resource != m_login && resource != m_logout) {
		return false; // no login processing done
	}

	std::string redirect_url = HTTPTypes::url_decode(http_request->getQuery("url"));
	std::string new_cookie;
	bool delete_cookie = false;

	if (resource == m_login) {
		// process login
		// check username
		std::string username = HTTPTypes::url_decode(http_request->getQuery("user"));
		std::string password = HTTPTypes::url_decode(http_request->getQuery("pass"));

		// match username/password
		PionUserPtr user=m_user_manager->getUser(username,password);
		if (!user) { // authentication failed, process as in case of failed authentication...
			handleUnauthorized(http_request,tcp_conn);
			return true;
		}
		// ok we have a new user session, create  a new cookie, add to cache

		// create random cookie
		std::string rand_binary;
		rand_binary.reserve(RANDOM_COOKIE_BYTES);
		for (unsigned int i=0; i<RANDOM_COOKIE_BYTES ; i++) {
			rand_binary += static_cast<unsigned char>(m_random_die());
		}
		HTTPTypes::base64_encode(rand_binary, new_cookie);

		// add new session to cache
		PionDateTime time_now(boost::posix_time::second_clock::universal_time());
		boost::mutex::scoped_lock cache_lock(m_cache_mutex);
		m_user_cache.insert(std::make_pair(new_cookie,std::make_pair(time_now,user)));
	} else {
		// process logout sequence
		// if auth cookie presented - clean cache out
		const std::string auth_cookie(http_request->getCookie(AUTH_COOKIE_NAME));
		if (! auth_cookie.empty()) {
			boost::mutex::scoped_lock cache_lock(m_cache_mutex);
			PionUserCache::iterator user_cache_itr=m_user_cache.find(auth_cookie);
			if (user_cache_itr!=m_user_cache.end()) {
				m_user_cache.erase(user_cache_itr);
			}
		}
		// and remove cookie from browser
		delete_cookie = true;
	}
	
	// if redirect defined - send redirect
	if (! redirect_url.empty()) {
		handleRedirection(http_request,tcp_conn,redirect_url,new_cookie,delete_cookie);
	} else {
		// otherwise - OK
		handleOk(http_request,tcp_conn,new_cookie,delete_cookie);
	}

	// yes, we processed login/logout somehow
	return true;
}