Merged DAVEW_V3.2 to HEAD

13659: Fix NTLMAuthenticationFilter to call super.afterPropertiesSet()
   13658: MOB-424: Utility to Dump JMX Data
      - new enterprise distributable jmx-dumper.jar
      - command line invocation via "java -jar jmx-dumper.jar"
      - admin web access via http://localhost:8080/alfresco/faces/jsp/admin/jmx-dumper.jsp
   13575: Preconfigured authentication stacks for alfresco, LDAP, Kerberos and NTLM. TODO: file server config.
   13493: Initial work to enable selection, configuration, testing and hot-swapping of different authentication subsystems via JMX or admin UI.
   13309: Changes to allow datasource and property configuration via JNDI
      - Move AVM catalina .jars into 3rd-party/lib/virtual-tomcat so that they don't get automatically included in the .war file and hence stop JNDI lookups from working
      - Allow JNDI lookup of datasource – use standard app server mechanisms for managing it but still fall back to 'normal' one
      - Allow properties to be overridden by JNDI env-entries as well as system properties. Including hibernate dialect ones. Web.xml can then declare required env-entries and these can be defined on deployment.
      - Rewire iBatis so that no config file edits are necessary when dialect is changed
      - Use proxy around datasource so that auto-commit is always activated for iBatis


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13668 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2009-03-18 12:49:12 +00:00
parent ae5ba076f3
commit 115b40d462
33 changed files with 1295 additions and 206 deletions

View File

@@ -5,7 +5,7 @@
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig> <sqlMapConfig>
<!-- note: dialect property is provided by SqlMapClientFactoryBean --> <!-- note: dialect property must be set in properties passed to SqlMapClientFactoryBean -->
<sqlMap resource="alfresco/activities/${hibernate.dialect}/ActivityPost.xml"/> <sqlMap resource="alfresco/activities/${hibernate.dialect}/ActivityPost.xml"/>
<sqlMap resource="alfresco/activities/${hibernate.dialect}/ActivityFeed.xml"/> <sqlMap resource="alfresco/activities/${hibernate.dialect}/ActivityFeed.xml"/>
<sqlMap resource="alfresco/activities/${hibernate.dialect}/ActivityFeedControl.xml"/> <sqlMap resource="alfresco/activities/${hibernate.dialect}/ActivityFeedControl.xml"/>

View File

@@ -14,15 +14,32 @@
<property name="maxFeedItems" value="100"/> <property name="maxFeedItems" value="100"/>
</bean> </bean>
<bean id="iBatisDataSource" parent="dataSource"> <bean id="iBatisDataSource" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="defaultAutoCommit" > <property name="proxyInterfaces">
<value>true</value> <value>javax.sql.DataSource</value>
</property>
<property name="target"><ref bean="dataSource"/></property>
<property name="interceptorNames">
<list>
<idref local="iBatisDataSource_autcommit" />
</list>
</property> </property>
</bean> </bean>
<bean id="sqlMapClient" class="org.alfresco.repo.domain.ibatis.AlfrescoSqlMapClientFactoryBean" singleton="true"> <bean id="iBatisDataSource_autcommit" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<bean class="org.alfresco.util.AutoCommitInterceptor" />
</property>
<property name="mappedName">
<value>getConnection</value>
</property>
</bean>
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean" singleton="true">
<property name="configLocation"><value>classpath:alfresco/activities/activities-SqlMapConfig.xml</value></property> <property name="configLocation"><value>classpath:alfresco/activities/activities-SqlMapConfig.xml</value></property>
<property name="dataSource" ref="iBatisDataSource"/> <property name="dataSource" ref="iBatisDataSource"/>
<!-- NOTE: although we use iBatis here rather than Hibernate, for consistency we make use of single SQL dialect property (hibernate.dialect) for consistency -->
<property name="sqlMapClientProperties" ref="hibernateConfigProperties"/>
</bean> </bean>
<bean id="postDaoService" class="org.alfresco.repo.activities.ibatis.IBatisActivityPostDaoServiceImpl"> <bean id="postDaoService" class="org.alfresco.repo.activities.ibatis.IBatisActivityPostDaoServiceImpl">

View File

@@ -74,30 +74,26 @@
<!-- The authroity DAO implements an interface extended from the Acegi --> <!-- The authroity DAO implements an interface extended from the Acegi -->
<!-- DAO that supports CRUD. --> <!-- DAO that supports CRUD. -->
<bean id="authenticationDao" class="org.alfresco.repo.security.authentication.RepositoryAuthenticationDao"> <bean id="alfrescoAuthentication" class="org.alfresco.repo.management.DefaultManagedApplicationContextFactory"/>
<property name="nodeService"> <bean id="kerberosAuthentication" class="org.alfresco.repo.management.DefaultManagedApplicationContextFactory"/>
<ref bean="nodeService" /> <bean id="ldapAuthentication" class="org.alfresco.repo.management.DefaultManagedApplicationContextFactory"/>
<bean id="ntlmAuthentication" class="org.alfresco.repo.management.DefaultManagedApplicationContextFactory"/>
<bean id="authenticationSelector" class="org.alfresco.repo.management.SwitchableManagedApplicationContextFactory">
<property name="sourceBeanName">
<value>alfrescoAuthentication</value>
</property> </property>
<property name="tenantService"> </bean>
<ref bean="tenantService"/>
<bean id="authenticationDao" class="org.alfresco.repo.management.ManagedSubsystemProxyFactory">
<property name="sourceApplicationContextFactory">
<ref bean="authenticationSelector" />
</property> </property>
<property name="dictionaryService"> <property name="interfaces">
<ref bean="dictionaryService" /> <list>
</property> <value>org.alfresco.repo.security.authentication.AuthenticationComponent</value>
<property name="namespaceService"> <value>org.alfresco.repo.security.authentication.MutableAuthenticationDao</value>
<ref bean="namespaceService" /> </list>
</property>
<property name="searchService">
<ref bean="admSearchService" />
</property>
<property name="retryingTransactionHelper">
<ref bean="retryingTransactionHelper"/>
</property>
<property name="userNameMatcher">
<ref bean="userNameMatcher" />
</property>
<property name="passwordEncoder">
<ref bean="passwordEncoder" />
</property> </property>
</bean> </bean>
@@ -161,29 +157,7 @@
</property> </property>
</bean> </bean>
<bean id="authenticationComponent" <alias name="authenticationDao" alias="authenticationComponent"/>
class="org.alfresco.repo.security.authentication.AuthenticationComponentImpl"
parent="authenticationComponentBase">
<property name="authenticationDao">
<ref bean="authenticationDao" />
</property>
<property name="authenticationManager">
<ref bean="authenticationManager" />
</property>
<property name="allowGuestLogin">
<value>true</value>
</property>
<property name="nodeService">
<ref bean="nodeService" />
</property>
<property name="personService">
<ref bean="personService" />
</property>
<property name="transactionService">
<ref bean="transactionService" />
</property>
</bean>
<!-- Simple Authentication component that rejects all authentication requests --> <!-- Simple Authentication component that rejects all authentication requests -->
<!-- Use this defintion for Novell IChain integration. --> <!-- Use this defintion for Novell IChain integration. -->

View File

@@ -25,29 +25,13 @@
<property name="authorityDAO"> <property name="authorityDAO">
<ref bean="authorityDAO" /> <ref bean="authorityDAO" />
</property> </property>
<property name="authenticationService">
<ref bean="authenticationService" />
</property>
<property name="permissionServiceSPI"> <property name="permissionServiceSPI">
<ref bean="permissionServiceImpl" /> <ref bean="permissionServiceImpl" />
</property> </property>
<!-- --> <!-- -->
<!-- A list of users with admin rights. -->
<!-- -->
<!-- If the security framework is case sensitive these values should -->
<!-- be case sensitive user names. If the security framework is not -->
<!-- case sensitive these values should be the lower-case user names. -->
<!-- -->
<!-- By default this includes: -->
<!-- admin (the user name of default alfresco admin user) -->
<!-- administrator (the windows default admin user) -->
<!-- -->
<!-- This assumes that user names are not case sensitive. -->
<!-- -->
<property name="adminUsers">
<set>
<value>admin</value>
<value>administrator</value>
</set>
</property>
<!-- -->
<!-- A list of groups with admin rights. --> <!-- A list of groups with admin rights. -->
<!-- --> <!-- -->
<property name="adminGroups"> <property name="adminGroups">

View File

@@ -15,7 +15,7 @@
<!-- load common properties --> <!-- load common properties -->
<bean id="repository-properties" <bean id="repository-properties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> class="org.alfresco.config.JndiPropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders"> <property name="ignoreUnresolvablePlaceholders">
<value>true</value> <value>true</value>
</property> </property>
@@ -42,7 +42,7 @@
<!-- or custom-db-and-data-context.xml file. --> <!-- or custom-db-and-data-context.xml file. -->
<bean id="shared-properties" <bean id="shared-properties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> class="org.alfresco.config.JndiPropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders"> <property name="ignoreUnresolvablePlaceholders">
<value>true</value> <value>true</value>
</property> </property>
@@ -181,7 +181,7 @@
<!-- Datasource bean --> <!-- Datasource bean -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <bean id="defaultDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"> <property name="driverClassName">
<value>${db.driver}</value> <value>${db.driver}</value>
</property> </property>
@@ -208,6 +208,15 @@
</property> </property>
</bean> </bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/dataSource</value>
</property>
<property name="defaultObject">
<ref bean="defaultDataSource" />
</property>
</bean>
<!-- Characterset decoder --> <!-- Characterset decoder -->
<bean id="charset.finder" class="org.alfresco.repo.content.encoding.ContentCharsetFinder"> <bean id="charset.finder" class="org.alfresco.repo.content.encoding.ContentCharsetFinder">
<property name="defaultCharset"> <property name="defaultCharset">

View File

@@ -4,7 +4,7 @@
<beans> <beans>
<!-- load hibernate configuration properties --> <!-- load hibernate configuration properties -->
<bean id="hibernateConfigProperties" class="org.alfresco.config.SystemPropertiesFactoryBean"> <bean id="hibernateConfigProperties" class="org.alfresco.config.JndiPropertiesFactoryBean">
<property name="systemProperties"> <property name="systemProperties">
<list> <list>
<value>hibernate.dialect</value> <value>hibernate.dialect</value>

View File

@@ -0,0 +1,52 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<bean id="authenticationComponent" class="org.alfresco.repo.security.authentication.AuthenticationComponentImpl"
parent="authenticationComponentBase">
<property name="authenticationDao">
<ref bean="authenticationDao" />
</property>
<property name="authenticationManager">
<ref bean="authenticationManager" />
</property>
<property name="allowGuestLogin">
<value>${alfresco.authentication.allowGuestLogin}</value>
</property>
<property name="nodeService">
<ref bean="nodeService" />
</property>
<property name="personService">
<ref bean="personService" />
</property>
<property name="transactionService">
<ref bean="transactionService" />
</property>
</bean>
<bean id="authenticationDao" class="org.alfresco.repo.security.authentication.RepositoryAuthenticationDao">
<property name="nodeService">
<ref bean="nodeService" />
</property>
<property name="tenantService">
<ref bean="tenantService" />
</property>
<property name="dictionaryService">
<ref bean="dictionaryService" />
</property>
<property name="namespaceService">
<ref bean="namespaceService" />
</property>
<property name="searchService">
<ref bean="admSearchService" />
</property>
<property name="retryingTransactionHelper">
<ref bean="retryingTransactionHelper" />
</property>
<property name="userNameMatcher">
<ref bean="userNameMatcher" />
</property>
<property name="passwordEncoder">
<ref bean="passwordEncoder" />
</property>
</bean>
</beans>

View File

@@ -0,0 +1 @@
alfresco.authentication.allowGuestLogin=true

View File

