added token validation to zms/zmu/zmuser
parent
e8f79f3254
commit
b293592e4c
|
@ -139,6 +139,70 @@ 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 == "" ) {
|
||||
Warning( "Can't determine remote address, using null" );
|
||||
remote_addr = "";
|
||||
}
|
||||
key += remote_addr;
|
||||
}
|
||||
|
||||
|
||||
Info ("Inside zmLoadTokenUser, formed key=%s", key.c_str());
|
||||
|
||||
auto decoded = jwt::decode(jwt_token_str);
|
||||
|
||||
auto verifier = jwt::verify()
|
||||
.allow_algorithm(jwt::algorithm::hs256{ key })
|
||||
.with_issuer("ZoneMinder");
|
||||
try {
|
||||
verifier.verify(decoded);
|
||||
}
|
||||
catch (const Exception &e) {
|
||||
Error( "Unable to verify token: %s", e.getMessage().c_str() );
|
||||
return 0;
|
||||
}
|
||||
// token is valid and not expired
|
||||
if (decoded.has_payload_claim("user")) {
|
||||
|
||||
// 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() );
|
||||
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MYSQL_ROW dbrow = mysql_fetch_row(result);
|
||||
User *user = new User(dbrow);
|
||||
Info ("Authenticated user '%s' via token", username.c_str());
|
||||
return user;
|
||||
|
||||
}
|
||||
else {
|
||||
Error ("User not found in claim");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to validate an authentication string
|
||||
User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) {
|
||||
#if HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
|
||||
User *zmLoadUser( const char *username, const char *password=0 );
|
||||
User *zmLoadAuthUser( const char *auth, bool use_remote_addr );
|
||||
User *zmLoadTokenUser( std::string jwt, bool use_remote_addr);
|
||||
bool checkUser ( const char *username);
|
||||
bool checkPass (const char *password);
|
||||
|
||||
|
|
13
src/zms.cpp
13
src/zms.cpp
|
@ -70,6 +70,7 @@ int main( int argc, const char *argv[] ) {
|
|||
std::string username;
|
||||
std::string password;
|
||||
char auth[64] = "";
|
||||
std::string jwt_token_str = "";
|
||||
unsigned int connkey = 0;
|
||||
unsigned int playback_buffer = 0;
|
||||
|
||||
|
@ -158,6 +159,10 @@ int main( int argc, const char *argv[] ) {
|
|||
playback_buffer = atoi(value);
|
||||
} else if ( !strcmp( name, "auth" ) ) {
|
||||
strncpy( auth, value, sizeof(auth)-1 );
|
||||
} else if ( !strcmp( name, "token" ) ) {
|
||||
jwt_token_str = value;
|
||||
Info("ZMS: JWT token found: %s", jwt_token_str.c_str());
|
||||
|
||||
} else if ( !strcmp( name, "user" ) ) {
|
||||
username = UriDecode( value );
|
||||
} else if ( !strcmp( name, "pass" ) ) {
|
||||
|
@ -181,11 +186,15 @@ int main( int argc, const char *argv[] ) {
|
|||
if ( config.opt_use_auth ) {
|
||||
User *user = 0;
|
||||
|
||||
if ( strcmp(config.auth_relay, "none") == 0 ) {
|
||||
if (jwt_token_str != "") {
|
||||
user = zmLoadTokenUser(jwt_token_str, config.auth_hash_ips);
|
||||
|
||||
}
|
||||
else if ( strcmp(config.auth_relay, "none") == 0 ) {
|
||||
if ( checkUser(username.c_str()) ) {
|
||||
user = zmLoadUser(username.c_str());
|
||||
} else {
|
||||
Error("")
|
||||
Error("Bad username");
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
12
src/zmu.cpp
12
src/zmu.cpp
|
@ -138,6 +138,7 @@ void Usage(int status=-1) {
|
|||
" -U, --username <username> : When running in authenticated mode the username and\n"
|
||||
" -P, --password <password> : password combination of the given user\n"
|
||||
" -A, --auth <authentication> : Pass authentication hash string instead of user details\n"
|
||||
" -T, --token <token> : Pass JWT token string instead of user details\n"
|
||||
"", stderr );
|
||||
|
||||
exit(status);
|
||||
|
@ -263,6 +264,7 @@ int main(int argc, char *argv[]) {
|
|||
char *username = 0;
|
||||
char *password = 0;
|
||||
char *auth = 0;
|
||||
std::string jwt_token_str = "";
|
||||
#if ZM_HAS_V4L
|
||||
#if ZM_HAS_V4L2
|
||||
int v4lVersion = 2;
|
||||
|
@ -378,6 +380,9 @@ int main(int argc, char *argv[]) {
|
|||
case 'A':
|
||||
auth = optarg;
|
||||
break;
|
||||
case 'T':
|
||||
jwt_token_str = std::string(optarg);
|
||||
break;
|
||||
#if ZM_HAS_V4L
|
||||
case 'V':
|
||||
v4lVersion = (atoi(optarg)==1)?1:2;
|
||||
|
@ -438,10 +443,13 @@ int main(int argc, char *argv[]) {
|
|||
user = zmLoadUser(username);
|
||||
} else {
|
||||
|
||||
if ( !(username && password) && !auth ) {
|
||||
Error("Username and password or auth string must be supplied");
|
||||
if ( !(username && password) && !auth && (jwt_token_str=="")) {
|
||||
Error("Username and password or auth/token string must be supplied");
|
||||
exit_zmu(-1);
|
||||
}
|
||||
if (jwt_token_str != "") {
|
||||
user = zmLoadTokenUser(jwt_token_str, false);
|
||||
}
|
||||
if ( auth ) {
|
||||
user = zmLoadAuthUser(auth, false);
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ class HostController extends AppController {
|
|||
// print ("relay=".$zmAuthRelay." haship=".$zmAuthHashIps." remote ip=".$_SERVER['REMOTE_ADDR']);
|
||||
|
||||
$expireAt = $issuedAt + $ttl * 3600;
|
||||
$expireAt = $issuedAt + 30; // TEST REMOVE
|
||||
$expireAt = $issuedAt + 60; // TEST REMOVE
|
||||
|
||||
$token = array(
|
||||
"iss" => "ZoneMinder",
|
||||
|
|
|
@ -215,20 +215,6 @@ function validateToken ($token) {
|
|||
return array(false, "No such user/credentials");
|
||||
}
|
||||
|
||||
|
||||
// We are NOT checking against session username for now...
|
||||
/*
|
||||
// at this stage, token is valid, but lets validate user with session user
|
||||
ZM\Info ("JWT user is ".$jwt['user']);
|
||||
if ($jwt['user'] != $_SESSION['username']) {
|
||||
ZM\Error ("Unable to authenticate user. Token doesn't belong to current user");
|
||||
return false;
|
||||
} else {
|
||||
ZM\Info ("Token validated for user:".$_SESSION['username']);
|
||||
return $user;
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
function getAuthUser($auth) {
|
||||
|
|
Loading…
Reference in New Issue