Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1082 → Rev 1075

/hostadmiral/trunk/backend/backend.pl
File deleted
Property changes:
Deleted: svn:executable
-*
\ No newline at end of property
/hostadmiral/trunk/doc/todo.txt
1,13 → 1,6
Host Admiral TODO
========================================================================================================================
 
No unique error handle by mail alias creation.
 
Additional attributes for all objects, configurable.
HTTP Basic Auth as option to replace form-based auth - to allow integration with
non-tomcat web applications.
Transaction control for listeners.
 
+/- Save user id for all db-update operations.
28,8 → 21,6
 
+/- Cascade object deletion, confirmation page.
 
Mail aliases are not cascade deleted by deleting connected mail box.
 
Check passwords quality (make a separate project for this).
 
Show filters, search.
38,7 → 29,6
 
Allow to use existing system users: enter uid or name only, check in system for full
information.
Import users from system - separate page.
 
Allow admin to define default language for server and domain.
 
58,7 → 48,7
 
Catch-all mail alias. Only one per domain.
 
+/- Basic scripts to push changes to the system.
Basic scripts to push changes to the system.
 
If mailbox is created, create an user and a mail alias for it in one step - as option.
Afterwards they are binded and change own name or deleted together. Bind by name? In witch directions?
70,12 → 60,9
Limit deep of cascade by 'before delete'.
Add/delete passwords stores of existing DB objects if they are changed in config.
If at least one store is reversable, set password in the new stores.
Double check concurency update.
Study Hibernate behavior if it cannot save some information - seems to be not recoverable, restart needed.
Done
------------------------------------------------------------------------------------------------------------------------
/hostadmiral/trunk/src/ak/hostadmiral/util/ConfigUtils.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/util/ConfigInit.java
6,7 → 6,6
{
/**
* This method is called by initialization from config file.
* FIMXE give more powerful structure, not just a map
*
* @param params map String -> String[] with pairs of param name -> values
* from the initializaion file
/hostadmiral/trunk/src/ak/hostadmiral/core/model/User.java
124,26 → 124,6
return getDefaultPasswordStore().getPassword();
}
 
public String getPassword(User editor, String digest)
throws ModelException
{
if(!partEditableBy(editor))
throw new ModelSecurityException();
 
for(Iterator i = passwords.iterator(); i.hasNext(); ) {
Object o = i.next();
if(!(o instanceof PasswordStore))
throw new ModelException("It's not a password store");
 
PasswordStore ps = (PasswordStore)o;
if(ps.getDigest().equals(digest)) {
return ps.getPassword();
}
}
 
throw new ModelException("Digest " + digest + " not found");
}
 
public void setPassword(User editor, String password)
throws ModelException
{
/hostadmiral/trunk/src/ak/hostadmiral/core/model/Mailbox.java
90,26 → 90,6
passwords.add(ps);
}
 
public String getPassword(User editor, String digest)
throws ModelException
{
if(!editableBy(editor))
throw new ModelSecurityException();
 
for(Iterator i = passwords.iterator(); i.hasNext(); ) {
Object o = i.next();
if(!(o instanceof PasswordStore))
throw new ModelException("It's not a password store");
 
PasswordStore ps = (PasswordStore)o;
if(ps.getDigest().equals(digest)) {
return ps.getPassword();
}
}
 
throw new ModelException("Digest " + digest + " not found");
}
 
public void setPassword(User editor, String password)
throws ModelException
{
/hostadmiral/trunk/src/ak/hostadmiral/core/model/PasswordStore.java
13,11 → 13,6
public String getDigest();
 
/**
* returns true if the store is able to return the original password
*/
public boolean getReversable();
 
/**
* to store to persistent store
*/
public String getPassword();
35,10 → 30,4
 
public boolean checkPassword(String password)
throws ModelException;
 
/**
* return the password in plain text if possible
*/
public String getOriginalPassword()
throws UnsupportedOperationException;
}
/hostadmiral/trunk/src/ak/hostadmiral/core/model/PasswordStoreAbstract.java
112,15 → 112,4
theClone.password = password;
return theClone;
}
 
public boolean getReversable()
{
return false;
}
 
