mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 17:03:58 +02:00
Merge pull request #3250 from birarda/master
add basic DS navbar, add support for basic auth
This commit is contained in:
commit
384e62f1b1
6 changed files with 123 additions and 50 deletions
|
@ -1,3 +1,4 @@
|
|||
</div>
|
||||
<script src='/js/jquery-2.0.3.min.js'></script>
|
||||
<script src='/js/bootstrap.min.js'></script>
|
||||
<script src='/js/bootstrap.min.js'></script>
|
||||
<script src='/js/domain-server.js'></script>
|
|
@ -8,4 +8,27 @@
|
|||
<link href="/css/style.css" rel="stylesheet" media="screen">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-default" role="navigation">
|
||||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#">domain-server</a>
|
||||
</div>
|
||||
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="/">Nodes</a></li>
|
||||
<li><a href="/settings/">Settings</a></li>
|
||||
<li><a href="/assignment">New Assignment</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div><!-- /.container-fluid -->
|
||||
</nav>
|
||||
<div class="container">
|
10
domain-server/resources/web/js/domain-server.js
Normal file
10
domain-server/resources/web/js/domain-server.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
$(document).ready(function(){
|
||||
var url = window.location;
|
||||
// Will only work if string in href matches with location
|
||||
$('ul.nav a[href="'+ url +'"]').parent().addClass('active');
|
||||
|
||||
// Will also work for relative and absolute hrefs
|
||||
$('ul.nav a').filter(function() {
|
||||
return this.href == url;
|
||||
}).parent().addClass('active');
|
||||
});
|
|
@ -28,33 +28,5 @@
|
|||
"default": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"voxels": {
|
||||
"label": "Voxels",
|
||||
"assignment-types": [2,3],
|
||||
"settings": {
|
||||
"voxel-wallet": {
|
||||
"label": "Destination Wallet ID",
|
||||
"help": "Wallet to be paid for voxel changes",
|
||||
"placeholder": "00000000-0000-0000-0000-000000000000",
|
||||
"default": ""
|
||||
},
|
||||
"per-voxel-credits": {
|
||||
"type": "double",
|
||||
"label": "Per Voxel Cost",
|
||||
"help": "Credit cost to change each voxel",
|
||||
"placeholder": "0.0",
|
||||
"default": "0.0",
|
||||
"input_addon": "₵"
|
||||
},
|
||||
"per-meter-cubed-credits": {
|
||||
"type": "double",
|
||||
"label": "Per Meter Cubed Cost",
|
||||
"help": "Credit cost to change each cubed meter of voxel space",
|
||||
"placeholder": "0.0",
|
||||
"default": "0.0",
|
||||
"input_addon": "₵"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1280,6 +1280,9 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
|
|||
const QByteArray HTTP_COOKIE_HEADER_KEY = "Cookie";
|
||||
const QString ADMIN_USERS_CONFIG_KEY = "admin-users";
|
||||
const QString ADMIN_ROLES_CONFIG_KEY = "admin-roles";
|
||||
const QString BASIC_AUTH_CONFIG_KEY = "basic-auth";
|
||||
|
||||
const QByteArray UNAUTHENTICATED_BODY = "You do not have permission to access this domain-server.";
|
||||
|
||||
if (!_oauthProviderURL.isEmpty()
|
||||
&& (_argumentVariantMap.contains(ADMIN_USERS_CONFIG_KEY) || _argumentVariantMap.contains(ADMIN_ROLES_CONFIG_KEY))) {
|
||||
|
@ -1293,6 +1296,11 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
|
|||
cookieUUID = cookieUUIDRegex.cap(1);
|
||||
}
|
||||
|
||||
if (_argumentVariantMap.contains(BASIC_AUTH_CONFIG_KEY)) {
|
||||
qDebug() << "Config file contains web admin settings for OAuth and basic HTTP authentication."
|
||||
<< "These cannot be combined - using OAuth for authentication.";
|
||||
}
|
||||
|
||||
if (!cookieUUID.isNull() && _cookieSessionHash.contains(cookieUUID)) {
|
||||
// pull the QJSONObject for the user with this cookie UUID
|
||||
DomainServerWebSessionData sessionData = _cookieSessionHash.value(cookieUUID);
|
||||
|
@ -1315,8 +1323,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
|
|||
}
|
||||
}
|
||||
|
||||
QString unauthenticatedRequest = "You do not have permission to access this domain-server.";
|
||||
connection->respond(HTTPConnection::StatusCode401, unauthenticatedRequest.toUtf8());
|
||||
connection->respond(HTTPConnection::StatusCode401, UNAUTHENTICATED_BODY);
|
||||
|
||||
// the user does not have allowed username or role, return 401
|
||||
return false;
|
||||
|
@ -1340,6 +1347,59 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
|
|||
// we don't know about this user yet, so they are not yet authenticated
|
||||
return false;
|
||||
}
|
||||
} else if (_argumentVariantMap.contains(BASIC_AUTH_CONFIG_KEY)) {
|
||||
// config file contains username and password combinations for basic auth
|
||||
const QByteArray BASIC_AUTH_HEADER_KEY = "Authorization";
|
||||
|
||||
// check if a username and password have been provided with the request
|
||||
QString basicAuthString = connection->requestHeaders().value(BASIC_AUTH_HEADER_KEY);
|
||||
|
||||
if (!basicAuthString.isEmpty()) {
|
||||
QStringList splitAuthString = basicAuthString.split(' ');
|
||||
QString base64String = splitAuthString.size() == 2 ? splitAuthString[1] : "";
|
||||
QString credentialString = QByteArray::fromBase64(base64String.toLocal8Bit());
|
||||
|
||||
if (!credentialString.isEmpty()) {
|
||||
QStringList credentialList = credentialString.split(':');
|
||||
if (credentialList.size() == 2) {
|
||||
QString username = credentialList[0];
|
||||
QString password = credentialList[1];
|
||||
|
||||
// we've pulled a username and password - now check if there is a match in our basic auth hash
|
||||
QJsonObject basicAuthObject = _argumentVariantMap.value(BASIC_AUTH_CONFIG_KEY).toJsonValue().toObject();
|
||||
|
||||
if (basicAuthObject.contains(username)) {
|
||||
const QString BASIC_AUTH_USER_PASSWORD_KEY = "password";
|
||||
QJsonObject userObject = basicAuthObject.value(username).toObject();
|
||||
|
||||
if (userObject.contains(BASIC_AUTH_USER_PASSWORD_KEY)
|
||||
&& userObject.value(BASIC_AUTH_USER_PASSWORD_KEY).toString() == password) {
|
||||
// this is username / password match - let this user in
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// basic HTTP auth being used but no username and password are present
|
||||
// or the username and password are not correct
|
||||
// send back a 401 and ask for basic auth
|
||||
|
||||
const QByteArray HTTP_AUTH_REQUEST_HEADER_KEY = "WWW-Authenticate";
|
||||
static QString HTTP_AUTH_REALM_STRING = QString("Basic realm='%1 %2'")
|
||||
.arg(_hostname.isEmpty() ? "localhost" : _hostname)
|
||||
.arg("domain-server");
|
||||
|
||||
Headers basicAuthHeader;
|
||||
basicAuthHeader.insert(HTTP_AUTH_REQUEST_HEADER_KEY, HTTP_AUTH_REALM_STRING.toUtf8());
|
||||
|
||||
connection->respond(HTTPConnection::StatusCode401, UNAUTHENTICATED_BODY,
|
||||
HTTPConnection::DefaultContentType, basicAuthHeader);
|
||||
|
||||
// not authenticated, bubble up false
|
||||
return false;
|
||||
|
||||
} else {
|
||||
// we don't have an OAuth URL + admin roles/usernames, so all users are authenticated
|
||||
return true;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QJsonDocument>
|
||||
|
@ -68,29 +69,35 @@ QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringL
|
|||
|
||||
int configIndex = argumentList.indexOf(CONFIG_FILE_OPTION);
|
||||
|
||||
QString configFilePath;
|
||||
|
||||
if (configIndex != -1) {
|
||||
// we have a config file - try and read it
|
||||
QString configFilePath = argumentList[configIndex + 1];
|
||||
QFile configFile(configFilePath);
|
||||
|
||||
if (configFile.exists()) {
|
||||
qDebug() << "Reading JSON config file at" << configFilePath;
|
||||
configFile.open(QIODevice::ReadOnly);
|
||||
|
||||
QJsonDocument configDocument = QJsonDocument::fromJson(configFile.readAll());
|
||||
QJsonObject rootObject = configDocument.object();
|
||||
|
||||
// enumerate the keys of the configDocument object
|
||||
foreach(const QString& key, rootObject.keys()) {
|
||||
|
||||
if (!mergedMap.contains(key)) {
|
||||
// no match in existing list, add it
|
||||
mergedMap.insert(key, QVariant(rootObject[key]));
|
||||
}
|
||||
configFilePath = argumentList[configIndex + 1];
|
||||
} else {
|
||||
// no config file - try to read a file at resources/config.json
|
||||
configFilePath = QCoreApplication::applicationDirPath() + "/resources/config.json";
|
||||
}
|
||||
|
||||
QFile configFile(configFilePath);
|
||||
|
||||
if (configFile.exists()) {
|
||||
qDebug() << "Reading JSON config file at" << configFilePath;
|
||||
configFile.open(QIODevice::ReadOnly);
|
||||
|
||||
QJsonDocument configDocument = QJsonDocument::fromJson(configFile.readAll());
|
||||
QJsonObject rootObject = configDocument.object();
|
||||
|
||||
// enumerate the keys of the configDocument object
|
||||
foreach(const QString& key, rootObject.keys()) {
|
||||
|
||||
if (!mergedMap.contains(key)) {
|
||||
// no match in existing list, add it
|
||||
mergedMap.insert(key, QVariant(rootObject[key]));
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Could not find JSON config file at" << configFilePath;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Could not find JSON config file at" << configFilePath;
|
||||
}
|
||||
|
||||
return mergedMap;
|
||||
|
|
Loading…
Reference in a new issue