TiddlyWiki / TiddlyWiki5

A self-contained JavaScript wiki for the browser, Node.js, AWS Lambda etc.
https://tiddlywiki.com/
Other
7.97k stars 1.18k forks source link

Multi-User Environments - Authentication and ACLs/Policies #1276

Open Azrael808 opened 9 years ago

Azrael808 commented 9 years ago

Currently, there doesn't appear to be a way to set up TW5 in a multi-user environment; no user authentication and no way to restrict access to tiddlers (or bags of tiddlers).

After speaking with @Jermolene, I've been made aware of an ongoing effort to add this functionality to the project, but there's been little/no use case. Hopefully, I can bring the use case and some additional sysadmin-level help/knowledge to the project!

My use case is this: my team and I would like to use TW5 as a knowledge base, but one that we can invite external users to so they can benefit from the information stored within. We would like to at least be able to:

We would need to consider where user credentials are stored (LDAP?) as well.

I'm raising this ticket to get a discussion going around this topic, feel free to jump in and contribute if you're interested!

tobibeer commented 9 years ago

This issue appears to be entirely centered around infrastructures CRUDing individual tiddlers. Currently, I see TiddlyWiki 5 talking to...

  1. a node.js server
  2. a TiddlyWeb server
  3. a google drive (via Google Apps Script in TiddlyDrive)

To which degree authentication layers and access controls can be implemented in either enviroment needs exploring. Any other server-side not mentioned?

Maybe @PoulStaugaard is interested in the necessary creating syncer module(s) that allow porting GieWiki to TiddlyWiki 5 and thus leverage Google App Engine as yet another tiddler store.

RichShumaker commented 9 years ago

Another Rabbit Hole found. As I stated on the last GitHub thread. I need a way to implement TW5 on a Raspberry Pi which would be a huge opportunity for TW5. There are millions of RasPi's and having an easy way to add TW5 for a group using one would be very helpful. TW5 is great for taking notes and keeping data stored so having it on a RasPi for a classroom would be very helpful for the students. Since TiddlyWeb is based on Python and Python is the primary language on the RasPi I wonder if there might be a synergy for help on the RasPi side of things.

Azrael808 commented 9 years ago

If there's anything I can do to assist in the development of this feature, please let me know.

I have been working on spinning up TW5 as a node.js application in a Docker container, which makes it pretty easy for me to push this to Elastic Beanstalk if we want something that we can all work on. I am primarily a sysadmin, so I would be quite far out of my comfort zone trying to develop multi-user functionality myself, but I'm happy to lend a hand wherever; I just need to be pointed in the right direction!

tobibeer commented 9 years ago

@Azrael808, could you perhaps publish an article somewhere on the details of what you have implemented, with a few screenshots / diagrams?

Azrael808 commented 9 years ago

@tobibeer - it's not particularly complex at the moment, just a single Docker container running TW5 on node.js. I've created a gist of the relevant files, which I hope is useful:

https://gist.github.com/Azrael808/8823aeb9608c23ec092d

Please let me know if you need additional info. :)

tobibeer commented 9 years ago

The thing is, I'm not a *nix user atm, so the general concept of a "docker container" escapes me.

Azrael808 commented 9 years ago

@tobibeer ah, apologies... You can think of a container as a (very) lightweight virtual machine. It's not actually a VM, but an environment that's compartmentalised from the operating system at the kernel level.

The Dockerfile is used to build the container; each step in the file is executed in turn to build an image. The final line in that file (CMD) is what's executed when you run that particular container. In this case, it's a custom startup script (also in that gist) I quickly wrote to fire up TW5.

I am running this particular container locally atm, but because Elastic Beanstalk supports Docker now, it would be easy enough to get this running in the cloud. :smile:

Azrael808 commented 9 years ago

Is the #tiddlywiki IRC channel used by many people here? It might be a good place to chat if we want to collaborate closely.

tobibeer commented 9 years ago

IRC — I'm never there, but that's just me

Azrael808 commented 9 years ago

@tobibeer heh, no matter; I'm used to jumping into them because many of the tools/products I use often have one. :smile:

WRT the multi-user stuff, something I was trying to figure out is if TW5 should maintain an internal list of users, or if this should be delegated to something like LDAP? I'm all for not re-inventing the wheel, so using an LDAP server makes sense to me. However, I could envision a situation where a less-techie individual might want to spin up a TW5 instance that supported multiple users.

