move JWT/Bcrypt inside zm_crypt
This commit is contained in:
parent
2212244882
commit
4ab0c35962
|
@ -1,25 +1,59 @@
|
|||
#include "zm.h"
|
||||
# include "zm_crypt.h"
|
||||
#include "BCrypt.hpp"
|
||||
#include "jwt.h"
|
||||
#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() {
|
||||
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");
|
||||
|
|
|
@ -23,10 +23,9 @@
|
|||
|
||||
#include <string.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);
|
||||
std::string createToken();
|
||||
|
||||
std::string verifyToken(std::string token, std::string key);
|
||||
#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 ) {
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue