-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
mws authentication #8596
base: multi-wiki-support
Are you sure you want to change the base?
mws authentication #8596
Changes from 1 commit
9583fda
9b69959
d331115
4cb0379
c5bc0df
0f0d8be
0885eda
4e75360
0932f2c
887025b
316aa01
c5053f5
6a9dcac
13d7cd9
18f97ab
1a1675a
b61789b
f02c856
81f73de
851a7ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,18 @@ | |
"tiddlywiki/snowwhite" | ||
], | ||
"build": { | ||
"--mws-list-users": [ | ||
"--mws-list-users" | ||
], | ||
"mws-add-user": [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At the moment there is no parameterisation of build commands, so I can't see how this one could be used in practice. Is it intended to be part of the documentation? |
||
"--mws-add-permission", "READ", "Allows user to create tiddlers", | ||
"--mws-add-permission", "WRITE", "Gives the user the permission to edit and delete tiddlers", | ||
"--mws-add-role", "ADMIN", "System Administrator", | ||
"--mws-assign-role-permission", "ADMIN", "READ", | ||
"--mws-assign-role-permission", "ADMIN", "WRITE", | ||
"--mws-add-user", "user", "pass123", | ||
"--mws-assign-user-role", "user", "ADMIN" | ||
], | ||
"load-mws-demo-data": [ | ||
"--mws-load-wiki-folder","./editions/tw5.com","docs", "TiddlyWiki Documentation from https://tiddlywiki.com","docs","TiddlyWiki Documentation from https://tiddlywiki.com", | ||
"--mws-load-wiki-folder","./editions/dev","dev","TiddlyWiki Developer Documentation from https://tiddlywiki.com/dev","dev-docs", "TiddlyWiki Developer Documentation from https://tiddlywiki.com/dev", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/*\ | ||
title: $:/plugins/tiddlywiki/multiwikiserver/commands/mws-add-permission.js | ||
type: application/javascript | ||
module-type: command | ||
|
||
Command to create a permission | ||
|
||
\*/ | ||
(function(){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tiddlywiki code uses tabs for indentation. Tab width = 4 The first level inside the |
||
|
||
/*jslint node: true, browser: true */ | ||
/*global $tw: false */ | ||
"use strict"; | ||
|
||
exports.info = { | ||
name: "mws-add-permission", | ||
synchronous: false | ||
}; | ||
|
||
var Command = function(params,commander,callback) { | ||
this.params = params; | ||
this.commander = commander; | ||
this.callback = callback; | ||
}; | ||
|
||
Command.prototype.execute = function() { | ||
var self = this; | ||
|
||
if(this.params.length < 2) { | ||
return "Usage: --mws-add-permission <permission_name> <description>"; | ||
} | ||
|
||
if(!$tw.mws || !$tw.mws.store || !$tw.mws.store.sqlTiddlerDatabase) { | ||
return "Error: MultiWikiServer or SQL database not initialized."; | ||
} | ||
|
||
var permission_name = this.params[0]; | ||
var description = this.params[1]; | ||
|
||
$tw.mws.store.sqlTiddlerDatabase.createPermission(permission_name, description); | ||
|
||
console.log(permission_name+" Permission Created Successfully!") | ||
self.callback(); | ||
return null; | ||
}; | ||
|
||
exports.Command = Command; | ||
|
||
})(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/*\ | ||
title: $:/plugins/tiddlywiki/multiwikiserver/commands/mws-add-role.js | ||
type: application/javascript | ||
module-type: command | ||
|
||
Command to create a role | ||
|
||
\*/ | ||
(function(){ | ||
|
||
/*jslint node: true, browser: true */ | ||
/*global $tw: false */ | ||
"use strict"; | ||
|
||
exports.info = { | ||
name: "mws-add-role", | ||
synchronous: false | ||
}; | ||
|
||
var Command = function(params,commander,callback) { | ||
this.params = params; | ||
this.commander = commander; | ||
this.callback = callback; | ||
}; | ||
|
||
Command.prototype.execute = function() { | ||
var self = this; | ||
|
||
if(this.params.length < 2) { | ||
return "Usage: --mws-add-role <role_name> <description>"; | ||
} | ||
|
||
if(!$tw.mws || !$tw.mws.store || !$tw.mws.store.sqlTiddlerDatabase) { | ||
return "Error: MultiWikiServer or SQL database not initialized."; | ||
} | ||
|
||
var role_name = this.params[0]; | ||
var description = this.params[1]; | ||
|
||
$tw.mws.store.sqlTiddlerDatabase.createRole(role_name, description); | ||
|
||
console.log(role_name+" Role Created Successfully!") | ||
self.callback(null, "Role Created Successfully!"); | ||
return null; | ||
}; | ||
|
||
exports.Command = Command; | ||
|
||
})(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/*\ | ||
title: $:/plugins/tiddlywiki/multiwikiserver/commands/mws-add-user.js | ||
type: application/javascript | ||
module-type: command | ||
|
||
Command to create users and grant permission | ||
|
||
\*/ | ||
(function(){ | ||
|
||
/*jslint node: true, browser: true */ | ||
/*global $tw: false */ | ||
"use strict"; | ||
|
||
var crypto = require("crypto"); | ||
|
||
exports.info = { | ||
name: "mws-add-user", | ||
synchronous: false | ||
}; | ||
|
||
var Command = function(params,commander,callback) { | ||
this.params = params; | ||
this.commander = commander; | ||
this.callback = callback; | ||
}; | ||
|
||
Command.prototype.execute = function() { | ||
var self = this; | ||
|
||
if(this.params.length < 2) { | ||
return "Usage: --mws-add-user <username> <password> [email]"; | ||
} | ||
|
||
if(!$tw.mws || !$tw.mws.store || !$tw.mws.store.sqlTiddlerDatabase) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the usernames and passwords should never be stored with the content. So for me There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @pmario I think it's perfectly OK for this data to be in the same database. There's no more obvious way for queries of the tiddler database to accidentally start returning results from the user database than there is for any data corruption within a program. What I do want to pay attention to is the best practice of making the admin UI run off of a different HTTP host/port, so that administrators can use external tools to lock down admin access. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But this will prevent us from using different authentication and authorisation services / mechanisms in the future. Using Usernames and passwords is notoriously unsecure and imo outdated already today. The minimal requirement I would consider somewhat save is username/password in a combination with a time based 2-factor-code generated with an authenticator app. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The plan is to have pluggable authentication schemes. Form-based authentication is still pretty standard for website logins and so I don't think we can avoid offering it, but I definitely want to support things like logging in with Google or GitHub credentials. |
||
return "Error: MultiWikiServer or SQL database not initialized."; | ||
} | ||
|
||
var username = this.params[0]; | ||
var password = this.params[1]; | ||
var email = this.params[2] || username + "@tiddlywiki.com"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps use |
||
var hashedPassword = crypto.createHash("sha256").update(password).digest("hex"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simple sha256 hashing the password is not enough. The password needs to be salted and then encrypted at least 10000 times. Key-stretching makes it harder to use rainbow-tables and brute force password attacks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm comfortable with having a placeholder implementation to begin with. At this point, I think clarity is the most important consideration, and with adequate encapsulation it will be straightforward for us to revisit the implementation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem is, that it should be done right from the beginning, because the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @pmario the challenge is that we need to merge this PR to get feedback. If we wait until we've got a production ready authentication system then this PR would have to stay open for a long time, making all other work on MWS much more complicated. At this point we have the freedom that if required MWS can nuke the user database on an upgrade. We will lose that freedom as MWS moves beyond the experimental stage, so we should take advantage of it now to improve our overall velocity. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK |
||
|
||
var user = $tw.mws.store.sqlTiddlerDatabase.getUserByUsername(username); | ||
|
||
if(user) { | ||
self.callback("WARNING: An account with the username (" + username + ") already exists"); | ||
} else { | ||
$tw.mws.store.sqlTiddlerDatabase.createUser(username, email, hashedPassword); | ||
console.log("User Account Created Successfully!") | ||
self.callback(); | ||
} | ||
return null; | ||
}; | ||
|
||
exports.Command = Command; | ||
|
||
})(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/*\ | ||
title: $:/plugins/tiddlywiki/multiwikiserver/commands/mws-assign-role-permission.js | ||
type: application/javascript | ||
module-type: command | ||
|
||
Command to assign permission to a role | ||
|
||
\*/ | ||
(function(){ | ||
|
||
/*jslint node: true, browser: true */ | ||
/*global $tw: false */ | ||
"use strict"; | ||
|
||
exports.info = { | ||
name: "mws-assign-role-permission", | ||
synchronous: false | ||
}; | ||
|
||
var Command = function(params,commander,callback) { | ||
this.params = params; | ||
this.commander = commander; | ||
this.callback = callback; | ||
}; | ||
|
||
Command.prototype.execute = function() { | ||
var self = this; | ||
|
||
if(this.params.length < 2) { | ||
return "Usage: --mws-assign-role-permission <role_name> <permission_name>"; | ||
} | ||
|
||
if(!$tw.mws || !$tw.mws.store || !$tw.mws.store.sqlTiddlerDatabase) { | ||
return "Error: MultiWikiServer or SQL database not initialized."; | ||
} | ||
|
||
var role_name = this.params[0]; | ||
var permission_name = this.params[1]; | ||
var role = $tw.mws.store.sqlTiddlerDatabase.getRoleByName(role_name); | ||
var permission = $tw.mws.store.sqlTiddlerDatabase.getPermissionByName(permission_name); | ||
|
||
if(!role) { | ||
return "Error: Unable to find Role: "+role_name; | ||
} | ||
|
||
if(!permission) { | ||
return "Error: Unable to find Permission: "+permission_name; | ||
} | ||
|
||
var permission = $tw.mws.store.sqlTiddlerDatabase.getPermissionByName(permission_name); | ||
|
||
|
||
$tw.mws.store.sqlTiddlerDatabase.addPermissionToRole(role.role_id, permission.permission_id); | ||
|
||
console.log(permission_name+" permission assigned to "+role_name+" role successfully!") | ||
self.callback(); | ||
return null; | ||
}; | ||
|
||
exports.Command = Command; | ||
|
||
})(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/*\ | ||
title: $:/plugins/tiddlywiki/multiwikiserver/commands/mws-assign-user-role.js | ||
type: application/javascript | ||
module-type: command | ||
|
||
Command to assign a role to a user | ||
|
||
\*/ | ||
(function(){ | ||
|
||
/*jslint node: true, browser: true */ | ||
/*global $tw: false */ | ||
"use strict"; | ||
|
||
exports.info = { | ||
name: "mws-assign-user-role", | ||
synchronous: false | ||
}; | ||
|
||
var Command = function(params,commander,callback) { | ||
this.params = params; | ||
this.commander = commander; | ||
this.callback = callback; | ||
}; | ||
|
||
Command.prototype.execute = function() { | ||
var self = this; | ||
|
||
if(this.params.length < 2) { | ||
return "Usage: --mws-assign-user-role <username> <role_name>"; | ||
} | ||
|
||
if(!$tw.mws || !$tw.mws.store || !$tw.mws.store.sqlTiddlerDatabase) { | ||
return "Error: MultiWikiServer or SQL database not initialized."; | ||
} | ||
|
||
var username = this.params[0]; | ||
var role_name = this.params[1]; | ||
var role = $tw.mws.store.sqlTiddlerDatabase.getRoleByName(role_name); | ||
var user = $tw.mws.store.sqlTiddlerDatabase.getUserByUsername(username); | ||
|
||
if(!role) { | ||
return "Error: Unable to find Role: "+role_name; | ||
} | ||
|
||
if(!user) { | ||
return "Error: Unable to find user with the username "+username; | ||
} | ||
|
||
$tw.mws.store.sqlTiddlerDatabase.addRoleToUser(user.user_id, role.role_id); | ||
|
||
console.log(role_name+" role has been assigned to user with username "+username) | ||
self.callback(); | ||
return null; | ||
}; | ||
|
||
exports.Command = Command; | ||
|
||
})(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/*\ | ||
title: $:/plugins/tiddlywiki/multiwikiserver/commands/mws-list-users.js | ||
type: application/javascript | ||
module-type: command | ||
|
||
Command to list users | ||
|
||
\*/ | ||
(function(){ | ||
|
||
/*jslint node: true, browser: true */ | ||
/*global $tw: false */ | ||
"use strict"; | ||
|
||
exports.info = { | ||
name: "mws-list-users", | ||
synchronous: false | ||
}; | ||
|
||
var Command = function(params,commander,callback) { | ||
this.params = params; | ||
this.commander = commander; | ||
this.callback = callback; | ||
}; | ||
|
||
Command.prototype.execute = function() { | ||
var self = this; | ||
|
||
if(!$tw.mws || !$tw.mws.store || !$tw.mws.store.sqlTiddlerDatabase) { | ||
return "Error: MultiWikiServer or SQL database not initialized."; | ||
} | ||
|
||
var users = $tw.mws.store.sqlTiddlerDatabase.listUsers().map(function(user){ | ||
return ({ | ||
username: user.username, | ||
email: user.email, | ||
created_at: user.created_at, | ||
}) | ||
}); | ||
console.log("Users:", users); | ||
self.callback(null, "Users retrieved successfully:\n" + JSON.stringify(users, null, 2)); | ||
}; | ||
|
||
exports.Command = Command; | ||
|
||
})(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be confusing to have a named build that matches a built-in command. Perhaps this one isn't necessary in any case?