1 7 8 package org.jboss.security.plugins; 9 10 import java.lang.reflect.Constructor ; 11 import java.lang.reflect.InvocationHandler ; 12 import java.lang.reflect.Method ; 13 import java.lang.reflect.Proxy ; 14 import java.security.Principal ; 15 import java.util.Enumeration ; 16 import java.util.Hashtable ; 17 import java.util.Set ; 18 import java.util.List ; 19 import java.beans.PropertyEditorManager ; 20 21 import javax.management.MBeanServer ; 22 import javax.naming.CommunicationException ; 23 import javax.naming.Context ; 24 import javax.naming.InitialContext ; 25 import javax.naming.Name ; 26 import javax.naming.NameClassPair ; 27 import javax.naming.NameParser ; 28 import javax.naming.NamingEnumeration ; 29 import javax.naming.NamingException ; 30 import javax.naming.OperationNotSupportedException ; 31 import javax.naming.RefAddr ; 32 import javax.naming.Reference ; 33 import javax.naming.StringRefAddr ; 34 import javax.naming.spi.ObjectFactory ; 35 import javax.security.auth.callback.CallbackHandler ; 36 import javax.security.auth.Subject ; 37 import javax.security.jacc.PolicyContext ; 38 39 import org.jboss.logging.Logger; 40 import org.jboss.security.AuthenticationManager; 41 import org.jboss.security.SecurityAssociation; 42 import org.jboss.security.SecurityProxyFactory; 43 import org.jboss.security.SecurityDomain; 44 import org.jboss.security.jacc.SubjectPolicyContextHandler; 45 import org.jboss.security.propertyeditor.PrincipalEditor; 46 import org.jboss.security.propertyeditor.SecurityDomainEditor; 47 import org.jboss.system.ServiceMBeanSupport; 48 import org.jboss.util.CachePolicy; 49 import org.jboss.util.TimedCachePolicy; 50 51 66 public class JaasSecurityManagerService 67 extends ServiceMBeanSupport 68 implements JaasSecurityManagerServiceMBean 69 { 70 private static final String SECURITY_MGR_PATH = "java:/jaas"; 71 private static final String DEFAULT_CACHE_POLICY_PATH = "java:/timedCacheFactory"; 72 73 private static Logger log; 74 75 private static String securityMgrClassName = "org.jboss.security.plugins.JaasSecurityManager"; 76 77 private static Class securityMgrClass; 78 79 private static String callbackHandlerClassName = "org.jboss.security.auth.callback.SecurityAssociationHandler"; 80 private static Class callbackHandlerClass = org.jboss.security.auth.callback.SecurityAssociationHandler.class; 81 82 88 private static String cacheJndiName = DEFAULT_CACHE_POLICY_PATH; 89 private static int defaultCacheTimeout = 30*60; 90 private static int defaultCacheResolution = 60; 91 92 private static String securityProxyFactoryClassName = "org.jboss.security.SubjectSecurityProxyFactory"; 93 private static Class securityProxyFactoryClass = org.jboss.security.SubjectSecurityProxyFactory.class; 94 95 private static Hashtable securityDomainCtxMap = new Hashtable (); 96 private static NameParser parser; 97 private static MBeanServer server; 98 99 100 private static String defaultUnauthenticatedPrincipal = "Unauthenticated Principal"; 101 102 static 103 { 104 log = Logger.getLogger(JaasSecurityManagerService.class); 107 108 } 109 110 114 public JaasSecurityManagerService() 115 { 116 } 117 118 public String getSecurityManagerClassName() 119 { 120 return securityMgrClassName; 121 } 122 public void setSecurityManagerClassName(String className) 123 throws ClassNotFoundException , ClassCastException 124 { 125 securityMgrClassName = className; 126 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 127 securityMgrClass = loader.loadClass(securityMgrClassName); 128 if( AuthenticationManager.class.isAssignableFrom(securityMgrClass) == false ) 129 throw new ClassCastException (securityMgrClass+" does not implement "+AuthenticationManager.class); 130 } 131 public String getSecurityProxyFactoryClassName() 132 { 133 return securityProxyFactoryClassName; 134 } 135 public void setSecurityProxyFactoryClassName(String className) 136 throws ClassNotFoundException 137 { 138 securityProxyFactoryClassName = className; 139 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 140 securityProxyFactoryClass = loader.loadClass(securityProxyFactoryClassName); 141 } 142 143 147 public String getCallbackHandlerClassName() 148 { 149 return JaasSecurityManagerService.callbackHandlerClassName; 150 } 151 154 public void setCallbackHandlerClassName(String className) 155 throws ClassNotFoundException 156 { 157 callbackHandlerClassName = className; 158 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 159 callbackHandlerClass = loader.loadClass(callbackHandlerClassName); 160 } 161 162 164 public String getAuthenticationCacheJndiName() 165 { 166 return cacheJndiName; 167 } 168 170 public void setAuthenticationCacheJndiName(String jndiName) 171 { 172 cacheJndiName = jndiName; 173 } 174 177 public int getDefaultCacheTimeout() 178 { 179 return defaultCacheTimeout; 180 } 181 185 public void setDefaultCacheTimeout(int timeoutInSecs) 186 { 187 defaultCacheTimeout = timeoutInSecs; 188 } 189 191 public int getDefaultCacheResolution() 192 { 193 return defaultCacheResolution; 194 } 195 199 public void setDefaultCacheResolution(int resInSecs) 200 { 201 defaultCacheResolution = resInSecs; 202 } 203 204 212 public void setCacheTimeout(String securityDomain, int timeoutInSecs, int resInSecs) 213 { 214 CachePolicy cache = getCachePolicy(securityDomain); 215 if( cache != null && cache instanceof TimedCachePolicy ) 216 { 217 TimedCachePolicy tcp = (TimedCachePolicy) cache; 218 synchronized( tcp ) 219 { 220 tcp.setDefaultLifetime(timeoutInSecs); 221 tcp.setResolution(resInSecs); 222 } 223 } 224 else 225 { 226 log.warn("Failed to find cache policy for securityDomain='" 227 + securityDomain + "'"); 228 } 229 } 230 231 234 public void flushAuthenticationCache(String securityDomain) 235 { 236 CachePolicy cache = getCachePolicy(securityDomain); 237 if( cache != null ) 238 { 239 cache.flush(); 240 } 241 else 242 { 243 log.warn("Failed to find cache policy for securityDomain='" 244 + securityDomain + "'"); 245 } 246 } 247 248 254 public void flushAuthenticationCache(String securityDomain, Principal user) 255 { 256 CachePolicy cache = getCachePolicy(securityDomain); 257 if( cache != null ) 258 { 259 cache.remove(user); 260 } 261 else 262 { 263 log.warn("Failed to find cache policy for securityDomain='" 264 + securityDomain + "'"); 265 } 266 } 267 268 273 public List getAuthenticationCachePrincipals(String securityDomain) 274 { 275 CachePolicy cache = getCachePolicy(securityDomain); 276 List validPrincipals = null; 277 if( cache instanceof TimedCachePolicy ) 278 { 279 TimedCachePolicy tcache = (TimedCachePolicy) cache; 280 validPrincipals = tcache.getValidKeys(); 281 } 282 return validPrincipals; 283 } 284 285 public boolean isValid(String securityDomain, Principal principal, Object credential) 287 { 288 boolean isValid = false; 289 try 290 { 291 SecurityDomainContext sdc = lookupSecurityDomain(securityDomain); 292 isValid = sdc.getSecurityManager().isValid(principal, credential, null); 293 } 294 catch(NamingException e) 295 { 296 log.debug("isValid("+securityDomain+") failed", e); 297 } 298 return isValid; 299 } 300 301 public Principal getPrincipal(String securityDomain, Principal principal) 302 { 303 Principal realmPrincipal = null; 304 try 305 { 306 SecurityDomainContext sdc = lookupSecurityDomain(securityDomain); 307 realmPrincipal = sdc.getRealmMapping().getPrincipal(principal); 308 } 309 catch(NamingException e) 310 { 311 log.debug("getPrincipal("+securityDomain+") failed", e); 312 } 313 return realmPrincipal; 314 } 315 316 public boolean doesUserHaveRole(String securityDomain, Principal principal, 317 Object credential, Set roles) 318 { 319 boolean doesUserHaveRole = false; 320 try 321 { 322 SecurityDomainContext sdc = lookupSecurityDomain(securityDomain); 323 Subject subject = new Subject (); 325 sdc.getSecurityManager().isValid(principal, credential, subject); 326 SubjectActions.pushSubjectContext(principal, credential, subject); 328 doesUserHaveRole = sdc.getRealmMapping().doesUserHaveRole(principal, roles); 329 SubjectActions.popSubjectContext(); 330 } 331 catch(NamingException e) 332 { 333 log.debug("doesUserHaveRole("+securityDomain+") failed", e); 334 } 335 return doesUserHaveRole; 336 } 337 338 public Set getUserRoles(String securityDomain, Principal principal, Object credential) 339 { 340 Set userRoles = null; 341 try 342 { 343 SecurityDomainContext sdc = lookupSecurityDomain(securityDomain); 344 sdc.getSecurityManager().isValid(principal, credential, null); 346 userRoles = sdc.getRealmMapping().getUserRoles(principal); 348 } 349 catch(NamingException e) 350 { 351 log.debug("getUserRoles("+securityDomain+") failed", e); 352 } 353 return userRoles; 354 } 355 357 protected void startService() throws Exception 358 { 359 SecurityAssociation.setServer(); 361 362 SubjectPolicyContextHandler handler = new SubjectPolicyContextHandler(); 364 PolicyContext.registerHandler(SubjectPolicyContextHandler.SUBJECT_CONTEXT_KEY, 365 handler, true); 366 367 Context ctx = new InitialContext (); 368 parser = ctx.getNameParser(""); 369 370 374 RefAddr refAddr = new StringRefAddr ("nns", "JSM"); 375 String factoryName = SecurityDomainObjectFactory.class.getName(); 376 Reference ref = new Reference ("javax.naming.Context", refAddr, factoryName, null); 377 ctx.rebind(SECURITY_MGR_PATH, ref); 378 log.debug("securityMgrCtxPath="+SECURITY_MGR_PATH); 379 380 refAddr = new StringRefAddr ("nns", "JSMCachePolicy"); 381 factoryName = DefaultCacheObjectFactory.class.getName(); 382 ref = new Reference ("javax.naming.Context", refAddr, factoryName, null); 383 ctx.rebind(DEFAULT_CACHE_POLICY_PATH, ref); 384 log.debug("cachePolicyCtxPath="+cacheJndiName); 385 386 SecurityProxyFactory proxyFactory = (SecurityProxyFactory) securityProxyFactoryClass.newInstance(); 388 ctx.bind("java:/SecurityProxyFactory", proxyFactory); 389 log.debug("SecurityProxyFactory="+proxyFactory); 390 391 PropertyEditorManager.registerEditor(Principal .class, PrincipalEditor.class); 393 PropertyEditorManager.registerEditor(SecurityDomain.class, SecurityDomainEditor.class); 394 } 395 396 protected void stopService() throws Exception 397 { 398 InitialContext ic = new InitialContext (); 399 400 try 401 { 402 ic.unbind(SECURITY_MGR_PATH); 403 } 404 catch(CommunicationException e) 405 { 406 } 408 finally 409 { 410 ic.close(); 411 } 412 } 413 414 416 public void registerSecurityDomain(String securityDomain, SecurityDomain instance) 417 { 418 log.debug("Added "+securityDomain+", "+instance+" to map"); 419 CachePolicy authCache = lookupCachePolicy(securityDomain); 420 SecurityDomainContext sdc = new SecurityDomainContext(instance, authCache); 421 securityDomainCtxMap.put(securityDomain, sdc); 422 setSecurityDomainCache(instance, authCache); 424 } 425 426 430 private static CachePolicy getCachePolicy(String securityDomain) 431 { 432 if( securityDomain.startsWith(SECURITY_MGR_PATH) ) 433 securityDomain = securityDomain.substring(SECURITY_MGR_PATH.length()+1); 434 CachePolicy cache = null; 435 try 436 { 437 SecurityDomainContext sdc = lookupSecurityDomain(securityDomain); 438 if( sdc != null ) 439 cache = sdc.getAuthenticationCache(); 440 } 441 catch(NamingException e) 442 { 443 log.debug("getCachePolicy("+securityDomain+") failure", e); 444 } 445 return cache; 446 } 447 448 455 private static CachePolicy lookupCachePolicy(String securityDomain) 456 { 457 CachePolicy authCache = null; 458 String domainCachePath = cacheJndiName + '/' + securityDomain; 459 try 460 { 461 InitialContext iniCtx = new InitialContext (); 462 authCache = (CachePolicy) iniCtx.lookup(domainCachePath); 463 } 464 catch(Exception e) 465 { 466 try 468 { 469 InitialContext iniCtx = new InitialContext (); 470 authCache = (CachePolicy) iniCtx.lookup(cacheJndiName); 471 } 472 catch(Exception e2) 473 { 474 log.warn("Failed to locate auth CachePolicy at: "+cacheJndiName 475 + " for securityDomain="+securityDomain); 476 } 477 } 478 return authCache; 479 } 480 481 486 private static void setSecurityDomainCache(AuthenticationManager securityMgr, 487 CachePolicy cachePolicy) 488 { 489 try 490 { 491 Class [] setCachePolicyTypes = {CachePolicy.class}; 492 Method m = securityMgrClass.getMethod("setCachePolicy", setCachePolicyTypes); 493 Object [] setCachePolicyArgs = {cachePolicy}; 494 m.invoke(securityMgr, setCachePolicyArgs); 495 log.debug("setCachePolicy, c="+setCachePolicyArgs[0]); 496 } 497 catch(Exception e2) 498 { log.debug("setCachePolicy failed", e2); 500 } 501 } 502 503 508 private static SecurityDomainContext lookupSecurityDomain(String securityDomain) 509 throws NamingException 510 { 511 SecurityDomainContext securityDomainCtx = (SecurityDomainContext) securityDomainCtxMap.get(securityDomain); 512 if( securityDomainCtx == null ) 513 { 514 securityDomainCtx = newSecurityDomainCtx(securityDomain); 515 securityDomainCtxMap.put(securityDomain, securityDomainCtx); 516 log.debug("Added "+securityDomain+", "+securityDomainCtx+" to map"); 517 } 518 return securityDomainCtx; 519 } 520 521 526 private static SecurityDomainContext newSecurityDomainCtx(String securityDomain) 527 throws NamingException 528 { 529 SecurityDomainContext sdc = null; 530 try 531 { 532 Class [] parameterTypes = {String .class, CallbackHandler .class}; 534 Constructor ctor = securityMgrClass.getConstructor(parameterTypes); 535 CallbackHandler handler = (CallbackHandler ) callbackHandlerClass.newInstance(); 536 Object [] args = {securityDomain, handler}; 537 AuthenticationManager securityMgr = (AuthenticationManager) ctor.newInstance(args); 538 log.debug("Created securityMgr="+securityMgr); 539 CachePolicy cachePolicy = lookupCachePolicy(securityDomain); 540 sdc = new SecurityDomainContext(securityMgr, cachePolicy); 541 setSecurityDomainCache(securityMgr, cachePolicy); 543 } 544 catch(Exception e2) 545 { 546 log.error("Failed to create sec mgr", e2); 547 throw new NamingException ("Failed to create sec mgr:"+e2.getMessage()); 548 } 549 return sdc; 550 } 551 552 556 public String getDefaultUnauthenticatedPrincipal() 557 { 558 return defaultUnauthenticatedPrincipal; 559 } 560 561 565 public void setDefaultUnauthenticatedPrincipal(String principal) 566 { 567 defaultUnauthenticatedPrincipal = principal; 568 } 569 570 572 public static class SecurityDomainObjectFactory 573 implements InvocationHandler , ObjectFactory 574 { 575 579 public Object getObjectInstance(Object obj, Name name, Context nameCtx, 580 Hashtable environment) 581 throws Exception 582 { 583 ClassLoader loader = SubjectActions.getContextClassLoader(); 584 Class [] interfaces = {Context .class}; 585 Context ctx = (Context ) Proxy.newProxyInstance(loader, interfaces, this); 586 return ctx; 587 } 588 589 590 594 public Object invoke(Object obj, Method method, Object [] args) throws Throwable 595 { 596 String methodName = method.getName(); 597 if( methodName.equals("toString") == true ) 598 return SECURITY_MGR_PATH + " Context proxy"; 599 if( methodName.equals("list") == true ) 600 return new DomainEnumeration(securityDomainCtxMap.keys(), securityDomainCtxMap); 601 602 if( methodName.equals("lookup") == false ) 603 throw new OperationNotSupportedException ("Only lookup is supported, op="+method); 604 String securityDomain = null; 605 Name name = null; 606 if( args[0] instanceof String ) 607 name = parser.parse((String ) args[0]); 608 else 609 name = (Name )args[0]; 610 securityDomain = name.get(0); 611 SecurityDomainContext securityDomainCtx = lookupSecurityDomain(securityDomain); 612 Object binding = securityDomainCtx.getSecurityManager(); 613 if( name.size() == 2 ) 615 { 616 String request = name.get(1); 617 binding = securityDomainCtx.lookup(request); 618 } 619 return binding; 620 } 621 } 622 static class DomainEnumeration implements NamingEnumeration 623 { 624 Enumeration domains; 625 Hashtable ctxMap; 626 DomainEnumeration(Enumeration domains, Hashtable ctxMap) 627 { 628 this.domains = domains; 629 this.ctxMap = ctxMap; 630 } 631 632 public void close() 633 { 634 } 635 public boolean hasMoreElements() 636 { 637 return domains.hasMoreElements(); 638 } 639 public boolean hasMore() 640 { 641 return domains.hasMoreElements(); 642 } 643 public Object next() 644 { 645 String name = (String ) domains.nextElement(); 646 Object value = ctxMap.get(name); 647 String className = value.getClass().getName(); 648 NameClassPair pair = new NameClassPair (name, className); 649 return pair; 650 } 651 public Object nextElement() 652 { 653 return domains.nextElement(); 654 } 655 } 656 657 659 public static class DefaultCacheObjectFactory implements InvocationHandler , ObjectFactory 660 { 661 665 public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) 666 throws Exception 667 { 668 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 669 Class [] interfaces = {Context .class}; 670 Context ctx = (Context ) Proxy.newProxyInstance(loader, interfaces, this); 671 return ctx; 672 } 673 677 public Object invoke(Object obj, Method method, Object [] args) throws Throwable 678 { 679 TimedCachePolicy cachePolicy = new TimedCachePolicy(defaultCacheTimeout, 680 true, defaultCacheResolution); 681 cachePolicy.create(); 682 cachePolicy.start(); 683 return cachePolicy; 684 } 685 } 686 } 687 | Popular Tags |