Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1015 → Rev 1014

/hostadmiral/trunk/src/ak/hostadmiral/util/DigestMd5.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/util/BinUtils.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/util/DigestCrypt.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/util/DatabaseVersion.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/util/Digest.java
0,0 → 1,51
package ak.hostadmiral.util;
 
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
 
public class Digest
{
/**
* digest to encode passwords
*/
protected static MessageDigest digest = null;
 
private static final char[] hexDigits = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
 
public static String encode(String password)
{
return bytesToHex(digest.digest(password.getBytes()));
}
 
/**
* converts password bytes to hex string
*/
protected static String bytesToHex(byte[] bytes)
{
char[] buffer = new char[bytes.length * 2];
 
for (int i = 0; i < bytes.length; i++) {
int low = (int)( bytes[i] & 0x0f);
int high = (int)((bytes[i] & 0xf0) >> 4);
 
buffer[i * 2] = hexDigits[high];
buffer[i * 2 + 1] = hexDigits[low];
}
 
return new String(buffer);
}
 
/**
* digest initialization
*/
static {
try {
digest = MessageDigest.getInstance("MD5");
}
catch(NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
}
}
/hostadmiral/trunk/src/ak/hostadmiral/util/HibernateUtil.java
1,42 → 1,14
package ak.hostadmiral.util;
 
import java.util.Collection;
 
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
 
public class HibernateUtil
{
public static final int DATABASE_VERSION = 1;
 
private static Configuration configuration;
private static SessionFactory sessionFactory;
private static final ThreadLocal hibernateBean = new ThreadLocal();
private static boolean validated = false;
 
private static void validate()
throws HibernateException, ModelException
{
synchronized(HibernateUtil.class) {
if(validated) return;
 
Collection versions = currentSession().find("from DatabaseVersion");
 
if(versions == null || versions.size() == 0)
throw new ModelException("Database structure version not found");
 
if(versions.size() > 1)
throw new ModelException("Too much entries in database structure version table");
 
int version = ((DatabaseVersion)versions.iterator().next()).getVersion();
if(version != DATABASE_VERSION)
throw new ModelException("Expected database structure version "
+ DATABASE_VERSION + ", found " + version);
 
validated = true;
}
}
 
public static Configuration getConfiguration()
throws HibernateException
{
95,10 → 67,6
throw new ModelException("Transaction is already open");
 
currentBean().transaction = currentSession().beginTransaction();
 
// validate database structure version
if(!validated) // just try to speed up by avoiding synchronization
validate();
}
 
public static boolean isTransactionOpen()
/hostadmiral/trunk/src/ak/hostadmiral/core/action/ActionUtils.java
10,6 → 10,7
public static void prepare(HttpServletRequest request, HttpServletResponse response)
throws Exception
{
System.out.println("SET VERSION");
request.setAttribute("projectVersion", ProjectVersion.getVersion());
}
}
/hostadmiral/trunk/src/ak/hostadmiral/core/model/PasswordStorePlain.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/core/model/PasswordStoreMd5.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/core/model/PasswordStoreCrypt.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/core/model/PasswordStore.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/core/model/PasswordStoreAbstract.java
File deleted
/hostadmiral/trunk/src/ak/hostadmiral/core/model/UserManager.java
70,11 → 70,6
user.setBoss(editor);
}
 
// FIXME: make this configurable
user.addPasswordStore(new PasswordStoreMd5());
user.addPasswordStore(new PasswordStoreCrypt());
user.addPasswordStore(new PasswordStorePlain());
 
return user;
}
 
/hostadmiral/trunk/src/ak/hostadmiral/core/model/MailboxManager.java
65,14 → 65,7
{
if(!allowedToCreate(editor)) throw new ModelSecurityException();
 
Mailbox mailbox = new Mailbox();
 
// FIXME: make this configurable
mailbox.addPasswordStore(new PasswordStoreMd5());
mailbox.addPasswordStore(new PasswordStoreCrypt());
mailbox.addPasswordStore(new PasswordStorePlain());
 
return mailbox;
return new Mailbox();
}
 
public boolean allowedToCreate(User editor)
/hostadmiral/trunk/src/ak/hostadmiral/core/model/User.java
1,6 → 1,5
package ak.hostadmiral.core.model;
 
