mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-10-06 12:30:31 +00:00
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:
@@ -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>
|
||||
*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user