@@ -10,10 +10,10 @@
class="org.alfresco.repo.security.authentication.jaas.JAASAuthenticationComponent" class="org.alfresco.repo.security.authentication.jaas.JAASAuthenticationComponent"
parent="authenticationComponentBase"> parent="authenticationComponentBase">
<property name="realm"> <property name="realm">
<value>DEFAULT.REALM</value> <value>${kerberos.authentication.realm}</value>
</property> </property>
<property name="jaasConfigEntryName"> <property name="jaasConfigEntryName">
<value>Alfresco</value> <value>${kerberos.authentication.user.configEntryName}</value>
</property> </property>
<property name="nodeService"> <property name="nodeService">
<ref bean="nodeService" /> <ref bean="nodeService" />
@@ -24,6 +24,9 @@
<property name="transactionService"> <property name="transactionService">
<ref bean="transactionService" /> <ref bean="transactionService" />
</property> </property>
<property name="defaultAdministratorUserNames">
<value>${kerberos.authentication.defaultAdministratorUserNames}</value>
</property>
</bean> </bean>
<!-- DAO that rejects changes - JAAS is read only at the moment. --> <!-- DAO that rejects changes - JAAS is read only at the moment. -->

View File

@@ -0,0 +1,3 @@
kerberos.authentication.realm=ALFRESCO.ORG
kerberos.authentication.user.configEntryName=Alfresco
kerberos.authentication.defaultAdministratorUserNames=

View File

@@ -2,18 +2,6 @@
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'> <!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans> <beans>
<!-- The main configuration has moved into a properties file -->
<bean name="ldapAuthenticationPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders">
<value>true</value>
</property>
<property name="locations">
<value>classpath:alfresco/extension/ldap-authentication.properties</value>
</property>
</bean>
<!-- DAO that rejects changes - LDAP is read only at the moment. It does allow users to be deleted with out warnings from the UI. --> <!-- DAO that rejects changes - LDAP is read only at the moment. It does allow users to be deleted with out warnings from the UI. -->
<bean id="authenticationDao" class="org.alfresco.repo.security.authentication.DefaultMutableAuthenticationDao" > <bean id="authenticationDao" class="org.alfresco.repo.security.authentication.DefaultMutableAuthenticationDao" >
@@ -68,6 +56,12 @@
<property name="escapeCommasInUid"> <property name="escapeCommasInUid">
<value>${ldap.authentication.escapeCommasInUid}</value> <value>${ldap.authentication.escapeCommasInUid}</value>
</property> </property>
<property name="allowGuestLogin">
<value>${ldap.authentication.allowGuestLogin}</value>
</property>
<property name="defaultAdministratorUserNames">
<value>${ldap.authentication.defaultAdministratorUserNames}</value>
</property>
</bean> </bean>
<!-- <!--

View File

@@ -1,7 +1,7 @@
# #
# This properties file brings together the common options for LDAP authentication rather than editing the bean definitions # This properties file brings together the common options for LDAP authentication rather than editing the bean definitions
# #
ldap.authentication.allowGuestLogin=true
# How to map the user id entered by the user to taht passed through to LDAP # How to map the user id entered by the user to taht passed through to LDAP
# - simple # - simple
# - this must be a DN and would be something like # - this must be a DN and would be something like
@@ -35,3 +35,6 @@ ldap.authentication.escapeCommasInBind=false
# pulled in as part of an LDAP sync # pulled in as part of an LDAP sync
# If this option is set to true it will break the default home folder provider as space names can not contain \ # If this option is set to true it will break the default home folder provider as space names can not contain \
ldap.authentication.escapeCommasInUid=false ldap.authentication.escapeCommasInUid=false
# Comma separated list of user names who should be considered users by default
ldap.authentication.defaultAdministratorUserNames=

View File

@@ -3,21 +3,48 @@
<beans> <beans>
<bean name="ldapSynchronisationPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders">
<value>true</value>
</property>
<property name="locations">
<value>classpath:alfresco/extension/ldap-synchronisation.properties</value>
</property>
</bean>
<!-- <!--
Wire up the same context as used for LDAP authentication. You could use another context: just replace this
alias with the bean definition This bean is used to provide read only access to users and groups to pull them out of the LDAP reopsitory
--> -->
<alias alias="ldapSyncInitialDirContextFactory" name="ldapInitialDirContextFactory"/> <bean id="ldapInitialDirContextFactory" class="org.alfresco.repo.security.authentication.ldap.LDAPInitialDirContextFactoryImpl">
<property name="initialDirContextEnvironment">
<map>
<!-- The LDAP provider -->
<entry key="java.naming.factory.initial">
<value>${ldap.synchronisation.java.naming.factory.initial}</value>
</entry>
<!-- The url to the LDAP server -->
<!-- Note you can use space separated urls - they will be tried in turn until one works -->
<!-- This could be used to authenticate against one or more ldap servers (you will not know which one ....) -->
<entry key="java.naming.provider.url">
<value>${ldap.synchronisation.java.naming.provider.url}</value>
</entry>
<!-- The authentication mechanism to use -->
<!-- Some sasl authentication mechanisms may require a realm to be set -->
<!-- java.naming.security.sasl.realm -->
<!-- The available options will depend on your LDAP provider -->
<entry key="java.naming.security.authentication">
<value>${ldap.synchronisation.java.naming.security.authentication}</value>
</entry>
<!-- The id of a user who can read group and user information -->
<!-- This does not go through the pattern substitution defined above and is used "as is" -->
<entry key="java.naming.security.principal">
<value>${ldap.synchronisation.java.naming.security.principal}</value>
</entry>
<!-- The password for the user defined above -->
<entry key="java.naming.security.credentials">
<value>${ldap.authentication.java.naming.security.credentials}</value>
</entry>
</map>
</property>
</bean>
<!-- Ldap Syncronisation support --> <!-- Ldap Syncronisation support -->

View File

@@ -2,6 +2,21 @@
# This properties file is used to configure LDAP syncronisation # This properties file is used to configure LDAP syncronisation
# #
# The LDAP context factory to use
ldap.synchronisation.java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
# The URL to connect to the LDAP server
ldap.synchronisation.java.naming.provider.url=ldap://openldap.domain.com:389
# The synchronisation mechanism to use
ldap.synchronisation.java.naming.security.authentication=DIGEST-MD5
# The default principal to use (only used for LDAP sync)
ldap.synchronisation.java.naming.security.principal=reader
# The password for the default principal (only used for LDAP sync)
ldap.synchronisation.java.naming.security.credentials=secret
# The query to find the people to import # The query to find the people to import
ldap.synchronisation.personQuery=(objectclass=inetOrgPerson) ldap.synchronisation.personQuery=(objectclass=inetOrgPerson)

View File