import java.util.Iterator;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
7,6 → 6,7
import java.util.Locale;
import java.util.StringTokenizer;
 
import ak.hostadmiral.util.Digest;
import ak.hostadmiral.util.ModelException;
import ak.hostadmiral.util.ModelSecurityException;
 
17,10 → 17,8
public class User
extends GeneralModelObject
{
public static final String DEFAULT_PASSWORD_STORE = "MD5";
 
private String login;
private Collection passwords; // Collection(PasswordStore)
private String password;
private User boss;
private Boolean superuser;
private Locale locale = Locale.getDefault();
34,17 → 32,11
protected User(User origin)
{
super(origin);
this.login = origin.login;
 
if(origin.passwords == null)
this.passwords = null;
else
this.passwords = new HashSet(origin.passwords);
 
this.boss = origin.boss;
this.login = origin.login;
this.password = origin.password;
this.boss = origin.boss;
this.superuser = origin.superuser;
this.locale = origin.locale;
 
this.locale = origin.locale;
if(origin.loginHistory == null)
this.loginHistory = null;
else
89,39 → 81,20
this.login = login;
}
 
protected void addPasswordStore(PasswordStore ps)
/**
*
* @hibernate.property
*/
protected String getPassword()
{
if(passwords == null) passwords = new HashSet();
passwords.add(ps);
return password;
}
 
protected PasswordStore getDefaultPasswordStore()
throws ModelException
protected void setPassword(String password)
{
if(passwords == null)
throw new ModelException("No password store");
 
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(DEFAULT_PASSWORD_STORE.equals(ps.getDigest()))
return ps;
}
 
throw new ModelException("No password store for digest " + DEFAULT_PASSWORD_STORE);
this.password = password;
}
 
public String getPassword(User editor)
throws ModelException
{
if(!partEditableBy(editor))
throw new ModelSecurityException();
 
return getDefaultPasswordStore().getPassword();
}
 
public void setPassword(User editor, String password)
throws ModelException
{
132,38 → 105,20
throw new NullPointerException("Null password");
 
backupMe();
 
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)o).setNewPassword(password);
}
this.password = Digest.encode(password);
}
 
public boolean checkPassword(String password)
throws ModelException
{
if(password == null)
throw new NullPointerException("Null password");
 
return getDefaultPasswordStore().checkPassword(password);
return checkMd5Password(Digest.encode(password));
}
 
/**
*
* @hibernate.set cascade="all"
* @hibernate.collection-key column="obj"
* @hibernate.collection-one-to-many class="ak.hostadmiral.core.model.PasswordStoreAbstract"
*/
protected Collection getPasswords()
{
return passwords;
}
 
protected void setPasswords(Collection passwords)
public boolean checkMd5Password(String password)
{
this.passwords = passwords;
return this.password.equals(password);
}
 
/**
/hostadmiral/trunk/src/ak/hostadmiral/core/model/Mailbox.java
1,9 → 1,6
package ak.hostadmiral.core.model;
 
import java.util.Iterator;
import java.util.Collection;
import java.util.HashSet;
 
import ak.hostadmiral.util.Digest;
import ak.hostadmiral.util.ModelException;
import ak.hostadmiral.util.ModelSecurityException;
 
15,7 → 12,7
extends GeneralModelObject
{
private String login;
private Collection passwords; // Collection(PasswordStore)
private String password;
private InetDomain domain;
private User owner;
private Boolean virusCheck;
31,12 → 28,7
{
super(origin);
this.login = origin.login;
 
if(origin.passwords == null)
this.passwords = null;
else
this.passwords = new HashSet(origin.passwords);
 
this.password = origin.password;
this.domain = origin.domain;
this.owner = origin.owner;
this.virusCheck = origin.virusCheck;
79,47 → 71,30
this.login = login;
}
 
protected void addPasswordStore(PasswordStore ps)
/**
*
* @hibernate.property
*/
protected String getPassword()
{
if(passwords == null) passwords = new HashSet();
passwords.add(ps);
return password;
}
 
protected void setPassword(String password)
{
this.password = password;
}
 
public void setPassword(User editor, String password)
throws ModelException
{
if(!editableBy(editor))
throw new ModelSecurityException();
 
if(password == null)
throw new NullPointerException("Null password");
 
backupMe();
 
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)o).setNewPassword(password);
}
this.password = Digest.encode(password);
}
 