public String getOriginalPassword()
throws UnsupportedOperationException
{
throw new UnsupportedOperationException("Not able to restore original password");
}
}
/hostadmiral/trunk/src/ak/hostadmiral/core/model/PasswordStorePlain.java
20,15 → 20,4
{
return password;
}
 
public boolean getReversable()
{
return true;
}
 
public String getOriginalPassword()
throws UnsupportedOperationException
{
return password;
}
}
/hostadmiral/trunk/src/ak/hostadmiral/core/config/Configurator.java
112,18 → 112,8
params.put(p.getName(), (String[])p.getValues().toArray(new String[0]));
}
 
try {
o.init(params);
}
catch(ModelException ex) {
logger.error("Cannot initialize instance of class "
+ c.getClass().getName(), ex);
}
o.init(params);
}
else {
logger.error("Class " + c.getClass().getName()
+ " does not implement ak.hostadmiral.util.ConfigInit interface");
}
}
}
 
/hostadmiral/trunk/src/ak/hostadmiral/listener/tcp/TcpListener.java
6,59 → 6,46
import java.io.Writer;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;
import ak.hostadmiral.util.ModelException;
import ak.hostadmiral.util.ConfigInit;
import ak.hostadmiral.util.ConfigUtils;
import ak.hostadmiral.core.model.*;
 
import org.apache.log4j.Logger;
 
