diff --git a/src/controller/controller_api.cpp b/src/controller/controller_api.cpp index 8de846ce..3f95e218 100644 --- a/src/controller/controller_api.cpp +++ b/src/controller/controller_api.cpp @@ -20,6 +20,15 @@ #include "controller_license.h" /*LTS-END*/ +/// Returns the challenge string for authentication, given the socket connection. +std::string getChallenge(Socket::Connection & conn){ + time_t Time = time(0); + tm * TimeInfo = localtime( &Time); + std::stringstream Date; + Date << TimeInfo->tm_mday << "-" << TimeInfo->tm_mon << "-" << TimeInfo->tm_year + 1900; + return Secure::md5(Date.str().c_str() + conn.getHost()); +} + ///\brief Checks an authorization request for a given user. ///\param Request The request to be parsed. ///\param Response The location to store the generated response. @@ -65,16 +74,8 @@ /// Please note that this is NOT secure. At all. Never use this mechanism over a public network! /// A status of `"ACC_MADE"` indicates the account was created successfully and can now be used to login as normal. bool Controller::authorize(JSON::Value & Request, JSON::Value & Response, Socket::Connection & conn){ - #ifdef NOAUTH - Response["authorize"]["status"] = "OK"; - return true; - #endif - time_t Time = time(0); - tm * TimeInfo = localtime( &Time); - std::stringstream Date; + std::string Challenge = getChallenge(conn); std::string retval; - Date << TimeInfo->tm_mday << "-" << TimeInfo->tm_mon << "-" << TimeInfo->tm_year + 1900; - std::string Challenge = Secure::md5(Date.str().c_str() + conn.getHost()); if (Request.isMember("authorize") && Request["authorize"]["username"].asString() != ""){ std::string UserID = Request["authorize"]["username"]; if (Storage["account"].isMember(UserID)){ @@ -114,17 +115,34 @@ int Controller::handleAPIConnection(Socket::Connection & conn){ //while connected and not past login attempt limit while (conn && logins < 4){ if ((conn.spool() || conn.Received().size()) && H.Read(conn)){ - //Catch prometheus requests - if (Controller::prometheus.size()){ - if (H.url == "/"+Controller::prometheus){ - handlePrometheus(H, conn, PROMETHEUS_TEXT); - H.Clean(); - continue; - } - if (H.url == "/"+Controller::prometheus+".json"){ - handlePrometheus(H, conn, PROMETHEUS_JSON); - H.Clean(); - continue; + //Are we local and not forwarded? Instant-authorized. + if (!authorized && !H.hasHeader("X-Real-IP") && conn.isLocal()){ + MEDIUM_MSG("Local API access automatically authorized"); + authorized = true; + } + #ifdef NOAUTH + //If auth is disabled, always allow access. + authorized = true; + #endif + if (!authorized && H.hasHeader("Authorization")){ + std::string auth = H.GetHeader("Authorization"); + if (auth.substr(0, 5) == "json "){ + INFO_MSG("Checking auth header"); + JSON::Value req; + req["authorize"] = JSON::fromString(auth.substr(5)); + if (Storage["account"]){ + tthread::lock_guard guard(configMutex); + authorized = authorize(req, req, conn); + if (!authorized){ + H.Clean(); + H.body = "Please login first or provide a valid token authentication."; + H.SetHeader("Server", "MistServer/" PACKAGE_VERSION); + H.SetHeader("WWW-Authenticate", "json "+req["authorize"].toString()); + H.SendResponse("403", "Not authorized", conn); + H.Clean(); + continue; + } + } } } JSON::Value Response; @@ -148,11 +166,6 @@ int Controller::handleAPIConnection(Socket::Connection & conn){ } {//lock the config mutex here - do not unlock until done processing tthread::lock_guard guard(configMutex); - //Are we local and not forwarded? Instant-authorized. - if (!authorized && !H.hasHeader("X-Real-IP") && conn.isLocal()){ - MEDIUM_MSG("Local API access automatically authorized"); - authorized = true; - } //if already authorized, do not re-check for authorization if (authorized && Storage["account"]){ Response["authorize"]["status"] = "OK";