diff --git a/SoObjects/SOGo/SOGoUserSettings.h b/SoObjects/SOGo/SOGoUserSettings.h index 973022660..280943953 100644 --- a/SoObjects/SOGo/SOGoUserSettings.h +++ b/SoObjects/SOGo/SOGoUserSettings.h @@ -26,6 +26,7 @@ @class NSArray; @class NSMutableDictionary; @class NSString; +@class NSNumber; @interface SOGoUserSettings : SOGoDefaultsSource @@ -35,6 +36,8 @@ - (NSArray *) subscribedAddressBooks; - (NSString *) userPrivateSalt; - (NSString *) userPublicSalt; +- (void)enableForceResetPassword; +- (void)disableForceResetPassword; @end diff --git a/SoObjects/SOGo/SOGoUserSettings.m b/SoObjects/SOGo/SOGoUserSettings.m index f03b77488..f4f6d58a6 100644 --- a/SoObjects/SOGo/SOGoUserSettings.m +++ b/SoObjects/SOGo/SOGoUserSettings.m @@ -116,4 +116,19 @@ static Class SOGoUserProfileKlass = Nil; return salt; } +- (void) enableForceResetPassword +{ + [self setObject: [NSNumber numberWithInt:1] forKey: @"ForceResetPassword"]; + [self synchronize]; +} + +- (void) disableForceResetPassword +{ + if ([self objectForKey: @"ForceResetPassword"]) { + [self removeObjectForKey: @"ForceResetPassword"]; + [self synchronize]; + } +} + + @end diff --git a/UI/MainUI/SOGoRootPage.m b/UI/MainUI/SOGoRootPage.m index fdd9569ea..d9569dbbf 100644 --- a/UI/MainUI/SOGoRootPage.m +++ b/UI/MainUI/SOGoRootPage.m @@ -254,6 +254,7 @@ static const NSString *kJwtKey = @"jwt"; loggedInUser = [SOGoUser userWithLogin: username]; ud = [loggedInUser userDefaults]; + us = [loggedInUser userSettings]; #if defined(MFA_CONFIG) if ([ud totpEnabled]) @@ -309,7 +310,6 @@ static const NSString *kJwtKey = @"jwt"; } // if ([verificationCode length] == 6 && [verificationCode unsignedIntValue] > 0) else { - us = [loggedInUser userSettings]; if ([us dictionaryForKey: @"General"] && ![[us dictionaryForKey: @"General"] objectForKey: @"PrivateSalt"]) { // Since v5.3.0, a new salt is used for TOTP. If it's missing, disable TOTP and alert the user. @@ -331,39 +331,43 @@ static const NSString *kJwtKey = @"jwt"; } } #endif + + if ([us objectForKey: @"ForceResetPassword"]) { + response = [self _responseWithLDAPPolicyError: PolicyPasswordExpired]; + } else { + [self _checkAutoReloadWebCalendars: loggedInUser]; - [self _checkAutoReloadWebCalendars: loggedInUser]; + [json setObject: [loggedInUser cn] + forKey: @"cn"]; + [json setObject: [NSNumber numberWithInt: expire] + forKey: @"expire"]; + [json setObject: [NSNumber numberWithInt: grace] + forKey: @"grace"]; - [json setObject: [loggedInUser cn] - forKey: @"cn"]; - [json setObject: [NSNumber numberWithInt: expire] - forKey: @"expire"]; - [json setObject: [NSNumber numberWithInt: grace] - forKey: @"grace"]; + response = [self responseWithStatus: 200 + andJSONRepresentation: json]; - response = [self responseWithStatus: 200 - andJSONRepresentation: json]; + authCookie = [auth cookieWithUsername: username + andPassword: password + inContext: context]; + [response addCookie: authCookie]; - authCookie = [auth cookieWithUsername: username - andPassword: password - inContext: context]; - [response addCookie: authCookie]; + // We prepare the XSRF protection cookie + creds = [auth parseCredentials: [authCookie value]]; + xsrfCookie = [WOCookie cookieWithName: @"XSRF-TOKEN" + value: [[SOGoSession valueForSessionKey: [creds lastObject]] asSHA1String]]; + [xsrfCookie setPath: [NSString stringWithFormat: @"/%@/", [[context request] applicationName]]]; + [response addCookie: xsrfCookie]; - // We prepare the XSRF protection cookie - creds = [auth parseCredentials: [authCookie value]]; - xsrfCookie = [WOCookie cookieWithName: @"XSRF-TOKEN" - value: [[SOGoSession valueForSessionKey: [creds lastObject]] asSHA1String]]; - [xsrfCookie setPath: [NSString stringWithFormat: @"/%@/", [[context request] applicationName]]]; - [response addCookie: xsrfCookie]; - - supportedLanguages = [[SOGoSystemDefaults sharedSystemDefaults] - supportedLanguages]; - [context setActiveUser: loggedInUser]; - if (language && [supportedLanguages containsObject: language]) - { - [ud setLanguage: language]; - [ud synchronize]; - } + supportedLanguages = [[SOGoSystemDefaults sharedSystemDefaults] + supportedLanguages]; + [context setActiveUser: loggedInUser]; + if (language && [supportedLanguages containsObject: language]) + { + [ud setLanguage: language]; + [ud synchronize]; + } + } } else { @@ -691,6 +695,8 @@ static const NSString *kJwtKey = @"jwt"; WOResponse *response; WORequest *request; BOOL passwordRecovery; + SOGoUserSettings *us; + SOGoUser *loggedInUser; request = [context request]; message = [[request contentAsString] objectFromJSONString]; @@ -772,6 +778,15 @@ static const NSString *kJwtKey = @"jwt"; username = [NSString stringWithFormat: @"%@@%@", username, domain]; } + loggedInUser = [SOGoUser userWithLogin: username]; + + if (loggedInUser) { + us = [loggedInUser userSettings]; + if (us && [us objectForKey: @"ForceResetPassword"]) { + [us disableForceResetPassword]; + } + } + response = [self responseWith204]; if (!passwordRecovery) { authCookie = [auth cookieWithUsername: username diff --git a/UI/WebServerResources/js/Main/Main.app.js b/UI/WebServerResources/js/Main/Main.app.js index 3978a346c..24cf00acd 100644 --- a/UI/WebServerResources/js/Main/Main.app.js +++ b/UI/WebServerResources/js/Main/Main.app.js @@ -206,7 +206,9 @@ this.passwords.newPasswordConfirmation && this.passwords.newPasswordConfirmation.length && this.passwords.newPassword == this.passwords.newPasswordConfirmation && ((this.isInPasswordRecoveryMode()) || - (!this.loginState && this.passwords.oldPassword && this.passwords.oldPassword.length > 0))) + (!this.loginState && this.passwords.oldPassword && this.passwords.oldPassword.length > 0) || + ('passwordchange' == this.loginState && this.passwords.oldPassword && this.passwords.oldPassword.length > 0) + )) return true; return false;