001 /*
002 * UserImpl.java
003 *
004 * Copyright (c) 1995-2010, The University of Sheffield. See the file
005 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006 *
007 * This file is part of GATE (see http://gate.ac.uk/), and is free
008 * software, licenced under the GNU Library General Public License,
009 * Version 2, June 1991 (in the distribution as file licence.html,
010 * and also available at http://gate.ac.uk/gate/licence.html).
011 *
012 * Marin Dimitrov, 19/Sep/2001
013 *
014 * $Id: UserImpl.java 12006 2009-12-01 17:24:28Z thomas_heitz $
015 */
016
017 package gate.security;
018
019 import java.sql.*;
020 import java.util.List;
021 import java.util.Vector;
022
023 import junit.framework.Assert;
024
025 import gate.Gate;
026 import gate.event.*;
027 import gate.persist.DBHelper;
028 import gate.persist.PersistenceException;
029 import gate.util.MethodNotImplementedException;
030
031
032 public class UserImpl
033 implements User, ObjectModificationListener {
034
035 /** user ID (must be unique) */
036 private Long id;
037
038 /** user name (must be unique) */
039 private String name;
040
041 /** list of groups the user belongs to */
042 private List groups;
043
044 /** Connection to the data store
045 * used for updates */
046 private Connection conn;
047
048 /** --- */
049 private int dbType;
050
051 /** reference to the security factory */
052 private AccessControllerImpl ac;
053
054 /** list of objects that should be modified when the state
055 * of this object is changed */
056 private Vector omModificationListeners;
057
058 /** list of objects that should be modified when
059 * this object is created */
060 private Vector omCreationListeners;
061
062 /** list of objects that should be modified when
063 * this object is deleted */
064 private Vector omDeletionListeners;
065
066
067 /** --- */
068 public UserImpl(Long id, String name, List groups,AccessControllerImpl ac,Connection conn) {
069
070 this.id = id;
071 this.name = name;
072 this.groups = groups;
073 this.ac = ac;
074 this.conn = conn;
075
076 try {
077 String jdbcURL = conn.getMetaData().getURL();
078 this.dbType = DBHelper.getDatabaseType(jdbcURL);
079 Assert.assertTrue(this.dbType == DBHelper.ORACLE_DB ||
080 this.dbType == DBHelper.POSTGRES_DB);
081 }
082 catch(SQLException sqex) {
083 sqex.printStackTrace();
084 }
085
086 this.omModificationListeners = new Vector();
087 this.omCreationListeners = new Vector();
088 this.omDeletionListeners = new Vector();
089
090 //register self as listener for the security factory events
091 //of type OBJECT_DELETED (groups)
092 //don't forget that only AC can delete groups, so he's the only
093 //source of such events
094 this.ac.registerObjectModificationListener(
095 this,
096 ObjectModificationEvent.OBJECT_DELETED);
097
098 }
099
100
101 /* Interface USER */
102
103 /** returns the ID of the user
104 * user IDs are uniques in the same
105 * data store
106 * */
107
108 public Long getID() {
109
110 return id;
111 }
112
113 /** returns the name of the user
114 * user names are unique in the
115 * same data store */
116 public String getName() {
117
118 return name;
119 }
120
121 /** returns a list with the groups that the
122 * user is member of */
123 public List getGroups() {
124
125 /** NOTE that we're returning a copy of the actuall collection of groups
126 * so that someone would not accidentaly modify it */
127 Vector copy = new Vector();
128 copy.addAll(this.groups);
129 return copy;
130 }
131
132 /** changes user name
133 * Only members of the ADMIN group have sufficient privileges.
134 * fires ObjectModificationEvent
135 * @see ObjectModificationEvent
136 * */
137 public void setName(String newName, Session s)
138 throws PersistenceException,SecurityException {
139
140 //1. check the session
141 if (this.ac.isValidSession(s) == false) {
142 throw new SecurityException("invalid session supplied");
143 }
144
145 //1.5 check if user has right to change name
146 if (s.getID() != this.id && false == s.isPrivilegedSession()) {
147 throw new SecurityException("insufficient privileges");
148 }
149
150 CallableStatement stmt = null;
151 PreparedStatement pstmt = null;
152
153 //2. update database
154
155 //Oracle / Postgres ?
156 if (this.dbType == DBHelper.ORACLE_DB) {
157 try {
158 stmt = this.conn.prepareCall(
159 "{ call "+Gate.DB_OWNER+".security.set_user_name(?,?)} ");
160 stmt.setLong(1,this.id.longValue());
161 stmt.setString(2,newName);
162 stmt.execute();
163 }
164 catch(SQLException sqle) {
165 throw new PersistenceException("can't change user name in DB: ["+ sqle.getMessage()+"]");
166 }
167 finally {
168 DBHelper.cleanup(stmt);
169 }
170 }
171
172 else if (this.dbType == DBHelper.POSTGRES_DB) {
173 try {
174 String sql = "select security_set_user_name(?,?)";
175 pstmt = this.conn.prepareStatement(sql);
176 pstmt.setLong(1,this.id.longValue());
177 pstmt.setString(2,newName);
178 pstmt.execute();
179 }
180 catch(SQLException sqle) {
181 throw new PersistenceException("can't change user name in DB: ["+ sqle.getMessage()+"]");
182 }
183 finally {
184 DBHelper.cleanup(pstmt);
185 }
186 }
187
188 else {
189 throw new IllegalArgumentException();
190 }
191
192 //4. create ObjectModificationEvent
193 ObjectModificationEvent e = new ObjectModificationEvent(
194 this,
195 ObjectModificationEvent.OBJECT_MODIFIED,
196 User.OBJECT_CHANGE_NAME);
197
198 //5. update member variable
199 this.name = newName;
200
201 //6. fire ObjectModificationEvent for all who care
202 fireObjectModifiedEvent(e);
203 }
204
205
206 /** changes user password
207 * Only members of the ADMIN group and the user himself
208 * have sufficient privileges */
209 public void setPassword(String newPass, Session s)
210 throws PersistenceException,SecurityException {
211
212 //1. first check the session
213 if (this.ac.isValidSession(s) == false) {
214 throw new SecurityException("invalid session supplied");
215 }
216
217 //2. check privileges
218 if (false == s.isPrivilegedSession() && s.getID() != this.id) {
219 throw new SecurityException("insuffieicent privileges");
220 }
221
222 CallableStatement stmt = null;
223 PreparedStatement pstmt = null;
224
225 //Oracle / Postgres ?
226 if (this.dbType == DBHelper.ORACLE_DB) {
227 try {
228 stmt = this.conn.prepareCall(
229 "{ call "+Gate.DB_OWNER+".security.set_user_password(?,?)} ");
230 stmt.setLong(1,this.id.longValue());
231 stmt.setString(2,newPass);
232 stmt.execute();
233 //release stmt???
234 }
235 catch(SQLException sqle) {
236 throw new PersistenceException("can't change user password in DB: ["+ sqle.getMessage()+"]");
237 }
238 finally {
239 DBHelper.cleanup(stmt);
240 }
241 }
242
243 else if (this.dbType == DBHelper.POSTGRES_DB) {
244 try {
245 String sql = "select security_set_user_password(?,?)";
246 pstmt = this.conn.prepareStatement(sql);
247 pstmt.setLong(1,this.id.longValue());
248 pstmt.setString(2,newPass);
249 pstmt.execute();
250 //release stmt???
251 }
252 catch(SQLException sqle) {
253 throw new PersistenceException("can't change user password in DB: ["+ sqle.getMessage()+"]");
254 }
255 finally {
256 DBHelper.cleanup(pstmt);
257 }
258 }
259
260 else {
261 throw new IllegalArgumentException();
262 }
263
264 }
265
266 /**
267 *
268 * this one is necessary for the contains() operations in Lists
269 * It is possible that two users have two different UserImpl that refer
270 * to the very same user in the DB, because they got it fromt he security
271 * factory at different times. So we assume that two instances refer the same
272 * GATE user if ID1==ID2 && NAME1==NAME2
273 *
274 * */
275 public boolean equals(Object obj)
276 {
277 Assert.assertTrue(obj instanceof User);
278
279 User usr2 = (User)obj;
280
281 return (this.id.equals(usr2.getID()));
282 }
283
284 /** registers an object fore receiving ObjectModificationEvent-s
285 * send by this object
286 * the only types of events sent by a user object are
287 * OBJECT_DELETED and OBJECT_MODIFIED, so any attempt for
288 * registering for other events is invalid */
289 public void registerObjectModificationListener(ObjectModificationListener l,
290 int eventType) {
291
292 if (eventType != ObjectModificationEvent.OBJECT_DELETED &&
293 eventType != ObjectModificationEvent.OBJECT_MODIFIED) {
294
295 throw new IllegalArgumentException();
296 }
297
298 switch(eventType) {
299 case ObjectModificationEvent.OBJECT_CREATED :
300 this.omCreationListeners.add(l);
301 break;
302 case ObjectModificationEvent.OBJECT_DELETED :
303 this.omDeletionListeners.add(l);
304 break;
305 case ObjectModificationEvent.OBJECT_MODIFIED :
306 this.omModificationListeners.add(l);
307 break;
308 default:
309 Assert.fail();
310 }
311
312 }
313
314 /** unregisters an object fore receiving ObjectModificationEvent-s
315 * send by this object
316 * the only types of events sent by a user object are
317 * OBJECT_DELETED and OBJECT_MODIFIED, so any attempt for
318 * unregistering for other events is invalid */
319 public void unregisterObjectModificationListener(ObjectModificationListener l,
320 int eventType) {
321
322 if (eventType != ObjectModificationEvent.OBJECT_DELETED &&
323 eventType != ObjectModificationEvent.OBJECT_MODIFIED) {
324
325 throw new IllegalArgumentException();
326 }
327
328 switch(eventType) {
329 case ObjectModificationEvent.OBJECT_CREATED :
330 this.omCreationListeners.remove(l);
331 break;
332 case ObjectModificationEvent.OBJECT_DELETED :
333 this.omDeletionListeners.remove(l);
334 break;
335 case ObjectModificationEvent.OBJECT_MODIFIED :
336 this.omModificationListeners.remove(l);
337 break;
338 default:
339 Assert.fail();
340 }
341 }
342
343 /** sends ObjectModificationEvent of type OBJECT_MODIFIED to all
344 * who have already registered */
345 private void fireObjectModifiedEvent(ObjectModificationEvent e) {
346
347 //sanity check
348 if (e.getType() != ObjectModificationEvent.OBJECT_MODIFIED) {
349 throw new IllegalArgumentException();
350 }
351
352 for (int i=0; i< this.omModificationListeners.size(); i++) {
353 ((ObjectModificationListener)omModificationListeners.elementAt(i)).objectModified(e);
354 }
355 }
356
357 //ObjectModificationListener interface
358
359 /** callback that is invoked from objects that were <b>created</b>
360 * and this user object is interested in
361 * <b>NOTE</b> that this events are just ignored*/
362 public void objectCreated(ObjectModificationEvent e) {
363 //ignore, we don't care about creations
364 return;
365 }
366
367 /** callback that is invoked from objects that were <b>modified</b>
368 * and this user object is interested in
369 * Useful when a group drops the user as member and
370 * this user should be notified so that it will remove the
371 * reference to the group from its internal collections
372 * (the user is no longer member of the group)
373 * */
374 public void objectModified(ObjectModificationEvent e) {
375
376 //only groups can disturb the user
377 Assert.assertTrue(e.getSubType() == Group.OBJECT_CHANGE_ADDUSER ||
378 e.getSubType() == Group.OBJECT_CHANGE_REMOVEUSER ||
379 e.getSubType() == Group.OBJECT_CHANGE_NAME);
380
381 //we get this event only if a group adds/removes user to it
382 Group grp = (Group)e.getSource();
383
384 switch(e.getSubType()) {
385
386 case Group.OBJECT_CHANGE_ADDUSER:
387
388 //1.check that the groupis not already in collection
389 Assert.assertTrue(false == this.groups.contains(grp));
390 //1.1 verify grp
391 Assert.assertTrue(grp instanceof Group);
392 //2.add group to collection
393 this.groups.add(grp);
394 //3. the group has laredy registered
395 //the user as listener for this group
396 ;
397 break;
398
399 case Group.OBJECT_CHANGE_REMOVEUSER:
400 //1.check that the group is in collection
401 Assert.assertTrue(true == this.groups.contains(grp));
402 //2.remove group from collection
403 this.groups.remove(grp);
404 //3. the group has laredy UNregistered
405 //the user as listener for this group
406 ;
407 break;
408
409 case Group.OBJECT_CHANGE_NAME:
410 //do nothing
411 break;
412
413 default:
414 throw new IllegalArgumentException();
415 }
416
417
418 }
419
420 /** callback that is invoked from objects that were <b>deleted</b>
421 * and this user object is interested in
422 * Useful when a group is deleted from the security factory and
423 * this user should be notified so that it will remove the
424 * reference to the group from its internal collections
425 * (the user is no longer member of the group)
426 * */
427 public void objectDeleted(ObjectModificationEvent e) {
428
429 if (e.getSource() instanceof Group) {
430
431 Group grp = (Group)e.getSource();
432 //check if the Group being deleted is one we belong to
433 if (true == this.groups.contains(grp)) {
434 this.groups.remove(grp);
435 }
436
437 }
438 }
439
440 /** huh? */
441 public void processGateEvent(GateEvent e){
442 throw new MethodNotImplementedException();
443 }
444
445
446 /*package*/ void setGroups(Vector groupIDs) {
447
448 for (int i=0; i< groupIDs.size(); i++) {
449 Long grp_id = (Long)groupIDs.elementAt(i);
450 Group grp = null;
451
452 try {
453 grp = (Group)this.ac.findGroup(grp_id);
454 }
455 catch(SecurityException se) {
456 Assert.fail();
457 }
458 catch(PersistenceException se) {
459 Assert.fail();
460 }
461
462 //is valid?
463 Assert.assertNotNull(grp);
464 Assert.assertTrue(grp instanceof Group);
465 //add to our collection, which was empty so far
466 this.groups.add(grp);
467 }
468 }
469
470
471 }
|