move JWT/Bcrypt inside zm_crypt
This commit is contained in:
parent
2212244882
commit
4ab0c35962
|
@ -1,25 +1,59 @@
|
||||||
#include "zm.h"
|
#include "zm.h"
|
||||||
# include "zm_crypt.h"
|
# include "zm_crypt.h"
|
||||||
|
#include "BCrypt.hpp"
|
||||||
|
#include "jwt.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
// 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() {
|
return username;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool verifyPassword(const char *username, const char *input_password, const char *db_password_hash) {
|
bool verifyPassword(const char *username, const char *input_password, const char *db_password_hash) {
|
||||||
bool password_correct = false;
|
bool password_correct = false;
|
||||||
Info ("JWT created as %s",createToken().c_str());
|
|
||||||
if (strlen(db_password_hash ) < 4) {
|
if (strlen(db_password_hash ) < 4) {
|
||||||
// actually, shoud be more, but this is min. for next code
|
// actually, shoud be more, but this is min. for next code
|
||||||
Error ("DB Password is too short or invalid to check");
|
Error ("DB Password is too short or invalid to check");
|
||||||
|
|
|
@ -23,10 +23,9 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
#include "BCrypt.hpp"
|
|
||||||
#include "jwt.h"
|
|
||||||
|
|
||||||
bool verifyPassword( const char *username, const char *input_password, const char *db_password_hash);
|
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
|
#endif // ZM_CRYPT_H
|
|
@ -142,6 +142,7 @@ User *zmLoadUser( const char *username, const char *password ) {
|
||||||
User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) {
|
User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) {
|
||||||
std::string key = config.auth_hash_secret;
|
std::string key = config.auth_hash_secret;
|
||||||
std::string remote_addr = "";
|
std::string remote_addr = "";
|
||||||
|
|
||||||
if (use_remote_addr) {
|
if (use_remote_addr) {
|
||||||
remote_addr = std::string(getenv( "REMOTE_ADDR" ));
|
remote_addr = std::string(getenv( "REMOTE_ADDR" ));
|
||||||
if ( 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());
|
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);
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
auto verifier = jwt::verify()
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
.allow_algorithm(jwt::algorithm::hs256{ key })
|
exit(mysql_errno(&dbconn));
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// something is wrong. All ZM tokens have type
|
MYSQL_RES *result = mysql_store_result(&dbconn);
|
||||||
Error ("Missing token type. This should not happen");
|
if ( !result ) {
|
||||||
return 0;
|
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
|
if ( n_users != 1 ) {
|
||||||
// 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());
|
|
||||||
mysql_free_result(result);
|
mysql_free_result(result);
|
||||||
return user;
|
Warning("Unable to authenticate user %s", username.c_str());
|
||||||
|
return NULL;
|
||||||
}
|
|
||||||
else {
|
|
||||||
Error ("User not found in claim");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
MYSQL_ROW dbrow = mysql_fetch_row(result);
|
||||||
catch (const std::exception &e) {
|
User *user = new User(dbrow);
|
||||||
Error("Unable to verify token: %s", e.what());
|
Info ("Authenticated user '%s' via token", username.c_str());
|
||||||
return 0;
|
mysql_free_result(result);
|
||||||
}
|
return user;
|
||||||
catch (...) {
|
|
||||||
Error ("unknown exception");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return 0;
|
else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to validate an authentication string
|
// Function to validate an authentication string
|
||||||
User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) {
|
User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) {
|
||||||
#if HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
|
#if HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
|
||||||
|
|
Loading…
Reference in New Issue