1 package com
.interrupt
.bookkeeping
.cc
.bkell
.aauth
;
4 import java
.io
.UnsupportedEncodingException
;
5 import java
.security
.MessageDigest
;
6 import java
.security
.NoSuchAlgorithmException
;
7 import java
.util
.Iterator
;
10 import javax
.security
.auth
.callback
.CallbackHandler
;
11 import javax
.security
.auth
.login
.LoginContext
;
12 import javax
.security
.auth
.login
.LoginException
;
14 import org
.apache
.log4j
.Logger
;
15 import org
.xmldb
.api
.DatabaseManager
;
16 import org
.xmldb
.api
.base
.Collection
;
17 import org
.xmldb
.api
.base
.XMLDBException
;
19 import com
.interrupt
.bob
.base
.Bob
;
20 import com
.interrupt
.bob
.base
.IBob
;
21 import com
.interrupt
.bob
.base
.IVisitor
;
22 import com
.interrupt
.bookkeeping
.cc
.bkell
.command
.ICommand
;
23 import com
.interrupt
.bookkeeping
.exception
.AuthorisationException
;
24 import com
.interrupt
.bookkeeping
.exception
.SystemException
;
25 import com
.interrupt
.bookkeeping
.http
.BookkeepingSystemFacade
;
26 import com
.interrupt
.bookkeeping
.system
.BookkeepingSystem
;
27 import com
.interrupt
.bookkeeping
.system
.BookkeepingSystemProperties
;
28 import com
.interrupt
.bookkeeping
.users
.GGroups
;
29 import com
.interrupt
.bookkeeping
.users
.Group
;
30 import com
.interrupt
.bookkeeping
.users
.Groups
;
31 import com
.interrupt
.bookkeeping
.users
.IGroup
;
32 import com
.interrupt
.bookkeeping
.users
.IGroups
;
33 import com
.interrupt
.bookkeeping
.users
.IUser
;
34 import com
.interrupt
.bookkeeping
.users
.IUserSession
;
35 import com
.interrupt
.bookkeeping
.users
.IUsers
;
36 import com
.interrupt
.bookkeeping
.users
.User
;
37 import com
.interrupt
.bookkeeping
.users
.UserSession
;
38 import com
.interrupt
.bookkeeping
.users
.Users
;
39 import com
.interrupt
.spittoon
.Spittoon
;
40 import com
.interrupt
.util
.IdGenerator
;
42 public class Aauthentication
extends GAauthentication
implements java
.io
.Serializable
{
45 public static final String AAUTHENTICATION
= "aauthentication";
46 private Logger logger
= Logger
.getLogger(Aauthentication
.class);
47 private static Aauthentication instance
= null;
49 private ThreadGroup userThreadGroup
= new ThreadGroup("UserThreadGroup");
50 private Spittoon spittoon
= null;
51 private AauthenticationMediator aauthenticationMediator
= null;
52 private Bob bob
= new Bob();
53 private IBob loadedAuthorise
= null;
54 private UserSession userSession
= null;
55 //private IUsers aauthUsers = null;
56 //private IGroups aauthGroups = null;
58 public Aauthentication() {
60 //spittoon = Spittoon.instance();
61 this.setId("main.authentication");
64 public static synchronized Aauthentication
instance() {
66 if(instance
== null) {
67 instance
= new Aauthentication();
68 instance
.initialise();
74 public synchronized void setup() {
76 //loadedAuthorise = bob.load(Aauthentication.class.getResourceAsStream("/bookkeeping.system.xml"), BookkeepingSystemProperties.instance().getProperty("bob.def"));
77 //logger.debug("loadedAuthorise:: "+ loadedAuthorise.toXML() );
79 //IUsers userResult = (IUsers)loadedAuthorise.find("users", "aauth.users");
80 //logger.debug("userResult:: "+ userResult.toXML() );
83 //spittoon.addDocument(BookkeepingSystemProperties.instance().getProperty("db.url") + "system/aauthentication/users/", userResult);
85 // put a default '/groups/' in the xml database
86 //IGroups groupResult = (IGroups)loadedAuthorise.find("groups", "aauth.groups");
87 //spittoon.addDocument(BookkeepingSystemProperties.instance().getProperty("db.url") + "system/aauthentication/groups/", groupResult);
90 public synchronized void teardown() throws XMLDBException
{
92 // remove default collections
93 //spittoon.removeCollection(BookkeepingSystemProperties.instance().getProperty("db.url") + "system/aauthentication/");
97 public synchronized void initialise() {
99 //BookkeepingSystemProperties bsproperties = BookkeepingSystemProperties.instance();
100 //IUsers rootUsers = (IUsers)spittoon.getDocument(
101 // bsproperties.getProperty("db.url") + "system/aauthentication/users/", "users", "aauth.users");
102 //IGroups rootGroups = (IGroups)spittoon.getDocument(
103 // bsproperties.getProperty("db.url") + "system/aauthentication/groups/", "groups", "aauth.groups");
104 //IUsers rootUsers = null;
105 //IGroups rootGroups = null;
107 //this.setUsers(rootUsers);
108 //this.setGroups(rootGroups);
112 public String
hashPassword(String passwd
) throws SystemException
{
114 MessageDigest digest
= null;
118 digest
= MessageDigest
.getInstance("SHA");
120 input
= digest
.digest(passwd
.getBytes("UTF-8"));
122 catch(NoSuchAlgorithmException e
) {
123 throw new SystemException(e
);
125 catch(UnsupportedEncodingException e
) {
126 throw new SystemException(e
);
129 String hashString
= new String(input
);
133 public synchronized AauthenticationMediator
getAauthenticationMediator() {
134 return aauthenticationMediator
;
136 public synchronized void setAauthenticationMediator(AauthenticationMediator aauthenticationMediator
) {
137 this.aauthenticationMediator
= aauthenticationMediator
;
139 public UserSession
getUserSession() { return userSession
; }
140 public void setUserSession(UserSession userSession
) { this.userSession
= userSession
; }
141 public synchronized IUsers
getUsers() {
142 return this.findUsersById("aauth.users");
144 public synchronized void setUsers(IUsers users
) {
145 users
.setId("aauth.users");
146 this.removeAllUsers();
147 this.addUsers(users
);
149 public synchronized IGroups
getGroups() {
150 return this.findGroupsById("aauth.groups");
152 public synchronized void setGroups(IGroups groups
) {
153 groups
.setId("aauth.groups");
154 this.removeAllGroups();
155 this.addGroups(groups
);
157 public Spittoon
getSpittoon() {
160 public void setSpittoon(Spittoon spittoon
) {
161 this.spittoon
= spittoon
;
165 public synchronized IUserSession
authenticate(String groupid
, IUser user
) {
168 logger
.debug("Aauthenticate::authenticate > groupid["+groupid
+"] / user["+user
+"]");
170 //** check if group contains the user
171 IGroup agroup
= this.getGroups().findGroupById(groupid
);
173 throw new AuthorisationException("This associated group does not exist");
175 IUser auser
= agroup
.findUserById(user
.getId());
176 if((auser
== null ) && (!agroup
.getOwner().equals(user
.getId()))) {
178 throw new AuthorisationException("The user is not associated with the group");
182 IUsers users
= this.getUsers();
183 IUser iuser
= users
.findUserById(user
.getId());
185 //String passwdHash = hashPassword(user.getPassword());
186 String passwdHash
= user
.getPassword();
189 //** TODO - come up with a better authentication scheme
190 if( user
.getUsername().equals(iuser
.getUsername()) &&
191 passwdHash
.equals(iuser
.getPassword())) {
193 logger
.debug("authenticated ok!!!");
195 this.userSession
= new UserSession();
197 this.userSession
.setTimeout(Long
.parseLong(user
.getLogintimeout()));
199 catch(java
.lang
.NumberFormatException e
) {
200 throw new AuthorisationException("Please set a login timeout for user["+user
.getId()+"]");
202 this.userSession
.setId(IdGenerator
.generateId());
203 this.userSession
.setGroupid(groupid
);
204 this.userSession
.setUserid(user
.getId());
206 //** this visitor will authenticate the use and fire
207 // off the UserSession thread
208 AuthenticateUserVisitor auvisitor
= new AuthenticateUserVisitor();
209 auvisitor
.setUname( user
.getUsername() );
210 auvisitor
.setPasswd( user
.getPassword() );
211 auvisitor
.setUserSession(this.userSession
);
213 this.accept(auvisitor
);
214 return this.userSession
;
219 public synchronized boolean authenticated(IUser user
) {
221 IUsers users
= this.getUsers();
222 User iuser
= (User
)users
.findUserById(user
.getId());
223 if(iuser
.isAuthenticated()) {
228 public synchronized IUserSession
getUserSession(String sessionid
) {
230 return (IUserSession
)this.find("userSession", sessionid
);
235 public synchronized boolean logout(IUser user
) {
237 //IUsers users = this.getUsers();
238 //IUser iuser = users.findUserById(user.getId());
240 /*IGroup agroup = this.getGroups().findGroupById(groupid);
242 throw new AuthorisationException("This associated group does not exist");
244 IUser auser = agroup.findUserById(user.getId());
245 if((auser == null ) && (!agroup.getOwner().equals(user.getId()))) {
247 throw new AuthorisationException("The user is not associated with the group");
251 ////** TODO - come up with a better authentication scheme
252 //if( user.getUsername().equals(iuser.getUsername()) &&
253 // user.getPassword().equals(iuser.getPassword())) {
255 LogoutUserVisitor auvisitor
= new LogoutUserVisitor();
256 auvisitor
.setUname( user
.getUsername() );
257 auvisitor
.setPasswd( user
.getPassword() );
258 this.accept(auvisitor
);
264 public synchronized boolean authorised(IUser user
, ICommand command
) {
266 if(!this.authenticated(user
)) {
270 IAllowedActions resultAllowed
= (IAllowedActions
)this.find("allowedActions", user
.getId() + ".allowedActions");
271 List commands
= resultAllowed
.allCommand();
272 Iterator iter
= commands
.iterator();
273 ICommand eachCommand
= null;
274 while(iter
.hasNext()) {
276 eachCommand
= (ICommand
)iter
.next();
277 //logger.debug(">>> each command: "+ eachCommand.toXML());
279 if( eachCommand
.getName().equals(command
.getName()) ) {
287 public synchronized IUser
findUser(String userid
) {
289 return (IUser
)this.getUsers().findUserById(userid
);
291 public synchronized IGroup
findGroup(String groupid
) {
293 return (IGroup
)this.getGroups().findGroupById(groupid
);
296 public synchronized void addGroup(Group group
) throws AuthorisationException
{
298 // 1. check that there's an owner reference
299 if(group
.getOwner() == null || group
.getOwner().trim().length() == 0) {
300 throw new AuthorisationException("A group must have an owner (user) that is referenced");
303 // 2. check that there's not a duplicate group
304 Group duplicateGroupCheck
= (Group
)this.find("group", group
.getId());
305 if(duplicateGroupCheck
!= null) {
306 throw new AuthorisationException("There is already a group with the id["+group
.getId()+"]");
309 // 3. check that the owner actually exists as a user
310 String dburl
= spittoon
.getAauthDbUrl();
311 StringBuffer sbuffer
= new
312 StringBuffer("/system[ @id='main.system' ]/aauthentication[ @id='main.authentication' ]/users[ @id='aauth.users' ]");
313 sbuffer
.append("/user[ @id='");
314 sbuffer
.append(group
.getOwner());
315 sbuffer
.append("']");
316 String xpath
= sbuffer
.toString();
318 User aauthUser
= (User
)spittoon
.retrieve(dburl
, xpath
, false);
320 if(aauthUser
== null) {
321 throw new AuthorisationException("The referenced owner / user ["+ group
.getOwner() +"] does not exist");
326 IBob nextPull
= this.pullNext();
327 while( nextPull
!= null) {
329 if( nextPull
.getTagName().equals("groups") &&
330 nextPull
.getAttributes().getValue("id").equals("aauth.groups")) {
332 ((GGroups
)nextPull
).addGroup(group
);
335 nextPull
= this.pullNext();
340 public synchronized void removeGroup(String groupId
) {
342 // 1. ensure there are no more users besides the default user before deleting
343 Group targetGroup
= (Group
)(this.getGroups().findGroupById(groupId
));
344 if(targetGroup
!= null) {
346 List userList
= targetGroup
.allUser();
347 if(userList
.size() > 1) {
348 throw new AuthorisationException("There are more users than the default owner");
352 // 2. move group / bookkeeping data to a removed folder for future reference
353 this.aauthenticationMediator
.messageMoveGroupBookkeepingToAttic(groupId
);
358 public synchronized void addUser(User user
) {
360 //** 1. check that there's not an existing user
361 //** this assumes that the existing user list is current with what's in the database
362 logger
.debug("Aauthentication.addUser 1: "+ (Users
)this.getUsers());
363 logger
.debug("Aauthentication.addUser 2: "+ user
);
366 User existingUser
= (User
)this.getUsers().findUserById(user
.getId());
367 if(existingUser
!= null) {
368 throw new AuthorisationException("There is already existing user with id["+user
.getId()+"]");
372 //** 2. now add a default group corresponding to the new user
373 // this is the default group to add
376 Aauthentication
.class.getResourceAsStream("/add.usergroup.xml"),
377 BookkeepingSystemProperties
.instance().getProperty("bob.def"));
378 defaultGroup
.setId(user
.getId() + ".group");
379 defaultGroup
.setName(user
.getId() + ".group");
380 defaultGroup
.setOwner(user
.getId());
382 //** 3. add to aauth.groups
383 String dburl
= spittoon
.getAauthDbUrl();
385 "/system[ @id='main.system' ]/aauthentication[ @id='main.authentication' ]/groups[ @id='aauth.groups' ]" +
386 "/group[ @id='"+ defaultGroup
.getId() +"' ]";
387 spittoon
.createR(dburl
, groupsXpath
, defaultGroup
.toXML(false));
390 //** 4. add the user to the database
391 user
.setDefaultGroup(defaultGroup
.getId()); // set this user's default group name
392 String authXpath
= "/system[ @id='main.system' ]/aauthentication[ @id='main.authentication' ]/users[ @id='aauth.users' ]";
393 Users aauthUsers
= (Users
)spittoon
.retrieve(dburl
, authXpath
, false);
394 aauthUsers
.addUser(user
);
395 this.setUsers( aauthUsers
);
398 //** 5. add the user to the database
399 spittoon
.createR(dburl
, authXpath
+ "/user[ @id='"+user
.getId()+"' ]", user
.toXML(false));
401 this.aauthenticationMediator
.addGroupSetAssociatedBookkeeping(defaultGroup
);
405 public synchronized void removeUser(String userId
) {
407 // 1. first remove the associated group
408 Group defaultGroup
= (Group
)this.getGroups().removeGroupByOwner(userId
);
409 this.removeGroup(defaultGroup
.getId());
412 // 2. remove the user
413 class RemoveUserVisitor
implements IVisitor
{
414 public String userid
= null;
415 public void visit(IBob bob
) {
416 if( bob
.getTagName().equals("user") &&
417 bob
.getAttributes().getValue("id").equals(userid
)) {
419 ((Users
)bob
.getParent()).removeUserById(userid
);
423 RemoveUserVisitor ruVisitor
= new RemoveUserVisitor();
424 ruVisitor
.userid
= userId
;
425 this.accept(ruVisitor
);
430 public synchronized void addUserToGroup(String groupId
, User user
) {
432 this.getGroups().findGroupById(groupId
).addUser(user
);
435 public synchronized void removeUserFromGroup(String groupid
, String userid
) {
437 // 1. check if group exists
438 Group group
= (Group
)this.getGroups().findGroupById(groupid
);
440 throw new AuthorisationException("There is no group with id '"+groupid
+"'");
443 // 2. check if user exists
444 User user
= (User
)this.getUsers().findUserById(userid
);
446 throw new AuthorisationException("There is no user with id '"+userid
+"'");
449 // 3. check if user is in the group
450 User removedUser
= (User
)group
.removeUserById(user
.getId());
451 if(removedUser
== null) {
452 throw new AuthorisationException("The user '"+user
.getId()+"' does not exist in the group '"+group
.getId()+"'");
455 this.getGroups().findGroupById(groupid
).removeUserById(userid
);
460 class SavePersistor
{
462 private String baseDir
= null;
463 private String groupDir
= "system/aauthentication/groups/";
464 private String usersDir
= "system/aauthentication/users/";
465 private BookkeepingSystemProperties bsprops
= null;
466 private Spittoon spittoon
= null;
468 public SavePersistor() {
469 bsprops
= BookkeepingSystemProperties
.instance();
471 public void setSpittoon(Spittoon spit
) {
474 public Spittoon
getSpittoon() {
477 public void setBaseDir(String bdir
) {
480 public String
getBaseDir() {
483 public void visit(IBob persistable
) {
485 if(persistable
instanceof IGroups
&& ((IGroups
)persistable
).getId().equals("aauth.groups")) {
487 //** save to system/aauthentication/groups/
488 //spittoon.updateDocument(
489 // BookkeepingSystemProperties.instance().getProperty("db.url") + "system/aauthentication/groups/",
490 // persistable.getTagName(),
491 // persistable.getAttributes().getValue("id"),
495 else if(persistable
instanceof IUsers
&& ((IUsers
)persistable
).getId().equals("aauth.users")) {
497 //** save to system/aauthentication/users/
498 //spittoon.updateDocument(
499 // BookkeepingSystemProperties.instance().getProperty("db.url") + "system/aauthentication/users/",
500 // persistable.getTagName(),
501 // persistable.getAttributes().getValue("id"),
509 public boolean ii
= true;
512 //** run until an shutdown interruption
514 // 1. how to communicate with running thread -> calling a synchronized method
515 // 2. how to send a shutdown signal -> interrupt();
518 logger
.debug("...running");
526 public static void main(String
[] args
) {
528 Logger
.getLogger(Aauthentication
.class).debug("Starting");
530 // Aauthentication aauth = Aauthentication.instance();
531 // Thread aauthThread = new Thread(aauth);
533 // Logger.getLogger(Aauthentication.class).debug("Helloooooooooooooooooooooooooooooooooooooooooo");
534 // aauthThread.start();
538 //try { aauthThread.join(); } catch(Throwable e) { }
539 //aauthThread.interrupt();
541 for(int j=0; j < 1000; j++) {}
545 //Logger.getLogger(Aauthentication.class).debug("Ending");