@@ -0,0 +1,5 @@
ntlm.authentication.useLocalServer=false
ntlm.authentication.domain=DOMAIN
ntlm.authentication.servers=
ntlm.authentication.guestAccess=false
ntlm.authentication.defaultAdministratorUserNames=

View File

@@ -27,10 +27,13 @@
class="org.alfresco.repo.security.authentication.ntlm.NTLMAuthenticationComponentImpl" class="org.alfresco.repo.security.authentication.ntlm.NTLMAuthenticationComponentImpl"
parent="authenticationComponentBase"> parent="authenticationComponentBase">
<property name="useLocalServer"> <property name="useLocalServer">
<value>false</value> <value>${ntlm.authentication.useLocalServer}</value>
</property>
<property name="domain">
<value>${ntlm.authentication.domain}</value>
</property> </property>
<property name="servers"> <property name="servers">
<value>192.168.0.1</value> <value>${ntlm.authentication.servers}</value>
</property> </property>
<property name="personService"> <property name="personService">
<ref bean="personService" /> <ref bean="personService" />
@@ -42,7 +45,10 @@
<ref bean="transactionComponent" /> <ref bean="transactionComponent" />
</property> </property>
<property name="guestAccess"> <property name="guestAccess">
<value>false</value> <value>${ntlm.authentication.guestAccess}</value>
</property>
<property name="defaultAdministratorUserNames">
<value>${ntlm.authentication.defaultAdministratorUserNames}</value>
</property> </property>
</bean> </bean>

View File

