1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.seasar.tuigwaa.security;
17
18 import java.io.UnsupportedEncodingException;
19 import java.util.ArrayList;
20 import java.util.Hashtable;
21 import java.util.List;
22 import java.util.Properties;
23
24 import javax.naming.NamingEnumeration;
25 import javax.naming.NamingException;
26 import javax.naming.directory.Attribute;
27 import javax.naming.directory.Attributes;
28 import javax.naming.directory.BasicAttribute;
29 import javax.naming.directory.BasicAttributes;
30 import javax.naming.directory.DirContext;
31 import javax.naming.directory.InitialDirContext;
32 import javax.naming.directory.SearchControls;
33 import javax.naming.directory.SearchResult;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.seasar.tuigwaa.security.auth.TgwRole;
38 import org.seasar.tuigwaa.security.auth.TgwUser;
39
40
41 /***
42 * @author someda
43 */
44 public class DirectoryServiceImpl implements DirectoryService {
45
46 private Hashtable environment;
47 private Properties props;
48
49 private DirContext ctx;
50
51 private Log log = LogFactory.getLog(getClass());
52
53 private Attribute userObjectClass;
54 private Attribute roleObjectClass;
55
56 private Attributes userRequiredAttributes;
57 private Attributes roleRequiredAttributes;
58
59 private String searchBase;
60
61 private String userPrefix;
62 private String userSuffix;
63 private String rolePrefix;
64 private String roleSuffix;
65 private String roleUserAttribute;
66
67 private String userSearchFilter;
68 private String roleSearchFilter;
69
70 private String passwordAttribute;
71 private String descriptionAttribute;
72
73 private String adminUsername;
74 private String adminRolename;
75
76 private boolean prefixOnly;
77
78 private SearchControls controls;
79
80 public DirectoryServiceImpl(Hashtable environment, Properties props){
81
82 this.environment = environment;
83 this.props = props;
84
85 try{
86 initialize();
87 }catch(NamingException ne){
88 log.error("startup failed, check config/directory.dicon.");
89 throw new RuntimeException(ne);
90 }
91 }
92
93 public void setRoleObjectClass(Attribute roleObjectClass) {
94 this.roleObjectClass = roleObjectClass;
95 }
96
97 public void setUserObjectClass(Attribute userObjectClass) {
98 this.userObjectClass = userObjectClass;
99 }
100
101 public void setRoleRequiredAttributes(Attributes roleRequiredAttributes) {
102 this.roleRequiredAttributes = roleRequiredAttributes;
103 }
104
105 public void setUserRequiredAttributes(Attributes userRequiredAttributes) {
106 this.userRequiredAttributes = userRequiredAttributes;
107 }
108
109 public TgwUser getUser(String userdn){
110 TgwUser user = null;
111
112 try{
113 ctx = new InitialDirContext(environment);
114 Attributes attrs = ctx.getAttributes(DirectoryUtils.getRDN(userdn,searchBase));
115 user = createUser(userdn,attrs);
116
117 }catch(NamingException ne){
118 log.error(ne.getMessage());
119
120 }finally{
121 DirectoryUtils.closeQuietly(ctx);
122 }
123 return user;
124 }
125
126 public List getUsers() {
127
128 List list = new ArrayList();
129
130 try{
131 ctx = new InitialDirContext(environment);
132 String userSearchBase = DirectoryUtils.buildSuffix(userSuffix,searchBase,false,false);
133 NamingEnumeration res = ctx.search(userSearchBase,userSearchFilter,controls);
134 while(res.hasMore()){
135 SearchResult entry = (SearchResult) res.next();
136 Attributes attrs = entry.getAttributes();
137
138 if(attrs == null){
139 log.info("attributes not found for " + entry.getName());
140 continue;
141 }
142
143 TgwUser user = createUser(getFullDN(entry.getName(),true),attrs);
144 list.add(user);
145 }
146
147 }catch(NamingException ne){
148 log.error("search failed.");
149 ne.printStackTrace();
150 }finally{
151 DirectoryUtils.closeQuietly(ctx);
152 }
153 return list;
154 }
155
156 public void addUser(TgwUser user) {
157
158 String dn = DirectoryUtils.getAbsoluteDN(user.getName(),userPrefix,userSuffix,searchBase);
159 user.setDn(dn);
160
161 try{
162 ctx = new InitialDirContext(environment);
163 Attributes attrs = createUserAttributes(user);
164
165 if(userRequiredAttributes != null){
166 NamingEnumeration reqattrs = userRequiredAttributes.getAll();
167 while(reqattrs.hasMore()){
168 attrs.put((Attribute)reqattrs.next());
169 }
170 }
171 updateRoles(user,user.getRoles(),DirContext.ADD_ATTRIBUTE);
172
173 ctx.createSubcontext(DirectoryUtils.getRDN(dn,searchBase),attrs);
174 log.info("adding " + dn + " completed.");
175
176 }catch(NamingException ne){
177
178 ne.printStackTrace();
179 }finally{
180 DirectoryUtils.closeQuietly(ctx);
181 }
182 }
183
184 public void deleteUser(String userdn){
185
186 TgwUser user = getUser(userdn);
187
188 if(user.isAdmin()){
189 log.warn(user.getName() + "couldn't delete user who has admin priviledge.");
190 return;
191 }
192
193 try{
194 ctx = new InitialDirContext(environment);
195 updateRoles(user,user.getRoles(),DirContext.REMOVE_ATTRIBUTE);
196 ctx.destroySubcontext(DirectoryUtils.getRDN(userdn,searchBase));
197 log.info("deleting " + userdn + " completed.");
198
199 }catch(NamingException ne){
200 ne.printStackTrace();
201 }finally{
202 DirectoryUtils.closeQuietly(ctx);
203 }
204 }
205
206 public void modifyUser(TgwUser user) {
207
208 String userdn = DirectoryUtils.getAbsoluteDN(user.getName(),userPrefix,userSuffix,searchBase);
209
210 String[] oldroles = null;
211 String[] deleteroles = null;
212 String[] addroles = null;
213 String[] updateroles = user.getRoles();
214
215
216 TgwUser olduser = getUser(userdn);
217 oldroles = olduser.getRoles();
218
219 if(updateroles != null && updateroles.length > 0){
220 addroles = getExclusiveStringArray(updateroles,oldroles);
221 deleteroles = getExclusiveStringArray(oldroles,updateroles);
222 }else if(oldroles != null && oldroles.length > 0){
223 deleteroles = new String[oldroles.length];
224 System.arraycopy(oldroles,0,deleteroles,0,oldroles.length);
225 }
226
227 if(olduser.isAdmin() && deleteroles != null){
228 for(int i=0;i<deleteroles.length;i++){
229 if(deleteroles[i].equals(adminRolename)){
230 deleteroles[i] = null;
231 log.info("admin role couldn't delete for admin user, ignore it.");
232 break;
233 }
234 }
235 }
236
237 try{
238 ctx = new InitialDirContext(environment);
239 Attributes attrs = createUserAttributes(user);
240 ctx.modifyAttributes(DirectoryUtils.getRDN(userdn,searchBase),DirContext.REPLACE_ATTRIBUTE,attrs);
241
242 updateRoles(olduser,addroles,DirContext.ADD_ATTRIBUTE);
243 updateRoles(olduser,deleteroles,DirContext.REMOVE_ATTRIBUTE);
244
245 }catch(NamingException ne){
246 ne.printStackTrace();
247 }finally{
248 DirectoryUtils.closeQuietly(ctx);
249 }
250 }
251
252 public TgwRole getRole(String roledn){
253 TgwRole role = null;
254 try{
255 ctx = new InitialDirContext(environment);
256 Attributes attrs = ctx.getAttributes(DirectoryUtils.getRDN(roledn,searchBase));
257 role = createRole(roledn,attrs);
258
259 }catch(NamingException ne){
260 log.error(ne.getMessage());
261
262 }finally{
263 DirectoryUtils.closeQuietly(ctx);
264 }
265 return role;
266 }
267
268 public List getRoles() {
269
270 List list = new ArrayList();
271
272 try{
273 ctx = new InitialDirContext(environment);
274 NamingEnumeration res = ctx.search(DirectoryUtils.buildSuffix(roleSuffix,searchBase,false,false),roleSearchFilter,controls);
275 while(res.hasMore()){
276 SearchResult entry = (SearchResult) res.next();
277 Attributes attrs = entry.getAttributes();
278
279
280 if(attrs == null){
281 log.info("attributes not found for " + entry.getName());
282 continue;
283 }
284
285 TgwRole role = createRole(getFullDN(entry.getName(),false),attrs);
286 list.add(role);
287 }
288
289 }catch(NamingException ne){
290 ne.printStackTrace();
291 }finally{
292 DirectoryUtils.closeQuietly(ctx);
293 }
294 return list;
295 }
296
297 public void addRole(TgwRole role) {
298 String dn = DirectoryUtils.getAbsoluteDN(role.getName(),rolePrefix,roleSuffix,searchBase);
299
300 try{
301 ctx = new InitialDirContext(environment);
302 Attributes attrs = createRoleAttributes(role);
303
304 if(roleRequiredAttributes != null){
305 NamingEnumeration reqattrs = roleRequiredAttributes.getAll();
306 while(reqattrs.hasMore()){
307 attrs.put((Attribute)reqattrs.next());
308 }
309 }
310 ctx.createSubcontext(DirectoryUtils.getRDN(dn,searchBase),attrs);
311
312 String adminUserDn = userPrefix + "=" + adminUsername + DirectoryUtils.buildSuffix(userSuffix,searchBase,true,true);
313 TgwUser admin = new TgwUser(adminUsername);
314 admin.setDn(adminUserDn);
315 updateRoles(admin,new String[]{role.getName()},DirContext.ADD_ATTRIBUTE);
316 log.info("adding " + dn + " completed.");
317
318 }catch(NamingException ne){
319 ne.printStackTrace();
320 }finally{
321 DirectoryUtils.closeQuietly(ctx);
322 }
323 }
324
325 public void deleteRole(String roledn) {
326
327 TgwRole role = getRole(roledn);
328 if(role.isAdmin()){
329 log.warn(role.getName() + "couldn't delete role which represents admin priviledge.");
330 return;
331 }
332
333 try{
334 ctx = new InitialDirContext(environment);
335 ctx.destroySubcontext(DirectoryUtils.getRDN(roledn,searchBase));
336 log.info("deleting " + roledn + " completed.");
337
338 }catch(NamingException ne){
339 ne.printStackTrace();
340 }finally{
341 DirectoryUtils.closeQuietly(ctx);
342 }
343 }
344
345 public void modifyRole(TgwRole role) {
346
347 String dn = DirectoryUtils.getAbsoluteDN(role.getName(),rolePrefix,roleSuffix,searchBase);
348 try{
349 ctx = new InitialDirContext(environment);
350 Attributes attrs = createRoleAttributes(role);
351 ctx.modifyAttributes(DirectoryUtils.getRDN(dn,searchBase),DirContext.REPLACE_ATTRIBUTE,attrs);
352
353 }catch(NamingException ne){
354 ne.printStackTrace();
355 }finally{
356 DirectoryUtils.closeQuietly(ctx);
357 }
358 }
359
360 public String buildUserDN(String username){
361 return DirectoryUtils.getAbsoluteDN(username,userPrefix,userSuffix,searchBase);
362 }
363
364 public void initialize() throws NamingException{
365
366
367 searchBase = props.getProperty(BASE_DN);
368 userPrefix = props.getProperty(USER_PREFIX);
369 userSuffix = props.getProperty(USER_SUFFIX);
370 rolePrefix = props.getProperty(ROLE_PREFIX);
371 roleSuffix = props.getProperty(ROLE_SUFFIX);
372
373 roleUserAttribute = props.getProperty(ROLE_USER_ATTRIBUTE);
374 passwordAttribute = props.getProperty(PASSWORD_ATTRIBUTE);
375 descriptionAttribute = props.getProperty(DESCRIPTION_ATTRIBUTE);
376 adminUsername = props.getProperty(ADMIN_USERNAME);
377 adminRolename = props.getProperty(ADMIN_ROLENAME);
378
379 StringBuffer buf = new StringBuffer();
380 buf.append("(" + userPrefix + "=*)");
381 userSearchFilter = buf.toString();
382
383 buf = new StringBuffer();
384 buf.append("(" + rolePrefix + "=*)");
385 roleSearchFilter = buf.toString();
386
387 controls = new SearchControls();
388 controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
389
390 String value = props.getProperty(DirectoryService.EMBEDED);
391 if(Boolean.valueOf(value).booleanValue()){
392 new InitialDirContext(environment);
393 }
394
395 String p = props.getProperty(DirectoryService.ROLE_USER_PREFIXONLY);
396 prefixOnly = Boolean.valueOf(p).booleanValue();
397 }
398
399
400 private TgwUser createUser(String dn, Attributes attrs) throws NamingException{
401
402 TgwUser user = new TgwUser();
403 user.setDn(dn);
404
405 Attribute uid = attrs.get(userPrefix);
406 if(uid != null){
407 user.setName((String)uid.get());
408 user.setAdmin(user.getName().equals(adminUsername));
409 }
410
411 Attributes member = null;
412 if(prefixOnly){
413 member = new BasicAttributes(roleUserAttribute,user.getName());
414 }else{
415 member = new BasicAttributes(roleUserAttribute,dn);
416 }
417
418 String searchName = DirectoryUtils.buildSuffix(roleSuffix,searchBase,false,false);
419 NamingEnumeration nenum = ctx.search(searchName,member);
420 List roleList = new ArrayList();
421 while(nenum.hasMore()){
422 SearchResult result = (SearchResult) nenum.next();
423 Attributes roleattrs = result.getAttributes();
424 Attribute roleattr = roleattrs.get(rolePrefix);
425 roleList.add((String)roleattr.get());
426 }
427 if(roleList.size() > 0)
428 user.setRoles((String[]) roleList.toArray(new String[roleList.size()]));
429
430 Attribute password = attrs.get(passwordAttribute);
431 if(password != null){
432 try{
433 user.setPassword((String)password.get());
434 }catch(ClassCastException cce){
435 try{
436 String p = new String((byte[])password.get(),"UTF8");
437 user.setPassword(p);
438 }catch(UnsupportedEncodingException uee){
439 uee.printStackTrace();
440 }
441 }
442 }
443
444 Attribute description = attrs.get(descriptionAttribute);
445 if(description != null)
446 user.setDescription((String)description.get());
447
448 return user;
449 }
450
451 private Attributes createUserAttributes(TgwUser user){
452
453 Attributes attrs = new BasicAttributes();
454 attrs.put(userObjectClass);
455 attrs.put(new BasicAttribute(userPrefix,user.getName()));
456 attrs.put(new BasicAttribute(passwordAttribute,user.getPassword()));
457 attrs.put(new BasicAttribute("cn",user.getName()));
458 attrs.put(new BasicAttribute("sn",user.getName()));
459 attrs.put(new BasicAttribute(descriptionAttribute,user.getDescription()));
460
461 return attrs;
462 }
463
464 private TgwRole createRole(String dn, Attributes attrs) throws NamingException{
465
466 TgwRole role = new TgwRole();
467 role.setDn(dn);
468
469 Attribute cn = attrs.get(rolePrefix);
470 if(cn != null){
471 role.setName((String)cn.get());
472 role.setAdmin(role.getName().equals(adminRolename));
473 }
474
475 Attribute description = attrs.get(descriptionAttribute);
476 if(description != null)
477 role.setDescription((String)description.get());
478
479 Attribute member = attrs.get(roleUserAttribute);
480 if(member != null){
481 int size = member.size();
482 String[] users = new String[size];
483 for(int i=0;i<size;i++){
484 users[i] = (String)member.get(i);
485 }
486 role.setUsers(users);
487 }
488 return role;
489 }
490
491 private Attributes createRoleAttributes(TgwRole role){
492
493 Attributes attrs = new BasicAttributes();
494 attrs.put(roleObjectClass);
495 attrs.put(new BasicAttribute(rolePrefix,role.getName()));
496 attrs.put(new BasicAttribute(descriptionAttribute,role.getDescription()));
497
498 return attrs;
499 }
500
501
502 private void updateRoles(TgwUser user, String[] roles, int mod_op) throws NamingException{
503
504 if(roles != null){
505 Attributes member = null;
506 if(prefixOnly){
507 member = new BasicAttributes(roleUserAttribute,user.getName());
508 }else{
509 member = new BasicAttributes(roleUserAttribute,user.getDn());
510 }
511
512 for(int i=0;i<roles.length;i++){
513 if(roles[i] != null){
514 String roledn = DirectoryUtils.getAbsoluteDN(roles[i],rolePrefix,roleSuffix,searchBase);
515 try{
516 ctx.modifyAttributes(DirectoryUtils.getRDN(roledn,searchBase),mod_op,member);
517 }catch(NamingException ne){
518 log.error("update failed for " + roledn);
519 continue;
520 }
521 }
522 }
523 }
524 }
525
526 private String[] getExclusiveStringArray(String[] src, String[] dest){
527
528 if(src == null) return null;
529 if(dest == null) return src;
530
531 List list = new ArrayList();
532 for(int i=0;i<src.length;i++){
533 boolean notIncluded = true;
534 for(int j=0;j<dest.length;j++){
535 if(src[i].equals(dest[j])){
536 notIncluded = false;
537 break;
538 }
539 }
540 if(notIncluded) list.add(src[i]);
541 }
542 return (list.size()>0)?(String[]) list.toArray(new String[list.size()]):null;
543 }
544
545
546
547 private String getFullDN(String dn, boolean user){
548 String ret = dn;
549 String suffix = null;
550
551 if(user){
552 suffix = DirectoryUtils.buildSuffix(userSuffix,searchBase,true,true);
553 }else{
554 suffix = DirectoryUtils.buildSuffix(roleSuffix,searchBase,true,true);
555 }
556
557 if(dn.indexOf(suffix) == -1){
558 ret += suffix;
559 }
560 return ret;
561 }
562 }