Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic login capabilities #659

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ before_script:
- sed -i "s/'vz'/'$USER'/" etc/volkszaehler.conf.php
- sed -i "s/'demo'/'$PASSWORD'/" etc/volkszaehler.conf.php
- sed -i "s/'volkszaehler'/'$DATABASE'/" etc/volkszaehler.conf.php
- sed -i "s/'secretkey'/'secretkey' =\> '08154711', \/\//" etc/volkszaehler.conf.php
- sed -i "s/\/\/ 'user'/'user'/" etc/volkszaehler.conf.php
- if [ "$DB" = "sqlite" ]; then sed -i "s/\?>/\$config['db']['path']\ =\ VZ_DIR.'\/sqlite.db3'\;\n?>/" etc/volkszaehler.conf.php; fi
- cat etc/volkszaehler.conf.php

Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
"andig/dbcopy": "^1.1",
"symfony/console": "^2.6|^3.0",
"symfony/http-kernel": "^2.6|^3.0",
"symfony/http-foundation": "^2.6|^3.0",
"symfony/http-foundation": "^3.3",
"symfony/routing": "^2.6|^3.0",
"cboden/ratchet": "^0.4",
"react/http": "^0.8",
"ringcentral/psr7": "^1.2",
"php-pm/php-pm": "^1.0",
"php-pm/httpkernel-adapter": "^1.0"
"php-pm/httpkernel-adapter": "^1.0",
"firebase/php-jwt": "^5.0"
},
"require-dev": {
"phpunit/phpunit": "^5.7|^6.0",
Expand Down
113 changes: 89 additions & 24 deletions etc/volkszaehler.conf.template.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,28 @@
$config['db']['password'] = 'demo';

/**
* @var string database name
* Database name
*
* See Doctrine doc for details: http://www.doctrine-project.org/projects/dbal/2.0/docs/reference/configuration/en
*/
$config['db']['dbname'] = 'volkszaehler';

/**
* @var database connection encoding - should not be changed
* Database connection encoding - should not be changed
*
* See http://stackoverflow.com/questions/13399912/symfony2-charset-for-queries-parameters
*/
$config['db']['charset'] = 'UTF8';

/**
* @var database optimizer class
* Path of the SQLite database - only used if $config['db']['driver'] = 'pdo_sqlite'
*
* See Doctrine doc for details: http://www.doctrine-project.org/projects/dbal/2.0/docs/reference/configuration/en
*/
$config['db']['path'] = 'volkszaehler.db3';

/**
* Database optimizer class
*
* For automatic leave empty. Other options:
* - MysqlOptimizer: provides additional group=15m setting (does not work with aggregation)
Expand All @@ -94,26 +101,92 @@
$config['aggregation'] = true;

/**
* Path of the SQLite database
* Push server settings
*
* See Doctrine doc for details: http://www.doctrine-project.org/projects/dbal/2.0/docs/reference/configuration/en
* See misc/tools/push-server.php for details
*/
//$config['db']['path'] = 'volkszaehler';
$config['push'] = array(
'enabled' => false, // set to true to enable push updates
'server' => 5582, // vzlogger will push to this ports (binds on 0.0.0.0)
'broadcast' => 8082, // frontend will subscribe on this port (binds on 0.0.0.0)
'routes' => array(
'wamp' => array('/', '/ws'), // routes for wamp access
'websocket' => array() // routes for plain web sockets, try array('/socket')
)
);

/**
* Push server settings
* Security settings
*/
$config['push']['enabled'] = false; // set to true to enable push updates
$config['push']['server'] = 5582; // vzlogger will push to this ports (binds on 0.0.0.0)
$config['push']['broadcast'] = 8082; // frontend will subscribe on this port (binds on 0.0.0.0)
$config['security']['maxbodysize'] = false; // limit maximum POST body size, e.g. 4096

$config['push']['routes']['wamp'] = array('/', '/ws'); // routes for wamp access
$config['push']['routes']['websocket'] = array(); // routes for plain web sockets, try array('/socket')
/**
* Access control
*
* Define firewall rules per ip, path or method and actions 'allow', 'deny' and 'auth'
*/
$config['firewall'] = array(
[ // localhost
'ips' => ['127.0.0.1/8', '::1'],
'action' => 'allow'
],
[ // local network
'ips' => ['192.168.0.0/16', '172.16.0.0/12', '10.0.0.0/8', 'fe80::/64'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(thumbsup), very good!

'action' => 'allow'
],
[ // always allow /auth - this is required
'path' => '/auth',
'methods' => 'POST',
'action' => 'allow'
],
[ // always allow GET - makes read access public
'methods' => 'GET',
'action' => 'allow'
],
[ // authorize all other requests
'action' => 'auth'
]
);

/**
* Security settings
* Proxies
*
* Trust any local machine as (reverse) proxy
*/
$config['security']['maxbodysize'] = false; // limit maximum POST body size, e.g. 4096
$config['proxies'] = array(
'127.0.0.1/8', '::1', '192.168.0.0/16', '172.16.0.0/12', '10.0.0.0/8', 'fe80::/64'
);

/**
* User authorization for firewall rule action 'auth'
*
* NOTE: if using authorization *ALWAYS* make sure HTTPS is enforced
*/
$config['authorization'] = array(
'secretkey' => '', // define your own random secret key
'valid' => 24 * 3600, // token validity period
);

// add users below as 'user' => 'pass'
$config['users']['plain'] = array(
// 'user' => 'pass'
);

/**
* Access restrictions per user as understood by misc/tools/token-helper.php
*
* NOTE: Constraints are effective when firewall rule demands 'auth', NOT otherwise.
* They are applied whenever a user logs in. Empty context/operation array
* means no constraints.
*/
$config['users']['constraints'] = array(
/*
'user' => [
'context' => [ array of allowed contexts ],
'operation' => [ array of allowed operations ],
]
*/
);

/**
* Timezone for the middleware
Expand All @@ -140,16 +213,8 @@
/**
* Developer mode
*
* This disables all caching mechanisms and enabled debugging by default
*/
$config['devmode'] = FALSE;
$config['cache']['ttl'] = 3600; // only used if devmode == FALSE

/**
* Debugging level
*
* Set to > 0 to enable debug messages by default
* This disables all caching mechanisms
*/
$config['debug'] = 0;
$config['devmode'] = false;

?>
7 changes: 7 additions & 0 deletions htdocs/.htaccess
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@

<IfModule mod_rewrite.c>
RewriteEngine On

# fix Authorization header not passed on
RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

# fix middleware suffix
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^middleware/(.*) middleware.php/$1 [L]

# frontend alias
Expand Down
11 changes: 11 additions & 0 deletions htdocs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,17 @@ <h3><img src="img/blank.png" class="icon-wrench" alt="" /> Optionen</h3>
</form>
</div>

<div id="authorization" class="dialog">
<form>
<table>
<tr><td>Middleware:</td><td><span class="middleware"></span></td></tr>
<tr><td colspan="2"><hr /></td></tr>
<tr><td><label for="username">Username:</label></td><td><input name="username" type="text" maxlength="128" /></td></tr>
<tr><td><label for="password">Passwort:</label></td><td><input name="password" type="password" maxlength="128" /></td></tr>
</table>
</form>
</div>

<div id="chart-export" class="dialog">
<div class="export"></div>
</div>
Expand Down
5 changes: 1 addition & 4 deletions htdocs/js/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,7 @@ vz.entities.loadDetails = function() {
// Use thenable form and skip default error handling to allow modifying deferred resolution for handling
// invalid/deleted entity uuids. Otherwise frontend loading will stall.
queue.push(entity.loadDetails(true).then(
function(json) {
return $.Deferred().resolveWith(this, [json]);
},
null, // success - no changes needed
function(xhr) {
var exception = (xhr.responseJSON || {}).exception;
// remove problematic entity
Expand All @@ -83,7 +81,6 @@ vz.entities.loadDetails = function() {
// return new resolved deferred
return $.Deferred().resolveWith(this, [xhr]);
}
vz.wui.dialogs.middlewareException(xhr);
return vz.load.errorHandler(xhr);
}
));
Expand Down
60 changes: 37 additions & 23 deletions htdocs/js/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,24 +87,43 @@ vz.getPermalink = function() {
return window.location.protocol + '//' + window.location.host + window.location.pathname + '?' + $.param(params);
};

/**
* Ajax prefilter for repeatable requests
*/
$.ajaxPrefilter(function(options, originalOptions, xhr) {
xhr.originalOptions = originalOptions;
});

/**
* Universal helper for middleware ajax requests with error handling
*
* @param skipDefaultErrorHandling according to http://stackoverflow.com/questions/19101670/provide-a-default-fail-method-for-a-jquery-deferred-object
*/
vz.load = function(args, skipDefaultErrorHandling) {
$.extend(args, {
accepts: 'application/json',
accepts: {
'json': 'application/json'
},
beforeSend: function (xhr, settings) {
// remember URL for potential error messages
xhr.requestUrl = settings.url;
xhr.middleware = args.middleware;

// add authorization header
var mw = vz.middleware.find(args.middleware);
if (mw && mw.authToken) {
xhr.setRequestHeader('Authorization', 'Bearer ' + mw.authToken);
}
}
});

if (args.url === undefined) { // local middleware by default
args.url = vz.options.middleware[0].url;
}

// store for later authentication
args.middleware = args.url;

if (args.controller !== undefined) {
args.url += '/' + args.controller;
}
Expand All @@ -124,6 +143,13 @@ vz.load = function(args, skipDefaultErrorHandling) {
args.data = { };
}

return vz.load.loadHandler(args, skipDefaultErrorHandling);
};

/**
* Reusable ajax request sender with error handling
*/
vz.load.loadHandler = function(args, skipDefaultErrorHandling) {
return $.ajax(args).then(
// success
function(json, error, xhr) {
Expand All @@ -145,7 +171,13 @@ vz.load = function(args, skipDefaultErrorHandling) {
* Reusable authorization-aware error handler
*/
vz.load.errorHandler = function(xhr, skipDefaultErrorHandling) {
if (!skipDefaultErrorHandling) {
// HTTP_UNAUTHORIZED
if (xhr.status == 401) {
return vz.wui.dialogs.authorizationException(xhr).then(function(token) {
return vz.load.loadHandler(xhr.originalOptions, skipDefaultErrorHandling);
});
}
else if (!skipDefaultErrorHandling) {
vz.wui.dialogs.middlewareException(xhr);
}
return xhr;
Expand Down Expand Up @@ -230,29 +262,11 @@ vz.parseUrlParams = function() {
* Load capabilities from middleware
*/
vz.capabilities.load = function() {
// execute query asynchronously to refresh from middleware
var deferred = vz.load({
controller: 'capabilities'
return vz.load({
controller: 'capabilities/definitions'
}).done(function(json) {
$.extend(true, vz.capabilities, json.capabilities);
try {
localStorage.setItem('vz.capabilities', JSON.stringify(json)); // cache it
}
catch (e) { }
$.extend(vz.capabilities.definitions, json.capabilities.definitions);
});

// get cached value to avoid blocking frontend startup
try {
var json = localStorage.getItem('vz.capabilities');
if (json !== false) {
// use cached value and return immediately
$.extend(true, vz.capabilities, JSON.parse(json).capabilities);
return $.Deferred().resolve();
}
}
catch (e) { }

return deferred;
};

/**
Expand Down
4 changes: 0 additions & 4 deletions htdocs/js/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,6 @@ $(document).ready(function() {
var params = $.getUrlParams();
if (params.hasOwnProperty('reset') && params.reset) {
$.setCookie('vz_entities', null);
try {
localStorage.removeItem('vz.capabilities');
}
catch (e) { }
}

// start loading cookies/url params
Expand Down
Loading