public class TcpListener
implements
ConfigInit,
UserCreatedListener,
UserModifiedListener,
UserDeletedListener,
InetDomainCreatedListener,
InetDomainModifiedListener,
InetDomainDeletedListener,
SystemUserCreatedListener,
SystemUserModifiedListener,
SystemUserDeletedListener,
MailboxCreatedListener,
MailboxModifiedListener,
MailboxDeletedListener,
MailAliasCreatedListener,
MailAliasModifiedListener,
MailAliasDeletedListener
implements
ConfigInit,
UserCreatedListener,
UserModifiedListener,
UserDeletedListener,
InetDomainCreatedListener,
InetDomainModifiedListener,
InetDomainDeletedListener,
SystemUserCreatedListener,
SystemUserModifiedListener,
SystemUserDeletedListener,
MailboxCreatedListener,
MailboxModifiedListener,
MailboxDeletedListener,
MailAliasCreatedListener,
MailAliasModifiedListener,
MailAliasDeletedListener
{
private static final Logger logger = Logger.getLogger(TcpListener.class);
 
private static String hostname;
private static int port;
private static String password;
protected static Object lock = new Object();
 
public static final String PROTOCOL_NAME = "HostAdmiral_TcpListener";
public static final String PROTOCOL_VER_MAJ = "1";
public static final String PROTOCOL_VER_MIN = "0";
public static final String PASSWORD_DIGEST = "crypt";
public static final String PROTOCOL_NAME = "HostAdmiral_TcpListener";
public static final String PROTOCOL_VERSION = "0.1";
 
public void init(Map params)
throws ModelException
{
ConfigUtils cfg = new ConfigUtils(params);
setHostname(((String[])params.get("hostname"))[0]);
setPort(Integer.parseInt(((String[])params.get("port"))[0]));
 
// save params
setHostname(cfg.getString("hostname", "127.0.0.1", true, false));
setPort(cfg.getInteger("port", null, false).intValue());
setPassword(cfg.getString("password", null, true, true));
 
// register listeners
UserManager.getInstance().addCreatedListener(this);
UserManager.getInstance().addModifiedListener(this);
UserManager.getInstance().addDeletedListener(this);
100,93 → 87,37
port = port_;
}
 
public static void setPassword(String password_)
{
password = password_;
}
protected static String escape(String s)
{
// FIXME: any other problem characters? optimize it?
s = s.replaceAll("\0", "\\\\0");
s = s.replaceAll("\\\\", "\\\\\\\\");
s = s.replaceAll("\t", "\\\\t");
s = s.replaceAll("\n", "\\\\n");
s = s.replaceAll("\r", "\\\\r");
return s;
}
 
protected static String escape(String s)
{
// FIXME: any other problem characters? optimize it?
s = s.replaceAll("\\\\", "\\\\\\\\");
s = s.replaceAll("\0", "\\\\0");
s = s.replaceAll("\t", "\\\\t");
s = s.replaceAll("\n", "\\\\n");
s = s.replaceAll("\r", "\\\\r");
return s;
}
 
protected static void send(String message)
throws ModelException
{
synchronized(lock) {
try {
Socket socket = new Socket(hostname, port);
 
// send request
Writer out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
 
out.write(PROTOCOL_NAME + " " + PROTOCOL_VER_MAJ + "." + PROTOCOL_VER_MIN + "\n");
if(password != null) {
out.write("password=" + password + "\n");
Socket socket = new Socket(hostname, port);
Writer out = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()));
 
if(PROTOCOL_NAME != null) {
out.write(PROTOCOL_NAME);
out.write(" ");
}
if(PROTOCOL_VERSION != null) {
out.write(PROTOCOL_VERSION);
out.write("\n");
}
out.write(message);
out.write("\n\n");
out.flush();
socket.shutdownOutput();
 
// get response
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String line;
boolean headerDone = false;
boolean codeDone = false;
while((line = in.readLine()) != null) {
if(!headerDone) {
if(!line.matches("^" + PROTOCOL_NAME + " " + PROTOCOL_VER_MAJ + "\\.\\d+$"))
throw new ModelException(
"Wrong response: wrong header in [" + line + "]");
 
headerDone = true;
}
else if(!codeDone) {
if(line.length() < 3)
throw new ModelException(
"Wrong response: code too short [" + line + "]");
if(line.length() >= 4 && line.charAt(3) != ' ')
throw new ModelException(
"Wrong response: cannot get code from [" + line + "]");
 
int code;
try {
code = Integer.parseInt(line.substring(0, 3));
}
catch(NumberFormatException ex) {
throw new ModelException(
"Wrong response: cannot parse code from [" + line + "]");
}
 
String response = (line.length() >= 5) ? line.substring(4) : null;
 
if(code >= 200 && code < 300) {
logger.info("Response from backend [" + line + "]");
}
else if(code >= 400 && code < 600) {
throw new ModelException(
"Error from backend [" + line + "]");
}
 
codeDone = true;
}
else {
if(!line.equals(""))
throw new ModelException(
"Wrong response: no more lines expected [" + line + "]");
}
}
 
// done
socket.close();
out.close();
}
catch(Exception ex) {
logger.error("Cannot send message over TCP", ex);
196,127 → 127,126
}
}
 
//=== user ====================================================================================
//=== user ====================================================================================
 
public void userCreated(User editor, User user)
throws ModelException
{
send("user\tcreate\tlogin=" + escape(user.getLogin())
+ "\tpassword=" + escape(user.getPassword(editor, PASSWORD_DIGEST))
+ "\tenabled=" + user.getEnabled()
+ "\tcomment=" + escape(user.getComment()));
send("user\tcreate\t" + escape(user.getLogin()) + "\t"
+ escape(/* FIXME user.getPassword() */ "") + "\t"
+ user.getEnabled() + "\t"
+ escape(user.getComment()));
}
 
public void userModified(User editor, User user, User oldUser)
throws ModelException
{
send("user\tmodify\toldLogin=" + escape(oldUser.getLogin())
+ "\tlogin=" + escape(user.getLogin())
+ "\tpassword=" + escape(user.getPassword(editor, PASSWORD_DIGEST))
+ "\tenabled=" + user.getEnabled()
+ "\tcomment=" + escape(user.getComment()));
send("user\tmodify\t" + escape(oldUser.getLogin()) + "\t"
+ escape(user.getLogin()) + "\t"
+ escape(/* FIXME user.getPassword() */ "") + "\t"
+ user.getEnabled() + "\t"
+ escape(user.getComment()));
}
 
public void userDeleted(User editor, User user)
throws ModelException
{
send("user\tdelete\tlogin=" + escape(user.getLogin()));
send("user\tdelete\t" + escape(user.getLogin()));
}
 
//=== inet domain =============================================================================
//=== inet domain =============================================================================
 
public void inetDomainCreated(User editor, InetDomain domain)
throws ModelException
{
send("inetDomain\tcreate\tname=" + escape(domain.getName())
+ "\tenabled=" + domain.getEnabled()
+ "\tcomment=" + escape(domain.getComment()));
send("inetDomain\tcreate\t" + escape(domain.getName()) + "\t"
+ domain.getEnabled() + "\t"
+ escape(domain.getComment()));
}
 
public void inetDomainModified(User editor, InetDomain domain, InetDomain oldDomain)
throws ModelException
{
send("inetDomain\tmodify\toldName=" + escape(oldDomain.getName())
+ "\tname=" + escape(domain.getName())
+ "\tenabled=" + domain.getEnabled()
+ "\tcomment=" + escape(domain.getComment()));
send("inetDomain\tmodify\t" + escape(oldDomain.getName()) + "\t"
+ escape(domain.getName()) + "\t"
+ domain.getEnabled() + "\t"
+ escape(domain.getComment()));
}
 
public void inetDomainDeleted(User editor, InetDomain domain)
throws ModelException
{
send("inetDomain\tdelete\tname=" + escape(domain.getName()));
send("inetDomain\tdelete\t" + escape(domain.getName()));
}
 
//=== system user =============================================================================
//=== system user =============================================================================
 
public void systemUserCreated(User editor, SystemUser systemUser)
throws ModelException
{
send("systemUser\tcreate\tuid=" + systemUser.getUid()
+ "\tname=" + escape(systemUser.getName())
+ "\tenabled=" + systemUser.getEnabled()
+ "\tcomment=" + escape(systemUser.getComment()));
send("systemUser\tcreate\t" + systemUser.getUid() + "\t"
+ escape(systemUser.getName()) + "\t"
+ systemUser.getEnabled() + "\t"
+ escape(systemUser.getComment()));
}
 
public void systemUserModified(User editor, SystemUser systemUser, SystemUser oldSystemUser)
throws ModelException
{
send("systemUser\tmodify\toldUid=" + oldSystemUser.getUid()
+ "\toldName=" + escape(oldSystemUser.getName())
+ "\tuid=" + systemUser.getUid()
+ "\tname=" + escape(systemUser.getName())
+ "\tenabled=" + systemUser.getEnabled()
+ "\tcomment=" + escape(systemUser.getComment()));
send("systemUser\tmodify\t" + oldSystemUser.getUid() + "\t"
+ escape(oldSystemUser.getName()) + "\t"
+ systemUser.getUid() + "\t"
+ escape(systemUser.getName()) + "\t"
+ systemUser.getEnabled() + "\t"
+ escape(systemUser.getComment()));
}
 
public void systemUserDeleted(User editor, SystemUser systemUser)
throws ModelException
{
send("systemUser\tdelete\tuid=" + systemUser.getUid()
+ "\tname=" + escape(systemUser.getName()));
send("systemUser\tdelete\t" + systemUser.getUid() + "\t" + escape(systemUser.getName()));
}
 
//=== mailbox =================================================================================
//=== mailbox =================================================================================
 
public void mailboxCreated(User editor, Mailbox mailbox)
throws ModelException
{
send("mailbox\tcreate\tlogin=" + escape(mailbox.getLogin())
+ "\tpassword=" + escape(mailbox.getPassword(editor, PASSWORD_DIGEST))
+ "\tdomain=" + escape(mailbox.getDomain().getName())
+ "\tvirusCheck=" + mailbox.getVirusCheck()
+ "\tspamCheck=" + mailbox.getSpamCheck()
+ "\tsystemUser=" + (mailbox.getSystemUser() == null
? "" : mailbox.getSystemUser().getUid().toString())
+ "\tenabled=" + mailbox.getEnabled()
+ "\tcomment=" + escape(mailbox.getComment()));
send("mailbox\tcreate\t" + escape(mailbox.getLogin()) + "\t"
+ escape(/* FIXME user.getPassword() */ "") + "\t"
+ escape(mailbox.getDomain().getName()) + "\t"
+ mailbox.getVirusCheck() + "\t"
+ mailbox.getSpamCheck() + "\t"
+ (mailbox.getSystemUser() == null ? "" : mailbox.getSystemUser().getUid().toString())
+ "\t"
+ mailbox.getEnabled() + "\t"
+ escape(mailbox.getComment()));
}
 
public void mailboxModified(User editor, Mailbox mailbox, Mailbox oldMailbox)
throws ModelException
{
send("mailbox\tmodify\toldLogin=" + escape(oldMailbox.getLogin())
+ "\toldDomain=" + escape(oldMailbox.getDomain().getName())
+ "\tlogin=" + escape(mailbox.getLogin())
+ "\tpassword=" + escape(mailbox.getPassword(editor, PASSWORD_DIGEST))
+ "\tdomain=" + escape(mailbox.getDomain().getName())
+ "\tvirusCheck=" + mailbox.getVirusCheck()
+ "\tspamCheck=" + mailbox.getSpamCheck()
+ "\tsystemUser=" + (mailbox.getSystemUser() == null
? "" : mailbox.getSystemUser().getUid().toString())
+ "\tenabled=" + mailbox.getEnabled()
+ "\tcomment=" + escape(mailbox.getComment()));
send("mailbox\tmodify\t" + escape(oldMailbox.getLogin()) + "\t"
+ escape(oldMailbox.getDomain().getName()) + "\t"
+ escape(mailbox.getLogin()) + "\t"
+ escape(/* FIXME user.getPassword() */ "") + "\t"
+ escape(mailbox.getDomain().getName()) + "\t"
+ mailbox.getVirusCheck() + "\t"
+ mailbox.getSpamCheck() + "\t"
+ (mailbox.getSystemUser() == null ? "" : mailbox.getSystemUser().getUid().toString())
+ "\t"
+ mailbox.getEnabled() + "\t"
+ escape(mailbox.getComment()));
}
 
public void mailboxDeleted(User editor, Mailbox mailbox)
throws ModelException
{
send("mailbox\tdelete\tlogin=" + escape(mailbox.getLogin())
+ "\tdomain=" + escape(mailbox.getDomain().getName()));
send("mailbox\tdelete\t" + escape(mailbox.getLogin()) + "\t"
+ escape(mailbox.getDomain().getName()));
}
 
//=== mail alias ==============================================================================
//=== mail alias ==============================================================================
 
private String formMailAliasDestinations(User editor, MailAlias mailAlias)
throws ModelException
341,29 → 271,29
public void mailAliasCreated(User editor, MailAlias mailAlias)
throws ModelException
{
send("mailAlias\tcreate\taddress=" + escape(mailAlias.getAddress())
+ "\tdomain=" + escape(mailAlias.getDomain().getName())
+ "\tenabled=" + mailAlias.getEnabled()
+ "\tcomment=" + escape(mailAlias.getComment())
+ formMailAliasDestinations(editor, mailAlias));
send(" mailAlias\tcreate\t" + escape(mailAlias.getAddress()) + "\t"
+ escape(mailAlias.getDomain().getName()) + "\t"
+ mailAlias.getEnabled() + "\t"
+ escape(mailAlias.getComment())
+ formMailAliasDestinations(editor, mailAlias));
}
 
public void mailAliasModified(User editor, MailAlias mailAlias, MailAlias oldMailAlias)
throws ModelException
{
send("mailAlias\tmodify\toldAddress=" + escape(oldMailAlias.getAddress())
+ "\toldDomain=" + escape(oldMailAlias.getDomain().getName())
+ "\taddress=" + escape(mailAlias.getAddress())
+ "\tdomain=" + escape(mailAlias.getDomain().getName())
+ "\tenabled=" + mailAlias.getEnabled()
+ "\tcomment=" + escape(mailAlias.getComment())
+ formMailAliasDestinations(editor, mailAlias));
send(" mailAlias\tmodify\t" + escape(oldMailAlias.getAddress()) + "\t"
+ escape(oldMailAlias.getDomain().getName()) + "\t"
+ escape(mailAlias.getAddress()) + "\t"
+ escape(mailAlias.getDomain().getName()) + "\t"
+ mailAlias.getEnabled() + "\t"
+ escape(mailAlias.getComment())
+ formMailAliasDestinations(editor, mailAlias));
}
 
public void mailAliasDeleted(User editor, MailAlias mailAlias)
throws ModelException
{
send("mailAlias\tdelete\taddress=" + escape(mailAlias.getAddress())
+ "\tdomain=" + escape(mailAlias.getDomain().getName()));
send(" mailAlias\tdelete\t" + escape(mailAlias.getAddress())+ "\t"
+ escape(mailAlias.getDomain().getName()));
}
}