Added new API JSON-based auth scheme
This commit is contained in:
parent
74baf8d4a4
commit
f126b17ed1
1 changed files with 40 additions and 10 deletions
|
@ -12,6 +12,15 @@
|
||||||
#include "controller_capabilities.h"
|
#include "controller_capabilities.h"
|
||||||
#include "controller_statistics.h"
|
#include "controller_statistics.h"
|
||||||
|
|
||||||
|
/// 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.
|
///\brief Checks an authorization request for a given user.
|
||||||
///\param Request The request to be parsed.
|
///\param Request The request to be parsed.
|
||||||
///\param Response The location to store the generated response.
|
///\param Response The location to store the generated response.
|
||||||
|
@ -57,12 +66,8 @@
|
||||||
/// Please note that this is NOT secure. At all. Never use this mechanism over a public network!
|
/// 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.
|
/// 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){
|
bool Controller::authorize(JSON::Value & Request, JSON::Value & Response, Socket::Connection & conn){
|
||||||
time_t Time = time(0);
|
std::string Challenge = getChallenge(conn);
|
||||||
tm * TimeInfo = localtime( &Time);
|
|
||||||
std::stringstream Date;
|
|
||||||
std::string retval;
|
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() != ""){
|
if (Request.isMember("authorize") && Request["authorize"]["username"].asString() != ""){
|
||||||
std::string UserID = Request["authorize"]["username"];
|
std::string UserID = Request["authorize"]["username"];
|
||||||
if (Storage["account"].isMember(UserID)){
|
if (Storage["account"].isMember(UserID)){
|
||||||
|
@ -102,6 +107,36 @@ int Controller::handleAPIConnection(Socket::Connection & conn){
|
||||||
//while connected and not past login attempt limit
|
//while connected and not past login attempt limit
|
||||||
while (conn && logins < 4){
|
while (conn && logins < 4){
|
||||||
if ((conn.spool() || conn.Received().size()) && H.Read(conn)){
|
if ((conn.spool() || conn.Received().size()) && H.Read(conn)){
|
||||||
|
//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<tthread::mutex> 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;
|
JSON::Value Response;
|
||||||
JSON::Value Request = JSON::fromString(H.GetVar("command"));
|
JSON::Value Request = JSON::fromString(H.GetVar("command"));
|
||||||
//invalid request? send the web interface, unless requested as "/api"
|
//invalid request? send the web interface, unless requested as "/api"
|
||||||
|
@ -123,11 +158,6 @@ int Controller::handleAPIConnection(Socket::Connection & conn){
|
||||||
}
|
}
|
||||||
{//lock the config mutex here - do not unlock until done processing
|
{//lock the config mutex here - do not unlock until done processing
|
||||||
tthread::lock_guard<tthread::mutex> guard(configMutex);
|
tthread::lock_guard<tthread::mutex> 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 already authorized, do not re-check for authorization
|
||||||
if (authorized && Storage["account"]){
|
if (authorized && Storage["account"]){
|
||||||
Response["authorize"]["status"] = "OK";
|
Response["authorize"]["status"] = "OK";
|
||||||
|
|
Loading…
Add table
Reference in a new issue