First Logins, folder generation, other user backends
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 36.9k
- Forks
- 5.2k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 713
Description
How to use GitHub
- Please use the 👍 reaction to show that you are interested into the same feature.
- Please don't comment if you have no relevant information to add. It's just extra noise for everyone subscribed to this issue.
- Subscribe to receive notifications on status change and new comments.
Is your feature request related to a problem? Please describe.
User Alice logs in for the first time with user_saml. As expected their file system is prepared with the contents of the skeleton directory. What they are perhaps not aware about is, that user_saml is duplicating folder generation code, because it has to override the login mechanism.
User Bob logs in for the first time with user_ldap. Due to the password policy they have to change the initial password after first login. Having done that Bob is redirected to the files app - but is greeted with a web page of death, because the file system was not generated. Bob calls his sysadmin.
User Cecile does the same as Bob. But because their sysadmin has patched the code, Nextcloud works for them, alas the directory is not filled with the default content. Cecile cannot read the "first 7 things to do after your first login.pdf" from their organization as instructed.
Initialization of the user directory happens in \OC\User\Session::prepareUserLogin() and is called after the postLogin events are handled. user_saml is beyond that, the described user_ldap scenario forces a redirect to its password renew controller. There are other issues reported, where this issue occured even with the local backend.
User backends following the regular login chain do not know whether the user logs in for the first time or not, because the information is withhold and the new login date is already written to the database. This is also questionable, because as apps can cancel the login during postLogin event handling.
Describe the solution you'd like
- The user folder initialization should be unbound from the login process. It shall be possible that this can happen at a later point, and/or be able to be triggered by another user backend.
- Updating the user last login time could be a late part of the
OC\Authentication\Login\Chain. It needs to be ensured that a delayed setting of this timestamp does not cause regressions. - The user folder initialization could be part of the
OC\Authentication\Login\Chain(just before the login timestamp is set). - The base.php does it's own logic with
handleLogin. The relevant parts might need to switch to using theOC\Authentication\Login\Chain. - The concrete user folder initialization method should still be part of the
OC\User\Session, but become public and part ofOCP\IUserSession, so it can be called out of context. Or, it shall be evaluated whether apps like user_saml should get a chance to trigger the relevant parts of the login chain handling tasks after the login was irrevocably successful. - a new [Login]RedirectException shall be an alternate way of cancelling the login process (currently it is LoginException) and redirect to a specified URL, instead of showing the error page. This avoids that apps have to use
exit(0)to solve this case, after sending headers themselves. The LoginController ought to catch it.
Additional context
This is eventually driven by a one line patch:
diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php
index 4ec7b27017..d3aa4d3695 100644
--- a/apps/user_ldap/lib/User/User.php
+++ b/apps/user_ldap/lib/User/User.php
@@ -752,6 +752,7 @@ class User {
//handle pwdReset attribute
if (!empty($pwdReset) && $pwdReset[0] === 'TRUE') { //user must change his password
$this->config->setUserValue($uid, 'user_ldap', 'needsPasswordReset', 'true');
+ \OC::$server->getUserFolder($uid); // ensure user folder exists on first login
header('Location: '.\OC::$server->getURLGenerator()->linkToRouteAbsolute(
'user_ldap.renewPassword.showRenewPasswordForm', ['user' => $uid]));
exit();
@rullzer @ChristophWurst this is my brain dump for today, and it well might not be the final state. I'll certainly sleep over it. Do you have thoughts about it?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading OC\User\Session::prepareUserLogin(), the OC\Authentication\Login\Chain, and the login flow in base.php and LoginController. Review apps/user_ldap/lib/User/User.php for the password-renewal redirect and compare the proposed folder initialization and LoginRedirectException paths. Done requires an agreed design covering first-login initialization, delayed login timestamps, backend-triggered flows, and redirect handling.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- authentication, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100