Author: dkatayev
Date: 2010-07-30 11:13:44 -0400 (Fri, 30 Jul 2010)
New Revision: 2846
Added:
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/conversationstate-when-membership-changed.xml
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/db-configuration-hibernate.xml
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/db-schema-creator-service.xml
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/ldap-configuration.xml
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/organization-service-initalizer.xml
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/organization-service-listener.xml
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/organization-service.xml
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/security-service.xml
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/spring-security-integration.xml
jcr/branches/1.12.x/docs/reference/en/src/main/resources/images/login-page.jpg
jcr/branches/1.12.x/docs/reference/en/src/main/resources/images/organization-exo.jpg
Modified:
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core.xml
Log:
EXOJCR-868 core documentation added
Added:
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/conversationstate-when-membership-changed.xml
===================================================================
---
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/conversationstate-when-membership-changed.xml
(rev 0)
+++
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/conversationstate-when-membership-changed.xml 2010-07-30
15:13:44 UTC (rev 2846)
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<chapter>
+ <title>Update ConversationState when user's Membership changed</title>
+
+ <para>When user logged in portal in ConversationRegistry added
+ ConversationSate for this user. ConversationState keeps user's Identity that
+ is actual for logged in time. In this case even user's Membership updated in
+ OrganizationService ConversationState still keeps old (not actual Identity).
+ User must logged out and loggin in again to update Identity. To fix this
+ issue need add special listener in configuration of OrganizationServicer.
+ This listener is extended MembershipEventListener.</para>
+
+ <para>Example of configuration.</para>
+
+ <programlisting><?xml version="1.0"
encoding="ISO-8859-1"?>
+<configuration
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_0.xsd
http://www.exoplaform.org/xml/ns/kernel_1_0.xsd"
+
xmlns="http://www.exoplaform.org/xml/ns/kernel_1_0.xsd">
+ <external-component-plugins>
+
<target-component>org.exoplatform.services.organization.OrganizationService</target-component>
+.....
+.....
+ <component-plugin>
+ <name>MembershipUpdateListener</name>
+ <set-method>addListenerPlugin</set-method>
+
<type>org.exoplatform.services.organization.impl.MembershipUpdateListener</type>
+ </component-plugin>
+
+ <external-component-plugins>
+</configuration></programlisting>
+</chapter>
Added:
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/db-configuration-hibernate.xml
===================================================================
---
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/db-configuration-hibernate.xml
(rev 0)
+++
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/db-configuration-hibernate.xml 2010-07-30
15:13:44 UTC (rev 2846)
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<chapter id="CoreDatabaseConfigurationforHibernate">
+ <title>Database Configuration for Hibernate</title>
+
+ <para>As usual, it is quite simple to use our configuration XML syntax to
+ configure and parametrize different Databases for eXo tables but also for
+ your own use.</para>
+
+ <section>
+ <title>Generic configuration</title>
+
+ <para>The default DB configuration uses HSQLDB, a Java Database quite
+ useful for demonstrations.</para>
+
+ <programlisting><component>
+
<key>org.exoplatform.services.database.HibernateService</key>
+ <jmx-name>exo-service:type=HibernateService</jmx-name>
+
<type>org.exoplatform.services.database.impl.HibernateServiceImpl</type>
+ <init-params>
+ <properties-param>
+ <name>hibernate.properties</name>
+ <description>Default Hibernate
Service</description>
+ <property name="hibernate.show_sql"
value="false"/>
+ <property name="hibernate.cglib.use_reflection_optimizer"
value="true"/>
+ <property name="hibernate.connection.url"
value="jdbc:hsqldb:file:../temp/data/portal"/>
+ <property name="hibernate.connection.driver_class"
value="org.hsqldb.jdbcDriver"/>
+ <property name="hibernate.connection.autocommit"
value="true"/>
+ <property name="hibernate.connection.username"
value="sa"/>
+ <property name="hibernate.connection.password"
value=""/>
+ <property name="hibernate.dialect"
value="org.hibernate.dialect.HSQLDialect"/>
+ <property name="hibernate.c3p0.min_size"
value="5"/>
+ <property name="hibernate.c3p0.max_size"
value="20"/>
+ <property name="hibernate.c3p0.timeout"
value="1800"/>
+ <property name="hibernate.c3p0.max_statements"
value="50"/>
+ </properties-param>
+ </init-params>
+</component></programlisting>
+
+ <para>In the init parameter section, we define the default hibernate
+ properties including the DB URL, the driver and the credentials in
+ use.</para>
+
+ <para>As for any portal that configuration can be overridden depending on
+ the needs of your environment.</para>
+
+ <para>Several databases have been tested and can be used in
+ production....which is not the case of HSQLDB, HSQLDB can only be used for
+ development environments and for demonstrations.</para>
+ </section>
+
+ <section>
+ <title>Example DB configuration</title>
+
+ <para>For MySQL</para>
+
+ <programlisting><component>
+
<key>org.exoplatform.services.database.HibernateService</key>
+ <jmx-name>database:type=HibernateService</jmx-name>
+
<type>org.exoplatform.services.database.impl.HibernateServiceImpl</type>
+ <init-params>
+ <properties-param>
+ <name>hibernate.properties</name>
+ <description>Default Hibernate
Service</description>
+ <property name="hibernate.show_sql"
value="false"/>
+ <property name="hibernate.cglib.use_reflection_optimizer"
value="true"/>
+ <property name="hibernate.connection.url"
value="jdbc:mysql://localhost:3306/exodb?relaxAutoCommit=true&amp;amp;autoReconnect=true&amp;amp;useUnicode=true&amp;amp;characterEncoding=utf8"/>
+ <property name="hibernate.connection.driver_class"
value="com.mysql.jdbc.Driver"/>
+ <property name="hibernate.connection.autocommit"
value="true"/>
+ <property name="hibernate.connection.username"
value="exo"/>
+ <property name="hibernate.connection.password"
value="exo"/>
+ <property name="hibernate.dialect"
value="org.hibernate.dialect.MySQLDialect"/>
+ <property name="hibernate.c3p0.min_size"
value="5"/>
+ <property name="hibernate.c3p0.max_size"
value="20"/>
+ <property name="hibernate.c3p0.timeout"
value="1800"/>
+ <property name="hibernate.c3p0.max_statements"
value="50"/>
+ </properties-param>
+ </init-params>
+</component></programlisting>
+ </section>
+
+ <section>
+ <title>Register custom Hibernate XML files into the service</title>
+
+ <para>It is possible to use the eXo hibernate service and register your
+ hibernate hbm.xml files to leverage some add-on features of the service
+ such as the table automatic creation as well as the cache of the hibernate
+ session in a ThreadLocal object during all the request lifecycle. To do so
+ you just have to add a plugin and indicate the location of your
+ files.</para>
+
+ <programlisting><?xml version="1.0"
encoding="ISO-8859-1"?>
+<configuration>
+ <external-component-plugins>
+
<target-component>org.exoplatform.services.database.HibernateService</target-component>
+ <component-plugin>
+ <name>add.hibernate.mapping</name>
+ <set-method>addPlugin</set-method>
+
<type>org.exoplatform.services.database.impl.AddHibernateMappingPlugin</type>
+ <init-params>
+ <values-param>
+ <name>hibernate.mapping</name>
+
<value>org/exoplatform/services/organization/impl/UserImpl.hbm.xml</value>
+
<value>org/exoplatform/services/organization/impl/MembershipImpl.hbm.xml</value>
+
<value>org/exoplatform/services/organization/impl/GroupImpl.hbm.xml</value>
+
<value>org/exoplatform/services/organization/impl/MembershipTypeImpl.hbm.xml</value>
+
<value>org/exoplatform/services/organization/impl/UserProfileData.hbm.xml</value>
+ </values-param>
+ </init-params>
+ </component-plugin>
+ </external-component-plugins>
+</configuration></programlisting>
+ </section>
+</chapter>
Added:
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/db-schema-creator-service.xml
===================================================================
---
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/db-schema-creator-service.xml
(rev 0)
+++
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/db-schema-creator-service.xml 2010-07-30
15:13:44 UTC (rev 2846)
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<chapter id="CoreDBSchemacreatorserviceJDBCimplementation">
+ <title>DB Schema creator service (JDBC implementation)</title>
+
+ <para>DB Schema Creator is responsible for database schema creating using a
+ DDL script inside service configuration or in an external file,
+ calling:</para>
+
+ <programlisting>
org.exoplatform.services.database.jdbc.DBSchemaCreator.createTables(String dsName, String
script)</programlisting>
+
+ <para>via</para>
+
+ <programlisting>org.exoplatform.services.database.jdbc.CreateDBSchemaPlugin
component plugin</programlisting>
+
+ <para>A configuration example:</para>
+
+ <programlisting><component>
+
<key>org.exoplatform.services.database.jdbc.DBSchemaCreator</key>
+
<type>org.exoplatform.services.database.jdbc.DBSchemaCreator</type>
+ <component-plugins>
+ <component-plugin>
+ <name>jcr.dbschema</name>
+ <set-method>addPlugin</set-method>
+
<type>org.exoplatform.services.database.jdbc.CreateDBSchemaPlugin</type>
+ <init-params>
+ <value-param>
+ <name>data-source</name>
+ <value>jdbcjcr</value>
+ </value-param>
+ <value-param>
+ <name>script-file</name>
+ <value>conf/storage/jcr-mjdbc.sql</value>
+ </value-param>
+ </init-params>
+ </component-plugin>
+ ........</programlisting>
+
+ <para>An example of a DDL script:</para>
+
+ <programlisting>CREATE TABLE JCR_MITEM(
+ ID VARCHAR(255) NOT NULL PRIMARY KEY,
+ VERSION INTEGER NOT NULL,
+ PATH VARCHAR(1024) NOT NULL
+ );
+CREATE INDEX JCR_IDX_MITEM_PATH ON JCR_MITEM(PATH);</programlisting>
+</chapter>
Added:
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/ldap-configuration.xml
===================================================================
---
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/ldap-configuration.xml
(rev 0)
+++
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/ldap-configuration.xml 2010-07-30
15:13:44 UTC (rev 2846)
@@ -0,0 +1,849 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<chapter id="CoreLDAPConfiguration">
+ <title>LDAP Configuration</title>
+
+ <section>
+ <title>Overview</title>
+
+ <para>You may decide that you want eXo users to be mapped to an existing
+ directory. eXo provides a flexible implementation of its
+ OrganizationService on top of LDAP. It can be used on any LDAP compliant
+ directory and even Active Directory. This page will guide you how to
+ configure eXo Platform to work with your directory.</para>
+ </section>
+
+ <section>
+ <title>Quickstart</title>
+
+ <para>If you just want to have a look at how eXo works with ldap. eXo
+ comes with a predefined ldap configuration. You just need to activate it
+ and eXo will create all it needs to work at startup.</para>
+
+ <para>You need to have a working ldap server and a user with write
+ permissions.</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Open <emphasis
+
role="bold">exo-tomcat/webapps/portal/WEB-INF/conf/configuration.xml</emphasis>
+ and replace:</para>
+ </listitem>
+ </itemizedlist>
+
+
<programlisting><import>war:/conf/organization/hibernate-configuration.xml</import></programlisting>
+
+ <para>With</para>
+
+
<programlisting><import>war:/conf/organization/ldap-configuration.xml</import></programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para>0pen <emphasis
role="bold">ldap-configuration.xml</emphasis> and
+ update the <emphasis role="bold">providerURL</emphasis>,
<emphasis
+ role="bold">rootdn</emphasis> and password settings according
to your
+ environment</para>
+ </listitem>
+ </itemizedlist>
+
+ <programlisting><field
name="providerURL"><string>ldap://127.0.0.1:389</string></field>
+<field
name="rootdn"><string>CN=Manager,DC=MyCompany,DC=com</string></field>
+<field
name="password"><string>secret</string></field></programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para>Delete <emphasis
role="bold">exo-tomcat/temp/</emphasis>* to
+ have a clean database and then start tomcat.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>eXo starts and autocreates its organization model in your directory
+ tree. Finally the structure of the default LDAP schema looks like:</para>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/organization-exo.jpg" />
+ </imageobject>
+ </mediaobject>
+
+ <para>That's it! Now eXo uses your LDAP directory as its org model
+ storage. Users, groups and memberships are now stored and retrieved from
+ there. We suggest that you complete some guideline functions with eXo user
+ management portlet and see what it changes in your directory tree.</para>
+ </section>
+
+ <section>
+ <title>Configuration</title>
+
+ <para>If you have an existing LDAP server, the eXo predefined settings
+ will likely not match your directory structure. eXo LDAP organization
+ service implementation was written with flexibility in mind and can
+ certainly be configured to meet your requirements.</para>
+
+ <para>The configuration is done in <emphasis
+ role="bold">ldap-configuration.xml</emphasis> file, and this
chapter will
+ explain the numerous parameters it contains.</para>
+
+ <section>
+ <title>Connection Settings</title>
+
+ <para>Firstly, start by connection settings which will tell eXo how to
+ connect to your directory server. These settings are very close to
+ <ulink url="JNDI
API>http://java.sun.com/products/jndi">JNDI
+
API>http://java.sun.com/products/jndi</ulink> context parameters.
+ This configuration is activated by the init-param ldap.config of service
+ LDAPServiceImpl.</para>
+
+ <programlisting><component>
+ <key>org.exoplatform.services.ldap.LDAPService</key>
+
<type>org.exoplatform.services.ldap.impl.LDAPServiceImpl</type>
+ <init-params>
+ <object-param>
+ <name>ldap.config</name>
+ <description>Default ldap config</description>
+ <object
type="org.exoplatform.services.ldap.impl.LDAPConnectionConfig">
+ <field
name="providerURL"><string>ldap://127.0.0.1:389,10.0.0.1:389</string></field>
+ <field
name="rootdn"><string>CN=Manager,DC=exoplatform,DC=org</string></field>
+ <field
name="password"><string>secret</string></field>
+ <!-- field
name="authenticationType"><string>simple</string></field-->
+ <field
name="version"><string>3</string></field>
+ <field
name="referralMode"><string>follow</string></field>
+ <!-- field
name="serverName"><string>active.directory</string></field-->
+ </object>
+ </object-param>
+ </init-params>
+</component></programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="bold">providerURL</emphasis>:
LDAP server URL
+ (see <ulink
+
url="PROVIDER_URL>http://java.sun.com/products/jndi/1.2/javad...>).
+ For multiple ldap servers, use comma separated list of host:port
+ (Ex. ldap://127.0.0.1:389,10.0.0.1:389).</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis role="bold">rootdn</emphasis>: dn
of user that will
+ be used by the service to authenticate on the server (see <ulink
+
url="SECURITY_PRINCIPAL>http://java.sun.com/products/jndi/1.2...
+ </listitem>
+
+ <listitem>
+ <para><emphasis role="bold">password</emphasis>:
password for user
+ rootdn (see <ulink
+
url="SECURITY_CREDENTIALS>http://java.sun.com/products/jndi/1...
+ </listitem>
+
+ <listitem>
+ <para><emphasis
role="bold">authenticationType</emphasis>: type of
+ authentication to be used (see <ulink
+
url="SECURITY_AUTHENTICATION>http://java.sun.com/products/jnd...>).
+ Use one of none, simple, strong. Default is simple.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis role="bold">version</emphasis>:
LDAP protocol
+ version (see <ulink
+
url="java.naming.ldap.version>http://java.sun.com/products/jn...>).
+ Set to 3 if your server supports LDAP V3.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis role="bold">referalMode</emphasis>:
one of follow,
+ ignore,throw (see <ulink
+
url="REFERRAL>http://java.sun.com/products/jndi/1.2/javadoc/j...
+ </listitem>
+
+ <listitem>
+ <para><emphasis role="bold">serverName</emphasis>:
you will need to
+ set this to active.directory in order to work with Active Directory
+ servers. Any other value will be ignore and the service will act as
+ on a standard LDAP.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Organization Service Configuration</title>
+
+ <para>Next, you need to configure the eXo <emphasis
+ role="bold">OrganizationService</emphasis> to tell him how the
directory
+ is structured and how to interact with it. This is managed by a couple
+ of of init-params : <emphasis
role="bold">ldap.userDN.key</emphasis> and
+ <emphasis role="bold">ldap.attribute.mapping</emphasis> in
file
+ <emphasis role="bold">ldap-configuration.xml</emphasis> (by
default
+ located at portal.war/WEB-INF/conf/organization)</para>
+
+ <programlisting><component>
+
<key>org.exoplatform.services.organization.OrganizationService</key>
+
<type>org.exoplatform.services.organization.ldap.OrganizationServiceImpl</type>
+ [...]
+ <init-params>
+ <value-param>
+ <name>ldap.userDN.key</name>
+ <description>The key used to compose user
DN</description>
+ <value>cn</value>
+ </value-param>
+ <object-param>
+ <name>ldap.attribute.mapping</name>
+ <description>ldap attribute mapping</description>
+ <object
type="org.exoplatform.services.organization.ldap.LDAPAttributeMapping">
+ [...]
+ </object-param>
+ </init-params>
+ [...]
+</component></programlisting>
+
+ <para><emphasis
role="bold">ldap.attribute.mapping</emphasis> maps your
+ ldap to eXo. At first there are two main parameters to configure in
+ it:</para>
+
+ <programlisting><field
name="baseURL"><string>dc=exoplatform,dc=org</string></field>
+<field
name="ldapDescriptionAttr"><string>description</string></field></programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="bold">baseURL</emphasis>:
root dn for eXo
+ organizational entities. This entry can't be created by eXo and must
+ preexist in directory.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis
role="bold">ldapDescriptionAttr</emphasis> (since
+ core 2.2+) : Name of a common attribute that will be used as
+ description for groups and membership types.</para>
+ </listitem>
+ </itemizedlist>
+
+ <note>
+ <para>(since core 2.2+) : Name of a common attribute that will be used
+ as description for groups and membership types.</para>
+ </note>
+
+ <para>Other parameters are discussed in the following sections.</para>
+
+ <section>
+ <title>Users</title>
+
+ <section>
+ <title>Main parameters</title>
+
+ <para>Here are the main parameters to map eXo users to your
+ directory :</para>
+
+ <programlisting><field
name="userURL"><string>ou=users,ou=portal,dc=exoplatform,dc=org</string></field>
+<field
name="userObjectClassFilter"><string>objectClass=person</string></field>
+<field
name="userLDAPClasses"><string>top,person,organizationalPerson,inetOrgPerson</string></field></programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="bold">userURL</emphasis>
: base dn for
+ users. Users are created in a flat structure under this base
+ with a dn of the form: <emphasis
+
role="bold">ldap.userDN.key=username,userURL</emphasis></para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Example : </para>
+
+
<programlisting>uid=john,cn=People,o=MyCompany,c=com</programlisting>
+
+ <para>However, if users exist deeply under userURL, eXo will be able
+ to retrieve them.</para>
+
+ <para>Example : </para>
+
+
<programlisting>uid=tom,ou=France,ou=EMEA,cn=People,o=MyCompany,c=com</programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
role="bold">userObjectClassFilter</emphasis>:
+ Filter used under userURL branch to distinguish eXo user entries
+ from others.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Example : john and tom will be recognized as valid eXo users
+ but EMEA and France entries will be ignored in the following subtree
+ :</para>
+
+ <programlisting>uid=john,cn=People,o=MyCompany,c=com
+ objectClass: person
+ …
+ou=EMEA,cn=People,o=MyCompany,c=com
+ objectClass: organizationalUnit
+ …
+ ou=France,ou=EMEA,cn=People,o=MyCompany,c=com
+ objectClass: organizationalUnit
+ …
+ uid=tom,ou=EMEA,cn=People,o=MyCompany,c=com
+ objectClass: person
+ …</programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
role="bold">userLDAPClasses</emphasis> : comma
+ separated list of classes used for user creation.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>When creating a new user, an entry will be created with the
+ given objectClass attributes. The classes must at least define cn
+ and any attribute refernced in the user mapping.</para>
+
+ <para>Example : Adding the user Marry Simons could produce
:</para>
+
+ <programlisting>uid=marry,cn=users,ou=portal,dc=exoplatform,dc=org
+ objectclass: top
+ objectClass: person
+ objectClass: organizationalPerson
+ objectClass: inetOrgPerson
+ …</programlisting>
+ </section>
+
+ <section>
+ <title>User mapping</title>
+
+ <para>The following parameters maps ldap attributes to eXo User java
+ objects attributes.</para>
+
+ <programlisting><field
name="userUsernameAttr"><string>uid</string></field>
+<field
name="userPassword"><string>userPassword</string></field>
+<field
name="userFirstNameAttr"><string>givenName</string></field>
+<field
name="userLastNameAttr"><string>sn</string></field>
+<field
name="userDisplayNameAttr"><string>displayName</string></field>
+<field
name="userMailAttr"><string>mail</string></field></programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
role="bold">userUsernameAttr</emphasis>:
+ username (login)</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis
role="bold">userPassword</emphasis>: password
+ (used when portal authentication is done by eXo login
+ module)</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis
role="bold">userFirstNameAttr</emphasis>:
+ firstname</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis
role="bold">userLastNameAttr</emphasis>:
+ lastname</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis
role="bold">userDisplayNameAttr</emphasis>:
+ displayed name</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis
role="bold">userMailAttr</emphasis>: email
+ address</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Example : In the previous example, user Marry Simons could
+ produce :</para>
+
+ <programlisting>uid=marry,cn=users,ou=portal,dc=exoplatform,dc=org
+ objectclass: top
+ objectClass: person
+ objectClass: organizationalPerson
+ objectClass: inetOrgPerson
+ …</programlisting>
+ </section>
+ </section>
+
+ <section>
+ <title>Groups</title>
+
+ <para>eXo groups can be mapped to organizational or applicative groups
+ defined in your directory.</para>
+
+ <programlisting><field
name="groupsURL"><string>ou=groups,ou=portal,dc=exoplatform,dc=org</string></field>
+<field
name="groupLDAPClasses"><string>top,organizationalUnit</string></field>
+<field
name="groupObjectClassFilter"><string>objectClass=organizationalUnit</string></field></programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="bold">groupsURL</emphasis>
: base dn for eXo
+ groups</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Groups can be structured hierarchically under
groupsURL.</para>
+
+ <para>Example: Groups communication, communication/marketing and
+ communication/press would map to :</para>
+
+ <programlisting>ou=communication,ou=groups,ou=portal,dc=exoplatform,dc=org
+…
+ ou=marketing,ou=communication,ou=groups,ou=portal,dc=exoplatform,dc=org
+ …
+ ou=press,ou=communication,ou=groups,ou=portal,dc=exoplatform,dc=org
+ …</programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
role="bold">groupLDAPClasses</emphasis>: comma
+ separated list of classes used for group creation.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>When creating a new group, an entry will be created with the
+ given objectClass attributes. The classes must define at least the
+ required attributes: <emphasis role="bold">ou</emphasis>,
<emphasis
+ role="bold">description</emphasis> and <emphasis
+ role="bold">l</emphasis>.</para>
+
+ <note>
+ <para>l attribute corresponds to the City property in OU property
+ editor</para>
+ </note>
+
+ <para>Example : Adding the group human-resources could
produce:</para>
+
+
<programlisting>ou=human-resources,ou=groups,ou=portal,dc=exoplatform,dc=org
+ objectclass: top
+ objectClass: organizationalunit
+ ou: human-resources
+ description: The human resources department
+ l: Human Resources
+ …</programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
role="bold">groupObjectClassFilter</emphasis>:
+ filter used under groupsURL branch to distinguish eXo groups from
+ other entries. You can also use a complex filter if you
+ need.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Example : groups WebDesign, WebDesign/Graphists and Sales could
+ be retrieved in :</para>
+
+ <programlisting>l=Paris,dc=sites,dc=mycompany,dc=com
+ …
+ ou=WebDesign,l=Paris,dc=sites,dc=mycompany,dc=com
+ …
+ ou=Graphists,WebDesign,l=Paris,dc=sites,dc=mycompany,dc=com
+ …
+l=London,dc=sites,dc=mycompany,dc=com
+ …
+ ou=Sales,l=London,dc=sites,dc=mycompany,dc=com
+ …</programlisting>
+ </section>
+
+ <section>
+ <title>Membership Types</title>
+
+ <para>Membership types are the possible roles that can be assigned to
+ users in groups.</para>
+
+ <programlisting><field
name="membershipTypeURL"><string>ou=memberships,ou=portal,dc=exoplatform,dc=org</string></field>
+<field
name="membershipTypeLDAPClasses"><string>top,organizationalRole</string></field>
+<field
name="membershipTypeNameAttr"><string>cn</string></field></programlisting>
+
+ <para></para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
role="bold">membershipTypeURL</emphasis> : base dn
+ for membership types storage.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>eXo stores membership types in a flat structure under
+ membershipTypeURL.</para>
+
+ <para>Example : Roles manager, user, admin and editor could by defined
+ by the subtree :</para>
+
+ <programlisting>ou=roles,ou=portal,dc=exoplatform,dc=org
+…
+ cn=manager,ou=roles,ou=portal,dc=exoplatform,dc=org
+ …
+ cn=user,ou=roles,ou=portal,dc=exoplatform,dc=org
+ …
+ cn=admin,ou=roles,ou=portal,dc=exoplatform,dc=org
+ …
+ cn=editor,ou=roles,ou=portal,dc=exoplatform,dc=org
+ …</programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
role="bold">membershipTypeLDAPClasses</emphasis>:
+ comma separated list of classes for membership types
+ creation.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>When creating a new membership type, an entry will be created
+ with the given objectClass attributes. The classes must define the
+ required attributes : <emphasis
role="bold">description</emphasis>,
+ <emphasis role="bold">cn</emphasis></para>
+
+ <para>Example : Adding membership type validator would produce
+ :</para>
+
+ <programlisting>cn=validator,ou=roles,ou=portal,dc=exoplatform,dc=org
+ objectclass: top
+ objectClass: organizationalRole
+ …</programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
role="bold">membershipTypeNameAttr</emphasis> :
+ Attribute that will be used as the name of the role</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Example : If membershipTypeNameAttr is 'cn', then role name
is
+ 'manager' for the following membership type entry :</para>
+
+ <programlisting>cn=manager,ou=roles,ou=portal,dc=exoplatform,dc=org
</pre></programlisting>
+ </section>
+
+ <section>
+ <title>Memberships</title>
+
+ <para>Memberships are used to assign a role within a group. They are
+ entries that are placed under the group entry of their scope group.
+ Users in this role are defined as attributes of the membership
+ entry.</para>
+
+ <para>Example: To designate tom as the manager of the group
+ human-resources :</para>
+
+
<programlisting>ou=human-resources,ou=groups,ou=portal,dc=exoplatform,dc=org
+ …
+ cn=manager,ou=human-resources,ou=groups,ou=portal,dc=exoplatform,dc=org
+ member: uid=tom,ou=users,ou=portal,dc=exoplatform,dc=org
+ …</programlisting>
+
+ <para>The parameters to configure memberships are :</para>
+
+ <programlisting><field
name="membershipLDAPClasses"><string>top,groupOfNames</string></field>
+<field
name="membershipTypeMemberValue"><string>member</string></field>
+<field
name="membershipTypeRoleNameAttr"><string>cn</string></field>
+<field
name="membershipTypeObjectClassFilter"><string>objectClass=organizationalRole</string></field></programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
role="bold">membershipLDAPClasses</emphasis> :
+ comma separated list of classes used to create memberships.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>When creating a new membership, an entry will be created with
+ the given objectClass attributes. The classes must at least define the
+ attribute designated by membershipTypeMemberValue.</para>
+
+ <para>Example : Adding membership validator would produce : </para>
+
+
<programlisting>cn=validator,ou=human-resources,ou=groups,ou=portal,dc=exoplatform,dc=org
+ objectclass: top
+ objectClass: groupOfNames
+ …</programlisting>
+
+ <para><pre>
+ cn=validator,ou=human-resources,ou=groups,ou=portal,dc=exoplatform,dc=org
+ objectclass: top objectClass: groupOfNames ... </pre></para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
role="bold">membershipTypeMemberValue</emphasis>:
+ Multivalued attribute used in memberships to reference users that
+ have the role in the group.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Values should be a user dn.</para>
+
+ <para>Example: james and root have admin role within the group
+ human-resources, would give:</para>
+
+
<programlisting>cn=admin,ou=human-resources,ou=groups,ou=portal,dc=exoplatform,dc=org
+ member: cn=james,ou=users,ou=portal,dc=exoplatform,dc=org
+ member: cn=root,ou=users,ou=portal,dc=exoplatform,dc=org
+ …</programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
role="bold">membershipTypeRoleNameAttr</emphasis>:
+ Attribute of the membership entry whose value references the
+ membership type.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Example : In the following membership entry:</para>
+
+ <para><pre>
+ cn=manager,ou=human-resources,ou=groups,ou=portal,dc=exoplatform,dc=org
+ </pre></para>
+
+ <para>'cn' attribute is used to designate the 'manager'
membership
+ type. Which could also be said : The name of the role is given by 'cn'
+ the attribute.</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
+ role="bold">membershipTypeObjectClassFilter</emphasis> :
Filter
+ used to distinguish membership entries under groups.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>You can use rather complex filters.</para>
+
+ <para>Example: Here is a filter we used for a customer that needed to
+ trigger a dynlist overlay on openldap.</para>
+
+ <programlisting>(&amp;(objectClass=ExoMembership)(membershipURL=*))
+</programlisting>
+
+ <para>Note : Pay attention to the xml escaping of the '&'
(and)
+ operator</para>
+ </section>
+
+ <section>
+ <title>User Profiles</title>
+
+ <para>eXo User profiles also have entries in the ldap but the actual
+ storage is still done with the hibernate service. You will need the
+ following parameters :</para>
+
+ <programlisting><field
name="profileURL"><string>ou=profiles,ou=portal,dc=exoplatform,dc=org</string></field>
+<field
name="profileLDAPClasses"><string>top,organizationalPerson</string></field></programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis
role="bold">profileURL</emphasis>: base dn to
+ store user profiles</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis
role="bold">profileLDAPClasses</emphasis>: Classes
+ used to when creating user profiles</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>Advanced topics</title>
+
+ <section>
+ <title>Automatic directory population</title>
+
+ <para>At startup eXo can populate the organization model based
on</para>
+
+ <para>eXo organizational model has User,Group,Membership and Profile
+ entities. For each, we define a base dn that should be below baseURL. At
+ startup, if one of userURL, groupsURL, membershipTypeURL or profileURL
+ does not exist fully, eXo will attempt to create the missing subtree by
+ parsing the dn and creating entries on-the-fly. To determine the classes
+ of the created entries, the following rules are applied :</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>ou=... :
objectClass=top,objectClass=organizationalUnit</para>
+ </listitem>
+
+ <listitem>
+ <para>cn=... :
objectClass=top,objectClass=organizationalRole</para>
+ </listitem>
+
+ <listitem>
+ <para>c=... : objectClass=country</para>
+ </listitem>
+
+ <listitem>
+ <para>o=... : objectClass=organization</para>
+ </listitem>
+
+ <listitem>
+ <para>dc=.. :
+ objectClass=top,objectClass=dcObject,objectClass=organization</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Example:</para>
+
+ <para>If baseURL is <emphasis
role="bold">o=MyCompany,c=com</emphasis>
+ and groupsURL is <emphasis
+
role="bold">dc=groups,cn=Extranet,c=France,ou=EMEA,o=MyCompany,c=com</emphasis>
+ then, the following subtree will be created :</para>
+
+ <programlisting>ou=EMEA,o=MyCompany,c=com
+ objectClass: top
+ objectClass: organizationalUnit
+ …
+ c=France,ou=EMEA,o=MyCompany,c=com
+ objectClass: top
+ objectClass: country
+ …
+ cn=Extranet,c=France,ou=EMEA,o=MyCompany,c=com
+ objectClass: top
+ objectClass: organizationalRole
+ …
+ dc=groups,cn=Extranet,c=France,ou=EMEA,o=MyCompany,c=com
+ objectClass: top
+ objectClass: dcObject
+ objectClass: organization
+ …</programlisting>
+ </section>
+
+ <section>
+ <title>Active Directory sample configuration</title>
+
+ <para>Here is an alternative configuration for active directory that you
+ can find in <emphasis
+
role="bold">activedirectory-configuration.xml</emphasis></para>
+
+ <note>
+ <para>There is a microsoft limitation: password can't be set in AD via
+ unsecured connection you have to use the ldaps protocol</para>
+ </note>
+
+ <para>#info("There is a microsoft limitation: password can't be set
in
+ AD via unsecured connection you have to use the ldaps protocol")</para>
+
+ <para>here is how to use LDAPS protocol with Active Directory :</para>
+
+ <programlisting>1 setup AD to use SSL:
+
+ * add Active Directory Certificate Services role
+ * install right certificate for DC machine
+
+2 enable Java VM to use certificate from AD:
+
+ * import root CA used in AD, to keystore, something like
+
+ keytool -importcert -file 2008.cer -keypass changeit -keystore
/home/user/java/jdk1.6/jre/lib/security/cacerts
+
+ * set java options
+
+ JAVA_OPTS="${JAVA_OPTS} -Djavax.net.ssl.trustStorePassword=changeit
-Djavax.net.ssl.trustStore=/home/user/java/jdk1.6/jre/lib/security/cacerts"</programlisting>
+
+ <programlisting>[...]
+ <component>
+ <key>org.exoplatform.services.ldap.LDAPService</key>
+[..]
+ <object
type="org.exoplatform.services.ldap.impl.LDAPConnectionConfig">
+ <!-- for multiple ldap servers, use comma seperated list of host:port
(Ex. ldap://127.0.0.1:389,10.0.0.1:389) -->
+ <!-- whether or not to enable ssl, if ssl is used ensure that the
javax.net.ssl.keyStore & java.net.ssl.keyStorePassword properties are set
-->
+ <!-- exo portal default installed javax.net.ssl.trustStore with file is
java.home/lib/security/cacerts-->
+ <!-- ldap service will check protocol, if protocol is ldaps, ssl is enable
(Ex. for enable ssl: ldaps://10.0.0.3:636 ;for disable ssl: ldap://10.0.0.3:389 )
-->
+ <!-- when enable ssl, ensure server name is *.directory and port (Ex.
active.directory) -->
+ <field
name="providerURL"><string>ldaps://10.0.0.3:636</string></field>
+ <field
name="rootdn"><string>CN=Administrator,CN=Users,
DC=exoplatform,DC=org</string></field>
+ <field
name="password"><string>site</string></field>
+ <field
name="version"><string>3</string></field>
+ <field
name="referralMode"><string>ignore</string></field>
+ <field
name="serverName"><string>active.directory</string></field>
+ </object>
+[..]
+ <component>
+
<key>org.exoplatform.services.organization.OrganizationService</key>
+ [...]
+ <object
type="org.exoplatform.services.organization.ldap.LDAPAttributeMapping">
+ [...]
+ <field
name="userAuthenticationAttr"><string>mail</string></field>
+ <field
name="userUsernameAttr"><string>sAMAccountName</string></field>
+ <field
name="userPassword"><string>unicodePwd</string></field>
+ <field
name="userLastNameAttr"><string>sn</string></field>
+ <field
name="userDisplayNameAttr"><string>displayName</string></field>
+ <field
name="userMailAttr"><string>mail</string></field>
+ [..]
+ <field
name="membershipTypeLDAPClasses"><string>top,group</string></field>
+ <field
name="membershipTypeObjectClassFilter"><string>objectClass=group</string></field>
+ [..]
+ <field
name="membershipLDAPClasses"><string>top,group</string></field>
+ <field
name="membershipObjectClassFilter"><string>objectClass=group</string></field>
+ </object>
+ [...]
+</component> </programlisting>
+ </section>
+
+ <section>
+ <title>OpenLDAP dynlist overlays</title>
+
+ <para>If you use OpenLDAP, you may want to use the <ulink
+ url="overlays >
http://www.openldap.org/faq/data/cache/1169.html">overlays
+ >
http://www.openldap.org/faq/data/cache/1169.html</ulink>. Here is
+ how you can use the <ulink
+ url="dynlist overlay >
http://www.openldap.org/faq/data/cache/1209.html">dynlist
+ overlay >
http://www.openldap.org/faq/data/cache/1209.html</ulink> to
+ have memberships dynamically populated.</para>
+
+ <para>The main idea is to have your memberships populated dynamically by
+ an ldap query. Thus, you no longer have to maintain manually the roles
+ on users.</para>
+
+ <para>To configure the dynlist, add the following to your <emphasis
+ role="bold">slapd.conf</emphasis> :</para>
+
+ <programlisting>dynlist-attrset ExoMembership membershipURL
member</programlisting>
+
+ <para>This snipet means : On entries that have ExoMembership class, use
+ the URL defined in the value of attribute membershipURL as a query and
+ populate results under the multivalues attribute member.</para>
+
+ <para>Now let's declare the corresponding schema (replace XXXXX to adapt
+ to your own IANA code):</para>
+
+ <programlisting>attributeType ( 1.3.6.1.4.1.XXXXX.1.59 NAME
'membershipURL' SUP memberURL )</programlisting>
+
+ <para>membershipURL inherits from memberURL.</para>
+
+ <programlisting>objectClass ( 1.3.6.1.4.1.XXXXX.2.12 NAME
'ExoMembership' SUP top MUST ( cn ) MAY (membershipURL $ member $ description )
)</programlisting>
+
+ <para>ExoMembership must define cn and can have attributes :</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>membershipURL: trigger for the dynlist</para>
+ </listitem>
+
+ <listitem>
+ <para>member : attribute populated by the dynlist</para>
+ </listitem>
+
+ <listitem>
+ <para>description : used by eXo for display</para>
+ </listitem>
+ </itemizedlist>
+
+ <programlisting># the TestGroup group
+dn: ou=testgroup,ou=groups,ou=portal,o=MyCompany,c=com
+objectClass: top
+objectClass: organizationalUnit
+ou: testgroup
+l: TestGroup
+description: the Test Group</programlisting>
+
+ <para>On this group, we can bind an eXo membership where the overlay
+ will occur:</para>
+
+ <programlisting># the manager membership on group TestGroup
+dn: cn=manager, ou=TestGroup,ou=groups,ou=portal,o=MyCompany,c=com
+objectClass: top
+objectClass: ExoMembership
+membershipURL: ldap:///ou=users,ou=portal,o=MyCompany,c=com??sub?(uid=*)
+cn: manager</programlisting>
+
+ <para>This dynlist assigns the role <emphasis
+ role="bold">manager:/testgroup</emphasis> to any
user.</para>
+ </section>
+ </section>
+</chapter>
Added:
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/organization-service-initalizer.xml
===================================================================
---
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/organization-service-initalizer.xml
(rev 0)
+++
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/organization-service-initalizer.xml 2010-07-30
15:13:44 UTC (rev 2846)
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<chapter id="CoreOrganizationServiceInitializer">
+ <title>Organization Service Initializer</title>
+
+ <para>Use the Organization Service Initializer to create users, groups and
+ membership types by default.</para>
+
+ <programlisting><external-component-plugins>
+
<target-component>org.exoplatform.services.organization.OrganizationService</target-component>
+ <component-plugin>
+ <name>init.service.listener</name>
+ <set-method>addListenerPlugin</set-method>
+
<type>org.exoplatform.services.organization.OrganizationDatabaseInitializer</type>
+ <description>this listener populate organization data for the first
launch</description>
+ <init-params>
+ <value-param>
+ <name>checkDatabaseAlgorithm</name>
+ <description>check database</description>
+ <value>entry</value>
+ </value-param>
+ <value-param>
+ <name>printInformation</name>
+ <description>Print information init
database</description>
+ <value>false</value>
+ </value-param>
+ <object-param>
+ <name>configuration</name>
+ <description>description</description>
+ <object
type="org.exoplatform.services.organization.OrganizationConfig">
+ <field name="membershipType">
+ <collection type="java.util.ArrayList">
+ <value>
+ <object
type="org.exoplatform.services.organization.OrganizationConfig$MembershipType">
+ <field name="type">
+ <string>manager</string>
+ </field>
+ <field name="description">
+ <string>manager membership
type</string>
+ </field>
+ </object>
+ </value>
+ </collection>
+ </field>
+
+ <field name="group">
+ <collection type="java.util.ArrayList">
+ <value>
+ <object
type="org.exoplatform.services.organization.OrganizationConfig$Group">
+ <field name="name">
+ <string>platform</string>
+ </field>
+ <field name="parentId">
+ <string></string>
+ </field>
+ <field name="description">
+ <string>the /platform group</string>
+ </field>
+ <field name="label">
+ <string>Platform</string>
+ </field>
+ </object>
+ </value>
+ <value>
+ <object
type="org.exoplatform.services.organization.OrganizationConfig$Group">
+ <field name="name">
+ <string>administrators</string>
+ </field>
+ <field name="parentId">
+ <string>/platform</string>
+ </field>
+ <field name="description">
+ <string>the /platform/administrators
group</string>
+ </field>
+ <field name="label">
+ <string>Administrators</string>
+ </field>
+ </object>
+ </value>
+ </collection>
+ </field>
+
+ <field name="user">
+ <collection type="java.util.ArrayList">
+ <value>
+ <object
type="org.exoplatform.services.organization.OrganizationConfig$User">
+ <field name="userName">
+ <string>root</string>
+ </field>
+ <field name="password">
+ <string>exo</string>
+ </field>
+ <field name="firstName">
+ <string>Root</string>
+ </field>
+ <field name="lastName">
+ <string>Root</string>
+ </field>
+ <field name="email">
+ <string>root@localhost</string>
+ </field>
+ <field name="groups">
+ <string>
+ manager:/platform/administrators
+ </string>
+ </field>
+ </object>
+ </value>
+ </collection>
+ </field>
+ </object>
+ </object-param>
+ </init-params>
+ </component-plugin>
+ </external-component-plugins></programlisting>
+
+ <para>Params for membership type: </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>type - The membership type's name</para>
+ </listitem>
+
+ <listitem>
+ <para>description - The membership type's description</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Params for group:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>name - The group's name</para>
+ </listitem>
+
+ <listitem>
+ <para>parentId - The id of the parent group. If the parent id is null,
+ it mean that the group is at the first level. The parentId should have
+ the form: /ancestor/parent</para>
+ </listitem>
+
+ <listitem>
+ <para>description - The group's description</para>
+ </listitem>
+
+ <listitem>
+ <para>label - The group's label</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Params for user:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>userName - The user's name</para>
+ </listitem>
+
+ <listitem>
+ <para>password - The user's password</para>
+ </listitem>
+
+ <listitem>
+ <para>firstName - The user's first name</para>
+ </listitem>
+
+ <listitem>
+ <para>lastName - The user's last name</para>
+ </listitem>
+
+ <listitem>
+ <para>email - The user's email</para>
+ </listitem>
+
+ <listitem>
+ <para>groups - The user's membership types and groups in which he
+ consist.</para>
+ </listitem>
+ </itemizedlist>
+</chapter>
Added:
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/organization-service-listener.xml
===================================================================
---
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/organization-service-listener.xml
(rev 0)
+++
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/organization-service-listener.xml 2010-07-30
15:13:44 UTC (rev 2846)
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"hp://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<chapter id="CoreOrganizationListener">
+ <title>Organization Listener</title>
+
+ <section>
+ <title>Overview</title>
+
+ <para>The <link linkend="CoreOrganizationService">Organization
+ Service</link>The Core Organization Service provides a mechanism to
+ receive notifications when :</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>a User is created, deleted or modified</para>
+ </listitem>
+
+ <listitem>
+ <para>a Group is created, deleted or modified</para>
+ </listitem>
+
+ <listitem>
+ <para>a Membership is created or removed</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>This mechanism is very useful to cascade some actions when the
+ organization model is modified. For example, it is currently used to
+ :</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>initialize the personal portal pages</para>
+ </listitem>
+
+ <listitem>
+ <para>initialize the personal calendars, address books and mail
+ accounts in CS</para>
+ </listitem>
+
+ <listitem>
+ <para>create drives and personal areas in ECM</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Writing your own listeners</title>
+
+ <para>To implement your own listener you just need to write extend some
+ existing listener classes. These classes define hooks that are invoked
+ before or after operations are performed on organization model.</para>
+
+ <section>
+ <title>UserEventListener</title>
+
+ <para>To listen to user changes, you need to extend
+
<>org.exoplatform.services.organization.UserEventListener</>
+ :</para>
+
+ <programlisting>public class MyUserListener extends UserEventListener {
+
+ public void preSave(User user, boolean isNew) throws Exception {
+ System.out.println("Before " +
(isNew?"creating":"updating") + " user " +
user.getUserName());
+ }
+
+ public void postSave(User user, boolean isNew) throws Exception {
+ System.out.println("After user " + user.getUserName() + (isNew?"
created":" updated"));
+ }
+
+ public void preDelete(User user) throws Exception {
+ System.out.println("Before deleting user " + user.getUserName());
+ }
+
+ public void preDelete(User user) throws Exception {
+ System.out.println("After deleting user " + user.getUserName());
+ }
+
+}</programlisting>
+ </section>
+
+ <section>
+ <title>GroupEventListener</title>
+
+ <para>To listen to group changes, you need to extend
+
<>org.exoplatform.services.organization.GroupEventListener</>
+ :</para>
+
+ <programlisting>public class MyGroupListener extends GroupEventListener {
+
+ public void preSave(Group group, boolean isNew) throws Exception {
+ System.out.println("Before " +
(isNew?"creating":"updating") + " group " +
group.getName());
+ }
+
+ public void postSave(Group group, boolean isNew) throws Exception {
+ System.out.println("After group " + group.getName() + (isNew?"
created":" updated"));
+ }
+
+ public void preDelete(Group group) throws Exception {
+ System.out.println("Before deleting group " + group.getName());
+ }
+
+ public void preDelete(Group group) throws Exception {
+ System.out.println("After deleting group " + group.getName());
+ }
+}</programlisting>
+ </section>
+
+ <section>
+ <title>MembershipEventListener</title>
+
+ <para>To listen to membership changes, you need to extend
+
<>org.exoplatform.services.organization.MembershipEventListener</>
+ :</para>
+
+ <programlisting>public class MyMembershipListener extends
MembershipEventListener {
+
+ public void preSave(Membership membership, boolean isNew) throws Exception {
+ System.out.println("Before " +
(isNew?"creating":"updating") + " membership.");
+ }
+
+ public void postSave(Membership membership, boolean isNew) throws Exception {
+ System.out.println("After membership " + (isNew?" created":"
updated"));
+ }
+
+ public void preDelete(Membership membership) throws Exception {
+ System.out.println("Before deleting membership");
+ }
+
+ public void preDelete(Membership membership) throws Exception {
+ System.out.println("After deleting membership");
+ }
+}</programlisting>
+ </section>
+ </section>
+
+ <section>
+ <title>Registering your listeners</title>
+
+ <para>Registering the listeners is then achieved by using the ExoContainer
+ plugin mechanism. Learn more about it on the <link
+ linkend="KernelServiceConfigurationForBeginners">Service Configuration
for
+ Beginners</link> article.</para>
+
+ <para>To effectively register organization service's listeners you simply
+ need to use the <>addListenerPlugin</> seer
injector.</para>
+
+ <para>So, the easiest way to register your listeners is to pack them into
+ a .jar and create a configuration file into it under <emphasis
+
role="bold">mylisteners.jar!/conf/portal/configuration.xml</emphasis></para>
+
+ <programlisting><?xml version="1.0"
encoding="ISO-8859-1"?>
+<configuration>
+ <external-component-plugins>
+
<target-component>org.exoplatform.services.organization.OrganizationService</target-component>
+ <component-plugin>
+ <name>myuserplugin</name>
+ <set-method>addListenerPlugin</set-method>
+ <type>org.example.MyUserListener</type>
+ <description></description>
+ </component-plugin>
+ <component-plugin>
+ <name>mygroupplugin</name>
+ <set-method>addListenerPlugin</set-method>
+ <type>org.example.MyGroupListener</type>
+ <description></description>
+ </component-plugin>
+ <component-plugin>
+ <name>mymembershipplugin</name>
+ <set-method>addListenerPlugin</set-method>
+ <type>org.example.MyMembershipListener</type>
+ <description></description>
+ </component-plugin>
+ </external-component-plugins>
+<configuration></programlisting>
+
+ <para>Now, simply deploy the jar under $TOMCAT_HOME/lib and your listeners
+ are ready!</para>
+ </section>
+</chapter>
Added:
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/organization-service.xml
===================================================================
---
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/organization-service.xml
(rev 0)
+++
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/organization-service.xml 2010-07-30
15:13:44 UTC (rev 2846)
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<chapter id="CoreOrganizationService">
+ <title>Organization Service</title>
+
+ <section id="Overview">
+ <title>Overview</title>
+
+ <para>OrganizationService is the service that allows to access the
+ Organization model. This model is composed of :</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Users</para>
+ </listitem>
+
+ <listitem>
+ <para>Groups</para>
+ </listitem>
+
+ <listitem>
+ <para>Memberships</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>It is the basis of eXo personalization and authorizations in eXo and
+ is used allover the platform. The model is abstract and does not rely on
+ any specific storage. Multiple implementations exist in exo :</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>hibernate : for storage into a RDBMS</para>
+ </listitem>
+
+ <listitem>
+ <para>jndi : for storage into a directory such as an LDAP or MS Active
+ Directory</para>
+ </listitem>
+
+ <listitem>
+ <para>jcr : for storage inside a Java Content Repository</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Organizational Model</title>
+
+ <section>
+ <title>User</title>
+
+ <itemizedlist>
+ <listitem>
+ <para>username used as the identified</para>
+ </listitem>
+
+ <listitem>
+ <para>Profile (identity and preferences)</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Group</title>
+
+ <para>Gather a set of users</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>applicative or business</para>
+ </listitem>
+
+ <listitem>
+ <para>tree structure</para>
+ </listitem>
+
+ <listitem>
+ <para>no inheritance</para>
+ </listitem>
+
+ <listitem>
+ <para>expressed as /group/subgroup/subsubgroup</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Membership</title>
+
+ <itemizedlist>
+ <listitem>
+ <para>qualifies the group belonging</para>
+ </listitem>
+
+ <listitem>
+ <para>"Member of group as XXX"</para>
+ </listitem>
+
+ <listitem>
+ <para>expressed as : manager:/organization/hr, *:/partners</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ </section>
+
+ <section>
+ <title>Related articles and how-tos</title>
+
+ <itemizedlist>
+ <listitem>
+ <para><ulink
+
url="http://wiki.exoplatform.org/xwiki/bin/view/JCR/Organization+Ser...
+ Organization Service</ulink></para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para><ulink
+
url="http://wiki.exoplatform.org/xwiki/bin/view/Core/Update+Conversa...
+ ConversationState when user's Membership changed</ulink></para>
+ </listitem>
+
+ <listitem>
+ <para><ulink url="Organization Service
Initializer">Organization
+ Service Initializer</ulink></para>
+ </listitem>
+
+ <listitem>
+ <para><ulink
+
url="http://wiki.exoplatform.org/xwiki/bin/view/Portal/Accessing+Use...
+ to Access User Profile in your code</ulink></para>
+ </listitem>
+
+ <listitem>
+ <para><ulink url="CoreOrganizationListener">How to create
your own
+ Organization Listener</ulink></para>
+ </listitem>
+
+ <listitem>
+ <para><ulink
+ url="How to manipulate Users and Memberships Programmatically">How
to
+ manipulate Users and Memberships Programmatically</ulink></para>
+ </listitem>
+ </itemizedlist>
+ </section>
+</chapter>
Added:
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/security-service.xml
===================================================================
---
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/security-service.xml
(rev 0)
+++
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/security-service.xml 2010-07-30
15:13:44 UTC (rev 2846)
@@ -0,0 +1,309 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<chapter id="CoreSecurityService">
+ <title>Security Service</title>
+
+ <section>
+ <title>1 Overview</title>
+
+ <para>The purpose is to make a simple, unified way for the authentication
+ and the storing/propagation of user sessions through all the eXo
+ components and J2EE containers. JAAS is supposed to be the primary login
+ mechanism but the Security Service framework should not prevent other
+ (custom or standard) mechanisms from being used. You can learn more about
+ JAAS in the <ulink
+ url="Java
Tutorial>http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/t...
+
Tutorial>http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/t...
+ </section>
+
+ <section>
+ <title>1 Framework</title>
+
+ <para>The central point of this framework is the <emphasis
+ role="bold">ConversationState</emphasis> object which stores all
+ information about the state of the current user (very similar to the
+ Session concept). The same ConversationState also stores acquired
+ attributes of an <emphasis role="bold">Identity</emphasis>
which is a set
+ of principals to identify a user.</para>
+
+ <para>The ConversationState has definite lifetime. This object should be
+ created when the user's identity becomes known by eXo (login procedure)
+ and destroyed when the user leaves an eXo based application (logout
+ procedure). Using JAAS it should happen in LoginModule's login() and
+ logout() methods respectively.</para>
+
+ <section>
+ <title>1.1 ConversationState and ConversationRegistry</title>
+
+ <para>The ConversationState can be stored</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>in a static <emphasis role="bold">local thread
+ variable</emphasis>, or</para>
+ </listitem>
+
+ <listitem>
+ <para>as a <emphasis role="bold">key-value
pair</emphasis> in the
+ <emphasis role="bold">ConversationRegistry</emphasis>
+ component.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>One or the other, or both methods can be used to set/retrieve the
+ state at runtime. The most important thing is that they should be
+ complementary, i.e. make sure that the conversation state is set before
+ you try to use it.</para>
+
+ <para><emphasis role="bold">Local Thread
Variable</emphasis> Storing the
+ ConversationState in a static local thread variable makes it possible to
+ represent it as a <emphasis role="bold">context</emphasis>
(current
+ user's state).</para>
+
+ <programlisting>ConversationState.setCurrent(conversationState);
+....
+ConversationState.getCurrent();</programlisting>
+
+ <para><emphasis role="bold">Key-Value
way</emphasis></para>
+
+ <para>If you store the ConversationState inside the <emphasis
+ role="bold">ConversationRegistry</emphasis> component as a set
of
+ key-value pairs, the session key is an arbitrary String (user name,
+ ticket id, httpSessionId etc).</para>
+
+ <programlisting>conversationRegistry.register("key",
conversationState);
+...
+conversationRegistry.getState("key");</programlisting>
+
+ <para><emphasis
role="bold">ConversationRegistry</emphasis> The
+ ConversationRegistry is a mandatory component deployed into eXo
+ Container as following:</para>
+
+ <programlisting><component>
+
<type>org.exoplatform.services.security.ConversationRegistry</type>
+</component></programlisting>
+ </section>
+
+ <section>
+ <title>1.1 Authenticator</title>
+
+ <para>An Authenticator is responsible for Identity creating, it contains
+ two methods:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>validateUser() accepts an array of credentials and returns the
+ userId (which can be something different from the username).</para>
+ </listitem>
+
+ <listitem>
+ <para>createIdentity() accepts the userId and returns a newly
+ created Identity object.</para>
+ </listitem>
+ </itemizedlist>
+
+ <programlisting>public interface Authenticator {
+ /**
+ * Authenticate user and return userId which can be different to username.
+ * @param credentials - list of users credentials (such as name/password, X509
certificate etc)
+ * @return userId
+ * @throws LoginException
+ * @throws Exception
+ */
+ String validateUser(Credential[] credentials) throws LoginException, Exception;
+
+ /**
+ * @param credentials - userId.
+ * @return Identity
+ * @throws Exception
+ */
+ Identity createIdentity(String userId) throws Exception;
+
+}</programlisting>
+
+ <para>It is up to the application developer (and deployer) whether to
+ use the Authenticator component(s) and how many implementations of this
+ components should be deployed in eXo container. The developer is free to
+ create an Identity object using a different way, but the Authenticator
+ component is the highly recommended way from architectural
+ considerations.</para>
+
+ <para>Typical functionality of the validateUser(Credential\[]
+ credentials) method is the comparison of incoming credentials
+ (username/password, digest etc) with those credentials that are stored
+ in an implementation specific database. Then validateUser(Credential\[]
+ credentials) returns back the userId or throws a LoginException in a
+ case of wrong credentials.</para>
+
+ <para>Default Authenticator implementation is
+ org.exoplatform.services.organization.auth.OrganizationAuthenticatorImpl
+ which compares incoming username/password credentials with the ones
+ stored in OrganizationService. Configuration example:</para>
+
+ <programlisting><component>
+ <key>org.exoplatform.services.security.Authenticator</key>
+
<type>org.exoplatform.services.organization.auth.OrganizationAuthenticatorImpl</type>
+</component></programlisting>
+ </section>
+ </section>
+
+ <section>
+ <title>Usage</title>
+
+ <section>
+ <title>JAAS login module</title>
+
+ <para>The framework described is not coupled with any authentication
+ mechanism but the most logical and implemented by default is the JAAS
+ Login module. The typical sequence looks as follows (see
+ org.exoplatform.services.security.jaas.DefaultLoginModule):</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>LoginModule.login() creates a list of credentials using
+ standard JAAS Callbacks features, obtains an Authenticator instance,
+ and creates an Identity object calling
+ Authenticator.authenticate(..) method</para>
+ </listitem>
+ </itemizedlist>
+
+ <programlisting>Authenticator authenticator = (Authenticator) container()
+ .getComponentInstanceOfType(Authenticator.class);
+// RolesExtractor can be null
+RolesExtractor rolesExtractor = (RolesExtractor) container().
+getComponentInstanceOfType(RolesExtractor.class);
+
+
+Credential[] credentials = new Credential[] {new UsernameCredential(username), new
PasswordCredential(password) };
+String userId = authenticator.validateUser(credentials);
+identity = authenticator.createIdentity(userId);</programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para>LoginModule.commit() obtains the IdentityRegistry object, and
+ register the identity using userId as a key.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>When initializing the login module you can set the option
+ parameter "singleLogin". With this option you can disallow the same
+ Identity to login for a second time.</para>
+
+ <para>By default singleLogin is disabled, so the same identity can be
+ registered more than one time. Parameter can be passed in this form
+ singleLogin=yes or singleLogin=true.</para>
+
+ <programlisting>IdentityRegistry identityRegistry = (IdentityRegistry)
getContainer().getComponentInstanceOfType(IdentityRegistry.class);
+
+if (singleLogin && identityRegistry.getIdentity(identity.getUserId()) !=
null)
+ throw new LoginException("User " + identity.getUserId() + " already
logined.");
+
+identity.setSubject(subject);
+identityRegistry.register(identity);</programlisting>
+
+ <para>In the case of using several LoginModules, JAAS allows to place
+ the login() and commit() methods in different REQUIRED modules.</para>
+
+ <para>After that, the web application must use SetCurrentIdentityFilter.
+ This filter obtains the ConversationRegistry object and tries to get the
+ ConversationState by sessionId (HttpSession). If there is no
+ ConversationState then SetCurrentIdentityFilter will create a new one,
+ register it and set it as current one using
+ ConversationState.setCurrent(state).</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>LoginModule.logout() can be called by
+ JAASConversationStateListener, it extends
+ ConversationStateListener.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>This listener must be configured in web.xml. The method
+ sessionDestroyed(HttpSessionEvent)is called by the ServletContainer.
+ This method removes the ConversationState from the ConversationRegistry
+ ConversationRegistry.unregister(sesionId) and calls the method
+ LoginModule.logout().</para>
+
+ <programlisting>ConversationRegistry conversationRegistry =
(ConversationRegistry)
getContainer().getComponentInstanceOfType(ConversationRegistry.class);
+
+ConversationState conversationState = conversationRegistry.unregister(sesionId);
+
+if (conversationState != null) {
+ log.info("Remove conversation state " + sesionId);
+ if (conversationState.getAttribute(ConversationState.SUBJECT) != null) {
+ Subject subject = (Subject)
conversationState.getAttribute(ConversationState.SUBJECT);
+ LoginContext ctx = new LoginContext("exo-domain", subject);
+ ctx.logout();
+} else {
+ log.warn("Subject was not found in ConversationState attributes.");
+}</programlisting>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>1.1 Predefinded JAAS login modules</title>
+
+ <para>There are several JAAS Login modules included in eXo Platform
+ sources:</para>
+
+ <para><emphasis
+
role="bold">org.exoplatform.services.security.jaas.DefaultLoginModule</emphasis>
+ which provides both authentication (using eXo Authenticator based
+ mechanism) and authorization, filling Conversation Registry as it
+ described in previous section. There are also several per-Application
+ Server extensions of this login module which can be found in
+ org.exoplatform.services.security.jaas package, which can be used in
+ appropriate AS. In particular, we have dedicated Login modules for
+ Tomcat, JBoss, Jonas and WebSphere.</para>
+
+ <para><emphasis role="bold">TODO: configuration examples for
Tomcat,
+ JBoss, Jonas and WebSphere</emphasis></para>
+
+ <para>Besides that, for the case when third party authentication
+ mechanism required, we have <emphasis
+
role="bold">org.exoplatform.services.security.jaas.IdentitySetLoginModule</emphasis>,
+ which catches a login identity from third party "authenticating" login
+ module and preforms eXo specific authorization job. In this case third
+ party login module has to put login (user) name to the shared state map
+ under <emphasis
role="bold">"javax.security.auth.login.name"</emphasis>
+ key and third party LM has to be configured before
+ IdentitySetLoginModule like:</para>
+
+ <programlisting>exo {
+ com.third.party.LoginModuleImpl required;
+ org.exoplatform.services.security.jaas.IdentitySetLoginModule required;
+};</programlisting>
+ </section>
+
+ <section>
+ <title>1.1 J2EE container authentication</title>
+
+ <para>As you know, when a user in JAAS is authenticated, a Subject is
+ created as a result. This Subject represents the authenticated user. It
+ is important to know and follow the rules regarding Subject filling
+ which are specific for each J2EE server, where eXo Platform is
+ deployed.</para>
+
+ <para>To make it workable for the particular J2EE server it is necessary
+ to add specific Principals/Credentials to the Subject to be propagated
+ into the specific J2EE container implementation. We extended the
+ DefaultLoginModule by overloading its commit() method with a dedicated
+ logic, presently available for Tomcat, JBOSS and JONAS application
+ servers.</para>
+
+ <para>Furthermore you can use the optional RolesExtractor which is
+ responsible for mapping primary Subject's principals (userId and a set
+ of groups) to J2EE Roles:</para>
+
+ <programlisting>public interface RolesExtractor {
+ Set <String> extractRoles(String userId,
Set<MembershipEntry> memberships);
+}</programlisting>
+
+ <para>This component may be used by Authenticator to create the Identity
+ with a particular set of <emphasis
role="bold">Roles</emphasis>.</para>
+ </section>
+ </section>
+</chapter>
Added:
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/spring-security-integration.xml
===================================================================
---
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/spring-security-integration.xml
(rev 0)
+++
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core/spring-security-integration.xml 2010-07-30
15:13:44 UTC (rev 2846)
@@ -0,0 +1,670 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<chapter id="CoreSpringSecurityIntegration">
+ <title>Spring Security Integration</title>
+
+ <section>
+ <title>Introduction</title>
+
+ <para>How to Integrate the spring security framework in the eXo
+ portal?</para>
+
+ <para>This tutorial will guide you through a few steps and show you how
+ easy it is to integrate spring security (or the Spring framework in
+ general) in eXo portal. We will create a login portlet example as a
+ support all along the document reading. The login portlet example has been
+ developed and deployed using the eXo WCM product running on the
+ application server JBoss 4.2.3. But it can easily be adapted to another
+ eXo product (such as ECM) and to other servers such as tomcat. Moreover,
+ the example, claiming to be a real world example, is implemented using JSF
+ 1.2, the JBoss portlet bridge and Spring and can serve as a example
+ project from where you can start your own portlet development targeting
+ the eXo platform.</para>
+ </section>
+
+ <section>
+ <title>Installation</title>
+
+ <para>This tutorial assumes that you have a working eXo WCM installation
+ running under JBoss 4.2.x.</para>
+
+ <para>Download the spring framework: <ulink
+
url="http://s3.amazonaws.com/dist.springframework.org/release/SPR/sp...
+
+ <para>Download spring-security: <ulink
+
url="http://sourceforge.net/project/showfiles.php?group_id=73357&...
+
+ <para>Unzip the 02portal.war file in the jboss
+ server/default/deploy/exoplatform.sar directory and copy the following
+ jars in WEB-INF/lib:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>spring.jar</para>
+ </listitem>
+
+ <listitem>
+ <para>spring-security-core.jar</para>
+ </listitem>
+
+ <listitem>
+ <para>aspectjrt-1.5.4.jar</para>
+ </listitem>
+
+ <listitem>
+ <para>exo-spring.jar (contains the filters and event handlers
+ described in this tutorial - see the attachment section of this
+ page)</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Configuration</title>
+
+ <para>To enable spring security in exo we need to go through a few
+ configuration steps:</para>
+
+ <section>
+ <title>JAAS disabling</title>
+
+ <para>First we need to disable the JAAS security which is the default
+ authentication mechanism in exo. Edit 02portal.war web.xml file and
+ comment out the JAAS configuration related lines:</para>
+
+ <programlisting>...
+ <session-config>
+ <session-timeout>15</session-timeout>
+ </session-config>
+
+ <!--
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>user
authentication</web-resource-name>
+ <url-pattern>/private/*</url-pattern>
+ <http-method>POST</http-method>
+ <http-method>GET</http-method>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>users</role-name>
+ </auth-constraint>
+ <user-data-constraint>
+ <transport-guarantee>NONE</transport-guarantee>
+ </user-data-constraint>
+ </security-constraint>
+
+ <login-config>
+ <auth-method>FORM</auth-method>
+ <realm-name>exo-domain</realm-name>
+ <form-login-config>
+
<form-login-page>/login/jsp/login.jsp</form-login-page>
+
<form-error-page>/login/jsp/login.jsp</form-error-page>
+ </form-login-config>
+ </login-config>
+ -->
+
+ <security-role>
+ <description>a simple user role</description>
+ <role-name>users</role-name>
+ </security-role>
+...</programlisting>
+ </section>
+
+ <section>
+ <title>Enabling spring security</title>
+
+ <para>To enable spring and set the spring security filter, add the
+ following lines:</para>
+
+ <programlisting>...
+ <context-param>
+ <param-name>contextConfigLocation</param-name>
+
<param-value>/WEB-INF/security-context.xml</param-value>
+ </context-param>
+
+ <listener>
+
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+ </listener>
+
+ <filter>
+ <filter-name>springSecurityFilterChain</filter-name>
+
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
+ </filter>
+...</programlisting>
+
+ <para>Activate the spring security filter at the right position, i.e.
+ just after the filter responsible of exo container
+ initialization.</para>
+
+ <programlisting>...
+ <filter-mapping>
+
<filter-name>PortalContainerInitializedFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <filter-mapping>
+ <filter-name>springSecurityFilterChain</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <filter-mapping>
+ <filter-name>SetCurrentIdentityFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+...</programlisting>
+ </section>
+
+ <section>
+ <title>security-context.xml</title>
+
+ <para>We need to configure the spring security filter chain for our
+ purposes. Create a file named security-context.xml in 02portal.war
+ WEB-INF directory containing the following lines:</para>
+
+ <programlisting><?xml version="1.0"
encoding="UTF-8"?>
+<beans:beans
xmlns="http://www.springframework.org/schema/security"
+
xmlns:beans="http://www.springframework.org/schema/beans"
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.1.xsd&...
+
+ <http auto-config="true">
+ <intercept-url pattern="/private/**" access="ROLE_USER"
/>
+ <form-login login-page='/public/classic/Login'
default-target-url='/private/classic/home' />
+ </http>
+
+ <authentication-provider>
+ <user-service>
+ <user name="rod" password="koala"
authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" />
+ <user name="root" password="exo"
authorities="ROLE_USER" />
+ </user-service>
+ </authentication-provider>
+
+</beans:beans></programlisting>
+
+ <para>The file contains two elements. The http node which is responsible
+ of configuring the filter chain. The auto-config mode set to true allows
+ us to do just a minimal configuration, everything else being smartly
+ initialized by default. We just set an intercept URL pointing to
+ '/private/**' with the ROLE_USER authority which corresponds to secured
+ resources in exo. In case of successful auhentication, the user will be
+ redirected to the specified default target URL.</para>
+
+ <para>The second element defines a simple authentication provider based
+ on the spring security InMemoryDaoImpl implementation of the
+ UserDetailsService. Note that we define the exo root user in the
+ configuration which will allow us to log in with admin privileges in the
+ exo portal.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Login portlet example</title>
+
+ <para>Now that we have successfully installed and configured spring
+ security in exo, we need a login portlet example to capture user
+ credentials and serve as an entry point in the authentication process. The
+ login portlet itself is based on JSF 1.2, Jboss portlet bridge and the
+ spring framework, but you can obviously use whatever web framework you
+ want to achieve the same.</para>
+
+ <section>
+ <title>Building the portlet</title>
+
+ <para>So we need a login form to capture user credentials inputs. The
+ portlet login form consists of the following lines of xml:</para>
+
+ <programlisting><f:view
xmlns:f="http://java.sun.com/jsf/core"
+
xmlns:h="http://java.sun.com/jsf/html"
+
xmlns:ice="http://www.icesoft.com/icefaces/component"
+
xmlns:liferay-faces="http://liferay.com/tld/faces"
+
xmlns:ui="http://java.sun.com/jsf/facelets"
+
xmlns:c="http://java.sun.com/jstl/core"
+
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
+
xmlns:t="http://myfaces.apache.org/tomahawk">
+
+ <style type="text/css" media="screen">
+ @import "/loginportlet/css/starter.css";
+ @import "/loginportlet/css/uni-form.css";
+ </style>
+
+ <script src="/loginportlet/js/jquery.js"
type="text/javascript"></script>
+ <script src="/loginportlet/js/uni-form.jquery.js"
type="text/javascript"></script>
+
+ <h:form styleClass="uniForm" >
+ <fieldset class="inlineLabels">
+ <legend>Sign in</legend>
+
+ <div class="ctrlHolder">
+ <h:outputLabel for="login" style="width:
70px"><em>*</em>Login:</h:outputLabel>
+ <h:inputText id="login" value="#{loginBean.login}"
required="true" styleClass="textInput" />
+ <h:message for="login"
styleClass="portlet-msg-error" />
+ </div>
+ <div class="ctrlHolder">
+ <h:outputLabel for="password" style="width:
70px"><em>*</em>Password:</h:outputLabel>
+ <h:inputSecret id="password"
value="#{loginBean.passwd}" required="true"
styleClass="textInput" />
+ <h:message for="password"
styleClass="portlet-msg-error" />
+ </div>
+ </fieldset>
+
+ <div class="buttonHolder" style="margin-top: 20px;
margin-right: 20px">
+ <h:commandButton styleClass="primaryAction"
value="Submit" action="#{loginBean.login}" />
+ </div>
+ </h:form>
+</f:view></programlisting>
+
+ <para>The interesting part resides in the backing bean which implements
+ the login action triggered when the user clicks the login form submit
+ button.</para>
+
+ <programlisting>package org.exoplatform.loginportlet;
+
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Controller;
+
+@Controller
+@Scope("request")
+public class LoginBean {
+
+ String login;
+
+ String passwd;
+
+ public String login() throws Exception {
+ String redirect = "/portal/j_spring_security_check?j_username=" + login
+ "&j_password=" + passwd;
+ PortalUtils.sendRedirect(redirect);
+ return null;
+ }
+
+ ...
+}</programlisting>
+
+ <para>The login action simply sends a HTTP redirect to the spring
+ security login URL passing the user login and password as parameters.
+ This URL informs the filter to try to authenticate the supplied user
+ credentials. This is the Spring security authentication process entry
+ point.</para>
+ </section>
+
+ <section>
+ <title>Setting up the login portal page</title>
+
+ <para>Now that we have a login portlet available we need to set it up
+ into a portal page.</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Log in as root in exo portal.</para>
+ </listitem>
+
+ <listitem>
+ <para>Go to application registry and import the
loginportlet</para>
+ </listitem>
+
+ <listitem>
+ <para>Add a new hidden page named 'Login' under the portal
classic's
+ navigation (read more on page creation <ulink
+
url="here>WCM.Tutorial">here>WCM.Tutorial</ulink>). Make
sure
+ that the visible flag is unchecked to hide the page. Also declare
+ the page as public so that everyone can access it without being
+ authenticated for obvious reasons.</para>
+ </listitem>
+
+ <listitem>
+ <para>Finally, drag & drop the login portlet in the page with
+ the desired layout.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Customization of portal login and logout urls</title>
+
+ <para>In the portal header there is a login or logout action displayed
+ depending whether you are already logged in or not. We need to customize
+ those actions so that when the user clicks on it she or he will be
+ redirected either to our login page or to the spring security logout
+ url. Edit the article, go to the default.js tab and apply the following
+ changes to the code:</para>
+
+ <programlisting>function validateUser() {
+
+ var user = eXo.env.portal.userName;
+ var rootObj = document.getElementById("classic-access");
+ var loginContentObj = eXo.core.DOMUtil.findFirstDescendantByClass(rootObj,
"div", "UIWCMLoginPortlet");
+ var welcomeObj = eXo.core.DOMUtil.findFirstDescendantByClass(rootObj,
"span", "Welcome");
+ var userObj = eXo.core.DOMUtil.findFirstDescendantByClass(rootObj, "span",
"LoggedUser");
+ var languageObj = eXo.core.DOMUtil.findFirstDescendantByClass(rootObj, "a",
"LanguageIcon");
+ var logXXXObj = eXo.core.DOMUtil.findPreviousElementByTagName(languageObj,
"a");
+
+ if (user != "null") {
+ welcomeObj.innerHTML = "Welcome: ";
+ userObj.innerHTML = user;
+ logXXXObj.innerHTML = "Logout";
+ if (eXo.core.DOMUtil.hasClass(logXXXObj, "LoginIcon")) {
+ eXo.core.DOMUtil.removeClass(logXXXObj, "LoginIcon");
+ eXo.core.DOMUtil.addClass(logXXXObj, "LogoutIcon");
+ }
+ logXXXObj.onclick = function() { document.location.href =
'/portal/j_spring_security_logout' }
+ } else {
+ if (eXo.core.DOMUtil.hasClass(logXXXObj, "LogoutIcon")) {
+ eXo.core.DOMUtil.removeClass(logXXXObj, "LogoutIcon");
+ eXo.core.DOMUtil.addClass(logXXXObj, "LoginIcon");
+ }
+ logXXXObj.innerHTML = "Login";
+ logXXXObj.onclick = function() { document.location.href =
'/portal/public/classic/Login' };
+ }
+
+ languageObj.onclick = function () {
if(document.getElementById('UIMaskWorkspace'))
ajaxGet(eXo.env.server.createPortalURL('UIPortal', 'ChangeLanguage',
true)); }
+}
+
+eXo.core.Browser.addOnLoadCallback("validateUser",
validateUser);</programlisting>
+
+ <para>As you can see, the two onclick event handler function bodies have
+ been changed to a simple redirect to the login page or the logout
+ URL.</para>
+ </section>
+
+ <section>
+ <title>A look at the login page</title>
+
+ <para>Once you are done with all this, just click on the login action
+ and you should be redirect to the login page looking something like
+ that:</para>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/login-page.jpg" />
+ </imageobject>
+ </mediaobject>
+ </section>
+ </section>
+
+ <section>
+ <title>Integration strategies</title>
+
+ <para>Until now we haven't discussed about any integration strategies
+ concerning a potential existing security realm outside of the eXo
+ platform. To address this problem we have the choice between at least two
+ different strategies:</para>
+
+ <para>1.1.1 <emphasis role="bold">Direct
integration</emphasis> We can
+ directly integrate eXo with the external realm. Everything related to
+ organisation and user management in exo is cleanly separated in its own
+ abstraction accessible through the OrganisationService. The authentication
+ process itself is encapsulated in the Authenticator abstraction which sits
+ on top of the organization service. eXo provides several implementations
+ of both. So whether your realm is based on LDAP or JDBC and because the
+ default implementations are generic enough, you will be able to use them
+ and fits them to your needs with a matter of a little configuration. You
+ can even develop a custom implementation to meet your more specific
+ needs.</para>
+
+ <section>
+ <title>Replication</title>
+
+ <para>Or we can go through a replication process between the external
+ realm and the eXo platform realm. This is the strategy that we are going
+ to use to build our login portlet example. Furthermore the replication
+ will occur dynamically on any user authentication attempt.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Integration with eXo portal</title>
+
+ <para>Being successfully authenticated against an external realm is not
+ sufficient by itself. We also need to propagate the newly created security
+ context to the portal own security mechanism. In eXo portal terminology,
+ it means we have to create an Identity object for the user and register it
+ into the Identity Registry.</para>
+
+ <para>Spring framework provides a simple notification model where a bean
+ can listen to application events published by other beans. Fortunately
+ spring security uses this mechanism and publishes an
+ InteractiveAuthenticationSuccessEvent in case of successful
+ authentication. That will allow us to hook up custom code to that
+ event.</para>
+
+ <para>Furthermore, we need to replicate the user details from the external
+ realm to the eXo portal one according to the integration strategy defined
+ above.</para>
+
+ <para>We create a SpringSecurityEventHandler bean that implements the
+ ApplicationListener interface and listens to the
+ InteractiveAuthenticationSuccessEvent event.</para>
+
+ <programlisting>package org.exoplatform.spring.security.web;
+
+...
+
+public class SpringSecurityEventHandler implements ApplicationListener {
+
+ private String portalContainerName = "portal";
+
+ public void onApplicationEvent(ApplicationEvent event) {
+ if (event instanceof InteractiveAuthenticationSuccessEvent) {
+ try {
+ InteractiveAuthenticationSuccessEvent successEvent =
(InteractiveAuthenticationSuccessEvent) event;
+ ExoContainer container = getContainer();
+
+ String login = successEvent.getAuthentication().getName();
+ String passwd =
successEvent.getAuthentication().getCredentials().toString();
+
+ IdentityRegistry identityRegistry = (IdentityRegistry)
container.getComponentInstanceOfType(IdentityRegistry.class);
+ Authenticator authenticator = (Authenticator)
container.getComponentInstanceOfType(Authenticator.class);
+ OrganizationService orgService = (OrganizationService)
container.getComponentInstanceOfType(OrganizationService.class);
+
+ User user = orgService.getUserHandler().findUserByName(login);
+ if (user == null) {
+ user = orgService.getUserHandler().createUserInstance(login);
+ user.setFirstName(login);
+ user.setLastName(login);
+ orgService.getUserHandler().createUser(user, false);
+ orgService.getUserHandler().saveUser(user, false);
+ //TODO: put some more integration code here
+ }
+
+ Identity identity = authenticator.createIdentity(login);
+
+ Subject subject = new Subject();
+ subject.getPrivateCredentials().add(passwd);
+ subject.getPublicCredentials().add(new UsernameCredential(login));
+
+ identity.setSubject(subject);
+ identityRegistry.register(identity);
+
+ } catch (Exception e) {
+ e.getMessage();
+ }
+ }
+ }
+
+ protected ExoContainer getContainer() {
+ // TODO set correct current container
+ ExoContainer container = ExoContainerContext.getCurrentContainer();
+ if (container instanceof RootContainer) {
+ container =
RootContainer.getInstance().getPortalContainer(portalContainerName);
+ }
+ return container;
+ }
+
+...
+
+}</programlisting>
+
+ <para>Basically the bean retrieves user login and password from the
+ InteractiveAuthenticationSuccessEvent object and tries to get the user
+ from the organization service. In case he cannot find it in the
+ repository, he simply creates it on the fly. In this example the user is
+ created with just a few details, but you can put some custom integration
+ code with the external realm here, and create the user with all the
+ details (email, birth date, roles, etc.) it seems appropriate to you.
+ After that, the bean creates an Identity object with the help of the
+ authenticator service, populates it with a subject containing the user
+ credentials and registers it. That's all we have to do to make the portal
+ aware of the user logging in.</para>
+
+ <para>Registering our bean is done the usual way in security-context.xml
+ file:</para>
+
+ <programlisting>...
+<beans:bean id="myEventHandler"
class="org.exoplatform.spring.security.web.SpringSecurityEventHandler"
/>
+...</programlisting>
+ </section>
+
+ <section>
+ <title>Security context propagation to portlets</title>
+
+ <para>Part of the problem is the question of security context propagation
+ between on one side the portal webapp and at the other side the portlets
+ webapps. This means that the security context has to be available in the
+ portlet side allowing the application logic to deal the with current user
+ principal and granted authorities. By default Spring security uses a
+ thread local variable to partially achieve this. But a problem may arise
+ due to the fact that the portal invokes the portlet through a webapp cross
+ context call. This means that it can lead to a class cast exceptions (two
+ different classloaders involved), or that the security context is simply
+ not propagated at all. To accommodate this we will need to set up two
+ request filters, one at the portal webapp side and the other at the
+ portlet webapp side and use the http request to propagate the context in
+ between.</para>
+
+ <section>
+ <title>Portal side filter</title>
+
+ <para>We will use the spring security extensible filter chain to plug in
+ our filter.</para>
+
+ <programlisting>package org.exoplatform.spring.security.web;
+
+...
+
+public class PortalSideSecurityContextFilter extends SpringSecurityFilter {
+
+ @Override
+ protected void doFilterHttp(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
+ //fill request with security context
+ SecurityContext context = SecurityContextHolder.getContext();
+
request.setAttribute(HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY,
context);
+
+ //fill request with security last exception
+ Object e =
request.getSession().getAttribute(AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY);
+ request.setAttribute(AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY,
e);
+
+ chain.doFilter(request, response);
+ }
+
+ public int getOrder() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+}</programlisting>
+
+ <para>The PortalSideSecurityContextFilter simply fills the request with
+ the security context and security last exception using the
+ HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY and
+ AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY attribute
+ names. The portlet can have a look to the
+ AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY attribute to
+ check if a security exception has occured.</para>
+
+ <para>The following lines in the security-context file register our
+ custom filter in the chain at the last position.</para>
+
+ <programlisting>...
+ <beans:bean id="myCustomFilter"
class="org.exoplatform.spring.security.web.PortalSideSecurityContextFilter">
+ <custom-filter after="LAST" />
+ </beans:bean>
+...</programlisting>
+ </section>
+
+ <section>
+ <title>Portlet side filter</title>
+
+ <para>In the portlet webapp we create a regular filter named
+ PortletSideSecurityContextFilter.</para>
+
+ <programlisting>package org.exoplatform.spring.security.web;
+
+...
+
+public class PortletSideSecurityContextFilter implements Filter {
+
+ public void destroy() {
+
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain
filterChain) throws IOException, ServletException {
+ Object object =
request.getAttribute(HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY);
+ SecurityContext context = (SecurityContext) serializeDeserialize(object);
+ if (context != null) {
+ SecurityContextHolder.setContext(context);
+ } else {
+ SecurityContextHolder.clearContext();
+ }
+
+ filterChain.doFilter(request, response);
+ }
+
+ public void init(FilterConfig arg0) throws ServletException {
+
+ }
+
+ private Object serializeDeserialize(Object obj) {
+ Object result = null;
+ try {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(bout);
+
+ out.writeObject(obj);
+
+ ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
+ ObjectInputStream in = new ObjectInputStream(bin);
+
+ result = in.readObject();
+ } catch (Exception e) {
+ //TODO: handle exception
+ }
+ return result;
+ }
+
+}</programlisting>
+
+ <para>The PortletSideSecurityContextFilter retrieves the security
+ context from the request and proceeds to a serialization
+ de-serialization of it to avoid a potential class cast exception that
+ may occur when propagating an object across webapps. Then the context is
+ simply set or cleared whether the context is null or not.</para>
+
+ <para>To register your filter simply add the following lines to your
+ portlet webapp web.xml file.</para>
+
+ <programlisting>...
+ <filter>
+
<filter-name>portletSideSecurityContextFilter</filter-name>
+
<filter-class>org.exoplatform.spring.security.web.PortletSideSecurityContextFilter</filter-class>
+ </filter>
+
+ <filter-mapping>
+
<filter-name>portletSideSecurityContextFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ <dispatcher>REQUEST</dispatcher>
+ <dispatcher>INCLUDE</dispatcher>
+ <dispatcher>FORWARD</dispatcher>
+ </filter-mapping>
+...</programlisting>
+ </section>
+ </section>
+
+ <section>
+ <title>Conclusion</title>
+
+ <para>We are done! Now we know how to integrate the spring security
+ framework in the eXo portal. Thanks to the the great integration
+ capabilities of both eXo portal and Spring framework. You can have a look
+ to the attachment section on this page and get the source code of this
+ tutorial.</para>
+ </section>
+</chapter>
Modified: jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core.xml
===================================================================
---
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core.xml 2010-07-30
13:29:37 UTC (rev 2845)
+++
jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/core.xml 2010-07-30
15:13:44 UTC (rev 2846)
@@ -8,8 +8,41 @@
<xi:include href="core/core.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
-
+
<xi:include href="core/db-creator-service.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="core/security-service.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="core/spring-security-integration.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="core/organization-service.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="core/organization-service-initalizer.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="core/organization-service-listener.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="core/conversationstate-when-membership-changed.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="core/db-schema-creator-service.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="core/db-configuration-hibernate.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="core/ldap-configuration.xml"
+
xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+
+
+
+
+
+
</part>
Added: jcr/branches/1.12.x/docs/reference/en/src/main/resources/images/login-page.jpg
===================================================================
(Binary files differ)
Property changes on:
jcr/branches/1.12.x/docs/reference/en/src/main/resources/images/login-page.jpg
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added:
jcr/branches/1.12.x/docs/reference/en/src/main/resources/images/organization-exo.jpg
===================================================================
(Binary files differ)
Property changes on:
jcr/branches/1.12.x/docs/reference/en/src/main/resources/images/organization-exo.jpg
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream