in the middle of the work for authentication

single-host
Marc Wäckerlin 9 years ago
parent bdaebcc92f
commit 82bb795b85
  1. 71
      nodejs/authentication/index.js
  2. 22
      nodejs/etc/servicedock.json
  3. 59
      nodejs/package.json.in
  4. 8
      nodejs/public/javascripts/servicedock.js
  5. 7
      nodejs/routes/index.js
  6. 108
      nodejs/servicedock.js
  7. 15
      nodejs/sockets/index.js
  8. 1
      nodejs/views/index.ejs
  9. 129
      scripts/docker-backup.sh

@ -0,0 +1,71 @@
module.exports = function(config) {
const crypto = require('crypto');
const password = crypto.randomBytes(256);
var cookie = require('cookie-encryption');
// const cipher = crypto.createCipher('aes256', password);
// const decipher = crypto.createDecipher('aes256', password);
// var encrypted = cipher.update(JSON.stringify(user), 'utf8', 'base64')
// + cipher.final('base64');
// console.log("encrypted", encrypted);
// var decrypted = decipher.update(encrypted, 'base64', 'utf8') + decipher.final('utf8');
// console.log("decrypted", decrypted);
var authentication = function (req, res, next) {
return next();
}
if (config) {
var cipher = config.cookies && config.cookies.cipher ? config.cookies.cipher : "aes256";
authentication = function (req, res, next) {
function unauthorized(res) {
res.setHeader('WWW-Authenticate', 'Basic realm=Authorization Required');
res.status(401).send('Not logged in. <a href="/">Login</a>');
};
var user = require('basic-auth')(req);
var vault = cookie('credentials');
if (!user || !user.name || !user.pass) {
return unauthorized(res);
};
if (config.passwords && config.passwords[user.name]) {
if (crypto.getHashes().indexOf(config.passwords[user.name][0])>=0) {
if (crypto.createHash(config.passwords[user.name][0])
.update(user.pass, 'utf8').digest('hex') === config.passwords[user.name][1]) {
return next();
}
} else {
console.log("**** HASH NOT FOUND ****");
console.log(config.passwords[user.name][0]);
console.log(crypto.getHashes());
}
}
if (config.ldap) try {
var LdapAuth = require('ldapauth');
var auth = new LdapAuth(config.ldap);
auth.authenticate(user.name, user.pass, function(err, usr) {
auth.close(function(err) {})
if (err) {
console.log("**** ERROR: LDAP Authentication failed:", err);
return unauthorized(res);
}
console.log("**** SUCCESS: LDAP Authentication:");
return next();
});
return; // need to block here!
} catch (e) {
console.log("**** Error: LDAP failed: ", e, e.stack);
}
return unauthorized(res);
};
}
return authentication;
}

@ -1,3 +1,23 @@
{ {
"port": 8888 "port": 8888,
"restrict": {
"cookies": {
"cipher": "aes256"
},
"passwords": {
"marc": ["sha256", "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"],
"foo": ["sha256", "fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9"]
},
"ldap": {
"tlsOptions": {
"requestCert": false,
"rejectUnauthorized": false
},
"url": "ldap://dev.marc.waeckerlin.org",
"adminDn": "cn=tmp,ou=system,ou=people,dc=dev,dc=marc,dc=waeckerlin,dc=org",
"adminPassword": "dGg7benUnZ9z",
"searchBase": "ou=person,ou=people,dc=dev,dc=marc,dc=waeckerlin,dc=org",
"searchFilter": "(uid={{username}})"
}
}
} }

@ -1,30 +1,33 @@
{ {
"name": "@PACKAGE_NAME@", "name": "@PACKAGE_NAME@",
"version": "@PACKAGE_VERSION@", "version": "@PACKAGE_VERSION@",
"private": true, "private": true,
"dependencies": { "description": "Docker as a Service",
"express": "~2.5.8", "main": "servicedock.js",
"stylus": "~0.53.0", "devDependencies": {},
"ejs": ">= 0.0.1", "scripts": {
"socket.io": "~1.4.4", "test": "echo \"Error: no test specified\" && exit 1"
"pty.js": "~0.3.0", },
"async": "~1.5.2" "author": "Marc Wäckerlin",
}, "license": "LGPL3",
"description": "Docker as a Service", "path": {
"main": "servicedock.js", "prefix": "@PREFIX@",
"devDependencies": {}, "sysconf": "@SYSCONFDIR@",
"scripts": { "pkgdata": "@PKGDATADIR@",
"test": "echo \"Error: no test specified\" && exit 1" "localstate": "@LOCALSTATEDIR@",
}, "log": "@LOCALSTATEDIR@/log/@PACKAGE_NAME@.log",
"author": "Marc Wäckerlin", "config": "@SYSCONFDIR@/@PACKAGE_NAME@.json",
"license": "LGPL3", "nodejs": "@PKGDATADIR@/nodejs"
"path": { },
"prefix": "@PREFIX@", "dependencies": {
"sysconf": "@SYSCONFDIR@", "express": "~2.5.8",
"pkgdata": "@PKGDATADIR@", "stylus": "~0.53.0",
"localstate": "@LOCALSTATEDIR@", "ejs": ">= 0.0.1",
"log": "@LOCALSTATEDIR@/log/@PACKAGE_NAME@.log", "socket.io": "~1.4.4",
"config": "@SYSCONFDIR@/@PACKAGE_NAME@.json", "pty.js": "~0.3.0",
"nodejs": "@PKGDATADIR@/nodejs" "async": "~1.5.2",
} "basic-auth": "~1.0.3",
"ldapauth": "~2.2.4",
"cookie-encryption": "~1.4.2"
}
} }

@ -8,7 +8,7 @@
// 1 2 3 4 5 6 7 8 // 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890 // 45678901234567890123456789012345678901234567890123456789012345678901234567890
var socket = io.connect(); var socket = null;
var focused = null; var focused = null;
var docker = new Docker(); var docker = new Docker();
@ -597,6 +597,12 @@ function initForms() {
} }
function init() { function init() {
$("#logout").attr("href",
window.location.protocol+"//X:X@"
+window.location.hostname
+(window.location.port?":":"")+window.location.port
+window.location.pathname);
socket = io.connect();
socket.io socket.io
.on("connect", connected) .on("connect", connected)
.on("reconnect", connected) .on("reconnect", connected)

@ -1,4 +1,3 @@
/* /*
* GET home page. * GET home page.
*/ */
@ -6,8 +5,8 @@
var package = require(__dirname+"/../package.json"); var package = require(__dirname+"/../package.json");
exports.index = function(req, res) { exports.index = function(req, res) {
res.render('index', { res.render('index', {
packagename: package.name, packagename: package.name,
packageversion: package.version packageversion: package.version
}); });
}; };

@ -1,55 +1,69 @@
try {
/** process.on('uncaughtException', function(e) {
* Module dependencies. console.log("**** UNCAUGHT EXCEPTION ****");
*/ console.log(e);
console.log(e.stack);
var express = require('express')
, routes = require(__dirname+'/routes');
var app = module.exports = express.createServer();
var io = require('socket.io').listen(app);
var sockets = require(__dirname+'/sockets')(io);
var package = require(__dirname+'/package.json');
var config = require(package.path.config);
var docker = require(__dirname+'/docker')(app);
// Configuration
process.argv.forEach(function(val, index) {
if (index<2) {return}
if (index!=2 || typeof val != 'number') {
console.log("**** ERROR: Unexpected Argument - allowed is only a port number");
process.exit(1); process.exit(1);
} });
config.port = val;
}); /**
if (typeof config.port != 'number') { * Module dependencies.
console.log("**** WARNING: no valid port given, defaults to 8888"); */
config.port = 8888;
} var express = require('express')
, routes = require(__dirname+'/routes');
app.configure(function(){ var app = module.exports = express.createServer();
app.set('views', __dirname + '/views'); var io = require('socket.io').listen(app);
app.set('view engine', 'ejs'); var sockets = require(__dirname+'/sockets')(io);
app.use(express.bodyParser()); var package = require(__dirname+'/package.json');
app.use(express.methodOverride()); var config = require(package.path.config);
app.use(require('stylus').middleware({ src: __dirname + '/public' })); var docker = require(__dirname+'/docker')(app);
app.use(app.router); var authentication = require(__dirname+'/authentication')(config.restrict);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){ // Configuration
app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); process.argv.forEach(function(val, index) {
}); if (index<2) {return}
if (index!=2 || typeof val != 'number') {
console.log("**** ERROR: Unexpected Argument - allowed is only a port number");
process.exit(1);
}
config.port = val;
});
if (typeof config.port != 'number') {
console.log("**** WARNING: no valid port given, defaults to 8888");
config.port = 8888;
}
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(require('stylus').middleware({ src: __dirname + '/public' }));
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('production', function(){ app.configure('development', function(){
app.use(express.errorHandler()); app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
}); });
// Routes app.configure('production', function(){
app.use(express.errorHandler());
});
app.get('/', routes.index); // Routes
app.get('/', authentication, routes.index);
app.listen(config.port, function() { app.listen(config.port, function() {
console.log("Express server listening on port %d in %s mode", console.log("Express server listening on port %d in %s mode",
app.address().port, app.settings.env); app.address().port, app.settings.env);
}); });
} catch (e) {
console.log("**** EXCEPTION ****");
console.log(e);
console.log(e.stack);
process.exit(1);
}