@@ -0,0 +1,162 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.management;
import java.util.Properties;
import org.alfresco.service.Managed;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* A factory allowing initialisation of an entire 'subsystem' in a child application context. As with other
* {@link ManagedBean}s, can be stopped, reconfigured, started and tested. Doesn't actually implement FactoryBean
* because we need first class access to the factory itself to be able to configure its properties.
*/
public class DefaultManagedApplicationContextFactory implements ManagedApplicationContextFactory,
InitializingBean, ApplicationContextAware, BeanNameAware
{
private static final long serialVersionUID = 6368629257690177326L;
private ApplicationContext parent;
private String beanName;
private ClassPathXmlApplicationContext applicationContext;
private Properties properties;
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.
* ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.parent = applicationContext;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
*/
public void setBeanName(String name)
{
this.beanName = name;
}
/**
* @param properties
* the properties to set
*/
@Managed(category="management")
public void setProperties(Properties properties)
{
this.properties = properties;
}
/**
* @return the properties
*/
public Properties getProperties()
{
return this.properties;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception
{
PropertiesFactoryBean factory = new PropertiesFactoryBean();
if (this.properties != null)
{
factory.setLocalOverride(true);
factory.setProperties(this.properties);
}
factory.setLocations(this.parent.getResources("classpath*:alfresco/subsystems/" + this.beanName
+ "/*.properties"));
factory.afterPropertiesSet();
this.properties = (Properties) factory.getObject();
}
/*
* (non-Javadoc)
* @see org.alfresco.enterprise.repo.management.ConfigurableBean#onStart()
*/
public void onStart()
{
this.applicationContext = new ClassPathXmlApplicationContext(new String[]
{
"classpath*:alfresco/subsystems/" + this.beanName + "/*-context.xml"
}, false, this.parent);
// Add all the post processors of the parent, e.g. to make sure system placeholders get expanded properly
for (Object postProcessor : this.parent.getBeansOfType(BeanFactoryPostProcessor.class).values())
{
this.applicationContext.addBeanFactoryPostProcessor((BeanFactoryPostProcessor) postProcessor);
}
// Add a property placeholder configurer, with the subsystem-scoped default properties
PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
configurer.setProperties(this.properties);
configurer.setIgnoreUnresolvablePlaceholders(true);
this.applicationContext.addBeanFactoryPostProcessor(configurer);
this.applicationContext.setClassLoader(parent.getClassLoader());
this.applicationContext.refresh();
}
/*
* (non-Javadoc)
* @see org.alfresco.enterprise.repo.management.ConfigurableBean#onTest()
*/
public void onTest()
{
this.applicationContext.getBean("testBean");
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public void destroy() throws Exception
{
if (this.applicationContext != null)
{
this.applicationContext.close();
this.applicationContext = null;
}
}
/* (non-Javadoc)
* @see org.alfresco.repo.management.ManagedApplicationContextFactory#getApplicationContext()
*/
public ApplicationContext getApplicationContext()
{
return this.applicationContext;
}
}

View File

@@ -0,0 +1,350 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.management;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.management.JMException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
/**
* A utility class providing a method to dump a local or remote MBeanServer's entire object tree for support purposes.
* Nested arrays and CompositeData objects in MBean attribute values are handled.
*
* @author dward
*/
public class JmxDumpUtil
{
/** Table header for attribute names. */
private static final String NAME_HEADER = "Attribute Name";
/** Table header for attribute values. */
private static final String VALUE_HEADER = "Attribute Value";
/** Place holder for nulls. */
private static final String NULL_VALUE = "<null>";
/** Place holder for unreadable values. */
private static final String UNREADABLE_VALUE = "<not readable>";
/**
* Dumps a local or remote MBeanServer's entire object tree for support purposes. Nested arrays and CompositeData
* objects in MBean attribute values are handled.
*
* @param connection
* the server connection (or server itself)
* @param out
* PrintWriter to write the output to
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static void dumpConnection(MBeanServerConnection connection, PrintWriter out) throws IOException
{
// Get all the object names
Set<ObjectName> objectNames = connection.queryNames(null, null);
// Sort the names
objectNames = new TreeSet<ObjectName>(objectNames);
// Dump each MBean
for (ObjectName objectName : objectNames)
{
try
{
printMBeanInfo(connection, objectName, out);
}
catch (JMException e)
{
// Sometimes beans can disappear while we are examining them
}
}
}
/**
* Dumps the details of a single MBean.
*
* @param connection
* the server connection (or server itself)
* @param objectName
* the object name
* @param out
* PrintWriter to write the output to
* @throws IOException
* Signals that an I/O exception has occurred.
* @throws JMException
* Signals a JMX error
*/
private static void printMBeanInfo(MBeanServerConnection connection, ObjectName objectName, PrintWriter out)
throws IOException, JMException
{
Map<String, Object> attributes = new TreeMap<String, Object>();
MBeanInfo info = connection.getMBeanInfo(objectName);
attributes.put("** Object Name", objectName.toString());
attributes.put("** Object Type", info.getClassName());
for (MBeanAttributeInfo element : info.getAttributes())
{
Object value;
if (element.isReadable())
{
try
{
value = connection.getAttribute(objectName, element.getName());
}
catch (Exception e)
{
value = JmxDumpUtil.UNREADABLE_VALUE;
}
}
else
{
value = JmxDumpUtil.UNREADABLE_VALUE;
}
attributes.put(element.getName(), value);
}
tabulate(JmxDumpUtil.NAME_HEADER, JmxDumpUtil.VALUE_HEADER, attributes, out, 0);
}
/**
* Dumps the details of a single CompositeData object.
*
* @param composite
* the composite object
* @param out
* PrintWriter to write the output to
* @param nestLevel
* the nesting level
* @throws IOException
* Signals that an I/O exception has occurred.
*/
private static void printCompositeInfo(CompositeData composite, PrintWriter out, int nestLevel) throws IOException
{
Map<String, Object> attributes = new TreeMap<String, Object>();
for (String key : composite.getCompositeType().keySet())
{
Object value;
try
{
value = composite.get(key);
}
catch (Exception e)
{
value = JmxDumpUtil.UNREADABLE_VALUE;
}
attributes.put(key, value);
}
tabulate(JmxDumpUtil.NAME_HEADER, JmxDumpUtil.VALUE_HEADER, attributes, out, nestLevel);
}
/**
* Tabulates a given String -> Object Map.
*
* @param keyHeader
* the key header
* @param valueHeader
* the value header
* @param rows
* Map containing key value pairs forming the rows
* @param out
* PrintWriter to write the output to
* @param nestLevel
* the nesting level
* @throws IOException
* Signals that an I/O exception has occurred.
*/
private static void tabulate(String keyHeader, String valueHeader, Map<String, Object> rows, PrintWriter out,
int nestLevel) throws IOException
{
if (rows.isEmpty())
{
return;
}
// Calculate column lengths
int maxKeyLength = keyHeader.length(), maxValLength = valueHeader.length();
for (Map.Entry<String, Object> entry : rows.entrySet())
{
maxKeyLength = Math.max(maxKeyLength, entry.getKey().length());
maxValLength = Math.max(maxValLength, getValueLength(entry.getValue()));
}
// Output Header
outputRow(out, maxKeyLength, keyHeader, valueHeader, nestLevel);
indent(out, nestLevel);
for (int col = 0; col < maxKeyLength; col++)
{
out.print('-');
}
out.print(' ');
for (int col = 0; col < maxValLength; col++)
{
out.print('-');
}
out.println();
// Output Body
for (Map.Entry<String, Object> entry : rows.entrySet())
{
outputRow(out, maxKeyLength, entry.getKey(), entry.getValue(), nestLevel);
}
out.println();
}
/**
* Outputs spaces in the left hand margin appropriate for the given nesting level.
*
* @param out
* PrintWriter to write the output to
* @param nestLevel
* the nesting level
*/
private static void indent(PrintWriter out, int nestLevel)
{
int size = nestLevel * 3;
for (int i = 0; i < size; i++)
{
out.print(' ');
}
}
/**
* Outputs a single row in a two-column table. The first column is padded with spaces so that the second column is
* aligned.
*
* @param out
* PrintWriter to write the output to
* @param maxKeyLength
* maximum number of characters in the first column
* @param key
* the first column value
* @param value
* the second column value
* @param nestLevel
* the nesting level
* @throws IOException
* Signals that an I/O exception has occurred.
*/
private static void outputRow(PrintWriter out, int maxKeyLength, String key, Object value, int nestLevel)
throws IOException
{
indent(out, nestLevel);
out.print(key);
for (int i = key.length() - 1; i < maxKeyLength; i++)
{
out.print(' ');
}
outputValue(out, value, nestLevel);
}
/**
* Outputs a single value, dealing with nested arrays and CompositeData objects.
*
* @param out
* PrintWriter to write the output to
* @param value
* the value to output
* @param nestLevel
* the nesting level
* @throws IOException
* Signals that an I/O exception has occurred.
*/
private static void outputValue(PrintWriter out, Object value, int nestLevel) throws IOException
{
if (value == null)
{
out.println(JmxDumpUtil.NULL_VALUE);
}
else if (value.getClass().isArray())
{
int length = Array.getLength(value);
if (length == 0)
{
out.println("[]");
}
else
{
out.println();
indent(out, nestLevel + 1);
out.println('[');
for (int i = 0; i < length; i++)
{
indent(out, nestLevel + 2);
outputValue(out, Array.get(value, i), nestLevel + 2);
if (i + 1 < length)
{
indent(out, nestLevel + 1);
out.println(',');
}
}
indent(out, nestLevel + 1);
out.println(']');
}
}
else if (value instanceof CompositeData)
{
out.println();
indent(out, nestLevel + 1);
out.println('[');
printCompositeInfo((CompositeData) value, out, nestLevel + 2);
indent(out, nestLevel + 1);
out.println(']');
}
else
{
out.println(value.toString());
}
}
/**
* Gets the number of characters required to encode a value.
*
* @param value
* the value to be encoded
* @return the number of characters
*/
private static int getValueLength(Object value)
{
if (value == null)
{
return JmxDumpUtil.NULL_VALUE.length();
}
else if (value.getClass().isArray() || value instanceof CompositeData)
{
// We continue arrays and composites on a new line
return 0;
}
else
{
return value.toString().length();
}
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.management;
import org.springframework.context.ApplicationContext;
/**
* An interface for {@link ManagedBean}s providing access to a child application context corresonding to a particular
* subsystem. As with other {@link ManagedBean}s, can be stopped, reconfigured, started and tested. Doesn't actually
* implement FactoryBean because we need first class access to the factory itself to be able to configure its
* properties.
*
* @author dward
*/
public interface ManagedApplicationContextFactory extends ManagedBean
{
/**
* Gets the application context, configured according to the properties of the factory.
*
* @return the application context
*/
public ApplicationContext getApplicationContext();
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.management;
import org.springframework.beans.factory.DisposableBean;
/**
* An interface for beans that can be reconfigured using an administration UI or JMX console. A bean in use must be
* 'stopped' before it can be configured with {@link #destroy}. After reconfiguration, it can then be put back into use
* with {@link #onStart} and if this is successful, further tests can be carried out with {@link #onTest}.
*
* @author dward
*/
public interface ManagedBean extends DisposableBean
{
/**
* Puts the bean into use after its properties have been set.
*/
public void onStart();
/**
* Carries out tests on the bean after it has been started.
*/
public void onTest();
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.management;
import java.lang.reflect.Method;
import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.support.DefaultPointcutAdvisor;
/**
* A factory bean, normally used in conjunction with {@link DefaultManagedApplicationContextFactory} allowing selected
* interfaces in a child application context to be proxied by a bean in the parent application context. This allows
* 'hot-swapping' and reconfiguration of entire subsystems.
*/
public class ManagedSubsystemProxyFactory extends ProxyFactoryBean
{
private static final long serialVersionUID = -4186421942840611218L;
/** The source application context factory. */
private ManagedApplicationContextFactory sourceApplicationContextFactory;
/** An optional bean name to look up in the source application context **/
private String sourceBeanName;
/**
* Instantiates a new managed subsystem proxy factory.
*/
public ManagedSubsystemProxyFactory()
{
addAdvisor(new DefaultPointcutAdvisor(new MethodInterceptor()
{
public Object invoke(MethodInvocation mi) throws Throwable
{
Method method = mi.getMethod();
if (ManagedSubsystemProxyFactory.this.sourceBeanName == null)
{
Map<?, ?> beans = ManagedSubsystemProxyFactory.this.sourceApplicationContextFactory
.getApplicationContext().getBeansOfType(method.getDeclaringClass());
if (beans.size() != 1)
{
throw new RuntimeException("Don't know where to route call to method " + method);
}
return method.invoke(beans.values().iterator().next(), mi.getArguments());
}
else
{
Object bean = ManagedSubsystemProxyFactory.this.sourceApplicationContextFactory
.getApplicationContext().getBean(ManagedSubsystemProxyFactory.this.sourceBeanName);
return method.invoke(bean, mi.getArguments());
}
}
}));
}
/**
* Sets the source application context factory.
*
* @param sourceApplicationContextFactory
* the sourceApplicationContextFactory to set
*/
public void setSourceApplicationContextFactory(ManagedApplicationContextFactory sourceApplicationContextFactory)
{
this.sourceApplicationContextFactory = sourceApplicationContextFactory;
}
/**
* Sets optional bean name to target all calls to in the source application context. If not set, an appropriate
* bean is looked up based on method class.
*
* @param sourceBeanName
* the sourceBeanName to set
*/
public void setSourceBeanName(String sourceBeanName)
{
this.sourceBeanName = sourceBeanName;
}
}

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.management;
import org.alfresco.service.Managed;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* A configurable proxy for a set of {@link ManagedApplicationContextFactory} beans that allows dynamic selection of one
* or more alternative subsystems via {@link #setSourceBeanName}. As with other {@link ManagedBean}s, can be stopped,
* reconfigured, started and tested. Doesn't actually implement FactoryBean because we need first class access to the
* factory itself to be able to configure its properties.
*/
public class SwitchableManagedApplicationContextFactory implements ApplicationContextAware,
ManagedApplicationContextFactory
{
/** The parent application context. */
private ApplicationContext parent;
/** The bean name of the source {@link ManagedApplicationContextFactory}. */
private String sourceBeanName;
/** The current source application context factory. */
private ManagedApplicationContextFactory sourceApplicationContextFactory;
/**
* Sets the bean name of the source {@link ManagedApplicationContextFactory}.
*
* @param sourceBeanName
* the bean name
* @throws Exception
* on error
*/
@Managed(category = "management")
public synchronized void setSourceBeanName(String sourceBeanName) throws Exception
{
if (this.sourceApplicationContextFactory != null)
{
destroy();
this.sourceBeanName = sourceBeanName;
onStart();
}
else
{
this.sourceBeanName = sourceBeanName;
}
}
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.
* ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.parent = applicationContext;
}
/*
* (non-Javadoc)
* @see org.alfresco.enterprise.repo.management.ConfigurableBean#onStart()
*/
public synchronized void onStart()
{
this.sourceApplicationContextFactory = (ManagedApplicationContextFactory) this.parent
.getBean(this.sourceBeanName);
this.sourceApplicationContextFactory.onStart();
}
/*
* (non-Javadoc)
* @see org.alfresco.enterprise.repo.management.ConfigurableBean#onTest()
*/
public synchronized void onTest()
{
if (this.sourceApplicationContextFactory != null)
{
this.sourceApplicationContextFactory.onTest();
}
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public synchronized void destroy() throws Exception
{
if (this.sourceApplicationContextFactory != null)
{
this.sourceApplicationContextFactory.destroy();
}
this.sourceApplicationContextFactory = null;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.management.ManagedApplicationContextFactory#getApplicationContext()
*/
public synchronized ApplicationContext getApplicationContext()
{
if (this.sourceApplicationContextFactory == null)
{
onStart();
}
return this.sourceApplicationContextFactory.getApplicationContext();
}
}

View File

@@ -24,6 +24,11 @@
*/ */
package org.alfresco.repo.security.authentication; package org.alfresco.repo.security.authentication;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl; import net.sf.acegisecurity.GrantedAuthorityImpl;
@@ -66,6 +71,8 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC
private TransactionService transactionService; private TransactionService transactionService;
private Set<String> defaultAdministratorUserNames = Collections.emptySet();
private boolean autoCreatePeopleOnLogin = true; private boolean autoCreatePeopleOnLogin = true;
public AbstractAuthenticationComponent() public AbstractAuthenticationComponent()
@@ -494,4 +501,39 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC
} }
} }
} }
/*
* (non-Javadoc)
* @see org.alfresco.repo.security.authentication.AuthenticationComponent#getDefaultAdministratorUserNames()
*/
public Set<String> getDefaultAdministratorUserNames()
{
return this.defaultAdministratorUserNames;
}
/**
* Sets the user names who for this particular authentication system should be considered administrators by default.
*
* @param defaultAdministratorUserNames
* a set of user names
*/
public void setDefaultAdministratorUserNames(Set<String> defaultAdministratorUserNames)
{
this.defaultAdministratorUserNames = defaultAdministratorUserNames;
}
/**
* Convenience method to allow the administrator user names to be specified as a comma separated list
*
* @param defaultAdministratorUserNames
*/
public void setDefaultAdministratorUserNames(String defaultAdministratorUserNames)
{
Set<String> nameSet = new TreeSet<String>();
if (!defaultAdministratorUserNames.isEmpty())
{
nameSet.addAll(Arrays.asList(defaultAdministratorUserNames.split(",")));
}
setDefaultAdministratorUserNames(nameSet);
}
} }

