Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Auth improvements #476

Closed
wants to merge 3 commits into from

2 participants

erno juj
erno
Owner
  • Async-enable the authentication hook

  • Expose QNetworkAccessManager in asset api so can enable http authentication there

Only thing is that asset api seems to be accessible also from untrusted scripts.
It already has some functionality that shouldn't be exposed (eg. like ability
to upload arbitrary stuff from filesystem to http storages). This should be solved
by either hiding the asset api from untrusted scripts, moving the sensitive
slots out of AssetAPI.

erno added some commits
erno erno Add nonblocking API for authentication fbd619b
erno erno Expose QNetworkAccessManager through asset API, so can use HTTP
authentication with assets.  Also add untested and unfinished test script to
exercise it.
d314d96
erno erno Working test script for asset api authentication
(through exposing the QNetworkAccessManager).
35f356c
erno
Owner

collecting feedback from irc:
12:41 < Pforce_> e`: virtual QNetworkAccessManager* GetNetworkAccessManager() {
return NULL; }
12:42 < Pforce_> 0 would be nicer, we are not a c app

12:45 < Stinkfist> e`: you can remove GetNetworkAccessManager from IAssetStorage
12:46 < Stinkfist> put to HttpAssetStorage only
12:46 < Stinkfist> goes to same metaobject anyways, so can be accessed ok from
scripts
12:46 < Stinkfist> also remove the Get-prefix ;)

juj
Owner

Having a virtual QNetworkAccessManager* IAssetStorage::GetNetworkAccessManager() is not ok, as it leaks implementation details only relevant to HttpAssetStorage to the IAssetStorage implementation. If this is for scripting purposes, the property can be exposed at runtime without exposing the details into the base class, as Stinkfist outlined.

juj juj closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 22, 2012
  1. erno
  2. erno

    Expose QNetworkAccessManager through asset API, so can use HTTP

    erno authored
    authentication with assets.  Also add untested and unfinished test script to
    exercise it.
  3. erno

    Working test script for asset api authentication

    erno authored
    (through exposing the QNetworkAccessManager).