@ -13,8 +13,12 @@ module.exports = function(io) {
} }
function exec(cmd, callback) { function exec(cmd, callback) {
console.log("== "+cmd); if (cmd.length>40) {
proc.exec(cmd, callback); console.log("== "+cmd.slice(0, 30+cmd.slice(30).indexOf(' '))+" ...");
} else {
console.log("== "+cmd);
}
proc.exec(cmd, {maxBuffer: 10*1024*1024}, callback);
} }
function fail(txt, data) { function fail(txt, data) {
@ -68,7 +72,8 @@ module.exports = function(io) {
return fail("list docker images failed", { return fail("list docker images failed", {
error: error, stderr: stderr, stdout: stdout error: error, stderr: stderr, stdout: stdout
}); });
exec("docker inspect "+stdout.trim().replace(/\n/g, " "), imageinspect); exec("docker inspect "+stdout.trim().replace(/\n/g, " "),
imageinspect);
} }
function updateimages(error, stdout, stderr) { function updateimages(error, stdout, stderr) {
@ -80,8 +85,8 @@ module.exports = function(io) {
} }
function connection(socket) { function connection(socket) {
console.log("new client"); console.log("new connection");
function emit(signal, data, info) { function emit(signal, data, info) {
if (typeof data == 'string' && !data.match("\n")) { if (typeof data == 'string' && !data.match("\n")) {

@ -31,6 +31,7 @@
<ul id="menu" style="display: none" onmouseleave="$('#menu').hide();"> <ul id="menu" style="display: none" onmouseleave="$('#menu').hide();">
<li onclick="$('#menu').hide(); showCreate()">Create</li> <li onclick="$('#menu').hide(); showCreate()">Create</li>
<li><label for="upload">Upload</label><input autocomplete="off" type="file" accept="*.json" id="upload"/></li> <li><label for="upload">Upload</label><input autocomplete="off" type="file" accept="*.json" id="upload"/></li>
<li><a id="logout" href="">Logout</a></li>
</ul> </ul>
<script type="text/javascript"> <script type="text/javascript">
$(function() { $(function() {

@ -0,0 +1,129 @@
#!/bin/bash -e
function get-volumes() {
local vols=""
for vol in ${*}; do
local vf=$(docker inspect -f '{{.HostConfig.VolumesFrom}}' ${vol} | sed -n 's,^\[\(.*\)\]$,\1,p')
if test -n "$vf"; then
vols+=" "$(get-volumes $vf)
fi
vols+=" "$(docker inspect -f '{{.Config.Volumes}}' ${vol} | sed -n 's,^map\[\(.*\)\]$,\1,p' | sed 's,:[^ ]*,,g')
done
echo ${vols} | tr '[ ]' '[\n]' | sort | uniq | tr '[\n]' '[ ]'
}
backup=""
volumes=""
infile=""
tofile=""
toserver=""
tocontainer=""
while test $# -gt 0; do
case "$1" in
(-h|--help)
cat <<EOF
$0 -b [OPTIONS]
OPTIONS:
-b, --backup <container> name of the docker container to backup
-v, --volume <volume> add volume path to backup from container
-a, --auto automatically detect volumes to backup from container
-i, --in-file <file> take already existing backup file to import
-s, --to-server <server> copy backup to docker instance on ssh server
-c, --to-container <container> write backup into container on ssh server
-o, --to-file <file> write backup to file
DESCRIPTION:
Take docker backups and copy them to a file or restore them into a
docker instance on an ssh target server.
Note: Use ssh key exchange to prevent password query.
Note: Only volume paths are backed-up correctly
EXAMPLE:
$0 -b wordpress -a -o /tmp/wordpress.bak.tar.bz2
$0 -i /tmp/wordpress.bak.tar.bz2 -c wordpress
$0 -b backup-test -a -s server -c backup-test
EOF
exit 0
;;
(-b|--backup)
shift
backup="$1"
;;
(-i|--in-file)
shift
infile="$1"
;;
(-o|--to-file)
shift
tofile="$1"
;;
(-s|--to-server)
shift
toserver="$1"
;;
(-c|--to-container)
shift
tocontainer="$1"
;;
(-a|--auto)
if test -z "$backup"; then
echo "**** Error: --auto first requires --backup, try $0 --help" 1>&2
exit 1
fi
volumes+=" "$(get-volumes $backup)
;;
(-v|--volume)
shift
volumes+=("$1")
;;
(*)
echo "**** Error: unknown argument $1, try $0 --help" 1>&2
exit 1
;;
esac
if test $# -eq 0; then
echo "**** Error: missing argument, try $0 --help" 1>&2
exit 1
fi
shift
done
if test -n "$backup"; then
if test -z "${volumes}"; then
echo "**** Error: no volumes to backup, try $0 --help" 1>&2
exit 1
fi
elif test -z "$infile"; then
echo "**** Error: no input source specified, try $0 --help" 1>&2
exit 1
fi
if test -n "$toserver"; then
if test -z "$tocontainer"; then
echo "**** Error: no target container specified, try $0 --help" 1>&2
exit 1
fi
elif test -z "$tofile" -a -z "$tocontainer";then
echo "**** Error: no target specified, try $0 --help" 1>&2
exit 1
fi
(
if test -n "$backup"; then
docker run --rm -i -w / --volumes-from $backup ubuntu tar cjP ${volumes}
elif test -n "$infile"; then
cat "$infile"
fi
) | (
if test -n "$toserver"; then
ssh $toserver docker run --rm -i -w / --volumes-from $tocontainer ubuntu tar xjP
elif test -n "$tocontainer"; then
docker run --rm -i -w / --volumes-from $tocontainer ubuntu tar xjP
elif test -n "$tofile";then
cat > "$tofile"
fi
)
Loading…
Cancel
Save