From do-not-reply at jboss.org Fri Jul 30 11:13:45 2010 Content-Type: multipart/mixed; boundary="===============0903027441959976257==" MIME-Version: 1.0 From: do-not-reply at jboss.org To: exo-jcr-commits at lists.jboss.org Subject: [exo-jcr-commits] exo-jcr SVN: r2846 - in jcr/branches/1.12.x/docs/reference/en/src/main: docbook/en-US/modules/core and 1 other directories. Date: Fri, 30 Jul 2010 11:13:45 -0400 Message-ID: <201007301513.o6UFDjSu005372@svn01.web.mwc.hst.phx2.redhat.com> --===============0903027441959976257== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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/cor= e/conversationstate-when-membership-changed.xml jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/cor= e/db-configuration-hibernate.xml jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/cor= e/db-schema-creator-service.xml jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/cor= e/ldap-configuration.xml jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/cor= e/organization-service-initalizer.xml jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/cor= e/organization-service-listener.xml jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/cor= e/organization-service.xml jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/cor= e/security-service.xml jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/cor= e/spring-security-integration.xml jcr/branches/1.12.x/docs/reference/en/src/main/resources/images/login-pa= ge.jpg jcr/branches/1.12.x/docs/reference/en/src/main/resources/images/organiza= tion-exo.jpg Modified: jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/cor= e.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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/conversationstate-when-membership-changed.xml (r= ev 0) +++ jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/conversationstate-when-membership-changed.xml 2010-07-30 15:13:44 UTC (r= ev 2846) @@ -0,0 +1,34 @@ + + + + Update ConversationState when user's Membership changed + + 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 update= d in + OrganizationService ConversationState still keeps old (not actual Identi= ty). + 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. + + Example of configuration. + + <?xml version=3D"1.0" encoding=3D"ISO-8859-1"?> +<configuration + xmlns:xsi=3D"http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation=3D"http://www.exoplaform.org/xml/ns/kernel_1_0.xsd h= ttp://www.exoplaform.org/xml/ns/kernel_1_0.xsd" + xmlns=3D"http://www.exoplaform.org/xml/ns/kernel_1_0.xsd"> + <external-component-plugins> + <target-component>org.exoplatform.services.organization.Organiza= tionService</target-component> +..... +..... + <component-plugin> + <name>MembershipUpdateListener</name> + <set-method>addListenerPlugin</set-method> + <type>org.exoplatform.services.organization.impl.MembershipUpd= ateListener</type> + </component-plugin> + + <external-component-plugins> +</configuration> + Added: jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules= /core/db-configuration-hibernate.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/db-configuration-hibernate.xml (rev 0) +++ jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/db-configuration-hibernate.xml 2010-07-30 15:13:44 UTC (rev 2846) @@ -0,0 +1,115 @@ + + + + Database Configuration for Hibernate + + 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. + +
+ Generic configuration + + The default DB configuration uses HSQLDB, a Java Database quite + useful for demonstrations. + + <component> = + <key>org.exoplatform.services.database.HibernateService</key&g= t; + <jmx-name>exo-service:type=3DHibernateService</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=3D"hibernate.show_sql" value=3D"false"/> + <property name=3D"hibernate.cglib.use_reflection_optimizer" va= lue=3D"true"/> + <property name=3D"hibernate.connection.url" value=3D"jdbc:hsql= db:file:../temp/data/portal"/> + <property name=3D"hibernate.connection.driver_class" value=3D"= org.hsqldb.jdbcDriver"/> + <property name=3D"hibernate.connection.autocommit" value=3D"tr= ue"/> + <property name=3D"hibernate.connection.username" value=3D"sa"/= > + <property name=3D"hibernate.connection.password" value=3D""/&g= t; + <property name=3D"hibernate.dialect" value=3D"org.hibernate.di= alect.HSQLDialect"/> + <property name=3D"hibernate.c3p0.min_size" value=3D"5"/> + <property name=3D"hibernate.c3p0.max_size" value=3D"20"/> + <property name=3D"hibernate.c3p0.timeout" value=3D"1800"/> + <property name=3D"hibernate.c3p0.max_statements" value=3D"50"/= > + </properties-param> + </init-params> +</component> + + In the init parameter section, we define the default hibernate + properties including the DB URL, the driver and the credentials in + use. + + As for any portal that configuration can be overridden depending= on + the needs of your environment. + + 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. +
+ +
+ Example DB configuration + + For MySQL + + <component> = + <key>org.exoplatform.services.database.HibernateService</key&g= t; + <jmx-name>database:type=3DHibernateService</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=3D"hibernate.show_sql" value=3D"false"/> + <property name=3D"hibernate.cglib.use_reflection_optimizer" va= lue=3D"true"/> + <property name=3D"hibernate.connection.url" value=3D"jdbc:mysq= l://localhost:3306/exodb?relaxAutoCommit=3Dtrue&amp;amp;autoReconnect= =3Dtrue&amp;amp;useUnicode=3Dtrue&amp;amp;characterEncoding=3Dutf8"= /> + <property name=3D"hibernate.connection.driver_class" value=3D"= com.mysql.jdbc.Driver"/> + <property name=3D"hibernate.connection.autocommit" value=3D"tr= ue"/> + <property name=3D"hibernate.connection.username" value=3D"exo"= /> + <property name=3D"hibernate.connection.password" value=3D"exo"= /> + <property name=3D"hibernate.dialect" value=3D"org.hibernate.di= alect.MySQLDialect"/> + <property name=3D"hibernate.c3p0.min_size" value=3D"5"/> + <property name=3D"hibernate.c3p0.max_size" value=3D"20"/> + <property name=3D"hibernate.c3p0.timeout" value=3D"1800"/> + <property name=3D"hibernate.c3p0.max_statements" value=3D"50"/= > + </properties-param> + </init-params> +</component> +
+ +
+ Register custom Hibernate XML files into the service + + 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 hiber= nate + session in a ThreadLocal object during all the request lifecycle. To d= o so + you just have to add a plugin and indicate the location of your + files. + + <?xml version=3D"1.0" encoding=3D"ISO-8859-1"?> +<configuration> + <external-component-plugins> + <target-component>org.exoplatform.services.database.HibernateSer= vice</target-component> + <component-plugin> = + <name>add.hibernate.mapping</name> + <set-method>addPlugin</set-method> + <type>org.exoplatform.services.database.impl.AddHibernateMappi= ngPlugin</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/Membersh= ipImpl.hbm.xml</value> + <value>org/exoplatform/services/organization/impl/GroupImp= l.hbm.xml</value> + <value>org/exoplatform/services/organization/impl/Membersh= ipTypeImpl.hbm.xml</value> + <value>org/exoplatform/services/organization/impl/UserProf= ileData.hbm.xml</value> + </values-param> + </init-params> + </component-plugin> + </external-component-plugins> = +</configuration> +
+
Added: jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules= /core/db-schema-creator-service.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/db-schema-creator-service.xml (rev 0) +++ jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/db-schema-creator-service.xml 2010-07-30 15:13:44 UTC (rev 2846) @@ -0,0 +1,48 @@ + + + + DB Schema creator service (JDBC implementation) + + DB Schema Creator is responsible for database schema creating usin= g a + DDL script inside service configuration or in an external file, + calling: + + org.exoplatform.services.database.jdbc.DBSchemaCreator= .createTables(String dsName, String script) + + via + + org.exoplatform.services.database.jdbc.CreateDBSchemaPlu= gin component plugin + + A configuration example: + + <component> + <key>org.exoplatform.services.database.jdbc.DBSchemaCreator</k= ey> + <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.CreateDBSchema= Plugin</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> + ........ + + An example of a DDL script: + + 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); + Added: jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules= /core/ldap-configuration.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/ldap-configuration.xml (rev 0) +++ jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/ldap-configuration.xml 2010-07-30 15:13:44 UTC (rev 2846) @@ -0,0 +1,849 @@ + + + + LDAP Configuration + +
+ Overview + + You may decide that you want eXo users to be mapped to an existi= ng + directory. eXo provides a flexible implementation of its + OrganizationService on top of LDAP. It can be used on any LDAP complia= nt + directory and even Active Directory. This page will guide you how to + configure eXo Platform to work with your directory. +
+ +
+ Quickstart + + 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. + + You need to have a working ldap server and a user with write + permissions. + + + + Open exo-tomcat/webapps/portal/WEB-INF/conf/configuration= .xml + and replace: + + + + <import>war:/conf/organization/hibernate-configu= ration.xml</import> + + With + + <import>war:/conf/organization/ldap-configuratio= n.xml</import> + + + + 0pen ldap-configuration.xml and + update the providerURL, rootdn and password settings according to= your + environment + + + + <field name=3D"providerURL"><string>ldap:/= /127.0.0.1:389</string></field> +<field name=3D"rootdn"><string>CN=3DManager,DC=3DMyCompany,DC= =3Dcom</string></field> +<field name=3D"password"><string>secret</string></fie= ld> + + + + Delete exo-tomcat/temp/* = to + have a clean database and then start tomcat. + + + + eXo starts and autocreates its organization model in your direct= ory + tree. Finally the structure of the default LDAP schema looks like: + + + + + + + + That's it! Now eXo uses your LDAP directory as its org model + storage. Users, groups and memberships are now stored and retrieved fr= om + there. We suggest that you complete some guideline functions with eXo = user + management portlet and see what it changes in your directory tree. +
+ +
+ Configuration + + 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. + + The configuration is done in ldap-configuration.xml file, and this chapter= will + explain the numerous parameters it contains. + +
+ Connection Settings + + Firstly, start by connection settings which will tell eXo how = to + connect to your directory server. These settings are very close to + JNDI + API>http://java.sun.com/products/jndi context parameters. + This configuration is activated by the init-param ldap.config of ser= vice + LDAPServiceImpl. + + <component> + <key>org.exoplatform.services.ldap.LDAPService</key> + <type>org.exoplatform.services.ldap.impl.LDAPServiceImpl</type&= gt; + <init-params> + <object-param> + <name>ldap.config</name> + <description>Default ldap config</description> + <object type=3D"org.exoplatform.services.ldap.impl.LDAPConnection= Config"> + <field name=3D"providerURL"><string>ldap://127.0.0.1:3= 89,10.0.0.1:389</string></field> + <field name=3D"rootdn"><string>CN=3DManager,DC=3Dexopl= atform,DC=3Dorg</string></field> + <field name=3D"password"><string>secret</string>= </field> + <!-- field name=3D"authenticationType"><string>simple= </string></field--> = + <field name=3D"version"><string>3</string></f= ield> + <field name=3D"referralMode"><string>follow</strin= g></field> = + <!-- field name=3D"serverName"><string>active.directo= ry</string></field--> + </object> + </object-param> + </init-params> +</component> + + + + providerURL: LDAP serve= r URL + (see PROVIDER_URL>http://java.su= n.com/products/jndi/1.2/javadoc/javax/naming/Context.html#PROVIDER_URL). + For multiple ldap servers, use comma separated list of host:port + (Ex. ldap://127.0.0.1:389,10.0.0.1:389). + + + + rootdn: dn of user that= will + be used by the service to authenticate on the server (see SECURITY_PRINCIPAL= >http://java.sun.com/products/jndi/1.2/javadoc/javax/naming/Context.html= #SECURITY_PRINCIPAL). + + + + password: password for = user + rootdn (see SECURITY_CREDE= NTIALS>http://java.sun.com/products/jndi/1.2/javadoc/javax/naming/Contex= t.html#SECURITY_CREDENTIALS). + + + + authenticationType: typ= e of + authentication to be used (see SECURITY= _AUTHENTICATION>http://java.sun.com/products/jndi/1.2/javadoc/javax/nami= ng/Context.html#SECURITY_AUTHENTICATION). + Use one of none, simple, strong. Default is simple. + + + + version: LDAP protocol + version (see java.naming.ldap.version>http://ja= va.sun.com/products/jndi/tutorial/ldap/misc/version.html). + Set to 3 if your server supports LDAP V3. + + + + referalMode: one of fol= low, + ignore,throw (see REFERRAL>http://java.sun.com/produc= ts/jndi/1.2/javadoc/javax/naming/Context.html#REFERRAL). + + + + serverName: you will ne= ed to + set this to active.directory in order to work with Active Direct= ory + servers. Any other value will be ignore and the service will act= as + on a standard LDAP. + + +
+ +
+ Organization Service Configuration + + Next, you need to configure the eXo OrganizationService to tell him how the dir= ectory + is structured and how to interact with it. This is managed by a coup= le + of of init-params : ldap.userDN.key and + ldap.attribute.mapping in file + ldap-configuration.xml (by default + located at portal.war/WEB-INF/conf/organization) + + <component> + <key>org.exoplatform.services.organization.OrganizationService<= /key> + <type>org.exoplatform.services.organization.ldap.OrganizationServi= ceImpl</type> + [...] + <init-params> + <value-param> + <name>ldap.userDN.key</name> + <description>The key used to compose user DN</description&g= t; + <value>cn</value> + </value-param> + <object-param> + <name>ldap.attribute.mapping</name> + <description>ldap attribute mapping</description> + <object type=3D"org.exoplatform.services.organization.ldap.LDAPAt= tributeMapping"> + [...] + </object-param> + </init-params> + [...] +</component> + + ldap.attribute.mapping maps= your + ldap to eXo. At first there are two main parameters to configure in + it: + + <field name=3D"baseURL"><string>dc=3Dexo= platform,dc=3Dorg</string></field> +<field name=3D"ldapDescriptionAttr"><string>description</st= ring></field> + + + + baseURL: root dn for eXo + organizational entities. This entry can't be created by eXo and = must + preexist in directory. + + + + ldapDescriptionAttr (si= nce + core 2.2+) : Name of a common attribute that will be used as + description for groups and membership types. + + + + + (since core 2.2+) : Name of a common attribute that will be = used + as description for groups and membership types. + + + Other parameters are discussed in the following sections. + +
+ Users + +
+ Main parameters + + Here are the main parameters to map eXo users to your + directory : + + <field name=3D"userURL"><string>ou= =3Dusers,ou=3Dportal,dc=3Dexoplatform,dc=3Dorg</string></field> +<field name=3D"userObjectClassFilter"><string>objectClass=3Dpe= rson</string></field> +<field name=3D"userLDAPClasses"><string>top,person,organizatio= nalPerson,inetOrgPerson</string></field> + + + + userURL : base dn f= or + users. Users are created in a flat structure under this base + with a dn of the form: ldap.userDN.key=3Dusername,userURL<= /para> + + + + Example : + + uid=3Djohn,cn=3DPeople,o=3DMyCompany,c=3Dcom + + However, if users exist deeply under userURL, eXo will be = able + to retrieve them. + + Example : + + uid=3Dtom,ou=3DFrance,ou=3DEMEA,cn=3DPeople,o=3D= MyCompany,c=3Dcom + + + + userObjectClassFilter: + Filter used under userURL branch to distinguish eXo user ent= ries + from others. + + + + Example : john and tom will be recognized as valid eXo use= rs + but EMEA and France entries will be ignored in the following sub= tree + : + + uid=3Djohn,cn=3DPeople,o=3DMyCompany,c=3Dcom + objectClass: person + =E2=80=A6 +ou=3DEMEA,cn=3DPeople,o=3DMyCompany,c=3Dcom + objectClass: organizationalUnit + =E2=80=A6 + ou=3DFrance,ou=3DEMEA,cn=3DPeople,o=3DMyCompany,c=3Dcom + objectClass: organizationalUnit + =E2=80=A6 + uid=3Dtom,ou=3DEMEA,cn=3DPeople,o=3DMyCompany,c=3Dcom + objectClass: person + =E2=80=A6 + + + + userLDAPClasses : c= omma + separated list of classes used for user creation. + + + + 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. + + Example : Adding the user Marry Simons could produce : + + uid=3Dmarry,cn=3Dusers,ou=3Dportal,dc=3Dexoplatf= orm,dc=3Dorg + objectclass: top + objectClass: person + objectClass: organizationalPerson + objectClass: inetOrgPerson + =E2=80=A6 +
+ +
+ User mapping + + The following parameters maps ldap attributes to eXo User = java + objects attributes. + + <field name=3D"userUsernameAttr"><strin= g>uid</string></field> +<field name=3D"userPassword"><string>userPassword</string&g= t;</field> +<field name=3D"userFirstNameAttr"><string>givenName</string= ></field> +<field name=3D"userLastNameAttr"><string>sn</string><= /field> = +<field name=3D"userDisplayNameAttr"><string>displayName</st= ring></field> +<field name=3D"userMailAttr"><string>mail</string></f= ield> + + + + userUsernameAttr: + username (login) + + + + userPassword: passw= ord + (used when portal authentication is done by eXo login + module) + + + + userFirstNameAttr: + firstname + + + + userLastNameAttr: + lastname + + + + userDisplayNameAttr: + displayed name + + + + userMailAttr: email + address + + + + Example : In the previous example, user Marry Simons could + produce : + + uid=3Dmarry,cn=3Dusers,ou=3Dportal,dc=3Dexoplatf= orm,dc=3Dorg + objectclass: top + objectClass: person + objectClass: organizationalPerson + objectClass: inetOrgPerson + =E2=80=A6 +
+
+ +
+ Groups + + eXo groups can be mapped to organizational or applicative gr= oups + defined in your directory. + + <field name=3D"groupsURL"><string>ou= =3Dgroups,ou=3Dportal,dc=3Dexoplatform,dc=3Dorg</string></field> +<field name=3D"groupLDAPClasses"><string>top,organizationalUni= t</string></field> +<field name=3D"groupObjectClassFilter"><string>objectClass=3Do= rganizationalUnit</string></field> + + + + groupsURL : base dn f= or eXo + groups + + + + Groups can be structured hierarchically under groupsURL. + + Example: Groups communication, communication/marketing and + communication/press would map to : + + ou=3Dcommunication,ou=3Dgroups,ou=3Dportal,dc=3Dex= oplatform,dc=3Dorg +=E2=80=A6 + ou=3Dmarketing,ou=3Dcommunication,ou=3Dgroups,ou=3Dportal,dc=3Dexoplatfo= rm,dc=3Dorg + =E2=80=A6 = + ou=3Dpress,ou=3Dcommunication,ou=3Dgroups,ou=3Dportal,dc=3Dexoplatform,d= c=3Dorg = + =E2=80=A6 + + + + groupLDAPClasses: com= ma + separated list of classes used for group creation. + + + + When creating a new group, an entry will be created with the + given objectClass attributes. The classes must define at least the + required attributes: ou, description and l. + + + l attribute corresponds to the City property in OU property + editor + + + Example : Adding the group human-resources could produce: + + ou=3Dhuman-resources,ou=3Dgroups,ou=3Dportal,dc=3D= exoplatform,dc=3Dorg + objectclass: top + objectClass: organizationalunit + ou: human-resources + description: The human resources department + l: Human Resources + =E2=80=A6 + + + + groupObjectClassFilter: + filter used under groupsURL branch to distinguish eXo groups f= rom + other entries. You can also use a complex filter if you + need. + + + + Example : groups WebDesign, WebDesign/Graphists and Sales co= uld + be retrieved in : + + l=3DParis,dc=3Dsites,dc=3Dmycompany,dc=3Dcom + =E2=80=A6 + ou=3DWebDesign,l=3DParis,dc=3Dsites,dc=3Dmycompany,dc=3Dcom + =E2=80=A6 + ou=3DGraphists,WebDesign,l=3DParis,dc=3Dsites,dc=3Dmycompany,dc=3Dcom + =E2=80=A6 +l=3DLondon,dc=3Dsites,dc=3Dmycompany,dc=3Dcom + =E2=80=A6 + ou=3DSales,l=3DLondon,dc=3Dsites,dc=3Dmycompany,dc=3Dcom + =E2=80=A6 +
+ +
+ Membership Types + + Membership types are the possible roles that can be assigned= to + users in groups. + + <field name=3D"membershipTypeURL"><string= >ou=3Dmemberships,ou=3Dportal,dc=3Dexoplatform,dc=3Dorg</string>&l= t;/field> = +<field name=3D"membershipTypeLDAPClasses"><string>top,organiza= tionalRole</string></field> +<field name=3D"membershipTypeNameAttr"><string>cn</string&g= t;</field> + + + + + + membershipTypeURL : b= ase dn + for membership types storage. + + + + eXo stores membership types in a flat structure under + membershipTypeURL. + + Example : Roles manager, user, admin and editor could by def= ined + by the subtree : + + ou=3Droles,ou=3Dportal,dc=3Dexoplatform,dc=3Dorg +=E2=80=A6 + cn=3Dmanager,ou=3Droles,ou=3Dportal,dc=3Dexoplatform,dc=3Dorg + =E2=80=A6 + cn=3Duser,ou=3Droles,ou=3Dportal,dc=3Dexoplatform,dc=3Dorg + =E2=80=A6 + cn=3Dadmin,ou=3Droles,ou=3Dportal,dc=3Dexoplatform,dc=3Dorg = = + =E2=80=A6 + cn=3Deditor,ou=3Droles,ou=3Dportal,dc=3Dexoplatform,dc=3Dorg + =E2=80=A6 + + + + membershipTypeLDAPClasses: + comma separated list of classes for membership types + creation. + + + + When creating a new membership type, an entry will be created + with the given objectClass attributes. The classes must define the + required attributes : description, + cn + + Example : Adding membership type validator would produce + : + + cn=3Dvalidator,ou=3Droles,ou=3Dportal,dc=3Dexoplat= form,dc=3Dorg + objectclass: top + objectClass: organizationalRole + =E2=80=A6 + + + + membershipTypeNameAttr : + Attribute that will be used as the name of the role + + + + Example : If membershipTypeNameAttr is 'cn', then role name = is + 'manager' for the following membership type entry : + + cn=3Dmanager,ou=3Droles,ou=3Dportal,dc=3Dexoplatfo= rm,dc=3Dorg </pre> +
+ +
+ Memberships + + Memberships are used to assign a role within a group. They a= re + entries that are placed under the group entry of their scope group. + Users in this role are defined as attributes of the membership + entry. + + Example: To designate tom as the manager of the group + human-resources : + + ou=3Dhuman-resources,ou=3Dgroups,ou=3Dportal,dc=3D= exoplatform,dc=3Dorg + =E2=80=A6 + cn=3Dmanager,ou=3Dhuman-resources,ou=3Dgroups,ou=3Dportal,dc=3Dexoplatfo= rm,dc=3Dorg + member: uid=3Dtom,ou=3Dusers,ou=3Dportal,dc=3Dexoplatform,dc=3Dorg + =E2=80=A6 + + The parameters to configure memberships are : + + <field name=3D"membershipLDAPClasses"><st= ring>top,groupOfNames</string></field> +<field name=3D"membershipTypeMemberValue"><string>member</s= tring></field> = +<field name=3D"membershipTypeRoleNameAttr"><string>cn</stri= ng></field> +<field name=3D"membershipTypeObjectClassFilter"><string>object= Class=3DorganizationalRole</string></field> + + + + membershipLDAPClasses= : + comma separated list of classes used to create memberships. + + + + 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. + + Example : Adding membership validator would produce : + + cn=3Dvalidator,ou=3Dhuman-resources,ou=3Dgroups,ou= =3Dportal,dc=3Dexoplatform,dc=3Dorg + objectclass: top + objectClass: groupOfNames + =E2=80=A6 + + <pre> + cn=3Dvalidator,ou=3Dhuman-resources,ou=3Dgroups,ou=3Dportal,dc=3De= xoplatform,dc=3Dorg + objectclass: top objectClass: groupOfNames ... </pre> + + + + membershipTypeMemberValue: + Multivalued attribute used in memberships to reference users t= hat + have the role in the group. + + + + Values should be a user dn. + + Example: james and root have admin role within the group + human-resources, would give: + + cn=3Dadmin,ou=3Dhuman-resources,ou=3Dgroups,ou=3Dp= ortal,dc=3Dexoplatform,dc=3Dorg + member: cn=3Djames,ou=3Dusers,ou=3Dportal,dc=3Dexoplatform,dc=3Dorg + member: cn=3Droot,ou=3Dusers,ou=3Dportal,dc=3Dexoplatform,dc=3Dorg + =E2=80=A6 + + + + membershipTypeRoleNameAttr: + Attribute of the membership entry whose value references the + membership type. + + + + Example : In the following membership entry: + + <pre> + cn=3Dmanager,ou=3Dhuman-resources,ou=3Dgroups,ou=3Dportal,dc=3Dexo= platform,dc=3Dorg + </pre> + + '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. + + + + membershipTypeObjectClassFilter : Fil= ter + used to distinguish membership entries under groups. + + + + You can use rather complex filters. + + Example: Here is a filter we used for a customer that needed= to + trigger a dynlist overlay on openldap. + + (&amp;(objectClass=3DExoMembership)(membership= URL=3D*)) = + + + Note : Pay attention to the xml escaping of the '&' (and) + operator +
+ +
+ User Profiles + + eXo User profiles also have entries in the ldap but the actu= al + storage is still done with the hibernate service. You will need the + following parameters : + + <field name=3D"profileURL"><string>ou= =3Dprofiles,ou=3Dportal,dc=3Dexoplatform,dc=3Dorg</string></field&= gt; +<field name=3D"profileLDAPClasses"><string>top,organizationalP= erson</string></field> + + + + profileURL: base dn to + store user profiles + + + + profileLDAPClasses: C= lasses + used to when creating user profiles + + +
+
+
+ +
+ Advanced topics + +
+ Automatic directory population + + At startup eXo can populate the organization model based on + + 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 profileU= RL + 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 cla= sses + of the created entries, the following rules are applied : + + + + ou=3D... : objectClass=3Dtop,objectClass=3DorganizationalU= nit + + + + cn=3D... : objectClass=3Dtop,objectClass=3DorganizationalR= ole + + + + c=3D... : objectClass=3Dcountry + + + + o=3D... : objectClass=3Dorganization + + + + dc=3D.. : + objectClass=3Dtop,objectClass=3DdcObject,objectClass=3Dorganizat= ion + + + + Example: + + If baseURL is o=3DMyCompany,c=3Dcom + and groupsURL is dc=3Dgroups,cn=3DExtranet,c=3DFrance,ou=3DEMEA,o=3DMyC= ompany,c=3Dcom + then, the following subtree will be created : + + ou=3DEMEA,o=3DMyCompany,c=3Dcom + objectClass: top + objectClass: organizationalUnit + =E2=80=A6 + c=3DFrance,ou=3DEMEA,o=3DMyCompany,c=3Dcom + objectClass: top + objectClass: country + =E2=80=A6 + cn=3DExtranet,c=3DFrance,ou=3DEMEA,o=3DMyCompany,c=3Dcom + objectClass: top + objectClass: organizationalRole + =E2=80=A6 + dc=3Dgroups,cn=3DExtranet,c=3DFrance,ou=3DEMEA,o=3DMyCompany,c=3Dc= om + objectClass: top + objectClass: dcObject + objectClass: organization = + =E2=80=A6 +
+ +
+ Active Directory sample configuration + + Here is an alternative configuration for active directory that= you + can find in activedirectory-configuration.xml + + + There is a microsoft limitation: password can't be set in AD= via + unsecured connection you have to use the ldaps protocol + + + #info("There is a microsoft limitation: password can't be set = in + AD via unsecured connection you have to use the ldaps protocol") + + here is how to use LDAPS protocol with Active Directory : + + 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=3D"${JAVA_OPTS} -Djavax.net.ssl.trustStorePassword=3Dchang= eit -Djavax.net.ssl.trustStore=3D/home/user/java/jdk1.6/jre/lib/security/ca= certs" + + [...] + <component> + <key>org.exoplatform.services.ldap.LDAPService</key> +[..] + <object type=3D"org.exoplatform.services.ldap.impl.LDAPConnecti= onConfig"> = + <!-- for multiple ldap servers, use comma seperated list of ho= st: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 j= avax.net.ssl.keyStore & java.net.ssl.keyStorePassword properties are se= t --> + <!-- exo portal default installed javax.net.ssl.trustStore with fil= e 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 (E= x. active.directory) --> = + <field name=3D"providerURL"><string>ldaps://10.0.0.3:636&= lt;/string></field> + <field name=3D"rootdn"><string>CN=3DAdministrator,CN=3DUs= ers, DC=3Dexoplatform,DC=3Dorg</string></field> + <field name=3D"password"><string>site</string></= field> = + <field name=3D"version"><string>3</string></fiel= d> = + <field name=3D"referralMode"><string>ignore</string= ></field> = + <field name=3D"serverName"><string>active.directory<= ;/string></field> = + </object> +[..] + <component> + <key>org.exoplatform.services.organization.OrganizationService&l= t;/key> + [...] + <object type=3D"org.exoplatform.services.organization.ldap.LDAP= AttributeMapping"> = + [...] + <field name=3D"userAuthenticationAttr"><string>mail= </string></field> + <field name=3D"userUsernameAttr"><string>sAMAccount= Name</string></field> + <field name=3D"userPassword"><string>unicodePwd<= /string></field> = + <field name=3D"userLastNameAttr"><string>sn</str= ing></field> + <field name=3D"userDisplayNameAttr"><string>display= Name</string></field> + <field name=3D"userMailAttr"><string>mail</strin= g></field> + [..] + <field name=3D"membershipTypeLDAPClasses"><string>t= op,group</string></field> + <field name=3D"membershipTypeObjectClassFilter"><strin= g>objectClass=3Dgroup</string></field> + [..] + <field name=3D"membershipLDAPClasses"><string>top,g= roup</string></field> + <field name=3D"membershipObjectClassFilter"><string>= ;objectClass=3Dgroup</string></field> + </object> + [...] = +</component> +
+ +
+ OpenLDAP dynlist overlays + + If you use OpenLDAP, you may want to use the overlays + > http://www.openldap.org/faq/data/cache/1169.html. Here = is + how you can use the dynlist + overlay > http://www.openldap.org/faq/data/cache/1209.html to + have memberships dynamically populated. + + The main idea is to have your memberships populated dynamicall= y by + an ldap query. Thus, you no longer have to maintain manually the rol= es + on users. + + To configure the dynlist, add the following to your slapd.conf : + + dynlist-attrset ExoMembership membershipURL = member + + This snipet means : On entries that have ExoMembership class, = use + the URL defined in the value of attribute membershipURL as a query a= nd + populate results under the multivalues attribute member. + + Now let's declare the corresponding schema (replace XXXXX to a= dapt + to your own IANA code): + + attributeType ( 1.3.6.1.4.1.XXXXX.1.59 NAME 'members= hipURL' SUP memberURL ) + + membershipURL inherits from memberURL. + + objectClass ( 1.3.6.1.4.1.XXXXX.2.12 NAME 'ExoMembe= rship' SUP top MUST ( cn ) MAY (membershipURL $ member $ description ) ) + + ExoMembership must define cn and can have attributes : + + + + membershipURL: trigger for the dynlist + + + + member : attribute populated by the dynlist + + + + description : used by eXo for display + + + + # the TestGroup group +dn: ou=3Dtestgroup,ou=3Dgroups,ou=3Dportal,o=3DMyCompany,c=3Dcom +objectClass: top +objectClass: organizationalUnit +ou: testgroup +l: TestGroup +description: the Test Group + + On this group, we can bind an eXo membership where the overlay + will occur: + + # the manager membership on group TestGroup +dn: cn=3Dmanager, ou=3DTestGroup,ou=3Dgroups,ou=3Dportal,o=3DMyCompany,c= =3Dcom +objectClass: top +objectClass: ExoMembership +membershipURL: ldap:///ou=3Dusers,ou=3Dportal,o=3DMyCompany,c=3Dcom??sub?(= uid=3D*) +cn: manager + + This dynlist assigns the role manager:/testgroup to any user. +
+
+
Added: jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules= /core/organization-service-initalizer.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/organization-service-initalizer.xml (rev 0) +++ jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/organization-service-initalizer.xml 2010-07-30 15:13:44 UTC (rev 2846) @@ -0,0 +1,180 @@ + + + + Organization Service Initializer + + Use the Organization Service Initializer to create users, groups a= nd + membership types by default. + + <external-component-plugins> + <target-component>org.exoplatform.services.organization.Organiza= tionService</target-component> + <component-plugin> + <name>init.service.listener</name> + <set-method>addListenerPlugin</set-method> + <type>org.exoplatform.services.organization.OrganizationDataba= seInitializer</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</descripti= on> + <value>false</value> + </value-param> + <object-param> + <name>configuration</name> + <description>description</description> + <object type=3D"org.exoplatform.services.organization.Organiz= ationConfig"> + <field name=3D"membershipType"> + <collection type=3D"java.util.ArrayList"> + <value> + <object type=3D"org.exoplatform.services.organization= .OrganizationConfig$MembershipType"> + <field name=3D"type"> + <string>manager</string> + </field> + <field name=3D"description"> + <string>manager membership type</string> + </field> + </object> + </value> + </collection> + </field> + = + <field name=3D"group"> + <collection type=3D"java.util.ArrayList"> + <value> + <object type=3D"org.exoplatform.services.organization= .OrganizationConfig$Group"> + <field name=3D"name"> + <string>platform</string> + </field> + <field name=3D"parentId"> + <string></string> + </field> + <field name=3D"description"> + <string>the /platform group</string> + </field> + <field name=3D"label"> + <string>Platform</string> + </field> + </object> + </value> + <value> + <object type=3D"org.exoplatform.services.organization= .OrganizationConfig$Group"> + <field name=3D"name"> + <string>administrators</string> + </field> + <field name=3D"parentId"> + <string>/platform</string> + </field> + <field name=3D"description"> + <string>the /platform/administrators group<= /string> + </field> + <field name=3D"label"> + <string>Administrators</string> + </field> + </object> + </value> + </collection> + </field> + = + <field name=3D"user"> + <collection type=3D"java.util.ArrayList"> + <value> + <object type=3D"org.exoplatform.services.organization= .OrganizationConfig$User"> + <field name=3D"userName"> + <string>root</string> + </field> + <field name=3D"password"> + <string>exo</string> + </field> + <field name=3D"firstName"> + <string>Root</string> + </field> + <field name=3D"lastName"> + <string>Root</string> + </field> + <field name=3D"email"> + <string>root(a)localhost</string> + </field> + <field name=3D"groups"> + <string> + manager:/platform/administrators + </string> + </field> + </object> + </value> + </collection> + </field> + </object> + </object-param> + </init-params> + </component-plugin> + </external-component-plugins> + + Params for membership type: + + + + type - The membership type's name + + + + description - The membership type's description + + + + Params for group: + + + + name - The group's name + + + + parentId - The id of the parent group. If the parent id is nul= l, + it mean that the group is at the first level. The parentId should ha= ve + the form: /ancestor/parent + + + + description - The group's description + + + + label - The group's label + + + + Params for user: + + + + userName - The user's name + + + + password - The user's password + + + + firstName - The user's first name + + + + lastName - The user's last name + + + + email - The user's email + + + + groups - The user's membership types and groups in which he + consist. + + + Added: jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules= /core/organization-service-listener.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/organization-service-listener.xml (rev 0) +++ jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/organization-service-listener.xml 2010-07-30 15:13:44 UTC (rev 2846) @@ -0,0 +1,181 @@ + + + + Organization Listener + +
+ Overview + + The Organization + ServiceThe Core Organization Service provides a mechanism to + receive notifications when : + + + + a User is created, deleted or modified + + + + a Group is created, deleted or modified + + + + a Membership is created or removed + + + + This mechanism is very useful to cascade some actions when the + organization model is modified. For example, it is currently used to + : + + + + initialize the personal portal pages + + + + initialize the personal calendars, address books and mail + accounts in CS + + + + create drives and personal areas in ECM + + +
+ +
+ Writing your own listeners + + 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. + +
+ UserEventListener + + To listen to user changes, you need to extend + <>org.exoplatform.services.organization.UserEventListener</= > + : + + public class MyUserListener extends UserEventListene= r { + + 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?" creat= ed":" 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()); + } + +} +
+ +
+ GroupEventListener + + To listen to group changes, you need to extend + <>org.exoplatform.services.organization.GroupEventListener<= /> + : + + public class MyGroupListener extends GroupEventListe= ner { + + 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()); + } +} +
+ +
+ MembershipEventListener + + To listen to membership changes, you need to extend + <>org.exoplatform.services.organization.MembershipEventListene= r</> + : + + public class MyMembershipListener extends Membership= EventListener { + + public void preSave(Membership membership, boolean isNew) throws Excepti= on { + System.out.println("Before " + (isNew?"creating":"updating") + " membe= rship."); + } + + public void postSave(Membership membership, boolean isNew) throws Except= ion { = + 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"); + } +} +
+
+ +
+ Registering your listeners + + Registering the listeners is then achieved by using the ExoConta= iner + plugin mechanism. Learn more about it on the Service Configurati= on for + Beginners article. + + To effectively register organization service's listeners you sim= ply + need to use the <>addListenerPlugin</> seer injector. + + So, the easiest way to register your listeners is to pack them i= nto + a .jar and create a configuration file into it under mylisteners.jar!/conf/portal/configuration.xml + + <?xml version=3D"1.0" encoding=3D"ISO-8859-1"?> +<configuration> + <external-component-plugins> + <target-component>org.exoplatform.services.organization.Organizati= onService</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> + + Now, simply deploy the jar under $TOMCAT_HOME/lib and your liste= ners + are ready! +
+
Added: jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules= /core/organization-service.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/organization-service.xml (rev 0) +++ jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/organization-service.xml 2010-07-30 15:13:44 UTC (rev 2846) @@ -0,0 +1,148 @@ + + + + Organization Service + +
+ Overview + + OrganizationService is the service that allows to access the + Organization model. This model is composed of : + + + + Users + + + + Groups + + + + Memberships + + + + 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 : + + + + hibernate : for storage into a RDBMS + + + + jndi : for storage into a directory such as an LDAP or MS Ac= tive + Directory + + + + jcr : for storage inside a Java Content Repository + + +
+ +
+ Organizational Model + +
+ User + + + + username used as the identified + + + + Profile (identity and preferences) + + +
+ +
+ Group + + Gather a set of users + + + + applicative or business + + + + tree structure + + + + no inheritance + + + + expressed as /group/subgroup/subsubgroup + + +
+ +
+ Membership + + + + qualifies the group belonging + + + + "Member of group as XXX" + + + + expressed as : manager:/organization/hr, *:/partners + + +
+
+ +
+ Related articles and how-tos + + + + JCR + Organization Service + + + + + + Update + ConversationState when user's Membership changed + + + + Organization + Service Initializer + + + + How + to Access User Profile in your code + + + + How to create your o= wn + Organization Listener + + + + H= ow to + manipulate Users and Memberships Programmatically + + +
+
Added: jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules= /core/security-service.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/security-service.xml (rev 0) +++ jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/security-service.xml 2010-07-30 15:13:44 UTC (rev 2846) @@ -0,0 +1,309 @@ + + + + Security Service + +
+ 1 Overview + + The purpose is to make a simple, unified way for the authenticat= ion + and the storing/propagation of user sessions through all the eXo + components and J2EE containers. JAAS is supposed to be the primary log= in + mechanism but the Security Service framework should not prevent other + (custom or standard) mechanisms from being used. You can learn more ab= out + JAAS in the Java + Tutorial>http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/tu= torials/GeneralAcnAndAzn.html +
+ +
+ 1 Framework + + The central point of this framework is the ConversationState 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 Identity which is = a set + of principals to identify a user. + + 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. + +
+ 1.1 ConversationState and ConversationRegistry + + The ConversationState can be stored + + + + in a static local thread + variable, or + + + + as a key-value pair in = the + ConversationRegistry + component. + + + + 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 bef= ore + you try to use it. + + Local Thread Variable Stori= ng the + ConversationState in a static local thread variable makes it possibl= e to + represent it as a context (current + user's state). + + ConversationState.setCurrent(conversationState); +.... +ConversationState.getCurrent(); + + Key-Value way + + If you store the ConversationState inside the ConversationRegistry component as a set of + key-value pairs, the session key is an arbitrary String (user name, + ticket id, httpSessionId etc). + + conversationRegistry.register("key", conversationSta= te); = +... +conversationRegistry.getState("key"); + + ConversationRegistry The + ConversationRegistry is a mandatory component deployed into eXo + Container as following: + + <component> + <type>org.exoplatform.services.security.ConversationRegistry<= /type> +</component> +
+ +
+ 1.1 Authenticator + + An Authenticator is responsible for Identity creating, it cont= ains + two methods: + + + + validateUser() accepts an array of credentials and returns= the + userId (which can be something different from the username). + + + + createIdentity() accepts the userId and returns a newly + created Identity object. + + + + public interface Authenticator { + /** + * Authenticate user and return userId which can be different to usernam= e. = + * @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, Exc= eption; + + /** + * @param credentials - userId. + * @return Identity + * @throws Exception + */ + Identity createIdentity(String userId) throws Exception; = + +} + + It is up to the application developer (and deployer) whether to + use the Authenticator component(s) and how many implementations of t= his + components should be deployed in eXo container. The developer is fre= e to + create an Identity object using a different way, but the Authenticat= or + component is the highly recommended way from architectural + considerations. + + Typical functionality of the validateUser(Credential\[] + credentials) method is the comparison of incoming credentials + (username/password, digest etc) with those credentials that are stor= ed + in an implementation specific database. Then validateUser(Credential= \[] + credentials) returns back the userId or throws a LoginException in a + case of wrong credentials. + + Default Authenticator implementation is + org.exoplatform.services.organization.auth.OrganizationAuthenticator= Impl + which compares incoming username/password credentials with the ones + stored in OrganizationService. Configuration example: + + <component> + <key>org.exoplatform.services.security.Authenticator</key> = + <type>org.exoplatform.services.organization.auth.OrganizationAuthe= nticatorImpl</type> +</component> +
+
+ +
+ Usage + +
+ JAAS login module + + 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): + + + + LoginModule.login() creates a list of credentials using + standard JAAS Callbacks features, obtains an Authenticator insta= nce, + and creates an Identity object calling + Authenticator.authenticate(..) method + + + + Authenticator authenticator =3D (Authenticator) cont= ainer() + .getComponentInstanceOfType(Authenticator.class); = +// RolesExtractor can be null = +RolesExtractor rolesExtractor =3D (RolesExtractor) container(). +getComponentInstanceOfType(RolesExtractor.class); + + +Credential[] credentials =3D new Credential[] {new UsernameCredential(user= name), new PasswordCredential(password) }; +String userId =3D authenticator.validateUser(credentials); +identity =3D authenticator.createIdentity(userId); + + + + LoginModule.commit() obtains the IdentityRegistry object, = and + register the identity using userId as a key. + + + + 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. + + By default singleLogin is disabled, so the same identity can be + registered more than one time. Parameter can be passed in this form + singleLogin=3Dyes or singleLogin=3Dtrue. + + IdentityRegistry identityRegistry =3D (IdentityRegis= try) getContainer().getComponentInstanceOfType(IdentityRegistry.class); + = +if (singleLogin && identityRegistry.getIdentity(identity.getUserId= ()) !=3D null) = + throw new LoginException("User " + identity.getUserId() + " already logi= ned."); + +identity.setSubject(subject); +identityRegistry.register(identity); + + In the case of using several LoginModules, JAAS allows to place + the login() and commit() methods in different REQUIRED modules. + + After that, the web application must use SetCurrentIdentityFil= ter. + 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 on= e, + register it and set it as current one using + ConversationState.setCurrent(state). + + + + LoginModule.logout() can be called by + JAASConversationStateListener, it extends + ConversationStateListener. + + + + This listener must be configured in web.xml. The method + sessionDestroyed(HttpSessionEvent)is called by the ServletContainer. + This method removes the ConversationState from the ConversationRegis= try + ConversationRegistry.unregister(sesionId) and calls the method + LoginModule.logout(). + + ConversationRegistry conversationRegistry =3D (Conve= rsationRegistry) getContainer().getComponentInstanceOfType(ConversationRegi= stry.class); + +ConversationState conversationState =3D conversationRegistry.unregister(se= sionId); + +if (conversationState !=3D null) { + log.info("Remove conversation state " + sesionId); + if (conversationState.getAttribute(ConversationState.SUBJECT) !=3D null)= { + Subject subject =3D (Subject) conversationState.getAttribute(Conversat= ionState.SUBJECT); = + LoginContext ctx =3D new LoginContext("exo-domain", subject); + ctx.logout(); +} else { + log.warn("Subject was not found in ConversationState attributes."); +} + + +
+ +
+ 1.1 Predefinded JAAS login modules + + There are several JAAS Login modules included in eXo Platform + sources: + + org.exoplatform.services.security.jaas.DefaultLoginMod= ule + 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. + + TODO: configuration examples for Tomca= t, + JBoss, Jonas and WebSphere + + Besides that, for the case when third party authentication + mechanism required, we have org.exoplatform.services.security.jaas.IdentitySetLogi= nModule, + which catches a login identity from third party "authenticating" log= in + module and preforms eXo specific authorization job. In this case thi= rd + party login module has to put login (user) name to the shared state = map + under "javax.security.auth.login.name" + key and third party LM has to be configured before + IdentitySetLoginModule like: + + exo { + com.third.party.LoginModuleImpl required; + org.exoplatform.services.security.jaas.IdentitySetLoginModule required; +}; +
+ +
+ 1.1 J2EE container authentication + + 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. + + To make it workable for the particular J2EE server it is neces= sary + to add specific Principals/Credentials to the Subject to be propagat= ed + into the specific J2EE container implementation. We extended the + DefaultLoginModule by overloading its commit() method with a dedicat= ed + logic, presently available for Tomcat, JBOSS and JONAS application + servers. + + Furthermore you can use the optional RolesExtractor which is + responsible for mapping primary Subject's principals (userId and a s= et + of groups) to J2EE Roles: + + public interface RolesExtractor { + Set <String> extractRoles(String userId, Set<MembershipEntry>= ; memberships); +} + + This component may be used by Authenticator to create the Iden= tity + with a particular set of Roles. +
+
+
Added: jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules= /core/spring-security-integration.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/spring-security-integration.xml (rev 0) +++ jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re/spring-security-integration.xml 2010-07-30 15:13:44 UTC (rev 2846) @@ -0,0 +1,670 @@ + + + + Spring Security Integration + +
+ Introduction + + How to Integrate the spring security framework in the eXo + portal? + + 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. Moreove= r, + 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. +
+ +
+ Installation + + This tutorial assumes that you have a working eXo WCM installati= on + running under JBoss 4.2.x. + + Download the spring framework: http://s3.amazonaws.com/dist.sp= ringframework.org/release/SPR/spring-framework-2.5.6-with-dependencies.zip<= /ulink> + + Download spring-security: http://sourceforge.net/proj= ect/showfiles.php?group_id=3D73357&package_id=3D270072&release_id= =3D630203 + + Unzip the 02portal.war file in the jboss + server/default/deploy/exoplatform.sar directory and copy the following + jars in WEB-INF/lib: + + + + spring.jar + + + + spring-security-core.jar + + + + aspectjrt-1.5.4.jar + + + + exo-spring.jar (contains the filters and event handlers + described in this tutorial - see the attachment section of this + page) + + +
+ +
+ Configuration + + To enable spring security in exo we need to go through a few + configuration steps: + +
+ JAAS disabling + + 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: + + ... + <session-config> + <session-timeout>15</session-timeout> + </session-config> + + <!-- + <security-constraint> + <web-resource-collection> + <web-resource-name>user authentication</web-resource-nam= e> + <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&g= t; + <form-error-page>/login/jsp/login.jsp</form-error-page&g= t; + </form-login-config> + </login-config> + --> + + <security-role> + <description>a simple user role</description> + <role-name>users</role-name> + </security-role> +... +
+ +
+ Enabling spring security + + To enable spring and set the spring security filter, add the + following lines: + + ... + <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.ContextLoaderL= istener</listener-class> + </listener> + + <filter> + <filter-name>springSecurityFilterChain</filter-name> + <filter-class>org.springframework.web.filter.DelegatingFilterP= roxy</filter-class> + </filter> +... + + Activate the spring security filter at the right position, i.e. + just after the filter responsible of exo container + initialization. + + ... + <filter-mapping> + <filter-name>PortalContainerInitializedFilter</filter-name&= gt; + <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> +... +
+ +
+ security-context.xml + + 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: + + <?xml version=3D"1.0" encoding=3D"UTF-8"?> +<beans:beans xmlns=3D"http://www.springframework.org/schema/security" + xmlns:beans=3D"http://www.springframework.org/schema/beans" + xmlns:xsi=3D"http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation=3D"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=3D"true"> + <intercept-url pattern=3D"/private/**" access=3D"ROLE_USER" />= = + <form-login login-page=3D'/public/classic/Login' default-target-u= rl=3D'/private/classic/home' /> + </http> + = + <authentication-provider> + <user-service> + <user name=3D"rod" password=3D"koala" authorities=3D"ROLE_SUPE= RVISOR, ROLE_USER, ROLE_TELLER" /> + <user name=3D"root" password=3D"exo" authorities=3D"ROLE_USER"= /> + </user-service> + </authentication-provider> = + +</beans:beans> + + The file contains two elements. The http node which is respons= ible + of configuring the filter chain. The auto-config mode set to true al= lows + 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 secu= red + resources in exo. In case of successful auhentication, the user will= be + redirected to the specified default target URL. + + The second element defines a simple authentication provider ba= sed + 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. +
+
+ +
+ Login portlet example + + 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. + +
+ Building the portlet + + So we need a login form to capture user credentials inputs. The + portlet login form consists of the following lines of xml: + + <f:view xmlns:f=3D"http://java.sun.com/jsf/core" + xmlns:h=3D"http://java.sun.com/jsf/html" + xmlns:ice=3D"http://www.icesoft.com/icefaces/component" + xmlns:liferay-faces=3D"http://liferay.com/tld/faces" + xmlns:ui=3D"http://java.sun.com/jsf/facelets" + xmlns:c=3D"http://java.sun.com/jstl/core" + xmlns:fn=3D"http://java.sun.com/jsp/jstl/functions" + xmlns:t=3D"http://myfaces.apache.org/tomahawk"> = + = + <style type=3D"text/css" media=3D"screen"> = + @import "/loginportlet/css/starter.css"; + @import "/loginportlet/css/uni-form.css"; + </style> + + <script src=3D"/loginportlet/js/jquery.js" type=3D"text/javascript"&= gt;</script> + <script src=3D"/loginportlet/js/uni-form.jquery.js" type=3D"text/jav= ascript"></script> + = + <h:form styleClass=3D"uniForm" > + <fieldset class=3D"inlineLabels"> + <legend>Sign in</legend> = + + <div class=3D"ctrlHolder"> = + <h:outputLabel for=3D"login" style=3D"width: 70px"><e= m>*</em>Login:</h:outputLabel> + <h:inputText id=3D"login" value=3D"#{loginBean.login}" requ= ired=3D"true" styleClass=3D"textInput" /> = + <h:message for=3D"login" styleClass=3D"portlet-msg-error" /= > + </div> + <div class=3D"ctrlHolder"> = + <h:outputLabel for=3D"password" style=3D"width: 70px">&l= t;em>*</em>Password:</h:outputLabel> + <h:inputSecret id=3D"password" value=3D"#{loginBean.passwd}= " required=3D"true" styleClass=3D"textInput" /> + <h:message for=3D"password" styleClass=3D"portlet-msg-error= " /> = + </div> = + </fieldset> + = + <div class=3D"buttonHolder" style=3D"margin-top: 20px; margin-rig= ht: 20px"> + <h:commandButton styleClass=3D"primaryAction" value=3D"Submit"= action=3D"#{loginBean.login}" /> = + </div> + </h:form> +</f:view> + + The interesting part resides in the backing bean which impleme= nts + the login action triggered when the user clicks the login form submit + button. + + package org.exoplatform.loginportlet; + +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Controller; + +(a)Controller +(a)Scope("request") +public class LoginBean { + + String login; + + String passwd; + + public String login() throws Exception { + String redirect =3D "/portal/j_spring_security_check?j_username=3D= " + login + "&j_password=3D" + passwd; + PortalUtils.sendRedirect(redirect); = + return null; + } + + ... +} + + 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. +
+ +
+ Setting up the login portal page + + Now that we have a login portlet available we need to set it up + into a portal page. + + + + Log in as root in exo portal. + + + + Go to application registry and import the loginportlet + + + + Add a new hidden page named 'Login' under the portal class= ic's + navigation (read more on page creation here>WCM.Tutorial). 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. + + + + Finally, drag & drop the login portlet in the page with + the desired layout. + + +
+ +
+ Customization of portal login and logout urls + + In the portal header there is a login or logout action display= ed + depending whether you are already logged in or not. We need to custo= mize + 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 follow= ing + changes to the code: + + function validateUser() { + + var user =3D eXo.env.portal.userName; + var rootObj =3D document.getElementById("classic-access"); + var loginContentObj =3D eXo.core.DOMUtil.findFirstDescendantByClass(ro= otObj, "div", "UIWCMLoginPortlet"); + var welcomeObj =3D eXo.core.DOMUtil.findFirstDescendantByClass(rootObj= , "span", "Welcome"); + var userObj =3D eXo.core.DOMUtil.findFirstDescendantByClass(rootObj, "= span", "LoggedUser"); + var languageObj =3D eXo.core.DOMUtil.findFirstDescendantByClass(rootOb= j, "a", "LanguageIcon"); + var logXXXObj =3D eXo.core.DOMUtil.findPreviousElementByTagName(langua= geObj, "a"); + + if (user !=3D "null") { + welcomeObj.innerHTML =3D "Welcome: "; = + userObj.innerHTML =3D user; + logXXXObj.innerHTML =3D "Logout"; + if (eXo.core.DOMUtil.hasClass(logXXXObj, "LoginIcon")) { + eXo.core.DOMUtil.removeClass(logXXXObj, "LoginIcon"); + eXo.core.DOMUtil.addClass(logXXXObj, "LogoutIcon"); + } + logXXXObj.onclick =3D function() { document.location.href =3D '/po= rtal/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 =3D "Login"; + logXXXObj.onclick =3D function() { document.location.href =3D '/po= rtal/public/classic/Login' }; + } + + languageObj.onclick =3D function () { if(document.getElementById('UIMa= skWorkspace')) ajaxGet(eXo.env.server.createPortalURL('UIPortal', 'ChangeLa= nguage', true)); } +} + +eXo.core.Browser.addOnLoadCallback("validateUser", validateUser); + + 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. +
+ +
+ A look at the login page + + 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: + + + + + + +
+
+ +
+ Integration strategies + + 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: + + 1.1.1 Direct integration We c= an + 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 authentica= tion + process itself is encapsulated in the Authenticator abstraction which = sits + on top of the organization service. eXo provides several implementatio= ns + 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 th= em + and fits them to your needs with a matter of a little configuration. Y= ou + can even develop a custom implementation to meet your more specific + needs. + +
+ Replication + + Or we can go through a replication process between the external + realm and the eXo platform realm. This is the strategy that we are g= oing + to use to build our login portlet example. Furthermore the replicati= on + will occur dynamically on any user authentication attempt. +
+
+ +
+ Integration with eXo portal + + Being successfully authenticated against an external realm is not + sufficient by itself. We also need to propagate the newly created secu= rity + context to the portal own security mechanism. In eXo portal terminolog= y, + it means we have to create an Identity object for the user and registe= r it + into the Identity Registry. + + Spring framework provides a simple notification model where a be= an + 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. + + Furthermore, we need to replicate the user details from the exte= rnal + realm to the eXo portal one according to the integration strategy defi= ned + above. + + We create a SpringSecurityEventHandler bean that implements the + ApplicationListener interface and listens to the + InteractiveAuthenticationSuccessEvent event. + + package org.exoplatform.spring.security.web; + +... + +public class SpringSecurityEventHandler implements ApplicationListener { + + private String portalContainerName =3D "portal"; + + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof InteractiveAuthenticationSuccessEvent) { + try { + InteractiveAuthenticationSuccessEvent successEvent =3D (In= teractiveAuthenticationSuccessEvent) event; + ExoContainer container =3D getContainer(); + + String login =3D successEvent.getAuthentication().getName(= ); + String passwd =3D successEvent.getAuthentication().getCred= entials().toString(); + + IdentityRegistry identityRegistry =3D (IdentityRegistry) c= ontainer.getComponentInstanceOfType(IdentityRegistry.class); + Authenticator authenticator =3D (Authenticator) container.= getComponentInstanceOfType(Authenticator.class); + OrganizationService orgService =3D (OrganizationService) c= ontainer.getComponentInstanceOfType(OrganizationService.class); + + User user =3D orgService.getUserHandler().findUserByName(l= ogin); + if (user =3D=3D null) { + user =3D orgService.getUserHandler().createUserInstanc= e(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 =3D authenticator.createIdentity(login); + + Subject subject =3D 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 =3D ExoContainerContext.getCurrentContainer= (); + if (container instanceof RootContainer) { + container =3D RootContainer.getInstance().getPortalContainer(p= ortalContainerName); + } + return container; + } + +... + +} + + 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 integrati= on + 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 por= tal + aware of the user logging in. + + Registering our bean is done the usual way in security-context.x= ml + file: + + ... +<beans:bean id=3D"myEventHandler" class=3D"org.exoplatform.spring.secur= ity.web.SpringSecurityEventHandler" /> +... +
+ +
+ Security context propagation to portlets + + Part of the problem is the question of security context propagat= ion + between on one side the portal webapp and at the other side the portle= ts + webapps. This means that the security context has to be available in t= he + portlet side allowing the application logic to deal the with current u= ser + principal and granted authorities. By default Spring security uses a + thread local variable to partially achieve this. But a problem may ari= se + due to the fact that the portal invokes the portlet through a webapp c= ross + context call. This means that it can lead to a class cast exceptions (= two + different classloaders involved), or that the security context is simp= ly + 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. + +
+ Portal side filter + + We will use the spring security extensible filter chain to plu= g in + our filter. + + package org.exoplatform.spring.security.web; + +... + +public class PortalSideSecurityContextFilter extends SpringSecurityFilter { + + @Override + protected void doFilterHttp(HttpServletRequest request, HttpServletRes= ponse response, FilterChain chain) throws IOException, ServletException { + //fill request with security context + SecurityContext context =3D SecurityContextHolder.getContext(); = = + request.setAttribute(HttpSessionContextIntegrationFilter.SPRING_S= ECURITY_CONTEXT_KEY, context); = + = + //fill request with security last exception + Object e =3D request.getSession().getAttribute(AbstractProcessing= Filter.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; + } +} + + The PortalSideSecurityContextFilter simply fills the request w= ith + 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 attribut= e to + check if a security exception has occured. + + The following lines in the security-context file register our + custom filter in the chain at the last position. + + ... + <beans:bean id=3D"myCustomFilter" class=3D"org.exoplatform.spring.se= curity.web.PortalSideSecurityContextFilter"> + <custom-filter after=3D"LAST" /> + </beans:bean> +... +
+ +
+ Portlet side filter + + In the portlet webapp we create a regular filter named + PortletSideSecurityContextFilter. + + 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 =3D request.getAttribute(HttpSessionContextIntegrati= onFilter.SPRING_SECURITY_CONTEXT_KEY); + SecurityContext context =3D (SecurityContext) serializeDeserialize= (object); + if (context !=3D 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 =3D null; = + try { + ByteArrayOutputStream bout =3D new ByteArrayOutputStream(); + ObjectOutputStream out =3D new ObjectOutputStream(bout); + + out.writeObject(obj); + + ByteArrayInputStream bin =3D new ByteArrayInputStream(bout.= toByteArray()); + ObjectInputStream in =3D new ObjectInputStream(bin); + + result =3D in.readObject(); = + } catch (Exception e) { + //TODO: handle exception + } + return result; + } + = +} + + 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 contex= t is + simply set or cleared whether the context is null or not. + + To register your filter simply add the following lines to your + portlet webapp web.xml file. + + ... + <filter> + <filter-name>portletSideSecurityContextFilter</filter-name&= gt; + <filter-class>org.exoplatform.spring.security.web.PortletSideS= ecurityContextFilter</filter-class> + </filter> + = + <filter-mapping> + <filter-name>portletSideSecurityContextFilter</filter-name&= gt; + <url-pattern>/*</url-pattern> + <dispatcher>REQUEST</dispatcher> + <dispatcher>INCLUDE</dispatcher> + <dispatcher>FORWARD</dispatcher> + </filter-mapping> +... +
+
+ +
+ Conclusion + + 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 l= ook + to the attachment section on this page and get the source code of this + tutorial. +
+
Modified: jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modu= les/core.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re.xml 2010-07-30 13:29:37 UTC (rev 2845) +++ jcr/branches/1.12.x/docs/reference/en/src/main/docbook/en-US/modules/co= re.xml 2010-07-30 15:13:44 UTC (rev 2846) @@ -8,8 +8,41 @@ = - + = + + + + + = + + = = + + + + = + = + + + = = + = + = = + = + = + + = + = + = + Added: jcr/branches/1.12.x/docs/reference/en/src/main/resources/images/logi= n-page.jpg =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D (Binary files differ) Property changes on: jcr/branches/1.12.x/docs/reference/en/src/main/resourc= es/images/login-page.jpg ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: jcr/branches/1.12.x/docs/reference/en/src/main/resources/images/orga= nization-exo.jpg =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D (Binary files differ) Property changes on: jcr/branches/1.12.x/docs/reference/en/src/main/resourc= es/images/organization-exo.jpg ___________________________________________________________________ Name: svn:mime-type + application/octet-stream --===============0903027441959976257==--