diff --git a/src/zm_crypt.cpp b/src/zm_crypt.cpp index 6c6f4c7c1..3a3f66aeb 100644 --- a/src/zm_crypt.cpp +++ b/src/zm_crypt.cpp @@ -1,25 +1,59 @@ #include "zm.h" # include "zm_crypt.h" +#include "BCrypt.hpp" +#include "jwt.h" #include +// returns username if valid, "" if not +std::string verifyToken(std::string jwt_token_str, std::string key) { + std::string username = ""; + try { + // is it decodable? + auto decoded = jwt::decode(jwt_token_str); + auto verifier = jwt::verify() + .allow_algorithm(jwt::algorithm::hs256{ key }) + .with_issuer("ZoneMinder"); + + // signature verified? + verifier.verify(decoded); + // make sure it has fields we need + if (decoded.has_payload_claim("type")) { + std::string type = decoded.get_payload_claim("type").as_string(); + if (type != "access") { + Error ("Only access tokens are allowed. Please do not use refresh tokens"); + return ""; + } + } + else { + // something is wrong. All ZM tokens have type + Error ("Missing token type. This should not happen"); + return ""; + } + if (decoded.has_payload_claim("user")) { + username = decoded.get_payload_claim("user").as_string(); + Info ("Got %s as user claim from token", username.c_str()); + } + else { + Error ("User not found in claim"); + return ""; + } + } // try + catch (const std::exception &e) { + Error("Unable to verify token: %s", e.what()); + return ""; + } + catch (...) { + Error ("unknown exception"); + return ""; - -std::string createToken() { - std::string token = jwt::create() - .set_issuer("auth0") - //.set_expires_at(jwt::date(expiresAt)) - //.set_issued_at(jwt::date(tp)) - //.set_issued_at(jwt::date(std::chrono::system_clock::now())) - //.set_expires_at(jwt::date(std::chrono::system_clock::now()+std::chrono::seconds{EXPIRY})) - .sign(jwt::algorithm::hs256{"secret"}); - return token; + } + return username; } bool verifyPassword(const char *username, const char *input_password, const char *db_password_hash) { bool password_correct = false; - Info ("JWT created as %s",createToken().c_str()); if (strlen(db_password_hash ) < 4) { // actually, shoud be more, but this is min. for next code Error ("DB Password is too short or invalid to check"); diff --git a/src/zm_crypt.h b/src/zm_crypt.h index a1e8945e4..8fb50cf00 100644 --- a/src/zm_crypt.h +++ b/src/zm_crypt.h @@ -23,10 +23,9 @@ #include #include -#include "BCrypt.hpp" -#include "jwt.h" + bool verifyPassword( const char *username, const char *input_password, const char *db_password_hash); -std::string createToken(); +std::string verifyToken(std::string token, std::string key); #endif // ZM_CRYPT_H \ No newline at end of file diff --git a/src/zm_user.cpp b/src/zm_user.cpp index 06ec3f76a..7ac934d2a 100644 --- a/src/zm_user.cpp +++ b/src/zm_user.cpp @@ -142,6 +142,7 @@ User *zmLoadUser( const char *username, const char *password ) { User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) { std::string key = config.auth_hash_secret; std::string remote_addr = ""; + if (use_remote_addr) { remote_addr = std::string(getenv( "REMOTE_ADDR" )); if ( remote_addr == "" ) { @@ -153,82 +154,44 @@ User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) { Info ("Inside zmLoadTokenUser, formed key=%s", key.c_str()); - try { + std::string username = verifyToken(jwt_token_str, key); + if (username != "") { + char sql[ZM_SQL_MED_BUFSIZ] = ""; + snprintf(sql, sizeof(sql), + "SELECT Id, Username, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds" + " FROM Users WHERE Username = '%s' and Enabled = 1", username.c_str() ); - auto decoded = jwt::decode(jwt_token_str); - auto verifier = jwt::verify() - .allow_algorithm(jwt::algorithm::hs256{ key }) - .with_issuer("ZoneMinder"); - - verifier.verify(decoded); - - // token is valid and not expired - - if (decoded.has_payload_claim("type")) { - std::string type = decoded.get_payload_claim("type").as_string(); - if (type != "access") { - Error ("Only access tokens are allowed. Please do not use refresh tokens"); - return 0; - } + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); } - else { - // something is wrong. All ZM tokens have type - Error ("Missing token type. This should not happen"); - return 0; + + MYSQL_RES *result = mysql_store_result(&dbconn); + if ( !result ) { + Error("Can't use query result: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); } - if (decoded.has_payload_claim("user")) { + int n_users = mysql_num_rows(result); - // We only need to check if user is enabled in DB and pass on - // correct access permissions - std::string username = decoded.get_payload_claim("user").as_string(); - Info ("Got %s as user claim from token", username.c_str()); - char sql[ZM_SQL_MED_BUFSIZ] = ""; - snprintf(sql, sizeof(sql), - "SELECT Id, Username, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds" - " FROM Users WHERE Username = '%s' and Enabled = 1", username.c_str() ); - - if ( mysql_query(&dbconn, sql) ) { - Error("Can't run query: %s", mysql_error(&dbconn)); - exit(mysql_errno(&dbconn)); - } - - MYSQL_RES *result = mysql_store_result(&dbconn); - if ( !result ) { - Error("Can't use query result: %s", mysql_error(&dbconn)); - exit(mysql_errno(&dbconn)); - } - int n_users = mysql_num_rows(result); - - if ( n_users != 1 ) { - mysql_free_result(result); - Warning("Unable to authenticate user %s", username.c_str()); - return NULL; - } - - MYSQL_ROW dbrow = mysql_fetch_row(result); - User *user = new User(dbrow); - Info ("Authenticated user '%s' via token", username.c_str()); + if ( n_users != 1 ) { mysql_free_result(result); - return user; - - } - else { - Error ("User not found in claim"); - return 0; + Warning("Unable to authenticate user %s", username.c_str()); + return NULL; } - } - catch (const std::exception &e) { - Error("Unable to verify token: %s", e.what()); - return 0; - } - catch (...) { - Error ("unknown exception"); + MYSQL_ROW dbrow = mysql_fetch_row(result); + User *user = new User(dbrow); + Info ("Authenticated user '%s' via token", username.c_str()); + mysql_free_result(result); + return user; } - return 0; + else { + return NULL; + } + } - + // Function to validate an authentication string User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) { #if HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT