/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.security.auth.login;
import java.net.URL;
import java.util.Iterator;
import java.util.Set;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.security.auth.login.AppConfigurationEntry;
import org.jboss.deployment.DeploymentException;
import org.jboss.mx.util.MBeanProxy;
import org.jboss.security.config.ApplicationPolicy;
import org.jboss.security.config.PolicyConfig;
import org.jboss.system.ServiceMBeanSupport;
/** A security config mbean that loads an xml login configuration using the
XMLLoginConfig.loadConfig(URL config) operation on start, and unloads
the contained login module configurations on stop.
<server>
<mbean code="org.jboss.security.auth.login.DynamicLoginConfig"
name="...">
<attribute name="AuthConfig">login-config.xml</attribute>
<!-- The service which supports dynamic processing of login-config.xml
configurations.
-->
<depends optional-attribute-name="LoginConfigService">
jboss.security:service=XMLLoginConfig
</depends>
<!-- Optionally specify the security mgr service to use when
this service is stopped to flush the auth caches of the domains
registered by this service.
-->
<depends optional-attribute-name="SecurityManagerService">
jboss.security:service=JaasSecurityManager
</depends>
</mbean>
</server>
@see org.jboss.security.auth.login.XMLLoginConfig
@author Scott.Stark@jboss.org
@author Anil.Saldhana@jboss.org
@version $Revision: 82920 $
*/
public class DynamicLoginConfig extends ServiceMBeanSupport
implements DynamicLoginConfigMBean
{
/** The JAAS login config file resource to load */
private String authConf = "login-config.xml";
/** The name of the XMLLoginConfig to use to load the login configs */
private ObjectName loginConfigService;
/** The name of the SecurityMgrService to use for cache flushes */
private ObjectName securityMgrService;
/** The names of the login module configs loaded during start */
private String[] configNames;
private PolicyConfig config;
public DynamicLoginConfig()
{
}
public String getName()
{
return "Dynamic JAAS Login Config";
}
public PolicyConfig getPolicyConfig()
{
return config;
}
public void setPolicyConfig(PolicyConfig config)
{
this.config = config;
}
public ObjectName getLoginConfigService()
{
return loginConfigService;
}
/** Get the XMLLoginConfig service to use for loading. This service must
* support a String[] loadConfig(URL) operation to load the configurations.
*
* @param serviceName - the XMLLoginConfig service name.
*/
public void setLoginConfigService(ObjectName serviceName)
{
this.loginConfigService = serviceName;
}
public ObjectName getSecurityManagerService()
{
return securityMgrService;
}
/** Set the SecurityManagerService used to flush the registered security
* domains. This service must support an flushAuthenticationCache(String)
* operation to flush the case for the argument security domain. Setting
* this triggers the flush of the authentication caches when the service
* is stopped.
* @param serviceName - the SecurityManagerService service name.
*/
public void setSecurityManagerService(ObjectName serviceName)
{
this.securityMgrService = serviceName;
}
/** Get the resource path to the JAAS login configuration file to use.
*/
public String getAuthConfig()
{
return authConf;
}
/** Set the resource path to the JAAS login configuration file to use.
The default is "login-config.xml".
*/
public void setAuthConfig(String authConf)
{
this.authConf = authConf;
}
/** Go through the registered login config names and flush the auth
* caches if there is a registered SecurityManagerService.
*
* @throws Exception
*/
public void flushAuthenticationCaches() throws Exception
{
if( this.securityMgrService != null && server.isRegistered(securityMgrService))
{
int count = configNames == null ? 0 : configNames.length;
String[] sig = {String.class.getName()};
for(int n = 0; n < count; n ++)
{
Object[] args = {configNames[n]};
server.invoke(securityMgrService, "flushAuthenticationCache", args, sig);
log.debug("Flushed domain: "+configNames[n]);
}
}
}
/** Start the service. This entails loading the AuthConf file contents
* using the LoginConfigService.
*/
protected void startService() throws Exception
{
if( config != null )
{
log.debug("Using embedded config");
Set names = config.getConfigNames();
Iterator iter = names.iterator();
MBeanServer server = super.getServer();
while( iter.hasNext() )
{
String name = (String) iter.next();
ApplicationPolicy aPolicy = config.get(name);
if(aPolicy == null)
throw new IllegalStateException("Application Policy is null for "+name);
AuthenticationInfo info = (AuthenticationInfo)aPolicy.getAuthenticationInfo();
if(info == null)
throw new IllegalStateException("Authentication Info is null for " + name);
AppConfigurationEntry[] entry = info.getAppConfigurationEntry();
// addAppConfig(String, AppConfigurationEntry[]);
//Object[] args = {name, entry};
//String[] sig = {String.class.getName(), entry.getClass().getName()};
Object[] args = {name, aPolicy};
String[] sig = {String.class.getName(), aPolicy.getClass().getName()};
//server.invoke(loginConfigService, "addAppConfig", args, sig);
server.invoke(loginConfigService, "addApplicationPolicy", args, sig);
}
configNames = new String[names.size()];
names.toArray(configNames);
}
else
{
//JBAS-3422: Ensure that the AuthConf is neither null nor default login-config.xml
if( authConf== null || authConf.length() == 0)
throw new IllegalStateException("AuthConf is null. Please " +
"configure an appropriate config resource");
// Look for the authConf as resource
ClassLoader loader = Thread.currentThread().getContextClassLoader();
URL loginConfig = loader.getResource(authConf);
if(loginConfig == null)
{
try
{
//JBAS-3210: Allow an absolute url
loginConfig = new URL(authConf);
}
catch(Exception e)
{
loginConfig = null;
}
}
if( loginConfig != null )
{
validateAuthConfigURL(loginConfig);
log.debug("Using JAAS AuthConfig: "+loginConfig.toExternalForm());
MBeanServer server = super.getServer();
Object[] args = {loginConfig};
String[] sig = {URL.class.getName()};
configNames = (String[]) server.invoke(loginConfigService,
"loadConfig", args, sig);
int count = configNames == null ? 0 : configNames.length;
for(int n = 0; n < count; n ++)
{
log.debug("Loaded config: "+configNames[n]);
}
}
else
{
throw new DeploymentException("Failed to find authConf as resource: "+authConf);
}
}
}
/** Start the service. This entails unloading the AuthConf file contents
* using the LoginConfigService.
*/
protected void stopService() throws Exception
{
MBeanServer server = super.getServer();
flushAuthenticationCaches();
if( configNames != null && configNames.length > 0 )
{
Object[] args = {configNames};
String[] sig = {configNames.getClass().getName()};
server.invoke(loginConfigService, "removeConfigs", args, sig);
}
}
/**
* Ensure that the AuthConfig resource is not defaulting to
* the default login-config in the conf directory
* @param url
* @throws Exception
*/
private void validateAuthConfigURL(URL url) throws Exception
{
String msg = "AuthConfig is defaulting to conf/login-config.xml. " +
"Please check your archive.";
XMLLoginConfigMBean xmlConfig = null;
try
{
xmlConfig = (XMLLoginConfigMBean) MBeanProxy.get(XMLLoginConfigMBean.class,
XMLLoginConfigMBean.OBJECT_NAME, server);
if(xmlConfig.getConfigURL().sameFile(url))
throw new IllegalStateException(msg);
}
finally
{
//Clear the proxy
xmlConfig = null;
}
}
}