View File

@@ -24,6 +24,8 @@
*/ */
package org.alfresco.repo.security.authentication; package org.alfresco.repo.security.authentication;
import java.util.Set;
import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.Authentication;
public interface AuthenticationComponent public interface AuthenticationComponent
@@ -134,4 +136,13 @@ public interface AuthenticationComponent
* Get the MD4 password hash, as required by NTLM based authentication methods. * Get the MD4 password hash, as required by NTLM based authentication methods.
*/ */
public String getMD4HashedPassword(String userName); public String getMD4HashedPassword(String userName);
/**
* Gets a set of user names who for this particular authentication system should be considered administrators by
* default. If the security framework is case sensitive these values should be case sensitive user names. If the
* security framework is not case sensitive these values should be the lower-case user names.
*
* @return a set of user names
*/
public Set<String> getDefaultAdministratorUserNames();
} }

View File

@@ -26,6 +26,8 @@ package org.alfresco.repo.security.authentication;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.Collections;
import java.util.Set;
import net.sf.acegisecurity.AuthenticationManager; import net.sf.acegisecurity.AuthenticationManager;
import net.sf.acegisecurity.UserDetails; import net.sf.acegisecurity.UserDetails;
@@ -59,7 +61,7 @@ public class AuthenticationComponentImpl extends AbstractAuthenticationComponent
* *
* @param authenticationDao * @param authenticationDao
*/ */
@Managed(category="Security") @Managed(category = "Security")
public void setAuthenticationDao(MutableAuthenticationDao authenticationDao) public void setAuthenticationDao(MutableAuthenticationDao authenticationDao)
{ {
this.authenticationDao = authenticationDao; this.authenticationDao = authenticationDao;
@@ -68,13 +70,14 @@ public class AuthenticationComponentImpl extends AbstractAuthenticationComponent
/** /**
* Authenticate * Authenticate
*/ */
@Override
protected void authenticateImpl(String userName, char[] password) throws AuthenticationException protected void authenticateImpl(String userName, char[] password) throws AuthenticationException
{ {
try try
{ {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userName, UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userName,
new String(password)); new String(password));
authenticationManager.authenticate(authentication); this.authenticationManager.authenticate(authentication);
setCurrentUser(userName); setCurrentUser(userName);
} }
@@ -92,28 +95,28 @@ public class AuthenticationComponentImpl extends AbstractAuthenticationComponent
} }
} }
/** /**
* We actually have an acegi object so override the default method. * We actually have an acegi object so override the default method.
*/ */
@Override
protected UserDetails getUserDetails(String userName) protected UserDetails getUserDetails(String userName)
{ {
return (UserDetails) authenticationDao.loadUserByUsername(userName); return this.authenticationDao.loadUserByUsername(userName);
} }
/** /**
* Get the password hash from the DAO * Get the password hash from the DAO
*/ */
@Override
public String getMD4HashedPassword(String userName) public String getMD4HashedPassword(String userName)
{ {
return authenticationDao.getMD4HashedPassword(userName); return this.authenticationDao.getMD4HashedPassword(userName);
} }
/** /**
* This implementation supported MD4 password hashes. * This implementation supported MD4 password hashes.
*/ */
@Override
public NTLMMode getNTLMMode() public NTLMMode getNTLMMode()
{ {
return NTLMMode.MD4_PROVIDER; return NTLMMode.MD4_PROVIDER;
@@ -125,5 +128,13 @@ public class AuthenticationComponentImpl extends AbstractAuthenticationComponent
return true; return true;
} }
/*
* (non-Javadoc)
* @see org.alfresco.repo.security.authentication.AuthenticationComponent#getDefaultAdministratorUserNames()
*/
@Override
public Set<String> getDefaultAdministratorUserNames()
{
return Collections.singleton(AuthenticationUtil.getAdminUserName());
}
} }