/**
*
* @hibernate.set cascade="all"
* @hibernate.collection-key column="obj"
* @hibernate.collection-one-to-many class="ak.hostadmiral.core.model.PasswordStoreAbstract"
*/
protected Collection getPasswords()
{
return passwords;
}
 
protected void setPasswords(Collection passwords)
{
this.passwords = passwords;
}
 
/**
*
* @hibernate.many-to-one
/hostadmiral/trunk/doc/todo.txt
1,11 → 1,9
Host Admiral TODO
=================
 
+ Track database structure version.
+ Listeners for all operations.
 
Config in one place. Allow configuration of each listener.
Allow configuration of each listener.
 
Transaction control for listners.
 
27,7 → 25,7
 
+/- Cascade object deletion, confirmation page.
 
+ Store user and malbox passwords in several forms; e.g. clear text, md5, encrypt. Allow
Store user and malbox passwords in several forms; e.g. clear text, md5, encrypt. Allow
admin to specify which forms to use.
 
Check passwords quality (make a separate project for this).
63,7 → 61,7
 
Allow user to create domains (?) and subdomains in his domains.
 
Change shell password for system user if its owner's password is changed (?).
Change shell password for system user if its onwer's password is changed (?).
 
Catch-all mail alias. Only one per domain.
 
72,4 → 70,3
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?
/hostadmiral/trunk/sql/00.tables.sql
2,33 → 2,9
-- hostadmiral sql tables
--
-- FIXME: which values has boolean in hibernate - '1':'0' or '1':'0'?
--
 
create sequence hibernate_sequence;
 
-- version of this database structure,
-- one and only one entry is allowed
create table dbversion
(
version integer not null
);
insert into dbversion (version) values (1);
 
-- passwords for different objects and crypted by different digests
create table passwords
(
id integer not null,
obj integer, -- to which object belongs FIXME: schould be NOT NULL
-- but hibernate makes insert first then update for obj
digest varchar(255) not null, -- 'MD5', 'ENCRYPT' etc
password varchar(255) not null, -- the crypted password
mod_stamp timestamp,
mod_user integer,
 
constraint passwords_prim primary key (id),
constraint passwords_unique unique(obj, digest)
);
 
-- an user is allowed to:
-- see/use an user if he is the 'boss' or is the same user
-- modify password - as above
39,6 → 15,7
(
id integer not null,
login varchar(255) not null,
password varchar(255) not null,
boss integer,
superuser char(1) default '0' check (superuser = '1' or superuser = '0'),
locale varchar(5) default 'en', -- language_country
67,10 → 44,8
);
 
-- default user admin:admin
insert into users (id, login, superuser) values (1, 'admin', '1');
insert into passwords (id, obj, digest, password) values (2, 1, 'MD5', '21232f297a57a5a743894a0e4a801fc3');
insert into users (id, login, password, superuser) values (1, 'admin', '21232f297a57a5a743894a0e4a801fc3', '1');
select nextval('hibernate_sequence'); -- skip id of the default user
select nextval('hibernate_sequence'); -- skip id of the default password
 
-- an user is allowed to see and use a system user if he is the 'owner' or the system user has no owner (null)
create table systemusers
106,12 → 81,12
);
 
-- name of mailbox = login + '@' + domain, e.g. user@example.com
-- if mailbox has no corresponding password entries, then owner's password is used
-- FIXME: make a possibility to use global unique mailboxes
create table mailboxes
(
id integer not null,
login varchar(255) not null,
password varchar(255), -- if null, then owner's password is used
domain integer not null,
owner integer not null,
virusCheck char(1) default '1' check (virusCheck = '1' or virusCheck = '0'),
/hostadmiral/trunk/conf/hibernate.cfg.xml.sample
15,10 → 15,5
 
<property name="dialect">net.sf.hibernate.dialect.PostgreSQLDialect</property>
<property name="show_sql">false</property>
 
<mapping resource="ak/hostadmiral/util/DatabaseVersion.hbm.xml"/>
<mapping resource="ak/hostadmiral/core/model/User.hbm.xml"/>
<mapping resource="ak/hostadmiral/core/model/UserLogin.hbm.xml"/>
<mapping resource="ak/hostadmiral/core/model/PasswordStoreAbstract.hbm.xml"/>
</session-factory>
</hibernate-configuration>