|
AccessControllerImpl |
|
1 /* 2 * AccessControllerImpl.java 3 * 4 * Copyright (c) 1998-2001, The University of Sheffield. 5 * 6 * This file is part of GATE (see http://gate.ac.uk/), and is free 7 * software, licenced under the GNU Library General Public License, 8 * Version 2, June 1991 (in the distribution as file licence.html, 9 * and also available at http://gate.ac.uk/gate/licence.html). 10 * 11 * Marin Dimitrov, 19/Sep/2001 12 * 13 * $Id: AccessControllerImpl.java,v 1.46 2002/03/13 14:52:11 marin Exp $ 14 */ 15 16 package gate.security; 17 18 import java.util.*; 19 import java.sql.*; 20 import java.net.*; 21 22 import junit.framework.*; 23 24 import gate.*; 25 import gate.event.*; 26 import gate.persist.*; 27 import gate.util.MethodNotImplementedException; 28 29 30 public class AccessControllerImpl 31 implements AccessController, ObjectModificationListener { 32 33 public static final int DEFAULT_SESSION_TIMEOUT_MIN = 4*60; 34 35 public static final int LOGIN_OK = 1; 36 public static final int LOGIN_FAILED = 2; 37 38 private static long MY_VERY_SECRET_CONSTANT; 39 private static final int RANDOM_MAX = 1024; 40 41 private HashMap sessions; 42 private HashMap sessionLastUsed; 43 private HashMap sessionTimeouts; 44 45 private Connection jdbcConn; 46 private String jdbcURL; 47 48 private HashMap usersByID; 49 private HashMap usersByName; 50 51 private HashMap groupsByID; 52 private HashMap groupsByName; 53 54 private static Random r; 55 private boolean isPooled; 56 57 private int refCnt; 58 59 /** --- */ 60 private Vector omModificationListeners; 61 /** --- */ 62 private Vector omCreationListeners; 63 /** --- */ 64 private Vector omDeletionListeners; 65 66 67 static { 68 r = new Random(); 69 MY_VERY_SECRET_CONSTANT = r.nextInt(RANDOM_MAX) * r.nextInt(RANDOM_MAX) 70 + Math.round(Math.PI * Math.E); 71 } 72 73 /** --- */ 74 public AccessControllerImpl(String jdbcURL) { 75 76 Assert.assertNotNull(jdbcURL); 77 78 this.refCnt = 0; 79 this.jdbcURL = jdbcURL; 80 81 sessions = new HashMap(); 82 sessionLastUsed = new HashMap(); 83 sessionTimeouts = new HashMap(); 84 85 usersByID = new HashMap(); 86 usersByName= new HashMap(); 87 88 groupsByID = new HashMap(); 89 groupsByName = new HashMap(); 90 91 this.omModificationListeners = new Vector(); 92 this.omCreationListeners = new Vector(); 93 this.omDeletionListeners = new Vector(); 94 } 95 96 /** --- */ 97 public void open() 98 throws PersistenceException{ 99 100 synchronized(this) { 101 if (refCnt++ == 0) { 102 //open connection 103 try { 104 //1. get connection to the database 105 jdbcConn = DBHelper.connect(this.jdbcURL); 106 107 Assert.assertNotNull(jdbcConn); 108 109 //2. initialize group/user collections 110 //init, i.e. read users and groups from DB 111 init(); 112 } 113 catch(SQLException sqle) { 114 throw new PersistenceException("could not get DB connection ["+ sqle.getMessage() +"]"); 115 } 116 catch(ClassNotFoundException clse) { 117 throw new PersistenceException("cannot locate JDBC driver ["+ clse.getMessage() +"]"); 118 } 119 } 120 } 121 122 123 } 124 125 /** --- */ 126 public void close() 127 throws PersistenceException{ 128 129 if (--this.refCnt == 0) { 130 131 //0. Invalidate all sessions 132 this.sessions.clear(); 133 this.sessionLastUsed.clear(); 134 this.sessionTimeouts.clear(); 135 136 //1. deregister self as listener for groups 137 Set groupMappings = this.groupsByName.entrySet(); 138 Iterator itGroups = groupMappings.iterator(); 139 140 while (itGroups.hasNext()) { 141 Map.Entry mapEntry = (Map.Entry)itGroups.next(); 142 GroupImpl grp = (GroupImpl)mapEntry.getValue(); 143 grp.unregisterObjectModificationListener(this, 144 ObjectModificationEvent.OBJECT_MODIFIED); 145 } 146 147 //1.1. deregister self as listener for users 148 Set userMappings = this.usersByName.entrySet(); 149 Iterator itUsers = userMappings.iterator(); 150 151 while (itUsers.hasNext()) { 152 Map.Entry mapEntry = (Map.Entry)itUsers.next(); 153 UserImpl usr = (UserImpl)mapEntry.getValue(); 154 usr.unregisterObjectModificationListener(this, 155 ObjectModificationEvent.OBJECT_MODIFIED); 156 } 157 158 //1.2 release all listeners registered for this object 159 this.omCreationListeners.removeAllElements(); 160 this.omDeletionListeners.removeAllElements(); 161 this.omModificationListeners.removeAllElements(); 162 163 //2. delete all groups/users collections 164 this.groupsByID.clear(); 165 this.groupsByName.clear(); 166 this.usersByID.clear(); 167 this.groupsByName.clear(); 168 169 //3.close connection (if not pooled) 170 try { 171 if (false == this.isPooled) { 172 this.jdbcConn.close(); 173 } 174 } 175 catch(SQLException sqle) { 176 throw new PersistenceException("can't close connection to DB:["+ 177 sqle.getMessage()+"]"); 178 } 179 } 180 } 181 182 /** --- */ 183 public Group findGroup(String name) 184 throws PersistenceException,SecurityException{ 185 186 Group grp = (Group)this.groupsByName.get(name); 187 188 if (null == grp) { 189 throw new SecurityException("No such group"); 190 } 191 192 return grp; 193 } 194 195 /** --- */ 196 public Group findGroup(Long id) 197 throws PersistenceException,SecurityException { 198 199 Group grp = (Group)this.groupsByID.get(id); 200 201 if (null == grp) { 202 throw new SecurityException("No such group"); 203 } 204 205 return grp; 206 } 207 208 /** --- */ 209 public User findUser(String name) 210 throws PersistenceException,SecurityException { 211 212 User usr = (User)this.usersByName.get(name); 213 214 if (null == usr) { 215 throw new SecurityException("No such user"); 216 } 217 218 return usr; 219 } 220 221 /** --- */ 222 public User findUser(Long id) 223 throws PersistenceException,SecurityException { 224 225 User usr = (User)this.usersByID.get(id); 226 227 if (null == usr) { 228 throw new SecurityException("No such user"); 229 } 230 231 return usr; 232 } 233 234 /** --- */ 235 public Session findSession(Long id) 236 throws SecurityException { 237 238 Session s = (Session)this.sessions.get(id); 239 240 if (null==s) { 241 throw new SecurityException("No such session ID!"); 242 } 243 244 return s; 245 } 246 247 /** --- */ 248 public Group createGroup(String name,Session s) 249 throws PersistenceException, SecurityException { 250 251 Assert.assertNotNull(name); 252 253 //-1. check session 254 if (false == isValidSession(s)) { 255 throw new SecurityException("invalid session supplied"); 256 } 257 258 //0. check privileges 259 if (false == s.isPrivilegedSession()) { 260 throw new SecurityException("insufficient privileges"); 261 } 262 263 264 //1. create group in DB 265 CallableStatement stmt = null; 266 Long new_id; 267 268 try { 269 stmt = this.jdbcConn.prepareCall( 270 "{ call "+Gate.DB_OWNER+".security.create_group(?,?)} "); 271 stmt.setString(1,name); 272 //numbers generated from Oracle sequences are BIGINT 273 stmt.registerOutParameter(2,java.sql.Types.BIGINT); 274 stmt.execute(); 275 new_id = new Long(stmt.getLong(2)); 276 } 277 catch(SQLException sqle) { 278 279 //check for more specifi exceptions 280 switch(sqle.getErrorCode()) { 281 282 case DBHelper.X_ORACLE_DUPLICATE_GROUP_NAME: 283 throw new PersistenceException( 284 "can't create a group in DB, name is not unique: [" 285 + sqle.getMessage()+"]"); 286 287 default: 288 throw new PersistenceException( 289 "can't create a group in DB: ["+ sqle.getMessage()+"]"); 290 } 291 292 } 293 finally { 294 DBHelper.cleanup(stmt); 295 } 296 297 //2. create GroupImpl for the new group and 298 // users list is empty 299 GroupImpl grp = new GroupImpl(new_id,name,new Vector(),this,this.jdbcConn); 300 301 //3. register as objectModification listener for this group 302 //we care only about name changes 303 grp.registerObjectModificationListener(this,ObjectModificationEvent.OBJECT_MODIFIED); 304 305 //4.put in collections 306 this.groupsByID.put(new_id,grp); 307 this.groupsByName.put(name,grp); 308 309 return grp; 310 } 311 312 /** --- */ 313 public void deleteGroup(Long id, Session s) 314 throws PersistenceException,SecurityException { 315 316 Group grp = (Group)this.groupsByID.get(id); 317 if (null == grp) { 318 throw new SecurityException("incorrect group id supplied ( id = ["+id+"])"); 319 } 320 321 //delegate 322 deleteGroup(grp,s); 323 } 324 325 /** --- */ 326 public void deleteGroup(Group grp, Session s) 327 throws PersistenceException,SecurityException { 328 329 //1. check session 330 if (false == isValidSession(s)) { 331 throw new SecurityException("invalid session supplied"); 332 } 333 334 //2. check privileges 335 if (false == s.isPrivilegedSession()) { 336 throw new SecurityException("insufficient privileges"); 337 } 338 339 //3. delete in DB 340 CallableStatement stmt = null; 341 342 try { 343 stmt = this.jdbcConn.prepareCall( 344 "{ call "+Gate.DB_OWNER+".security.delete_group(?) } "); 345 stmt.setLong(1,grp.getID().longValue()); 346 stmt.execute(); 347 } 348 catch(SQLException sqle) { 349 //check for more specific exceptions 350 switch(sqle.getErrorCode()) { 351 352 case DBHelper.X_ORACLE_GROUP_OWNS_RESOURCES: 353 throw new PersistenceException( 354 "can't delete a group from DB, the group owns LR(s): [" 355 + sqle.getMessage()+"]"); 356 357 default: 358 throw new PersistenceException( 359 "can't delete a group from DB: ["+ sqle.getMessage()+"]"); 360 } 361 } 362 finally { 363 DBHelper.cleanup(stmt); 364 } 365 366 //4. delete from collections 367 this.groupsByID.remove(grp.getID()); 368 this.groupsByName.remove(grp.getName()); 369 370 //5. notify all other listeners 371 //this one is tricky - sent OBJECT_DELETED event to all who care 372 //but note that the SOURCE is not us but the object being deleted 373 ObjectModificationEvent e = new ObjectModificationEvent( 374 grp, 375 ObjectModificationEvent.OBJECT_DELETED, 376 0); 377 378 fireObjectDeletedEvent(e); 379 380 //6. this one is tricky: invalidate all sessions 381 //that are for user logged in as members of this group 382 Set sessionMappings = this.sessions.entrySet(); 383 Iterator itSessions = sessionMappings.iterator(); 384 385 //6.1 to avoid ConcurrentModificationException store the sessions 386 //found in a temp vector 387 Vector sessionsToDelete = new Vector(); 388 while (itSessions.hasNext()) { 389 Map.Entry mapEntry = (Map.Entry)itSessions.next(); 390 SessionImpl ses = (SessionImpl)mapEntry.getValue(); 391 if (ses.getGroup().equals(grp)) { 392 //logout(ses); --> this will cause ConcurrentModificationException 393 sessionsToDelete.add(ses); 394 } 395 } 396 //6.2 now delete sessions 397 for (int i=0; i< sessionsToDelete.size(); i++) { 398 Session ses = (Session)sessionsToDelete.elementAt(i); 399 logout(ses); 400 } 401 402 } 403 404 /** --- */ 405 public User createUser(String name, String passwd,Session s) 406 throws PersistenceException,SecurityException { 407 408 Assert.assertNotNull(name); 409 410 //-1. check session 411 if (false == isValidSession(s)) { 412 throw new SecurityException("invalid session supplied"); 413 } 414 415 //0. check privileges 416 if (false == s.isPrivilegedSession()) { 417 throw new SecurityException("insufficient privileges"); 418 } 419 420 //1. create user in DB 421 CallableStatement stmt = null; 422 Long new_id; 423 424 try { 425 stmt = this.jdbcConn.prepareCall( 426 "{ call "+Gate.DB_OWNER+".security.create_user(?,?,?)} "); 427 stmt.setString(1,name); 428 stmt.setString(2,passwd); 429 //numbers generated from Oracle sequences are BIGINT 430 stmt.registerOutParameter(3,java.sql.Types.BIGINT); 431 stmt.execute(); 432 new_id = new Long(stmt.getLong(3)); 433 } 434 catch(SQLException sqle) { 435 //check for more specific exceptions 436 switch(sqle.getErrorCode()) { 437 438 case DBHelper.X_ORACLE_DUPLICATE_USER_NAME: 439 throw new PersistenceException( 440 "can't create a user in DB, name is not unique: [" 441 + sqle.getMessage()+"]"); 442 default: 443 throw new PersistenceException( 444 "can't create a user in DB: ["+ sqle.getMessage()+"]"); 445 } 446 } 447 finally { 448 DBHelper.cleanup(stmt); 449 } 450 451 //2. create UserImpl for the new user 452 // groups list is empty 453 UserImpl usr = new UserImpl(new_id,name,new Vector(),this,this.jdbcConn); 454 455 //3. register as objectModification listener for this user 456 //we care only about user changing name 457 usr.registerObjectModificationListener(this,ObjectModificationEvent.OBJECT_MODIFIED); 458 459 //4. put in collections 460 this.usersByID.put(new_id,usr); 461 this.usersByName.put(name,usr); 462 463 return usr; 464 } 465 466 /** --- */ 467 public void deleteUser(User usr, Session s) 468 throws PersistenceException,SecurityException { 469 470 //1. check session 471 if (false == isValidSession(s)) { 472 throw new SecurityException("invalid session supplied"); 473 } 474 475 //2. check privileges 476 if (false == s.isPrivilegedSession()) { 477 throw new SecurityException("insufficient privileges"); 478 } 479 480 //3. delete in DB 481 CallableStatement stmt = null; 482 483 try { 484 stmt = this.jdbcConn.prepareCall( 485 "{ call "+Gate.DB_OWNER+".security.delete_user(?) } "); 486 stmt.setLong(1,usr.getID().longValue()); 487 stmt.execute(); 488 } 489 catch(SQLException sqle) { 490 switch(sqle.getErrorCode()) { 491 492 case DBHelper.X_ORACLE_USER_OWNS_RESOURCES: 493 throw new PersistenceException( 494 "can't delete user from DB, the user owns LR(s): [" 495 + sqle.getMessage()+"]"); 496 default: 497 throw new PersistenceException( 498 "can't delete user from DB: ["+ sqle.getMessage()+"]"); 499 } 500 } 501 finally { 502 DBHelper.cleanup(stmt); 503 } 504 505 //4. delete from collections 506 this.usersByID.remove(usr.getID()); 507 this.usersByName.remove(usr.getName()); 508 509 //6. notify all other listeners 510 //this one is tricky - sent OBJECT_DELETED event to all who care 511 //but note that the SOURCE is not us but the object being deleted 512 ObjectModificationEvent e = new ObjectModificationEvent( 513 usr, 514 ObjectModificationEvent.OBJECT_DELETED, 515 0); 516 517 fireObjectDeletedEvent(e); 518 519 //7. this one is tricky: invalidate all sessions for the user 520 Set sessionMappings = this.sessions.entrySet(); 521 Iterator itSessions = sessionMappings.iterator(); 522 523 //7.1 to avoid ConcurrentModificationException store the sessions 524 //found in a temp vector 525 Vector sessionsToDelete = new Vector(); 526 while (itSessions.hasNext()) { 527 Map.Entry mapEntry = (Map.Entry)itSessions.next(); 528 SessionImpl ses = (SessionImpl)mapEntry.getValue(); 529 if (ses.getUser().equals(usr)) { 530 //logout(ses); --> this will cause ConcurrentModificationException 531 sessionsToDelete.add(ses); 532 } 533 } 534 //7.2 now delete sessions 535 for (int i=0; i< sessionsToDelete.size(); i++) { 536 Session ses = (Session)sessionsToDelete.elementAt(i); 537 logout(ses); 538 } 539 540 } 541 542 543 /** --- */ 544 public void deleteUser(Long id, Session s) 545 throws PersistenceException,SecurityException { 546 547 User usr = (User)usersByID.get(id); 548 if (null == usr) { 549 throw new SecurityException("incorrect user id supplied ( id = ["+id+"])"); 550 } 551 552 //delegate 553 deleteUser(usr,s); 554 } 555 556 /** --- */ 557 public Session login(String usr_name, String passwd,Long prefGroupID) 558 throws PersistenceException,SecurityException { 559 560 //1. check the user locally 561 User usr = (User)this.usersByName.get(usr_name); 562 if (null == usr) { 563 throw new SecurityException("no such user (username=["+usr_name+"])"); 564 } 565 566 //2. check group localy 567 Group grp = (Group)this.groupsByID.get(prefGroupID); 568 if (null == grp) { 569 throw new SecurityException("no such group (id=["+prefGroupID+"])"); 570 } 571 572 //2. check user/pass in DB 573 CallableStatement stmt = null; 574 boolean isPrivilegedUser = false; 575 576 try { 577 stmt = this.jdbcConn.prepareCall( 578 "{ call "+Gate.DB_OWNER+".security.login(?,?,?,?)} "); 579 stmt.setString(1,usr_name); 580 stmt.setString(2,passwd); 581 stmt.setLong(3,prefGroupID.longValue()); 582 stmt.registerOutParameter(4,java.sql.Types.NUMERIC); 583 stmt.execute(); 584 isPrivilegedUser = (stmt.getInt(4) == DBHelper.FALSE ? false : true ); 585 } 586 catch(SQLException sqle) { 587 switch(sqle.getErrorCode()) 588 { 589 case DBHelper.X_ORACLE_INVALID_USER_NAME : 590 throw new SecurityException("Login failed: incorrect user"); 591 case DBHelper.X_ORACLE_INVALID_USER_PASS : 592 throw new SecurityException("Login failed: incorrect password"); 593 case DBHelper.X_ORACLE_INVALID_USER_GROUP : 594 throw new SecurityException("Login failed: incorrect group"); 595 default: 596 throw new PersistenceException("can't login user, DB error is: ["+ 597 sqle.getMessage()+"]"); 598 } 599 } 600 finally { 601 DBHelper.cleanup(stmt); 602 } 603 604 605 //3. create a Session and set User/Group 606 Long sessionID = createSessionID(); 607 while (this.sessions.containsKey(sessionID)) { 608 sessionID = createSessionID(); 609 } 610 611 SessionImpl s = new SessionImpl(sessionID, 612 usr, 613 grp, 614 DEFAULT_SESSION_TIMEOUT_MIN, 615 isPrivilegedUser); 616 617 //4. add session to session collections 618 this.sessions.put(s.getID(),s); 619 620 //5. set the session timeouts and keep alives 621 this.sessionTimeouts.put(sessionID,new Long(DEFAULT_SESSION_TIMEOUT_MIN)); 622 touchSession(s); //this one changes the keepAlive time 623 624 return s; 625 } 626 627 /** --- */ 628 public void logout(Session s) 629 throws SecurityException { 630 631 Assert.assertNotNull(s); 632 Long SID = s.getID(); 633 634 //1.sessions 635 Session removedSession = (Session)this.sessions.remove(SID); 636 Assert.assertNotNull(removedSession); 637 638 //2. keep alives 639 Object lastUsed = this.sessionLastUsed.remove(SID); 640 Assert.assertNotNull(lastUsed); 641 642 //3. timeouts 643 Object timeout = this.sessionTimeouts.remove(SID); 644 Assert.assertNotNull(timeout); 645 } 646 647 /** --- */ 648 public void setSessionTimeout(Session s, int timeoutMins) 649 throws SecurityException { 650 651 this.sessionTimeouts.put(s.getID(),new Long(timeoutMins)); 652 } 653 654 /** --- */ 655 public boolean isValidSession(Session s) { 656 657 //1. do we have such session? 658 if (false == this.sessions.containsKey(s.getID())) { 659 return false; 660 } 661 662 //2. has it expired meanwhile? 663 Assert.assertNotNull(this.sessionLastUsed.get(s.getID())); 664 665 long lastUsedMS = ((Long)this.sessionLastUsed.get(s.getID())).longValue(); 666 long sessTimeoutMin = ((Long)this.sessionTimeouts.get(s.getID())).longValue(); 667 long currTimeMS = System.currentTimeMillis(); 668 //timeout is in minutes 669 long lastUsedMin = (currTimeMS-lastUsedMS)/(1000*60); 670 671 if (lastUsedMin > sessTimeoutMin) { 672 //oops, session expired 673 //invalidate it and fail 674 try { 675 logout(s); 676 } 677 catch(SecurityException se) { 678 //well, this can happen only if logout() was called together 679 //with isValidSesion() but the possibility it too low to care 680 //and synchronize access 681 ; 682 } 683 684 return false; 685 } 686 687 //everything ok 688 //touch session 689 touchSession(s); 690 691 return true; 692 } 693 694 /** -- */ 695 public List listGroups() 696 throws PersistenceException { 697 698 //1. read all groups from DB 699 Statement stmt = null; 700 ResultSet rs = null; 701 String sql; 702 Vector result = new Vector(); 703 704 try { 705 stmt = this.jdbcConn.createStatement(); 706 707 //1.1 read groups 708 sql = " SELECT grp_name "+ 709 " FROM "+Gate.DB_OWNER+".t_group "+ 710 " ORDER BY grp_name ASC"; 711 rs = stmt.executeQuery(sql); 712 713 while (rs.next()) { 714 //access by index is faster 715 //first column index is 1 716 String grp_name = rs.getString(1); 717 result.add(grp_name); 718 } 719 720 return result; 721 } 722 catch (SQLException sqle) { 723 throw new PersistenceException("cannot read groups from DB :["+ 724 sqle.getMessage() +"]"); 725 } 726 finally { 727 DBHelper.cleanup(rs); 728 DBHelper.cleanup(stmt); 729 } 730 } 731 732 /** -- */ 733 public List listUsers() 734 throws PersistenceException { 735 736 //1. read all users from DB 737 Statement stmt = null; 738 ResultSet rs = null; 739 String sql; 740 Vector result = new Vector(); 741 742 try { 743 stmt = this.jdbcConn.createStatement(); 744 745 //1.1 read groups 746 sql = " SELECT usr_login "+ 747 " FROM "+Gate.DB_OWNER+".t_user "+ 748 " ORDER BY usr_login DESC"; 749 rs = stmt.executeQuery(sql); 750 751 while (rs.next()) { 752 //access by index is faster 753 //first column index is 1 754 String usr_name = rs.getString(1); 755 result.add(usr_name); 756 } 757 758 return result; 759 } 760 catch (SQLException sqle) { 761 throw new PersistenceException("cannot read groups from DB :["+ 762 sqle.getMessage() +"]"); 763 } 764 finally { 765 DBHelper.cleanup(rs); 766 DBHelper.cleanup(stmt); 767 } 768 } 769 770 771 772 /* private methods */ 773 774 private void touchSession(Session s) { 775 776 this.sessionLastUsed.put(s.getID(), new Long(System.currentTimeMillis())); 777 } 778 779 780 private Long createSessionID() { 781 782 //need a hint? 783 return new Long(((System.currentTimeMillis() << 16) >> 16)* 784 (r.nextInt(RANDOM_MAX))* 785 Runtime.getRuntime().freeMemory()* 786 MY_VERY_SECRET_CONSTANT); 787 } 788 789 790 private boolean canDeleteGroup(Group grp) 791 throws PersistenceException, SecurityException{ 792 793 //1. check group localy 794 if (false == this.groupsByID.containsValue(grp)) { 795 throw new SecurityException("no such group (id=["+grp.getID()+"])"); 796 } 797 798 //2. check DB 799 CallableStatement stmt = null; 800 801 try { 802 stmt = this.jdbcConn.prepareCall( 803 "{ ? = call "+Gate.DB_OWNER+".security.can_delete_group(?) }"); 804 stmt.registerOutParameter(1,java.sql.Types.INTEGER); 805 stmt.setLong(2,grp.getID().longValue()); 806 stmt.execute(); 807 boolean res = stmt.getBoolean(1); 808 809 return res; 810 } 811 catch(SQLException sqle) { 812 throw new PersistenceException("can't perform document checks, DB error is: ["+ 813 sqle.getMessage()+"]"); 814 } 815 finally { 816 DBHelper.cleanup(stmt); 817 } 818 819 } 820 821 822 private boolean canDeleteUser(User usr) 823 throws PersistenceException, SecurityException{ 824 825 //1. check group localy 826 if (false == this.usersByID.containsValue(usr)) { 827 throw new SecurityException("no such user (id=["+usr.getID()+"])"); 828 } 829 830 //2. check DB 831 CallableStatement stmt = null; 832 833 try { 834 stmt = this.jdbcConn.prepareCall( 835 "{ ? = call "+Gate.DB_OWNER+".security.can_delete_user(?) }"); 836 837 stmt.registerOutParameter(1,java.sql.Types.INTEGER); 838 stmt.setLong(2,usr.getID().longValue()); 839 stmt.execute(); 840 boolean res = stmt.getBoolean(1); 841 842 return res; 843 } 844 catch(SQLException sqle) { 845 throw new PersistenceException("can't perform document checks, DB error is: ["+ 846 sqle.getMessage()+"]"); 847 } 848 finally { 849 DBHelper.cleanup(stmt); 850 } 851 852 } 853 854 private void init() 855 throws PersistenceException { 856 857 //1. read all groups and users from DB 858 Statement stmt = null; 859 ResultSet rs = null; 860 String sql; 861 Hashtable groupNames = new Hashtable(); 862 Hashtable groupMembers= new Hashtable(); 863 Hashtable userNames= new Hashtable(); 864 Hashtable userGroups= new Hashtable(); 865 866 try { 867 stmt = this.jdbcConn.createStatement(); 868 869 //1.1 read groups 870 sql = " SELECT grp_id, " + 871 " grp_name "+ 872 " FROM "+Gate.DB_OWNER+".t_group"; 873 rs = stmt.executeQuery(sql); 874 875 876 877 while (rs.next()) { 878 //access by index is faster 879 //first column index is 1 880 long grp_id = rs.getLong(1); 881 String grp_name = rs.getString(2); 882 groupNames.put(new Long(grp_id),grp_name); 883 groupMembers.put(new Long(grp_id),new Vector()); 884 } 885 DBHelper.cleanup(rs); 886 887 888 //1.2 read users 889 sql = " SELECT usr_id, " + 890 " usr_login "+ 891 " FROM "+Gate.DB_OWNER+".t_user"; 892 rs = stmt.executeQuery(sql); 893 894 while (rs.next()) { 895 //access by index is faster 896 //first column index is 1 897 long usr_id = rs.getLong(1); 898 String usr_name = rs.getString(2); 899 userNames.put(new Long(usr_id),usr_name); 900 userGroups.put(new Long(usr_id),new Vector()); 901 } 902 DBHelper.cleanup(rs); 903 904 905 //1.3 read user/group relations 906 sql = " SELECT UGRP_GROUP_ID, " + 907 " UGRP_USER_ID "+ 908 " FROM "+Gate.DB_OWNER+".t_user_group " + 909 " ORDER BY UGRP_GROUP_ID asc"; 910 rs = stmt.executeQuery(sql); 911 912 while (rs.next()) { 913 //access by index is faster 914 //first column index is 1 915 Long grp_id = new Long(rs.getLong(1)); 916 Long usr_id = new Long(rs.getLong(2)); 917 918 //append user to group members list 919 Vector currMembers = (Vector)groupMembers.get(grp_id); 920 currMembers.add(usr_id); 921 922 Vector currGroups = (Vector)userGroups.get(usr_id); 923 currGroups.add(grp_id); 924 } 925 DBHelper.cleanup(rs); 926 } 927 catch(SQLException sqle) { 928 throw new PersistenceException("DB error is: ["+ 929 sqle.getMessage()+"]"); 930 } 931 finally { 932 DBHelper.cleanup(rs); 933 DBHelper.cleanup(stmt); 934 } 935 936 //2. create USerImpl's and GroupImpl's and put them in collections 937 938 //2.1 create Groups 939 Vector toBeInitializedGroups = new Vector(); 940 941 Enumeration enGroups = groupNames.keys(); 942 while (enGroups.hasMoreElements()) { 943 Long grpId = (Long)enGroups.nextElement(); 944 // Vector grpMembers = (Vector)groupMembers.get(grpId); 945 String grpName = (String)groupNames.get(grpId); 946 947 //note that the Vector with group members is empty 948 //will beinitalized later (ugly hack for bad desgin) 949 GroupImpl grp = new GroupImpl(grpId,grpName,new Vector(),this,this.jdbcConn); 950 //register as listener for thsi group 951 //we care only about name changes 952 grp.registerObjectModificationListener(this,ObjectModificationEvent.OBJECT_MODIFIED); 953 954 //add to collection 955 this.groupsByID.put(grp.getID(),grp); 956 this.groupsByName.put(grp.getName(),grp); 957 958 //add to vector of the objects to be initialized 959 toBeInitializedGroups.add(grp); 960 } 961 962 //2.2 create Users 963 Vector toBeInitializedUsers = new Vector(); 964 965 Enumeration enUsers = userNames.keys(); 966 while (enUsers.hasMoreElements()) { 967 Long usrId = (Long)enUsers.nextElement(); 968 // Vector usrGroups = (Vector)userGroups.get(usrId); 969 String usrName = (String)userNames.get(usrId); 970 971 //note that the Vector with user's group is empty 972 //will be initalized later (ugly hack for bad desgin) 973 UserImpl usr = new UserImpl(usrId,usrName,new Vector(),this,this.jdbcConn); 974 //register as listener for thsi user 975 //we care only about user changing name 976 usr.registerObjectModificationListener(this,ObjectModificationEvent.OBJECT_MODIFIED); 977 978 //add to collection 979 this.usersByID.put(usr.getID(),usr); 980 this.usersByName.put(usr.getName(),usr); 981 982 //add to vector of the objects to be initialized 983 toBeInitializedUsers.add(usr); 984 } 985 986 //3. the hack itself: 987 //all the groups and users are not fully initialized yet 988 //(the groups/users Vectors are empty) 989 //initialize them now 990 991 //3.1 initialize groups 992 for (int i=0; i< toBeInitializedGroups.size(); i++) { 993 GroupImpl grp = (GroupImpl)toBeInitializedGroups.elementAt(i); 994 grp.setUsers((Vector)groupMembers.get(grp.getID())); 995 } 996 997 //3.2 initialize users 998 for (int i=0; i< toBeInitializedUsers.size(); i++) { 999 UserImpl usr = (UserImpl)toBeInitializedUsers.elementAt(i); 1000 usr.setGroups((Vector)userGroups.get(usr.getID())); 1001 } 1002 1003 } 1004 1005 1006 private void fireObjectCreatedEvent(ObjectModificationEvent e) { 1007 1008 //sanity check 1009 if (e.getType() != ObjectModificationEvent.OBJECT_CREATED) { 1010 throw new IllegalArgumentException(); 1011 } 1012 1013 for (int i=0; i< this.omCreationListeners.size(); i++) { 1014 ((ObjectModificationListener)this.omCreationListeners.elementAt(i)).objectCreated(e); 1015 } 1016 } 1017 1018 1019 private void fireObjectDeletedEvent(ObjectModificationEvent e) { 1020 1021 //sanity check 1022 if (e.getType() != ObjectModificationEvent.OBJECT_DELETED) { 1023 throw new IllegalArgumentException(); 1024 } 1025 1026 for (int i=0; i< this.omDeletionListeners.size(); i++) { 1027 ((ObjectModificationListener)this.omDeletionListeners.elementAt(i)).objectDeleted(e); 1028 } 1029 } 1030 1031 1032 private void fireObjectModifiedEvent(ObjectModificationEvent e) { 1033 1034 //sanity check 1035 if (e.getType() != ObjectModificationEvent.OBJECT_MODIFIED) { 1036 throw new IllegalArgumentException(); 1037 } 1038 1039 for (int i=0; i< this.omModificationListeners.size(); i++) { 1040 ((ObjectModificationListener)omModificationListeners.elementAt(i)).objectModified(e); 1041 } 1042 } 1043 1044 1045 1046 1047 public void registerObjectModificationListener(ObjectModificationListener l, 1048 int eventType) { 1049 1050 if (eventType != ObjectModificationEvent.OBJECT_CREATED && 1051 eventType != ObjectModificationEvent.OBJECT_DELETED && 1052 eventType != ObjectModificationEvent.OBJECT_MODIFIED) { 1053 1054 throw new IllegalArgumentException(); 1055 } 1056 1057 switch(eventType) { 1058 case ObjectModificationEvent.OBJECT_CREATED : 1059 this.omCreationListeners.add(l); 1060 break; 1061 case ObjectModificationEvent.OBJECT_DELETED : 1062 this.omDeletionListeners.add(l); 1063 break; 1064 case ObjectModificationEvent.OBJECT_MODIFIED : 1065 this.omModificationListeners.add(l); 1066 break; 1067 default: 1068 Assert.fail(); 1069 } 1070 1071 } 1072 1073 public void unregisterObjectModificationListener(ObjectModificationListener l, 1074 int eventType) { 1075 1076 if (eventType != ObjectModificationEvent.OBJECT_CREATED && 1077 eventType != ObjectModificationEvent.OBJECT_DELETED && 1078 eventType != ObjectModificationEvent.OBJECT_MODIFIED) { 1079 1080 throw new IllegalArgumentException(); 1081 } 1082 1083 switch(eventType) { 1084 case ObjectModificationEvent.OBJECT_CREATED : 1085 this.omCreationListeners.remove(l); 1086 break; 1087 case ObjectModificationEvent.OBJECT_DELETED : 1088 this.omDeletionListeners.remove(l); 1089 break; 1090 case ObjectModificationEvent.OBJECT_MODIFIED : 1091 this.omModificationListeners.remove(l); 1092 break; 1093 default: 1094 Assert.fail(); 1095 } 1096 1097 } 1098 1099 1100 1101 1102 /* ObjectModificationListener methods */ 1103 1104 public void objectCreated(ObjectModificationEvent e) { 1105 //I've never registered for these events 1106 Assert.fail(); 1107 } 1108 1109 public void objectModified(ObjectModificationEvent e) { 1110 1111 Object source = e.getSource(); 1112 int type = e.getType(); 1113 int subtype = e.getSubType(); 1114 1115 //sanity checks 1116 if (type != ObjectModificationEvent.OBJECT_MODIFIED) { 1117 throw new IllegalArgumentException(); 1118 } 1119 1120 //I'm interested only in Groups and Users 1121 if (false == source instanceof Group && 1122 false == source instanceof User) { 1123 1124 throw new IllegalArgumentException(); 1125 } 1126 1127 1128 if (source instanceof Group) { 1129 1130 Assert.assertTrue(subtype == Group.OBJECT_CHANGE_ADDUSER || 1131 subtype == Group.OBJECT_CHANGE_NAME || 1132 subtype == Group.OBJECT_CHANGE_REMOVEUSER); 1133 1134 //the name of the group could be different now (IDs are fixed) 1135 if (subtype == Group.OBJECT_CHANGE_NAME) { 1136 //rehash 1137 //any better idea how to do it? 1138 Set mappings = this.groupsByName.entrySet(); 1139 Iterator it = mappings.iterator(); 1140 1141 boolean found = false; 1142 while (it.hasNext()) { 1143 Map.Entry mapEntry = (Map.Entry)it.next(); 1144 String key = (String)mapEntry.getKey(); 1145 Group grp = (Group)mapEntry.getValue(); 1146 1147 if (false == key.equals(grp.getName())) { 1148 //gotcha 1149 this.groupsByName.remove(key); 1150 this.groupsByName.put(grp.getName(),grp); 1151 found = true; 1152 break; 1153 } 1154 } 1155 1156 Assert.assertTrue(found); 1157 } 1158 } 1159 else { 1160 1161 Assert.assertTrue(source instanceof User); 1162 1163 //the name of the user could be different now (IDs are fixed) 1164 1165 Assert.assertTrue(subtype == User.OBJECT_CHANGE_NAME); 1166 1167 //the name of the group could be different now (IDs are fixed) 1168 if (subtype == User.OBJECT_CHANGE_NAME) { 1169 //rehash 1170 //any better idea how to do it? 1171 Set mappings = this.usersByName.entrySet(); 1172 Iterator it = mappings.iterator(); 1173 1174 boolean found = false; 1175 while (it.hasNext()) { 1176 Map.Entry mapEntry = (Map.Entry)it.next(); 1177 String key = (String)mapEntry.getKey(); 1178 User usr = (User)mapEntry.getValue(); 1179 1180 if (false == key.equals(usr.getName())) { 1181 //gotcha 1182 this.usersByName.remove(key); 1183 this.usersByName.put(usr.getName(),usr); 1184 found = true; 1185 break; 1186 } 1187 } 1188 1189 Assert.assertTrue(found); 1190 } 1191 } 1192 1193 1194 } 1195 1196 public void objectDeleted(ObjectModificationEvent e) { 1197 //I've never registered for these events 1198 Assert.fail(); 1199 } 1200 1201 public void processGateEvent(GateEvent e){ 1202 throw new MethodNotImplementedException(); 1203 } 1204 1205 /** -- */ 1206 public boolean isValidSecurityInfo(SecurityInfo si) { 1207 1208 switch(si.getAccessMode()) { 1209 1210 case SecurityInfo.ACCESS_WR_GW: 1211 case SecurityInfo.ACCESS_GR_GW: 1212 return (null != si.getGroup()); 1213 1214 case SecurityInfo.ACCESS_GR_OW: 1215 return (null != si.getGroup() && 1216 null != si.getUser()); 1217 1218 case SecurityInfo.ACCESS_OR_OW: 1219 return (null != si.getUser()); 1220 1221 default: 1222 throw new IllegalArgumentException(); 1223 } 1224 } 1225 1226 public void finalize() { 1227 //close connection 1228 try { 1229 this.jdbcConn.close(); 1230 } 1231 catch(SQLException sqle) {} 1232 1233 } 1234 1235} 1236
|
AccessControllerImpl |
|