View File

@@ -303,4 +303,13 @@ public class AuthenticationServiceImpl extends AbstractAuthenticationService
{ {
return Collections.singleton(ticketComponent); return Collections.singleton(ticketComponent);
} }
/*
* (non-Javadoc)
* @see org.alfresco.service.cmr.security.AuthenticationService#getDefaultAdministratorUserNames()
*/
public Set<String> getDefaultAdministratorUserNames()
{
return authenticationComponent.getDefaultAdministratorUserNames();
}
} }

View File

@@ -26,6 +26,8 @@ package org.alfresco.repo.security.authentication;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.Authentication;
@@ -434,4 +436,17 @@ public class ChainingAuthenticationComponentImpl implements AuthenticationCompon
} }
} }
/*
* (non-Javadoc)
* @see org.alfresco.repo.security.authentication.AuthenticationComponent#getDefaultAdministratorUserNames()
*/
public Set<String> getDefaultAdministratorUserNames()
{
Set<String> defaultAdministratorUserNames = new TreeSet<String>();
for (AuthenticationComponent authComponent : getUsableAuthenticationComponents())
{
defaultAdministratorUserNames.addAll(authComponent.getDefaultAdministratorUserNames());
}
return defaultAdministratorUserNames;
}
} }

View File

@@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.TreeSet;
import org.alfresco.service.Managed; import org.alfresco.service.Managed;
import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.AuthenticationService;
@@ -470,4 +471,13 @@ public class ChainingAuthenticationServiceImpl extends AbstractAuthenticationSer
return tcs; return tcs;
} }
public Set<String> getDefaultAdministratorUserNames()
{
Set<String> defaultAdministratorUserNames = new TreeSet<String>();
for (AuthenticationService authService : getUsableAuthenticationServices())
{
defaultAdministratorUserNames.addAll(authService.getDefaultAdministratorUserNames());
}
return defaultAdministratorUserNames;
}
} }