Again, if it helps, I'm working on spinning up a directory server in EC2, which I'd be happy to test TW5 against once the necessary changes have been made.

Azrael808 commented 9 years ago

Update: over the past month or so, I have been working to automate the instantiation of one of the scenarios described in this thread. Specifically:

                     +------------------------------+
                     |         EC2 Instance         |
+--------------+     |   +-----+   +-------------+  |
|Client Browser| ----+-->|Nginx|-->|TW5 on NodeJS|  |
+--------------+     |   +-----+   +-------------+  |
                     |      |                       |
                     +------+-----------------------+
                            |
                    User Authentication
                         via LDAP
                            |     +------------------------------+
                            |     |         EC2 Instance         |
                            |     |     +--------------------+   |
                            +-----+---->|389 Directory Server|   |
                                  |     +--------------------+   |
                                  +------------------------------+

This was after a couple of conversations with @Jermolene about the best way(s) to implement a multi-user system for TW5. The above example hands off the authentication process to Nginx, which currently passes an Authorization header back to TW5 with each successfully authenticated request.

IDK enough about the process of coding a layer of access control in TW5 to know if the above information is enough for TiddlyWiki? Specifically, the Authorization header, which appears to simply be the user credentials encoded in base64.

I'm going to white-label my Chef cookbooks/recipes and get them up here on Github; @RichShumaker you might find these useful for instantiating a TW5 instance on a Pi. I actually have access to a couple at home, so I might give them a go.

pmario commented 9 years ago

Interesting approach.

Azrael808 commented 9 years ago

Here's the Chef cookbook I promised: https://github.com/Azrael808/chef-tiddlywiki5

It still needs a bit of work, but I'll be sure to keep updating it as and when needed.

sukima commented 9 years ago