This page is out of date. Refresh to see the latest.
43 bin/jsmodules/startup/assetauth.js
View
@@ -0,0 +1,43 @@
+engine.ImportExtension("qt.core");
+engine.ImportExtension("qt.network");
+
+var show_debug = true;
+function dprint(msg) {
+ if (!show_debug)
+ return;
+ print("######### " + msg);
+}
+
+asset.AssetStorageAdded.connect(function(storage) {
+ if (storage.Type() != "HttpAssetStorage")
+ return;
+ config_http_storage(storage);
+ });
+dprint("hooked AssetStorageAdded");
+
+var storages = asset.GetAssetStorages();
+for (var i = 0; i < storages.length; i++)
+ if (storage.Type() == "HttpAssetStorage")
+ config_http_storage(storages[i]);
+dprint("did existing storages");
+
+function auth_handler(reply, authenticator) {
+ dprint("auth handler called");
+ var username = "bob";
+ var password = "secretpassword";
+ if (reply.request().url().host() == "test.example.com" &&
+ reply.request().url().port(80) == 80 &&
+ reply.request().url().scheme() == "http") {
+ if (authenticator.realm() == "my-authtest") {
+ dprint("matching authenticationRequired seen, filling in credentials");
+ authenticator.setUser(username);
+ authenticator.setPassword(password);
+ }
+ }
+}
+
+function config_http_storage(storage) {
+ var qnam = storage.GetNetworkAccessManager();
+ qnam.authenticationRequired.connect(auth_handler);
+ dprint("handling auth for storage "+ storage.Name());
+}
38 bin/scenes/TestScenes/AsyncAuthentication/logintest.js
View
@@ -0,0 +1,38 @@
+if (server.IsRunning() || server.IsAboutToStart()) {
+ server.UserAboutToConnect.connect(ServerHandleUserAboutToConnect);
+ server.UserConnected.connect(ServerHandleUserConnected);
+ server.UserDisconnected.connect(ServerHandleUserDisconnected);
+ print("logintest signals connected");
+}
+
+function ServerHandleUserAboutToConnect(connectionID, user) {
+ user.FinishLoginLater();
+ frame.DelayedExecute(2.0).Triggered.connect(function(t) {
+ if (user.GetProperty("password") != "secret") {
+ user.DenyConnection("wrong password");
+ print("wrong password");
+ } else {
+ print("correct password");
+ }
+ print("calling FinishLogin");
+ server.FinishLogin(user);
+ });
+
+}
+
+function ServerHandleUserConnected(connectionID, user) {
+ var username = null;
+ if (user != null)
+ username = user.GetProperty("username");
+ print("user " + username + " connected");
+}
+
+function ServerHandleUserDisconnected(connectionID, user) {
+ var username = null;
+ if (user != null)
+ username = user.GetProperty("username");
+ print("user " + username + " disconnected");
+
+}
+
+print("logintest end");
16 bin/scenes/TestScenes/AsyncAuthentication/scene.txml
View
@@ -0,0 +1,16 @@
+<!DOCTYPE Scene>
+<scene>
+ <entity id="1" sync="1">
+ <component type="EC_Name" sync="true">
+ <attribute value="LoginScript" name="name"/>
+ <attribute value="" name="description"/>
+ </component>
+ <component type="EC_Script" sync="true">
+ <attribute value="local://logintest.js" name="Script ref"/>
+ <attribute value="true" name="Run on load"/>
+ <attribute value="0" name="Run mode"/>
+ <attribute value="" name="Script application name"/>
+ <attribute value="" name="Script class name"/>
+ </component>
+ </entity>
+</scene>
5 src/Core/Asset/IAssetStorage.h
View
@@ -9,6 +9,8 @@
#include "AssetFwd.h"
#include <boost/enable_shared_from_this.hpp>
+class QNetworkAccessManager;
+
/// A base class for a database or a collection of assets in a single source.
class IAssetStorage : public QObject, public boost::enable_shared_from_this<IAssetStorage>
{
@@ -85,6 +87,9 @@ public slots:
/// Specifies whether data can be uploaded to this asset storage.
virtual bool Writable() const { return writable; }
+ /// Get QNetworkAccessManager associated with this storage, if any
+ virtual QNetworkAccessManager* GetNetworkAccessManager() { return NULL; }
+
/// Specifies whether the assets in the storage should be subject to live update, once loaded
virtual bool HasLiveUpdate() const { return liveUpdate; }
6 src/Core/AssetModule/HttpAssetStorage.h
View
@@ -64,6 +64,9 @@ public slots:
/// Returns the local directory of this storage. Empty if not local.
const QString& LocalDir() const { return localDir; }
+ /// Get QNetworkAccessManager from the parent provider
+ virtual QNetworkAccessManager* GetNetworkAccessManager();
+
private slots:
void OnHttpTransferFinished(QNetworkReply *reply);
@@ -76,9 +79,6 @@ private slots:
/// Perform a PROPFIND search on a path in the http storage
void PerformSearch(QString path);
- /// Get QNetworkAccessManager from the parent provider
- QNetworkAccessManager* GetNetworkAccessManager();
-
/// Ongoing network requests for querying asset refs
std::vector<SearchRequest> searches;
12 src/Core/TundraProtocolModule/Server.cpp
View
@@ -287,6 +287,18 @@ void Server::HandleLogin(kNet::MessageConnection* source, const MsgLogin& msg)
user->properties["authenticated"] = "true";
emit UserAboutToConnect(user->userID, user.get());
+ if (user->properties["authenticated"] != "later")
+ FinishLogin(user);
+}
+
+void Server::FinishLogin(UserConnectionPtr user)
+{
+ if (!user)
+ {
+ ::LogWarning("Server::HandleLogin: Login message from an unknown user.");
+ return;
+ }
+
if (user->properties["authenticated"] != "true")
{
::LogInfo("User with connection ID " + QString::number(user->userID) + " was denied access.");
3  src/Core/TundraProtocolModule/Server.h
View
@@ -86,6 +86,9 @@ public slots:
QString GetProtocol() const; /**< @deprecated Use Protocol or 'protocol' property. */
UserConnectionPtr GetActionSender() const; /**< @deprecated Use ActionSender. */
+ /// Called from authentication handler to finish login
+ void FinishLogin(UserConnectionPtr user);
+
signals:
/// A user is connecting. This is your chance to deny access.
/** Call user->Disconnect() to deny access and kick the user out.
5 src/Core/TundraProtocolModule/UserConnection.cpp
View
@@ -45,6 +45,11 @@ void UserConnection::DenyConnection(const QString &reason)
properties["reason"] = reason;
}
+void UserConnection::FinishLoginLater()
+{
+ properties["authenticated"] = "later";
+}
+
void UserConnection::Disconnect()
{
if (connection)
3  src/Core/TundraProtocolModule/UserConnection.h
View
@@ -60,6 +60,9 @@ public slots:
/// Deny connection. Call as a response to server.UserAboutToConnect() if necessary
void DenyConnection(const QString& reason);
+ /// Indicate intent to call Server.FinishLogin() later when authentication status is known. Call as a response to server.UserAboutToConnect() if necessary
+ void FinishLoginLater();
+
/// Starts a benign disconnect procedure (one which waits for the peer acknowledge procedure).
void Disconnect();
Something went wrong with that request. Please try again.