View File

@@ -473,6 +473,11 @@ public class TestAuthenticationServiceImpl implements AuthenticationService
return authentication; return authentication;
} }
public Set<String> getDefaultAdministratorUserNames()
{
return Collections.singleton(AuthenticationUtil.getAdminUserName());
}
private static final String SYSTEM_USER_NAME = "System"; private static final String SYSTEM_USER_NAME = "System";
} }

View File

@@ -52,16 +52,11 @@ import org.alfresco.jlan.server.auth.passthru.PassthruServers;
import org.alfresco.jlan.smb.Protocol; import org.alfresco.jlan.smb.Protocol;
import org.alfresco.jlan.smb.SMBException; import org.alfresco.jlan.smb.SMBException;
import org.alfresco.jlan.smb.SMBStatus; import org.alfresco.jlan.smb.SMBStatus;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent; import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.NTLMMode; import org.alfresco.repo.security.authentication.NTLMMode;
import org.alfresco.service.Managed; import org.alfresco.service.Managed;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.NoSuchPersonException; import org.alfresco.service.cmr.security.NoSuchPersonException;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -284,7 +279,8 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
*/ */
@Managed(category="Security") @Managed(category="Security")
public void setDomain(String domain) { public void setDomain(String domain) {
if (!domain.isEmpty())
{
// Check if the passthru server list is already configured // Check if the passthru server list is already configured
if ( m_passthruServers.getTotalServerCount() > 0) if ( m_passthruServers.getTotalServerCount() > 0)
@@ -301,6 +297,7 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
throw new AlfrescoRuntimeException("Failed to set passthru domain, " + ex); throw new AlfrescoRuntimeException("Failed to set passthru domain, " + ex);
} }
} }
}
/** /**
* Set the server(s) to authenticate against * Set the server(s) to authenticate against
@@ -309,16 +306,18 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
*/ */
@Managed(category="Security") @Managed(category="Security")
public void setServers(String servers) { public void setServers(String servers) {
if (!servers.isEmpty())
{
// Check if the passthru server list is already configured // Check if the passthru server list is already configured
if ( m_passthruServers.getTotalServerCount() > 0) if (m_passthruServers.getTotalServerCount() > 0)
throw new AlfrescoRuntimeException("Passthru server list already configured"); throw new AlfrescoRuntimeException("Passthru server list already configured");
// Configure the passthru authenticaiton list using a list of server names/addresses // Configure the passthru authenticaiton list using a list of server names/addresses
m_passthruServers.setServerList(servers); m_passthruServers.setServerList(servers);
} }
}
/** /**
* Use the local server as the authentication server * Use the local server as the authentication server

View File

@@ -36,6 +36,7 @@ import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
@@ -61,6 +62,8 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
private AuthorityDAO authorityDAO; private AuthorityDAO authorityDAO;
private AuthenticationService authenticationService;
private PermissionServiceSPI permissionServiceSPI; private PermissionServiceSPI permissionServiceSPI;
private Set<String> adminSet = Collections.singleton(PermissionService.ADMINISTRATOR_AUTHORITY); private Set<String> adminSet = Collections.singleton(PermissionService.ADMINISTRATOR_AUTHORITY);
@@ -69,8 +72,6 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
private Set<String> allSet = Collections.singleton(PermissionService.ALL_AUTHORITIES); private Set<String> allSet = Collections.singleton(PermissionService.ALL_AUTHORITIES);
private Set<String> adminUsers = Collections.emptySet();
private Set<String> adminGroups = Collections.emptySet(); private Set<String> adminGroups = Collections.emptySet();
public AuthorityServiceImpl() public AuthorityServiceImpl()
@@ -98,6 +99,11 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
this.authorityDAO = authorityDAO; this.authorityDAO = authorityDAO;
} }
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
public void setPermissionServiceSPI(PermissionServiceSPI permissionServiceSPI) public void setPermissionServiceSPI(PermissionServiceSPI permissionServiceSPI)
{ {
this.permissionServiceSPI = permissionServiceSPI; this.permissionServiceSPI = permissionServiceSPI;
@@ -108,11 +114,6 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
logger.warn("Bean property 'authenticationService' no longer required on 'AuthorityServiceImpl'."); logger.warn("Bean property 'authenticationService' no longer required on 'AuthorityServiceImpl'.");
} }
public void setAdminUsers(Set<String> adminUsers)
{
this.adminUsers = adminUsers;
}
public void setAdminGroups(Set<String> adminGroups) public void setAdminGroups(Set<String> adminGroups)
{ {
this.adminGroups = adminGroups; this.adminGroups = adminGroups;
@@ -170,6 +171,8 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean
// Work out mapped roles // Work out mapped roles
// Check named admin users // Check named admin users
Set<String> adminUsers = this.authenticationService.getDefaultAdministratorUserNames();
// note: for multi-tenancy, this currently relies on a naming convention which assumes that all tenant admins will // note: for multi-tenancy, this currently relies on a naming convention which assumes that all tenant admins will
// have the same base name as the default non-tenant specific admin. Typically "admin" is the default required admin user, // have the same base name as the default non-tenant specific admin. Typically "admin" is the default required admin user,
// although, if for example "bob" is also listed as an admin then all tenant-specific bob's will also have admin authority // although, if for example "bob" is also listed as an admin then all tenant-specific bob's will also have admin authority

View File

@@ -231,5 +231,13 @@ public interface AuthenticationService
*/ */
@Auditable @Auditable
public Set<String> getDomiansThatAllowUserPasswordChanges(); public Set<String> getDomiansThatAllowUserPasswordChanges();
/**
* Gets a set of user names who should be considered administrators by default.
*
* @return a set of user names
*/
@Auditable
public Set<String> getDefaultAdministratorUserNames();
} }

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.util;
import java.sql.Connection;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* Can be used to wrap a datasource to ensure that the connections that it returns have auto-commit switched on.
*
* @author dward
*/
public class AutoCommitInterceptor implements MethodInterceptor
{
public Object invoke(MethodInvocation mi) throws Throwable
{
Connection result = (Connection) mi.proceed();
result.setAutoCommit(true);
return result;
}
}