I can imagine that (assuming that the nginx layer providing a Authorization is enough to validate the user's access to) then the node.js code for TW5 could easily filter out tiddlers which do or do not have a published metadata flag. It could also block POST or PUT requests to tiddlers that are filtered out.

Obviously this doesn't offer any kind of role base access control but it's enough to have a do or do not level of visibility to the data on a per tiddler basis.

PS: Love the ASCII Art @Azrael808

Jermolene commented 9 years ago

Hi @Azrael808 this is very, very cool.

IDK enough about the process of coding a layer of access control in TW5 to know if the above information is enough for TiddlyWiki? Specifically, the Authorization header, which appears to simply be the user credentials encoded in base64.

As @sukima implies, ideally TW5 would be able to extract a human readable username from the headers (and perhaps a displayname), and get a list of the groups/roles the user is assigned to. Do you think that would be possible?

But in terms of getting things working with what we've got for the simple initial scenario, presumably we could just store the authorization header values for each of your team members.

To set it up, we'll need two wiki folders: team and published. The tiddlywiki.info file for the team wiki folder would have an includeWikis field referencing the published wiki. There would also be a new authorizedUsers property containing an array of the authorization header values for the team members.

The HTTP server mechanism would be modified to perform security checks on each tiddler access according to the settings of the original wiki folder containing the tiddler. It would also handle assigning new tiddlers to the correct wiki folder. (All of this would be done by implementing the existing "bag" semantics of TiddlyWeb).

Then, we'd need a way for team members to move unpublished tiddlers into the published wiki.

I'm going to give the cookbook a try. New territory for me so I may ask lots of stupid questions over at https://github.com/Azrael808/chef-tiddlywiki5

Azrael808 commented 9 years ago

Thanks for the ASCII art love @sukima !

@Jermolene I will have a think about how we can expose the groups a user is a member of... I did realise this today that the only info TW5 would have access to in the above scenario is the user ID and their password. Maybe there's a way to have the group memberships extracted and added to header info... I'll do some digging.

Please, feel free to bother me... It'll be cool to flesh that TW5 cookbook out as and when people report issues/raise feature requests! One major thing I've noticed when testing the cookbook is that if you want to try the LDAP stuff, you'll want to have something already setup for the Nginx module to bind to... I am considering adding a recipe to the cookbook to spin up a test instance of 389 server, as that might help people who don't have access to such a thing.

Jermolene commented 9 years ago

One major thing I've noticed when testing the cookbook is that if you want to try the LDAP stuff, you'll want to have something already setup for the Nginx module to bind to... I am considering adding a recipe to the cookbook to spin up a test instance of 389 server, as that might help people who don't have access to such a thing.

Ah, that would be me - I don't have an LDAP server handy, so it would indeed be awesome if you were able to add a recipe that sets up a test instance with a couple of accounts.

RichShumaker commented 9 years ago

I am interested in testing on my Raspberry Pi. I can easily set up Nginx and node.js on the RasPi and I can get TiddlyWiki 5 running as well(I have used LAMP not Nginx so hopefully I won't hit too many speed bumps).

From there I will be lost as to the next thing to set up. If you have any suggestions on things to read up on or places to learn about setting this up I would greatly appreciate that. Thank you very much for creating this.

Here are my 'user' ideas(I have not done much development just talked to developers)

  1. Dual keys for the server side and client side with a handshake before sending data.
  2. Perform the authorization as a separate TiddlyWiki 5 with encrypted data(that way if they ping the TW5 directly they see nothing without the password) - Once the original decryption key is created then it creates a 'cookie' in the browser until the next session. 2a. A variant on this idea is a TW5 inside a TW5 something like a transclusion
  3. Obviously you have discussed this but I am not sure how to implement - User Levels so you can protect Tiddlers and TW's from unauthorized users - Read, Write, Delete(linux 777 style?)
  4. Create a 'protected' class or tiddler and those 'protected' tiddlers do not render - This is similar to Number 2 except it is all still the same TW with Tiddlers but TW knows not to show the 'special' tiddlers to the average person only to admins with the proper rights.
  5. Most systems have 2 sides, a user side and an admin side - Again this is similar to Number 2 as you would have 2 TiddlyWiki's or maybe just 2 views of the same TW. Again I am not sure how you would 'define' the Tiddlers. I can think of 2 or 3 ways using TAGS, field names & field values, and special Tiddler Names.

All of the ideas are spackle I am throwing at the wall to see if any stick. They are 'brainstorming' ideas as I don't do much code I am an advanced NOOB.

Your work on this is greatly appreciated and as I said earlier thank you very much for working on this.

Rich Shumaker

Azrael808 commented 9 years ago

@Jermolene et voila: https://github.com/Azrael808/chef-tiddlywiki5/tree/ldap_server

Hopefully that should get you a local installation with a directory server in the background... There's only one user atm:

Username: testuser Password: Testing1234

@RichShumaker it sounds like you're on track to having this running on a Pi. Given that all Nginx is doing in my basic Chef recipe is acting as a proxy, any webserver will do (as you've noted). If you have any more questions though, please throw them my way: I'm a sysadmin first and foremost, so this is my area of expertise. :smile:

Azrael808 commented 9 years ago

While researching form-based authentication in Nginx, I have happened across this post:

http://puyb.net/2012/12/authentication-for-nginx/

TL;DR - the author is using Nginx to host a bunch of web resources, with a single NodeJS application being used to handle authentication for them all.

This is quite a similar scenario to the one we have here for TW5; maybe a fork of his NodeJS application could be used to not only handle the LDAP auth, but pull out group membership information also and add that information to a cookie... Although, that could potentially be abused quite easily. Here's the Git repo for the authentication app as it stands currently:

https://github.com/Puyb/nginx-auth

Anyway, would love to get some thoughts/feedback on this; trying to keep as much of the authentication-level stuff out of TW5 as possible; maybe this is the solution?

tobibeer commented 9 years ago

Fwiw, authentication seems one major issue where the "everything is a tiddler" approach seems fundamentally inappropriate... unless perhaps we could stuff them into local storage and read them from there as well.

Azrael808 commented 9 years ago

FYI: I have struggled today to modify the NodeJS auth application I linked to previously; I tried integrating this: https://www.npmjs.com/package/ldapauth

However, I found the examples difficult to understand and I couldn't tell what I was supposed to be replacing/augmenting within the nginx-auth application!

IDK if anybody here fancies giving this a go? In the mean time, I'm going to work on adding a backend storage recipe to my cookbook; using the CouchDB plugin.

RichShumaker commented 9 years ago

Could a TW instance be created under node.js that is encrypted and is used for Users and Passwords? The encryption is to keep people from directly linking to the user names and passwords and getting plain text data back. Also it is it's own separate TW as you don't want it 'included' in everyones TW. The idea is to use TW as the back end database. Then we could use TW ability to add and remove as the front end for the user management. Also we could use either Tagging or Fields as the permissions to modify on a TW or Tiddler level.

Maybe when any TW loads there needs to be a check on this "User Password TW" to see if it is implemented. If that mechanism is not implemented it is ignored.

And unfortunately I do not have the technical expertise to create this.

Rich Shumaker

Azrael808 commented 9 years ago

@RichShumaker that would probably work well for an isolated TW5 installation, assuming all your points are accurate - I don't have enough knowledge about TW5 presently to say otherwise! :smile:

The use case I was aiming for requires the use of an external directory service for user data because it's likely I'll be combining the TW5 installation with other applications/services, which will need something like LDAP/Active Directory for user management.

RichShumaker commented 9 years ago

@Azrael808 That makes perfect sense and I understand why it wouldn't work in your environment. TW5 would have to be seen as an existing Db for whatever application you were using and TW5 does not have the 'hooks' that you get with most databases as it is not really a database.

Jermolene commented 9 years ago

@Azrael808 I'm finally trying https://github.com/Azrael808/chef-tiddlywiki5/tree/ldap_server, apologies for the delay.

I've got right to the end, where I can connect to http://tiddlywiki5.example.com/index.html, and see the text "It works!", but I can't figure out how to connect to the TiddlyWiki instance. Also, I wasn't sure how to safely stop the VM in VirtualBox; is there a polite shutdown?

Many thanks for your help.

Azrael808 commented 9 years ago

Hey @Jermolene I think I neglected to include an all important Vagrantfile setting: https://github.com/Azrael808/chef-tiddlywiki5/blob/ldap_auth/Vagrantfile#L41

Now you should be able to run vagrant up and have the VM present it's Nginx installation over port 8080: browsing to http://localhost:8080 should bring up the TW5 instance.

WRT managing Vagrant VMs:

vagrant halt - issues an ACPI soft-off, causing the machine to gracefully shut down. vagrant suspend - pauses the VM.

Jermolene commented 9 years ago

Excellent, thanks @Azrael808.

I patched that line into the Vagrantfile of my fork, and then ran vagrant up. Visiting http://tiddlywiki5.com:8080 is now giving me a working instance, yay!

However, it's not saving changes, I think because the tiddlywiki.info file in the root of the wiki folder doesn't include the two plugins that are needed: "tiddlywiki/tiddlyweb" and "tiddlywiki/filesystem". See https://github.com/Jermolene/TiddlyWiki5/blob/master/editions/server/tiddlywiki.info for an example. I can patch that temporarily by SSH-ing into the vagrant instance.

How do I experiment with using the LDAP authentication?

Jermolene commented 9 years ago

@Azrael808 I edited /srv/tw5/shared/wiki/tiddlywiki.info via nano over SSH, and then did vagrant halt and vagrant up. I expected the TW5 instance to restart with the plugins I had added to tiddlywiki.info, but there was no change; just the $:/core plugin was loaded.

Azrael808 commented 9 years ago

Hah, I've been a complete fool and given you the wrong branch to work from...

https://github.com/Azrael808/chef-tiddlywiki5/tree/ldap_server

That should set you up nicely! :smile:

Azrael808 commented 9 years ago

@Jermolene - I'm intrigued as to why those plugins you mentioned aren't installed by default. The recipe is pulling the code directly from your Github repo:

https://github.com/Azrael808/chef-tiddlywiki5/blob/ldap_server/recipes/nodejs.rb#L25

Maybe the issue lies in how the TW5 instance is being initialised?

https://github.com/Azrael808/chef-tiddlywiki5/blob/ldap_server/recipes/nodejs.rb#L30

Or with how the NodeJS application is started:

https://github.com/Azrael808/chef-tiddlywiki5/blob/ldap_server/recipes/nodejs.rb#L33

Any thoughts?

tgrosinger commented 8 years ago

@Azrael808 @Jermolene It's been a while. What are you two up to in regards to this ticket? Any updates I could hear about before embarking down this path myself? I too am very interested in a multi-user story, especially the ability to have read-only tiddlers which I can edit while authenticated, but others can only view.

Thanks.

BramChen commented 8 years ago

Hi @Azrael808

Maybe the issue lies in how the TW5 instance is being initialised?

https://github.com/Azrael808/chef-tiddlywiki5/blob/ldap_server/recipes/nodejs.rb#L30

You need specify the server edition to be initialized by using command --init server, like this:

 migration_command "node tiddlywiki.js #{node['tiddlywiki5']['tw5_path']}/shared/wiki/ --init server"
pmario commented 7 years ago

@Jermolene .. imo should be labeled "discussion" and "feature request"