joomla/joomla-cms — pull request #2749 by Bakual (2014-01-01 14:06:45+00:00)
Title: More fixes and cleanup for cookie authentication (aka remember me)

### Issue
There are various issues with the current remember-me feature. However the main one is that the code is spread over three plugins. The `remember` system plugin, the `cookie` authentication plugin and the `joomla` user plugin. This is mainly the case because the needed events are not triggered for each plugin group for sure. While this worked it made the code complicated and also in some cases duplicated that it was getting hard to understand what is going on. And complicate code tends to let bugs slip in. And there are a few of them. For example when using the same browser on different computers you could get unexpected results.

### Testing and tl;dr
Make sure the cookie authentication works as expected, that means after closing the browser and reopening you should be logged in again automatically.
After login, the first part (divided by a dot) in the cookie should change and the second part should stay the same.
After logout, the cookie is deleted.
In the #__user_keys table, the hashed token has to change after each login, the series should stay the same.
After logout, the entries are removed.

### Proposed Solution and technical stuff
This PR moves all code into the authentication `cookie` plugin.
The `joomla` user plugin has no code anymore related to cookie authentication.
The system `remember` plugin is still needed, but has no code anymore with actually dealing with the authentication. All it does is check for a specific cookie (if no user is logged in already), and if it exists it will initialise the login process without further checks, handing the authentication process to whatever plugin will do it. Yes that means you could exchange the core cookie plugin with a 3rd party one as long as it will use the same cookie name.
The `remember` system plugin will also make sure authentication plugins are loaded for the onUserAfterLogout event.
Other than that the system plugin will not do anything.

There are also some other changes:
* The plugin parameters and language strings moved from the `remember` plugin to the `cookie` plugin. I've written an MySQL query to move them during an update so this should be backward compatible. The other database queries would still be needed.
* This allowed to remove some unneeded special handling in the application which basically passed the remember parameters as options to the authentication plugins.
* Deprecated methods in JUserHelper which are very specific to the cookie authentication plugin. It is now dealt with directly in the plugin.
* Removed the uastring part in the cookie value. It's the same string as the cookie name and thus only redundant information. It's still stored in the database and is used to validate the cookie, but instead of relying on the cookie value, we now check against the cookie name.
* The token is stored in the database as hash using the same method we use for the password. The reason is that in case someone has access to the database, he can't just read out the token directly.

There are additionally some improvements to how the cookie is authenticated. For that I have to explain the system a bit:
#### How it works
If the remember-me checkbox is set when an user has successfully logged in, the plugin will create a cookie with the following information:
**cookie name:** The name of the cookie is created using `JUserHelper::getShortHashedUserAgent()` which generates a hash based on the Joomla URL and the browser user agent (without version part). It's just a way to generate a unique identifier on a given computer. This name doesn't have to be secure and can in fact easily recalculated.
** cookie value:** The value of the cookie consists of two parts, separated by a dot (.). The first part is the `token` and the second part is the `series`. Both are random strings generated using `JUserHelper::genRandomPassword()`. The `token` will be replaced after each successful login, making it a one-time-use "password". The `series` will be the same over the lifespan of the cookie, making it sort of a "user name", it's also unique in the database table.

When that user visits the page again later, the plugin will look for that specific cookie name and load it if present. Then it will check if the series part is valid. After that it will go and verify the token and if successful will look up the username in the database table and log in the user.
When the user logs out, the cookie and all entries for the current series are deleted.

Now the interesting part is what happens when something fails. Obviously when the cookie is not present, nothing happens. When the cookie is present but the series does not match or the value has a wrong format, the cookie will be deleted. If the series matches but the token doesn't validate, we assume an attack and delete all tokens for that user from the database. This case should only happen if the series was either guessed (brute forced) correctly or if the cookie was stolen and used twice (once by attacker and once by victim). This action is logged.