See ChangeLog

Monotone-Parent: 024380d579a482e49866c36ef54561cf8b39ab02
Monotone-Revision: 2cbc46c16f9b3d45d868b15a968f614dbbaf9749

Monotone-Author: ludovic@Sophos.ca
Monotone-Date: 2010-03-08T15:18:05
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Ludovic Marcotte
2010-03-08 15:18:05 +00:00
parent 13206f066d
commit 40c3cb74d0
26 changed files with 1059 additions and 98 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
/* SOGoRootPage.h - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
* Copyright (C) 2007-2010 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
+80 -4
View File
@@ -24,6 +24,7 @@
#import <Foundation/NSException.h>
#import <Foundation/NSTimeZone.h>
#import <Foundation/NSURL.h>
#import <Foundation/NSValue.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/WOApplication.h>
@@ -39,13 +40,17 @@
#import <NGExtensions/NSObject+Logs.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSDictionary+BSJSONAdditions.h>
#import <SOGo/SOGoCache.h>
#import <SOGo/SOGoCASSession.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserManager.h>
#import <SOGo/SOGoWebAuthenticator.h>
#import <SOGo/SOGoConstants.h>
#import "SOGoRootPage.h"
@interface SOGoRootPage (crashAdditions)
@@ -115,17 +120,37 @@
SOGoUserDefaults *ud;
NSString *username, *password, *language;
NSArray *supportedLanguages;
SOGoPasswordPolicyError err;
int expire, grace;
BOOL b;
err = PolicyNoError;
expire = grace = 0;
auth = [[WOApplication application]
authenticatorInContext: context];
authenticatorInContext: context];
request = [context request];
username = [request formValueForKey: @"userName"];
password = [request formValueForKey: @"password"];
language = [request formValueForKey: @"language"];
if ([auth checkLogin: username password: password])
if ((b = [auth checkLogin: username
password: password
perr: &err
expire: &expire
grace: &grace])
&& (err == PolicyNoError || err == PolicyChangeAfterReset))
{
[self logWithFormat: @"successful login for user '%@'", username];
response = [self responseWith204];
// We must warn the user that he has to change his password
if (err == PolicyChangeAfterReset)
{
}
authCookie = [self _cookieWithUsername: username andPassword: password
forAuthenticator: auth];
[response addCookie: authCookie];
@@ -141,7 +166,21 @@
}
else
{
[self logWithFormat: @"failed login for user '%@'", username];
[self logWithFormat: @"Login for user '%@' might not have worked - password policy: %d bound: ", username, err, b];
if (err == PolicyNoError)
{
[self logWithFormat: @"failed login for user '%@' due to wrong password", username];
}
else if (err == PolicyAccountLocked)
{
// Account has been locked due to too many failures
}
else if (err == PolicyPasswordExpired)
{
// The password MUST be changed - we need to ask for the old password and the new one here
}
response = [self responseWithStatus: 403];
}
@@ -372,4 +411,41 @@
return aString;
}
- (WOResponse *) changePasswordAction
{
NSString *username, *password, *newPassword;
SOGoUserManager *um;
SOGoPasswordPolicyError error;
WOResponse *response;
WORequest *request;
NSDictionary *message, *jsonError;
request = [context request];
message = [NSMutableDictionary dictionaryWithJSONString: [request contentAsString]];
username = [message objectForKey: @"userName"];
password = [message objectForKey: @"password"];
newPassword = [message objectForKey: @"newPassword"];
um = [SOGoUserManager sharedUserManager];
// This will also update the cached password in memcached.
if ([um changePasswordForLogin: username
oldPassword: password
newPassword: newPassword
perr: &error])
response = [self responseWith204];
else
{
jsonError
= [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: error]
forKey: @"LDAPPasswordPolicyError"];
response = [self responseWithStatus: 403
andJSONRepresentation: jsonError];
[response setHeader: @"application/json"
forKey: @"content-type"];
}
return response;
}
@end /* SOGoRootPage */
+5
View File
@@ -130,6 +130,11 @@
pageName = "SOGoRootPage";
actionName = "connect";
};
changePassword = {
protectedBy = "<public>";
pageName = "SOGoRootPage";
actionName = "changePassword";
};
GET = { // more or less a hack, see README of dbd
protectedBy = "<public>";
pageName = "SOGoRootPage";
+19 -19
View File
@@ -34,9 +34,9 @@
><var:if condition="shouldDisplayAdditionalPreferences">
<li target="additionalView"><span>
<var:string label:value="Additional Parameters"/></span></li>
<!-- </var:if -->
<!-- ><var:if condition="shouldDisplayPasswordChange"> -->
<!-- <li target="passwordView"><span><var:string label:value="Password"/></span></li> -->
</var:if
><var:if condition="shouldDisplayPasswordChange">
<li target="passwordView"><span><var:string label:value="Password"/></span></li>
</var:if>
</ul>
<div id="generalView" class="tab">
@@ -278,22 +278,22 @@
</div>
</div>
</var:if
></var:if>
<!-- <var:if condition="shouldDisplayPasswordChange"> -->
<!-- <div id="passwordView" class="tab"> -->
<!-- <label><var:string label:value="New password:" -->
<!-- /><input type="text" class="textField" -->
<!-- const:enabled="disabled" -->
<!-- var:value="newPassword"/></label><br/> -->
<!-- <label><var:string label:value="Confirmation:" -->
<!-- /><input type="text" class="textField" -->
<!-- const:enabled="disabled" -->
<!-- var:value="newPasswordConfirmation"/></label><br/> -->
<!-- <input type="button" class="button" -->
<!-- id="changePasswordBtn" label:value="Change"/> -->
<!-- </div> -->
<!-- </var:if> -->
<var:if condition="shouldDisplayAdditionalPreferences"
></var:if
><var:if condition="shouldDisplayPasswordChange">
<div id="passwordView" class="tab">
<p id="passwordFields"><label><var:string label:value="New password:"
/><input const:id="newPasswordField" class="textField"
type="text" const:value=""/></label><br/>
<label><var:string label:value="Confirmation:"
/><input const:id="newPasswordConfirmationField" class="textField"
type="text" const:value=""/></label><br/>
<a href="#" class="button" id="changePasswordBtn"
><span><var:string label:value="Change"/></span></a>
</p>
<p id="passwordError"><!-- space --></p>
</div>
</var:if
><var:if condition="shouldDisplayAdditionalPreferences"
><div id="additionalView" class="tab">
<var:component className="UIxAdditionalPreferences"/>
</div></var:if>
@@ -272,8 +272,7 @@ String.prototype.base64decode = function() {
var enc1, enc2, enc3, enc4;
var i = 0;
var input = this.replace(/[^A-Za-z0-9\+\/\=]/g, "");
var input = "" + this; // .replace(/[^A-Za-z0-9\+\/\=]/g, "")
while (i < input.length) {
enc1 = this._base64_keyStr.indexOf(input.charAt(i++));
enc2 = this._base64_keyStr.indexOf(input.charAt(i++));
@@ -294,7 +293,7 @@ String.prototype.base64decode = function() {
}
}
return output.utf8decode();
return output;
};
String.prototype.utf8encode = function() {
+22 -4
View File
@@ -5,10 +5,6 @@ DIV#preferencesTabs
right: 5px;
bottom: 5px; }
DIV#passwordView
{ padding-top: 3em;
padding-right: 10em; }
TEXTAREA#signature
{ position: absolute;
width: 100%;
@@ -107,3 +103,25 @@ TH#activeTableHeader
TD.activeColumn
{ text-align: center; }
P#passwordFields,
P#passwordError
{ position: absolute;
left: 0px; }
#passwordFields
{ top: 40px;
width: 410px;
text-align: right; }
P#passwordError
{ top: 92px;
width: 307px;
text-align: right;
margin-left: 40px; }
P.errorMessage#passwordError
{ color: #f00; }
P.infoMessage#passwordError
{ color: #00f; }
+132 -4
View File
@@ -105,7 +105,7 @@ function onChoiceChanged(event) {
_setupEvents(false);
}
function addDefaultEmailAddresses() {
function addDefaultEmailAddresses(event) {
var defaultAddresses = $("defaultEmailAddresses").value.split(/, */);
var addresses = $("autoReplyEmailAddresses").value.trim();
@@ -121,6 +121,8 @@ function addDefaultEmailAddresses() {
});
$("autoReplyEmailAddresses").value = addresses.join(", ");
event.stop();
}
function initPreferences() {
@@ -157,9 +159,13 @@ function initPreferences() {
onReplyPlacementListChange ();
}
if ($("addDefaultEmailAddresses"))
$("addDefaultEmailAddresses").observe("click",
addDefaultEmailAddresses);
var button = $("addDefaultEmailAddresses");
if (button)
button.observe("click", addDefaultEmailAddresses);
var button = $("changePasswordBtn");
if (button)
button.observe("click", onChangePasswordClick);
initSieveFilters();
}
@@ -549,4 +555,126 @@ function onComposeMessagesTypeChange(event) {
}
}
function onChangePasswordClick(event) {
var field = $("newPasswordField");
var confirmationField = $("newPasswordConfirmationField");
if (field && confirmationField) {
var password = field.value;
if (password == confirmationField.value) {
if (password.length > 0)
changePassword(password);
else
showPasswordMessage(_("Password must not be empty."),
"error");
}
else {
showPasswordMessage(_("The passwords do not match."
+ " Please try again."),
"error");
field.focus();
field.select();
}
}
event.stop();
}
/* TODO: this method could serve as a basis for a basic text container (for
example the log console. */
function showPasswordMessage(message, msgType) {
var para = $("passwordError");
if (para) {
if (!msgType)
msgType = "error";
var typeClass = msgType + "Message";
if (!para.typeClass || para.typeClass != typeClass) {
if (para.typeClass) {
para.removeClassName(para.typeClass);
}
para.typeClass = typeClass;
para.addClassName(typeClass);
}
if (!para.message || para.message != message) {
while (para.lastChild) {
para.removeChild(para.lastChild);
}
if (message) {
var sentences = message.split("\n");
para.appendChild(document.createTextNode(sentences[0]));
for (var i = 1; i < sentences.length; i++) {
para.appendChild(document.createElement("br"));
para.appendChild(document.createTextNode(sentences[i]));
}
para.message = message;
}
}
}
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function changePassword(newPassword) {
var loginValues = readLoginCookie();
if (loginValues) {
var content = Object.toJSON({ userName: loginValues[0],
password: loginValues[1],
newPassword: newPassword });
var url = ApplicationBaseURL + "../changePassword";
triggerAjaxRequest(url, changePasswordCallback, loginValues[1], content,
{"content-type": "application/json"} );
}
}
function changePasswordCallback(http) {
if (http.readyState == 4) {
if (isHttpStatus204(http.status)) {
log("it worked");
showPasswordMessage(_("The password was changed successfully."), "info");
setLoginCookie(UserLogin, http.callbackData);
} else {
var error;
log("header: " + http.header);
switch(http.status) {
case 403:
if (http.getResponseHeader("content-type") == "application/json") {
var jsonResponse = http.responseText.evalJSON(false);
var perr = jsonResponse["LDAPPasswordPolicyError"];
// Normal password change failed
if (perr == 65535) {
error = _("Password change failed");
} else if (perr == 3) {
error = _("Password change failed - Permission denied");
} else if (perr == 5) {
error = _("Password change failed - Insufficient password quality");
} else if (perr == 6) {
error = _("Password change failed - Password is too short");
} else if (perr == 7) {
error = _("Password change failed - Password is too young");
} else if (perr == 8) {
error = _("Password change failed - Password is in history");
}
} else {
error = _("Unhandled error code: ") + http.status;
}
break;
case 404:
error = _("Password changing is not supported.");
break;
default:
error = _("Unhandled error code: ") + http.status;
}
showPasswordMessage(error);
}
}
}
document.observe("dom:loaded", initPreferences);
+28
View File
@@ -1695,6 +1695,34 @@ AIM = {
i.onComplete(d.body.innerHTML);
}
};
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function readLoginCookie() {
var loginValues = null;
var cookie = readCookie("0xHIGHFLYxSOGo");
if (cookie && cookie.length > 8) {
var value = decodeURIComponent(cookie.substr(8));
loginValues = value.base64decode().split(":");
}
return loginValues;
}
function setLoginCookie(username, password) {
var value = (username + ":" + password).base64encode();
var cookieValue = encodeURIComponent("basic " + value);
window.alert("0xHIGHFLYxSOGo=" + cookieValue);
}
document.observe("dom:loaded", onLoadHandler);