MoinMoin and Authentication
Currently you have two options with moin & logins:
- use the build in login system, which is not really secure
- you can login by ID only
- the cookie is the plain ID
- enable HTTP Authentication by configuring your webserver to do it
- secures everything
- everyone needs accounts
- you need an account to get into userprefs, but generating an account for the webserver does not make a moin account.
IF we think about the origin and purpose of a wiki, this might seem enough, but for a closed, secured wiki, this has too much shortcomings.
Cornerpoints for a HTTP Auth inside Moin
- should be configurable (new auth scheme, the old must be still operational)
- both Basic and Digest auth should be available
- a session Cookie, that is unique for the connection (check ip), will be used.
- fallback to the Cookie is HTTP Auth.
way to map external usernames to internal WikiNames
Another thing would prove very useful for many people: accessing custom databases for user storage:
- hooks for linking in external authentication resources (LDAP, SomeSQL, ...)
- Base class which does username lookups and password checking. Default class that is based on moins user data files.
see RefactoringProposals for a simple way to split User class
Security considerations
- don't allow logins with user ID only!
- don't store plain IDs in the Session Cookie
- this means: there is still some id inside, but because of IP/BrowserID/whatever checking, it won't be easy to steal cookies (not as easy as it is now!)
- when creating a new account, user gets sent a validation code he needs to activate the account. same thing could be used to recover a lost password. naturally this should be configureable.
General Flow of Auth
The following 'flowchart' describes how the authentication process in moin should work:
Notes:
- If the user has no session and no auth, moin sends back an auth request (Authentication + Status header) plus the standard access denied message page. the browser now displays the password dialog. Either the user enters some and a new request is send, or the user hits cancel and the message page is displayed.
- If the user does not save cookies, moin will always respond with an auth request for protected pages. If the user had entered auth before, any standard browser will automatically respond with the saved auth. So a user without cookies still has to enter auth only one time.
The flowchart above does not establish a session if the user provided a valid username and password and the page acl does not allow this user. This could be changed to the red branch in the drawing.
What needs to be done?
- change Request classes:
need Authentication header (RewriteRule for cgi, FastCGI -pass-header, Twisted getHeaders, mod_py headers_in)
- add methods for authentication? (perhaps better in a extra module, all this thing needs are the headers and the ability to set headers)
- authentication module
- check auth
- request auth
- create sessions
- sessions are checked against the IP and some more unique things of the user session, so capturing is not possible
- session cookies are browser lifetime only!
- check sessions
- hooks in wikiacl may method
- if the answer would be no because of no session, try to establish one
- I would do this in another branch, since ui is not related to auth. The only change maybe is the login page, which we don't need for http auth.
Thats true, the layout of the UserPreferences page does not really influence the new auth methods. Ok.
- I would do this in another branch, since ui is not related to auth. The only change maybe is the login page, which we don't need for http auth.
Tuneability
this is just a brainstorm for what could be configureable
- newauth_enabled
- enables new authentication with moin doing HTTP Auth. Automatically disables the use of the MOIN_ID cookie and login action with uid only for security reasons.
- newauth_authtype
use Basic or Digest auth
- is digest widely enough supported meanwhile?
- don't know, but it's just an option
- is digest widely enough supported meanwhile?
- newauth_duplicate_sessions
allow duplicate sessions with the same WikiName
- newauth_ignore_ip
- don't check session IP (roaming sessions)
- newauth_sessiondb_file
- where to save sessions (for cgi or restarted long runs)
- just use caching module or data/cache/ location, no config needed
- true
- just use caching module or data/cache/ location, no config needed
- newauth_sessiondb_type
- pickle or dbhash?
- pickle!?
- bsddb/dbhash is faster in access
- pickle!?
- newauth_session_timeout
- maximum time between requests
- maybe use some fixed value making sense
- yeah, this option will have a default value, but it should be configureable
- maybe use some fixed value making sense
- newauth_cookie_lifetime
- how long is the cookie saved? (default browserlife, should be less than session_timeout)
- we have already some cookie lifetime setting, can that be reused?
- this replaces the old one
- we have already some cookie lifetime setting, can that be reused?
- newauth_validator
- set the validator class to use (to hook up external auth sources)
- ??
- to hook up external auth sources... LDAP, etc...
- ??
Useful Options for classic auth:
- auth_automap
automatically store a mapping to REMOTE_USER when creating a new login (mapping a non wiki external auth name to the WikiName just created).
Q & A
- Why use a session cookie? Cookies are not secure!
- Well, moin does currently use a unchecked MOIN_ID cookie. So switching to a checked session id cookie will not get more insecure than it is now. It will be more secure actually, cause:
- the session id changes with every login
- the session id is tied to ip, browser id, ... and can't be stolen easily
- faking a session id is near to impossible, depending on the width of the key.
- Do you think sending password and username with every request is more secure? It is not, cause it makes it easier to actually sniff the right information out of your transactions.
- Just switch to SSL connections to get more security with every moin wiki.
- Well, moin does currently use a unchecked MOIN_ID cookie. So switching to a checked session id cookie will not get more insecure than it is now. It will be more secure actually, cause:
- How can you do authentication in CGI?
Send Status: 401 plus WWW-Authenticate: basic realm="Test" and the browser will prompt with realm for username and password. These are send as Authorization header back to the server.
- now you just need to get the headers. Easy with mod_python or twisted, (fast-)cgi is a bit more tricky:
- either use a rewrite rule (for cgi, works for FastCGI, too):
RewriteCond %{HTTP:Authorization} ^(.*)$ RewriteRule ^/moin.cgi(.*)$ /moin.cgi$1 [e=HTTP_CGI_AUTHORIZATION:%1,l]
or add the -pass-header Authorization option to the FastCGI config.
- don't know if this is possible with other (non-apache) webservers.
- either use a rewrite rule (for cgi, works for FastCGI, too):
Integration in moin--main--1.3
- TLA Branch
ograf@bitart.de--2004-local/moin--newauth--1.3
- Live Examples
- none
TODO: marks finished steps
- move cookie handling into an extra module
- add MOIN_SESSION to replace MOIN_ID
Discussion
- Why do you want to fallback to HTTP basic auth? IMHO falling back to link rewriting is much better.
- cause its not needed. the browser does it on its own.
but adding an option to use link rewrites instead of cookies might be useful anyways, so perhaps I spend a thought or two on it...
Need for client-side hashing
A major shortcoming, I think, is that Moin currently lacks client side hashing of passwords. This is a disservice not to the installers of Moin, but to the non-technical users of Moin wikis who frequently reuse the same passwords for many applications. Ethernet sniffers can easily pick the password out of an office LAN and thus a stock installation of Moin can be detremental for the security of many applications and the user.
An obvious answer is just switch to SSL connections. But if this is the answer, it should become part of the default installation procedure and there should be big yellow warning signs warning of the potential problem when not using SSL. However, the same problem exists as the web site has access to the raw user password. From the user's point of view, it is better to have client side hashing and never have any web site have access to a raw password.
There is a Javascript procedure for SHA-1 encryption at http://pajhome.org.uk/crypt/md5. A way to implementing this is to store a hashed password formed by the cancatenation of
- user ID
- user password
application consistent salt -- a small string of junk (MoinMoin)
Using all three strings together results in unique hashes for the same password and the same user ID across multiple applications. Thus, capturing a hashed user password will be of no value in attacking other applications used by that user.
using the above, a page with a login form would include hidden fields consisting of the application consistent salt and some unique number such as a modified timestamp. When the form submit button is clicked, the client hashes ID, password, and salt to create the hashed password, and then hashes the result with the unique number. The resulting hash is passed by overwriting the password field.
The server side must remember the unique number by associating it with a temporary session cookie. When the incoming login form arrives, it uses the login ID to retrieve the stored hashed password and then hashes the stored password against the unique number associated with the session cookie. The resulting hash is compared against the incoming password. If it matches, a session cookie is created.
The weak point (where an SSL connection would be useful) is the change password transaction. Here the new hashed password must be transmitted without modification. Capturing the new hashed password could be useful to an attacker, but the opportunity does not come often and the result is useful only for an attack on the target site.
Roger Haase
Separation of Login from UserPreferences
A starting point is that I dislike HTTP Authentication. It is ugly, and confusing to novice users because the login messagebox is not obviously and elegantly connected to the design of the web site.
What I would like to see in this design, but do not see or understand, is a separation of login from user preferences. I think I want a UserLogin page that would contain a UserLogin macro where the login macro returns the html form part of the rendered page. The UserLogin page would be accessed by clicking a Login button or attempting to access a protected page.
Clicking the form submit button would normally reexecute the UserLogin page and the UserLogin macro would discover and process the incoming ID and password fields, validate the user, and if valid: establish the session cookie, and redirect the user's browser to the FrontPage or prior protected page (A potential hard part is macros seem to get control too late to issues a 302). Should user validation fail, the UserLogin macro regenerates the login form. The default UserLogin macro should allow new registrations by filling in an email address and clicking a new registration button.
The session cookie value would look similar to the current moin-ID and would be freshly generated for each new validated session. A server-side dictionary would connect the session-ID to a user name and perhaps an IP-address or browser name to be used for additional validation on every incoming request.
The UserPreference macro would be simplified to show and change only user preferences.
For those who dislike HTTP Authentication, the above provides new opportunities for easy customization and would enable sites to provide even more security by disallowing self-registration and validating logins from an external database.
I do not like HTTP auth as the only system either (but it is needed for easy 3rd party authentication integration). IMHO we just need to add a session system to MoinMoin and redesign the UserPreferences dialog. That would defeat all security problems and protect the secret user ID. It does not necessarily involve a redesign to completly use HTTP auth. -- AlexanderSchremmer 2005-01-03 16:13:34
Please note that thats exactly the way I see this: a better and independent session handling plus plugable authentication modules, that interface to some backend database (files, mysql, ldap) and do auth in a certain way (http auth, hashed javascript stuff, whatever you imagine). My preference is file and mysql based http auth, but after the API stands you are free to add whatever you like... -- OliverGraf 2005-01-03 20:55:20
I only can support a way to use pluggable modules. Our goal is to integrate wikis into a greater organisation. This is a typical intranet and user as well as groups are managed by active directory (LDAP). Therefore it would be much more easier to manage acls et al within LDAP. A pluggable authentication module shoud suffer our needs. -- CorneliusScheffel 2005-02-16 07:40:00
Modularization and separation of authentication and authorization
There should be a pluggable architecture for both authentication and authorization, but they must be separate. This way you can authenticate with HTTP Basic auth, GSS, Cookie or Session (login form with username and password) while authorization can be done either using the traditional "Moin way" of defining groups and ACL's or perhaps a totally different type of authorization backend. It's important not to treat authentication as "login", because there are many instances of authentication where you do not use logins at all (kerberos ticket forwarding, etc). Authentication should only tell the system "I really am this user", but what the user may do with the system is for the authorization API to take care of.
The important things to remember are:
- Authentication and authorization must be separate.
- User information (like prefs) must be separated from authentication and authorization mechanisms. (just like the above statement says)
Making the authentication API separate and pluggable would be a good first step.