mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	API Authentication/Authorization refactor
This commit is contained in:
		| @@ -70,6 +70,7 @@ void API::init() | |||||||
| 	_hyperion = _instanceManager->getHyperionInstance(0); | 	_hyperion = _instanceManager->getHyperionInstance(0); | ||||||
|  |  | ||||||
|     bool apiAuthRequired = _authManager->isAuthRequired(); |     bool apiAuthRequired = _authManager->isAuthRequired(); | ||||||
|  | 	qDebug() << "API::init - apiAuthRequired: " << apiAuthRequired; | ||||||
|  |  | ||||||
|     // For security we block external connections if default PW is set |     // For security we block external connections if default PW is set | ||||||
|     if (!_localConnection && API::hasHyperionDefaultPw()) |     if (!_localConnection && API::hasHyperionDefaultPw()) | ||||||
| @@ -77,21 +78,22 @@ void API::init() | |||||||
|         emit forceClose(); |         emit forceClose(); | ||||||
|     } |     } | ||||||
|     // if this is localConnection and network allows unauth locals, set authorized flag |     // if this is localConnection and network allows unauth locals, set authorized flag | ||||||
|     if (apiAuthRequired && _localConnection) | 	if (!_authManager->isLocalAuthRequired() && _localConnection) | ||||||
| 	{ | 	{ | ||||||
|         _authorized = !_authManager->isLocalAuthRequired(); | 		_authorized = true; | ||||||
| 	} | 		_adminAuthorized = !_authManager->isLocalAdminAuthRequired(); | ||||||
|  |  | ||||||
|     // admin access is allowed, when the connection is local and the option for local admin isn't set. Con: All local connections get full access | 	} | ||||||
|     if (_localConnection) | 	else | ||||||
|     { | 	{ | ||||||
|         _adminAuthorized = !_authManager->isLocalAdminAuthRequired(); | 		 if (_localConnection) | ||||||
|         // just in positive direction |  | ||||||
| 		if (_adminAuthorized) |  | ||||||
| 		{ | 		{ | ||||||
| 			_authorized = true; | 			_authorized = !_authManager->isLocalAuthRequired(); | ||||||
| 		} | 			 _adminAuthorized = !_authManager->isLocalAdminAuthRequired(); | ||||||
|     } | 		 } | ||||||
|  | 	} | ||||||
|  | 	qDebug() << "API::init - _authorized: " << _authorized; | ||||||
|  | 	qDebug() << "API::init - _adminAuthorized: " << _adminAuthorized; | ||||||
| } | } | ||||||
|  |  | ||||||
| void API::setColor(int priority, const std::vector<uint8_t> &ledColors, int timeout_ms, const QString &origin, hyperion::Components callerComp) | void API::setColor(int priority, const std::vector<uint8_t> &ledColors, int timeout_ms, const QString &origin, hyperion::Components callerComp) | ||||||
|   | |||||||
| @@ -114,8 +114,11 @@ JsonAPI::JsonAPI(QString peerAddress, Logger *log, bool localConnection, QObject | |||||||
|  |  | ||||||
| void JsonAPI::initialize() | void JsonAPI::initialize() | ||||||
| { | { | ||||||
|  | 	Debug(_log,""); | ||||||
| 	// init API, REQUIRED! | 	// init API, REQUIRED! | ||||||
| 	API::init(); | 	API::init(); | ||||||
|  | 	// Initialise jsonCB with current instance | ||||||
|  | 	_jsonCB->setSubscriptionsTo(_hyperion); | ||||||
|  |  | ||||||
| 	// setup auth interface | 	// setup auth interface | ||||||
| 	connect(this, &API::onPendingTokenRequest, this, &JsonAPI::newPendingTokenRequest); | 	connect(this, &API::onPendingTokenRequest, this, &JsonAPI::newPendingTokenRequest); | ||||||
| @@ -156,8 +159,12 @@ bool JsonAPI::handleInstanceSwitch(quint8 inst, bool forced) | |||||||
|  |  | ||||||
| void JsonAPI::handleMessage(const QString &messageString, const QString &httpAuthHeader) | void JsonAPI::handleMessage(const QString &messageString, const QString &httpAuthHeader) | ||||||
| { | { | ||||||
|  | 	Debug(_log,""); | ||||||
| 	const QString ident = "JsonRpc@" + _peerAddress; | 	const QString ident = "JsonRpc@" + _peerAddress; | ||||||
| 	QJsonObject message; | 	QJsonObject message; | ||||||
|  | 	//std::cout << "JsonAPI::handleMessage | [" << static_cast<int>(_hyperion->getInstanceIndex()) << "] Received: ["<< messageString.toStdString() << "]" << std::endl; | ||||||
|  | 	//std::cout << "JsonAPI::handleMessage - _noListener [" << _noListener << "]" << std::endl; | ||||||
|  | 	//std::cout << "JsonAPI::handleMessage - _authorized [" << _authorized << "] _adminAuthorized [" << _adminAuthorized << "]" << std::endl; | ||||||
|  |  | ||||||
| 	// parse the message | 	// parse the message | ||||||
| 	if (!JsonUtils::parse(ident, messageString, message, _log)) | 	if (!JsonUtils::parse(ident, messageString, message, _log)) | ||||||
| @@ -185,25 +192,26 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut | |||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// client auth before everything else but not for http |  | ||||||
| 	if (!_noListener && command == "authorize") |  | ||||||
| 	{ |  | ||||||
| 		handleAuthorizeCommand(message, command, tan); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// check auth state | 	// check auth state | ||||||
| 	if (!API::isAuthorized()) | 	if (!API::isAuthorized()) | ||||||
| 	{ | 	{ | ||||||
|  | 		Debug(_log,"!API::isAuthorized(), _noListener [%d]", _noListener); | ||||||
| 		// on the fly auth available for http from http Auth header | 		// on the fly auth available for http from http Auth header | ||||||
| 		if (_noListener) | 		if (_noListener) | ||||||
| 		{ | 		{ | ||||||
| 			QString cToken = httpAuthHeader.mid(5).trimmed(); | 			QString cToken = httpAuthHeader.mid(5).trimmed(); | ||||||
| 			if (API::isTokenAuthorized(cToken)) | 			if (API::isTokenAuthorized(cToken)) | ||||||
|  | 			{ | ||||||
|  | 				_authorized = true; | ||||||
|  | 				if (!_authManager->isLocalAdminAuthRequired()) | ||||||
|  | 				{ | ||||||
|  | 					_adminAuthorized = true; | ||||||
|  | 				} | ||||||
| 				goto proceed; | 				goto proceed; | ||||||
|  | 			} | ||||||
|  | 			sendErrorReply("No Authorization", command, tan); | ||||||
|  | 			return; | ||||||
| 		} | 		} | ||||||
| 		sendErrorReply("No Authorization", command, tan); |  | ||||||
| 		return; |  | ||||||
| 	} | 	} | ||||||
| proceed: | proceed: | ||||||
| 	if (_hyperion == nullptr) | 	if (_hyperion == nullptr) | ||||||
| @@ -211,9 +219,12 @@ proceed: | |||||||
| 		sendErrorReply("Service Unavailable", command, tan); | 		sendErrorReply("Service Unavailable", command, tan); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  | 	//Debug(_log,"proceed - cmd: [%s], _authorized[%d], _adminAuthorized[%d]", QSTRING_CSTR(command), _authorized, _adminAuthorized); | ||||||
|  |  | ||||||
| 	// switch over all possible commands and handle them | 	// switch over all possible commands and handle them | ||||||
| 	if (command == "color") | 	if (command == "authorize") | ||||||
|  | 		handleAuthorizeCommand(message, command, tan); | ||||||
|  | 	else if (command == "color") | ||||||
| 		handleColorCommand(message, command, tan); | 		handleColorCommand(message, command, tan); | ||||||
| 	else if (command == "image") | 	else if (command == "image") | ||||||
| 		handleImageCommand(message, command, tan); | 		handleImageCommand(message, command, tan); | ||||||
| @@ -1256,6 +1267,7 @@ void JsonAPI::handleVideoModeCommand(const QJsonObject &message, const QString & | |||||||
|  |  | ||||||
| void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString &command, int tan) | void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString &command, int tan) | ||||||
| { | { | ||||||
|  | 	Debug(_log,""); | ||||||
| 	const QString &subc = message["subcommand"].toString().trimmed(); | 	const QString &subc = message["subcommand"].toString().trimmed(); | ||||||
| 	const QString &id = message["id"].toString().trimmed(); | 	const QString &id = message["id"].toString().trimmed(); | ||||||
| 	const QString &password = message["password"].toString().trimmed(); | 	const QString &password = message["password"].toString().trimmed(); | ||||||
| @@ -1275,6 +1287,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & | |||||||
| 	// catch test if admin auth is required | 	// catch test if admin auth is required | ||||||
| 	if (subc == "adminRequired") | 	if (subc == "adminRequired") | ||||||
| 	{ | 	{ | ||||||
|  | 		Debug(_log,"adminRequired: [%d]", !API::isAdminAuthorized()); | ||||||
| 		QJsonObject req; | 		QJsonObject req; | ||||||
| 		req["adminRequired"] = !API::isAdminAuthorized(); | 		req["adminRequired"] = !API::isAdminAuthorized(); | ||||||
| 		sendSuccessDataReply(QJsonDocument(req), command + "-" + subc, tan); | 		sendSuccessDataReply(QJsonDocument(req), command + "-" + subc, tan); | ||||||
| @@ -1291,7 +1304,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// catch logout | 	// catch logout | ||||||
| 	if (subc == "logout") | 	if (!_noListener && subc == "logout") | ||||||
| 	{ | 	{ | ||||||
| 		// disconnect all kind of data callbacks | 		// disconnect all kind of data callbacks | ||||||
| 		JsonAPI::stopDataConnections(); // TODO move to API | 		JsonAPI::stopDataConnections(); // TODO move to API | ||||||
| @@ -1319,7 +1332,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// token created from ui | 	// token created from ui | ||||||
| 	if (subc == "createToken") | 	if (!_noListener && subc == "createToken") | ||||||
| 	{ | 	{ | ||||||
| 		// use comment | 		// use comment | ||||||
| 		// for user authorized sessions | 		// for user authorized sessions | ||||||
| @@ -1368,7 +1381,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// catch token request | 	// catch token request | ||||||
| 	if (subc == "requestToken") | 	if (!_noListener && subc == "requestToken") | ||||||
| 	{ | 	{ | ||||||
| 		// use id/comment | 		// use id/comment | ||||||
| 		const bool &acc = message["accept"].toBool(true); | 		const bool &acc = message["accept"].toBool(true); | ||||||
| @@ -1381,7 +1394,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// get pending token requests | 	// get pending token requests | ||||||
| 	if (subc == "getPendingTokenRequests") | 	if (!_noListener && subc == "getPendingTokenRequests") | ||||||
| 	{ | 	{ | ||||||
| 		QVector<AuthManager::AuthDefinition> vec; | 		QVector<AuthManager::AuthDefinition> vec; | ||||||
| 		if (API::getPendingTokenRequests(vec)) | 		if (API::getPendingTokenRequests(vec)) | ||||||
| @@ -1406,7 +1419,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// accept/deny token request | 	// accept/deny token request | ||||||
| 	if (subc == "answerRequest") | 	if (!_noListener && subc == "answerRequest") | ||||||
| 	{ | 	{ | ||||||
| 		// use id | 		// use id | ||||||
| 		const bool &accept = message["accept"].toBool(false); | 		const bool &accept = message["accept"].toBool(false); | ||||||
| @@ -1422,7 +1435,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & | |||||||
| 		if (API::getTokenList(defVect)) | 		if (API::getTokenList(defVect)) | ||||||
| 		{ | 		{ | ||||||
| 			QJsonArray tArr; | 			QJsonArray tArr; | ||||||
| 			for (const auto &entry : defVect) | 			for (const auto &entry : qAsConst(defVect)) | ||||||
| 			{ | 			{ | ||||||
| 				QJsonObject subO; | 				QJsonObject subO; | ||||||
| 				subO["comment"] = entry.comment; | 				subO["comment"] = entry.comment; | ||||||
| @@ -1439,16 +1452,20 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// login | 	// login | ||||||
| 	if (subc == "login") | 	if (!_noListener && subc == "login") | ||||||
| 	{ | 	{ | ||||||
| 		const QString &token = message["token"].toString().trimmed(); | 		const QString &token = message["token"].toString().trimmed(); | ||||||
|  |  | ||||||
|  | 		qDebug() << "token: len: " << token.count() << " [" << token; | ||||||
|  | 		qDebug() << "password: len: " << password.count() << " [" << password; | ||||||
|  |  | ||||||
| 		// catch token | 		// catch token | ||||||
| 		if (!token.isEmpty()) | 		if (!token.isEmpty()) | ||||||
| 		{ | 		{ | ||||||
| 			// userToken is longer | 			// userToken is longer | ||||||
| 			if (token.size() > 36) | 			if (token.size() > 36) | ||||||
| 			{ | 			{ | ||||||
|  | 				Debug(_log,"isUserTokenAuthorized [%d]", API::isUserTokenAuthorized(token)); | ||||||
| 				if (API::isUserTokenAuthorized(token)) | 				if (API::isUserTokenAuthorized(token)) | ||||||
| 					sendSuccessReply(command + "-" + subc, tan); | 					sendSuccessReply(command + "-" + subc, tan); | ||||||
| 				else | 				else | ||||||
| @@ -1459,6 +1476,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & | |||||||
| 			// usual app token is 36 | 			// usual app token is 36 | ||||||
| 			if (token.size() == 36) | 			if (token.size() == 36) | ||||||
| 			{ | 			{ | ||||||
|  | 				Debug(_log,"isTokenAuthorized [%d]", API::isTokenAuthorized(token)); | ||||||
| 				if (API::isTokenAuthorized(token)) | 				if (API::isTokenAuthorized(token)) | ||||||
| 				{ | 				{ | ||||||
| 					sendSuccessReply(command + "-" + subc, tan); | 					sendSuccessReply(command + "-" + subc, tan); | ||||||
| @@ -1466,6 +1484,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & | |||||||
| 				else | 				else | ||||||
| 					sendErrorReply("No Authorization", command + "-" + subc, tan); | 					sendErrorReply("No Authorization", command + "-" + subc, tan); | ||||||
| 			} | 			} | ||||||
|  | 			std::cout << "handleAuthorizeCommand [login] - _authorized [" << _authorized << "] _adminAuthorized [" << _adminAuthorized << "]" << std::endl; | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -1473,6 +1492,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & | |||||||
| 		// use password | 		// use password | ||||||
| 		if (password.size() >= 8) | 		if (password.size() >= 8) | ||||||
| 		{ | 		{ | ||||||
|  | 			Debug(_log,"password: isUserAuthorized [%d] ", API::isUserAuthorized(token)); | ||||||
| 			QString userTokenRep; | 			QString userTokenRep; | ||||||
| 			if (API::isUserAuthorized(password) && API::getUserToken(userTokenRep)) | 			if (API::isUserAuthorized(password) && API::getUserToken(userTokenRep)) | ||||||
| 			{ | 			{ | ||||||
| @@ -1482,10 +1502,24 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & | |||||||
| 				sendSuccessDataReply(QJsonDocument(obj), command + "-" + subc, tan); | 				sendSuccessDataReply(QJsonDocument(obj), command + "-" + subc, tan); | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
|  | 			{ | ||||||
| 				sendErrorReply("No Authorization", command + "-" + subc, tan); | 				sendErrorReply("No Authorization", command + "-" + subc, tan); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
|  | 		{ | ||||||
| 			sendErrorReply("Password too short", command + "-" + subc, tan); | 			sendErrorReply("Password too short", command + "-" + subc, tan); | ||||||
|  | 		} | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if(_noListener) | ||||||
|  | 	{ | ||||||
|  | 		sendErrorReply("Command not supported via single API calls using HTTP/S", command + "-" + subc, tan); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		handleNotImplemented(command, tan); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user