fix(core): Require current password on password change (#285)
Increase security by requiring the current password when changing the password. This increases the security for cases such as XSS, or just a forgotten browser window left open. Fixes #4140pull/287/head
parent
03d8ed5e92
commit
2300fe8aab
|
@ -133,7 +133,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
[loginCookie setPath: [NSString stringWithFormat: @"/%@/", appName]];
|
[loginCookie setPath: [NSString stringWithFormat: @"/%@/", appName]];
|
||||||
|
|
||||||
return loginCookie;
|
return loginCookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,14 +188,14 @@
|
||||||
NSDictionary *params;
|
NSDictionary *params;
|
||||||
NSString *username, *password, *language, *domain, *remoteHost, *verificationCode;
|
NSString *username, *password, *language, *domain, *remoteHost, *verificationCode;
|
||||||
NSArray *supportedLanguages, *creds;
|
NSArray *supportedLanguages, *creds;
|
||||||
|
|
||||||
SOGoPasswordPolicyError err;
|
SOGoPasswordPolicyError err;
|
||||||
int expire, grace;
|
int expire, grace;
|
||||||
BOOL rememberLogin, b;
|
BOOL rememberLogin, b;
|
||||||
|
|
||||||
err = PolicyNoError;
|
err = PolicyNoError;
|
||||||
expire = grace = -1;
|
expire = grace = -1;
|
||||||
|
|
||||||
auth = [[WOApplication application] authenticatorInContext: context];
|
auth = [[WOApplication application] authenticatorInContext: context];
|
||||||
request = [context request];
|
request = [context request];
|
||||||
params = [[request contentAsString] objectFromJSONString];
|
params = [[request contentAsString] objectFromJSONString];
|
||||||
|
@ -209,10 +209,10 @@
|
||||||
/* this will always be set to something more or less useful by
|
/* this will always be set to something more or less useful by
|
||||||
* [WOHttpTransaction applyAdaptorHeadersWithHttpRequest] */
|
* [WOHttpTransaction applyAdaptorHeadersWithHttpRequest] */
|
||||||
remoteHost = [request headerForKey:@"x-webobjects-remote-host"];
|
remoteHost = [request headerForKey:@"x-webobjects-remote-host"];
|
||||||
|
|
||||||
if ((b = [auth checkLogin: username password: password domain: &domain
|
if ((b = [auth checkLogin: username password: password domain: &domain
|
||||||
perr: &err expire: &expire grace: &grace useCache: NO])
|
perr: &err expire: &expire grace: &grace useCache: NO])
|
||||||
&& (err == PolicyNoError)
|
&& (err == PolicyNoError)
|
||||||
// no password policy
|
// no password policy
|
||||||
&& ((expire < 0 && grace < 0) // no password policy or everything is alright
|
&& ((expire < 0 && grace < 0) // no password policy or everything is alright
|
||||||
|| (expire < 0 && grace > 0) // password expired, grace still permits login
|
|| (expire < 0 && grace > 0) // password expired, grace still permits login
|
||||||
|
@ -221,7 +221,7 @@
|
||||||
NSDictionary *json;
|
NSDictionary *json;
|
||||||
|
|
||||||
[self logWithFormat: @"successful login from '%@' for user '%@' - expire = %d grace = %d", remoteHost, username, expire, grace];
|
[self logWithFormat: @"successful login from '%@' for user '%@' - expire = %d grace = %d", remoteHost, username, expire, grace];
|
||||||
|
|
||||||
// We get the proper username for cookie creation. If we are using a multidomain
|
// We get the proper username for cookie creation. If we are using a multidomain
|
||||||
// environment with SOGoEnableDomainBasedUID, we could have to append the domain
|
// environment with SOGoEnableDomainBasedUID, we could have to append the domain
|
||||||
// to the username. Also when SOGoEnableDomainBasedUID is enabled, we could be in
|
// to the username. Also when SOGoEnableDomainBasedUID is enabled, we could be in
|
||||||
|
@ -648,7 +648,7 @@
|
||||||
|
|
||||||
request = [context request];
|
request = [context request];
|
||||||
message = [[request contentAsString] objectFromJSONString];
|
message = [[request contentAsString] objectFromJSONString];
|
||||||
|
|
||||||
auth = [[WOApplication application]
|
auth = [[WOApplication application]
|
||||||
authenticatorInContext: context];
|
authenticatorInContext: context];
|
||||||
value = [[context request]
|
value = [[context request]
|
||||||
|
@ -662,6 +662,8 @@
|
||||||
password: &password];
|
password: &password];
|
||||||
|
|
||||||
newPassword = [message objectForKey: @"newPassword"];
|
newPassword = [message objectForKey: @"newPassword"];
|
||||||
|
// overwrite the value from the session to compare the actual input
|
||||||
|
password = [message objectForKey: @"oldPassword"];
|
||||||
|
|
||||||
um = [SOGoUserManager sharedUserManager];
|
um = [SOGoUserManager sharedUserManager];
|
||||||
|
|
||||||
|
@ -673,7 +675,7 @@
|
||||||
perr: &error])
|
perr: &error])
|
||||||
{
|
{
|
||||||
// We delete the previous session
|
// We delete the previous session
|
||||||
[SOGoSession deleteValueForSessionKey: [creds objectAtIndex: 1]];
|
[SOGoSession deleteValueForSessionKey: [creds objectAtIndex: 1]];
|
||||||
|
|
||||||
if ([domain isNotNull])
|
if ([domain isNotNull])
|
||||||
{
|
{
|
||||||
|
@ -682,7 +684,7 @@
|
||||||
[username rangeOfString: @"@"].location == NSNotFound)
|
[username rangeOfString: @"@"].location == NSNotFound)
|
||||||
username = [NSString stringWithFormat: @"%@@%@", username, domain];
|
username = [NSString stringWithFormat: @"%@@%@", username, domain];
|
||||||
}
|
}
|
||||||
|
|
||||||
response = [self responseWith204];
|
response = [self responseWith204];
|
||||||
authCookie = [auth cookieWithUsername: username
|
authCookie = [auth cookieWithUsername: username
|
||||||
andPassword: newPassword
|
andPassword: newPassword
|
||||||
|
|
|
@ -238,6 +238,7 @@
|
||||||
"Additional Parameters" = "Additional Parameters";
|
"Additional Parameters" = "Additional Parameters";
|
||||||
|
|
||||||
/* password */
|
/* password */
|
||||||
|
"Current password" = "Current password";
|
||||||
"New password" = "New password";
|
"New password" = "New password";
|
||||||
"Confirmation" = "Confirmation";
|
"Confirmation" = "Confirmation";
|
||||||
"Change" = "Change";
|
"Change" = "Change";
|
||||||
|
|
|
@ -233,6 +233,7 @@
|
||||||
"Additional Parameters" = "Zusätzliche Einstellungen";
|
"Additional Parameters" = "Zusätzliche Einstellungen";
|
||||||
|
|
||||||
/* password */
|
/* password */
|
||||||
|
"Current password" = "Aktuelles Passwort";
|
||||||
"New password" = "Neues Passwort";
|
"New password" = "Neues Passwort";
|
||||||
"Confirmation" = "Bestätigung";
|
"Confirmation" = "Bestätigung";
|
||||||
"Change" = "Ändern";
|
"Change" = "Ändern";
|
||||||
|
|
|
@ -262,16 +262,21 @@
|
||||||
label:label="Password">
|
label:label="Password">
|
||||||
<md-content id="passwordView" class="md-padding">
|
<md-content id="passwordView" class="md-padding">
|
||||||
<div layout="row">
|
<div layout="row">
|
||||||
|
<md-input-container class="md-block" flex="50">
|
||||||
|
<label><var:string label:value="Current password"/>
|
||||||
|
</label>
|
||||||
|
<input type="password" sg-no-dirty-check="true" ng-model="app.passwords.oldPassword"/>
|
||||||
|
</md-input-container>
|
||||||
<md-input-container class="md-block" flex="50">
|
<md-input-container class="md-block" flex="50">
|
||||||
<label><var:string label:value="New password"/>
|
<label><var:string label:value="New password"/>
|
||||||
</label>
|
</label>
|
||||||
<input type="password" sg-no-dirty-check="true" ng-model="app.passwords.newPassword"/>
|
<input type="password" sg-no-dirty-check="true" ng-model="app.passwords.newPassword"/>
|
||||||
</md-input-container>
|
</md-input-container>
|
||||||
|
|
||||||
<md-input-container class="md-block" flex="50">
|
<md-input-container class="md-block" flex="50">
|
||||||
<label><var:string label:value="Confirmation"/>
|
<label><var:string label:value="Confirmation"/>
|
||||||
</label>
|
</label>
|
||||||
<input type="password" sg-no-dirty-check="true" ng-model="app.passwords.newPasswordConfirmation"/>
|
<input type="password" sg-no-dirty-check="true" ng-model="app.passwords.newPasswordConfirmation"/>
|
||||||
</md-input-container>
|
</md-input-container>
|
||||||
</div>
|
</div>
|
||||||
<div layout="row" layout-align="end center">
|
<div layout="row" layout-align="end center">
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
return d.promise;
|
return d.promise;
|
||||||
}, // login: function(data) { ...
|
}, // login: function(data) { ...
|
||||||
|
|
||||||
changePassword: function(newPassword) {
|
changePassword: function(newPassword, oldPassword) {
|
||||||
var d = $q.defer(),
|
var d = $q.defer(),
|
||||||
xsrfCookie = $cookies.get('XSRF-TOKEN');
|
xsrfCookie = $cookies.get('XSRF-TOKEN');
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@
|
||||||
headers: {
|
headers: {
|
||||||
'X-XSRF-TOKEN' : xsrfCookie
|
'X-XSRF-TOKEN' : xsrfCookie
|
||||||
},
|
},
|
||||||
data: { newPassword: newPassword }
|
data: { newPassword: newPassword, oldPassword: oldPassword }
|
||||||
}).then(d.resolve, function(response) {
|
}).then(d.resolve, function(response) {
|
||||||
var error,
|
var error,
|
||||||
data = response.data,
|
data = response.data,
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
this.$onInit = function() {
|
this.$onInit = function() {
|
||||||
this.preferences = Preferences;
|
this.preferences = Preferences;
|
||||||
this.passwords = { newPassword: null, newPasswordConfirmation: null };
|
this.passwords = { newPassword: null, newPasswordConfirmation: null, oldPassword: null };
|
||||||
this.timeZonesList = $window.timeZonesList;
|
this.timeZonesList = $window.timeZonesList;
|
||||||
this.timeZonesSearchText = '';
|
this.timeZonesSearchText = '';
|
||||||
this.sieveVariablesCapability = ($window.sieveCapabilities.indexOf('variables') >= 0);
|
this.sieveVariablesCapability = ($window.sieveCapabilities.indexOf('variables') >= 0);
|
||||||
|
@ -465,14 +465,15 @@
|
||||||
this.canChangePassword = function() {
|
this.canChangePassword = function() {
|
||||||
if (this.passwords.newPassword && this.passwords.newPassword.length > 0 &&
|
if (this.passwords.newPassword && this.passwords.newPassword.length > 0 &&
|
||||||
this.passwords.newPasswordConfirmation && this.passwords.newPasswordConfirmation.length &&
|
this.passwords.newPasswordConfirmation && this.passwords.newPasswordConfirmation.length &&
|
||||||
this.passwords.newPassword == this.passwords.newPasswordConfirmation)
|
this.passwords.newPassword == this.passwords.newPasswordConfirmation &&
|
||||||
|
this.passwords.oldPassword && this.passwords.oldPassword.length > 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.changePassword = function() {
|
this.changePassword = function() {
|
||||||
Authentication.changePassword(this.passwords.newPassword).then(function() {
|
Authentication.changePassword(this.passwords.newPassword, this.passwords.oldPassword).then(function() {
|
||||||
var alert = $mdDialog.alert({
|
var alert = $mdDialog.alert({
|
||||||
title: l('Password'),
|
title: l('Password'),
|
||||||
content: l('The password was changed successfully.'),
|
content: l('The password was changed successfully.'),
|
||||||
|
|
Loading…
Reference in New Issue