Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

...

The configuration files that are enabled are specified in pentaho-solutions/system/pentaho-spring-beans.xml.

Code Block
xml
xml
titlepentaho-spring-beans.xmlxml

<beans>
  <!-- omitted -->
  <import resource="applicationContext-spring-security.xml" />
  <import resource="applicationContext-common-authorization.xml" />
  <import resource="applicationContext-spring-security-*.xml" />
  <import resource="applicationContext-pentaho-security-*.xml" />
  <!-- omitted -->
</beans>

...

But InMemoryDaoImpl doesn't take a UserMapFactoryBean! It takes a UserMap! The secret to this working lies in the Spring type called FactoryBean. When Spring detects a bean of this type, instead of returning the instance, it returns instance.getObject().

Code Block
xml
xml
titleapplicationContext-spring-security-memory.xmlxml
<bean id="userDetailsService" class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
  <property name="userMap">
    <ref local="userMapFactoryBean" />
  </property>
</bean>

<bean id="userMap" class="java.lang.String">
  <constructor-arg type="java.lang.String">
    <!-- case matters -->
    <value>
    <![CDATA[joe=password,ceo,Admin,User,Authenticated
    suzy=password,cto,is,User,Authenticated
    pat=password,dev,User,Authenticated
    tiffany=password,dev,devmgr,User,Authenticated]]>
    </value>
  </constructor-arg>
</bean>

<bean id="userMapFactoryBean" class="org.pentaho.platform.plugin.services.security.userrole.memory.UserMapFactoryBean">
  <property name="userMap">
    <ref local="userMap" />
  </property>
</bean>

...

There's one more property to mention: allAuthorities. This defines all authorities that are allowed to be granted to users. Why can't the platform get this information from the UserRoleListEnhancedUserMap? That's because the UserRoleListEnhancedUserMap might only contain a subset of all the available authorities.

Code Block
xml
xml
titleapplicationContext-pentaho-security-memory.xmlxml
<bean id="userRoleListEnhancedUserMapFactoryBean"
  class="org.pentaho.platform.plugin.services.security.userrole.memory.UserRoleListEnhancedUserMapFactoryBean">
  <property name="userMap" ref="userMap" />
</bean>

<bean id="inMemoryUserRoleListService"
  class="org.pentaho.platform.plugin.services.security.userrole.memory.InMemoryUserRoleListService">
  <property name="userRoleListEnhancedUserMap">
    <ref local="userRoleListEnhancedUserMapFactoryBean" />
  </property>
  <property name="userDetailsService" ref="userDetailsService" />
  <property name="allAuthorities">
    <list>
      <bean class="org.springframework.security.GrantedAuthorityImpl">
        <constructor-arg value="Authenticated" />
      </bean>
      <bean class="org.springframework.security.GrantedAuthorityImpl">
        <constructor-arg value="Admin" />
      </bean>
      <!-- some authorities omitted -->
    </list>
  </property>
  <property name="usernameComparator">
    <bean class="org.pentaho.platform.engine.security.DefaultUsernameComparator" />
  </property>
  <property name="grantedAuthorityComparator">
    <bean class="org.pentaho.platform.engine.security.DefaultGrantedAuthorityComparator" />
  </property>
</bean>

<bean id="pentahoUserRoleListService" class="org.pentaho.platform.engine.security.userrole.UserDetailsRoleListService">
  <property name="userRoleListService">
    <ref local="inMemoryUserRoleListService" />
  </property>
</bean>

...

Note: Be sure to add as username and as authorities where appropriate in your queries.

Code Block
xml
xml
titleapplicationContext-pentaho-security-jdbc.xmlxml
<bean id="jdbcUserRoleListService"
  class="org.pentaho.platform.plugin.services.security.userrole.jdbc.JdbcUserRoleListService">
  <constructor-arg index="0" ref="userDetailsService" />
  <property name="allAuthoritiesQuery">
    <value>
      <![CDATA[SELECT distinct(authority) as authority FROM AUTHORITIES ORDER BY authority]]>
    </value>
  </property>
  <property name="allUsernamesInRoleQuery">
    <value>
      <![CDATA[SELECT distinct(username) as username FROM GRANTED_AUTHORITIES where authority = ? ORDER BY username]]>
    </value>
  </property>
  <property name="allUsernamesQuery">
    <value>
      <![CDATA[SELECT distinct(username) as username FROM USERS ORDER BY username]]>
    </value>
  </property>
  <property name="dataSource" ref="dataSource" />
</bean>

<bean id="pentahoUserRoleListService"
  class="org.pentaho.platform.engine.security.userrole.UserDetailsRoleListService">
  <property name="userRoleListService">
    <ref local="jdbcUserRoleListService" />
  </property>
</bean>

...

And since DefaultLdapUserRoleListService is configured via Spring, the task is reduced to defining three GenericLdapSearch instances (plus an LdapUserDetailsService) in Spring! But before the Spring config is presented, the equivalent configuration via Java code is presented. This route is chosen since Spring configuration can be very verbose and most are more familiar with the more ubiquitous Java syntax.

Code Block
java
java
titleCreating a GenericLdapSearch Using Java Codejava
// create params factory with the following settings:
// search base="ou=users",
// filterExpr="(objectClass=person)",
LdapSearchParamsFactory paramsFactory = new LdapSearchParamsFactoryImpl(
  "ou=users", "(objectClass=Person)");

// create a resultsTransformer that extracts the uid attribute
Transformer transformer = new SearchResultToAttrValueList("uid");

// create a GenericLdapSearch with objects created above;
// (don't worry about getContextSource()--just know that
// it returns an ContextSource)
LdapSearch allUsernamesSearch = new GenericLdapSearch(
  getContextSource(), paramsFactory, transformer);

Now the equivalent Spring config is presented.

Code Block
xml
xml
titleCreating a GenericLdapSearch Using Springxml
<bean id="allUsernamesSearch"
  class="org.pentaho.platform.plugin.services.security.userrole.ldap.search.GenericLdapSearch">
  <constructor-arg index="0" ref="contextSource" />
  <constructor-arg index="1">
    <bean
      class="org.pentaho.platform.plugin.services.security.userrole.ldap.search.LdapSearchParamsFactoryImpl">
      <constructor-arg index="0" value="ou=users" />
      <constructor-arg index="1" value="objectClass=Person" />
    </bean>
  </constructor-arg>
  <constructor-arg index="2">
    <bean
      class="org.pentaho.platform.plugin.services.security.userrole.ldap.transform.SearchResultToAttrValueList">
      <constructor-arg index="0" value="uid" />
    </bean>
  </constructor-arg>
</bean>

...

The contents of application-pentaho-security-ldap.xml is below. Notice that some of the bean references refer to beans defined in applicationContext-spring-security-ldap.xml.

Code Block
xml
xml
titleapplicationContext-pentaho-security-ldap.xmlxml
<!-- be sure to escape ampersands -->
<bean id="allUsernamesSearch"
  class="org.pentaho.platform.plugin.services.security.userrole.ldap.search.GenericLdapSearch">
  <constructor-arg index="0" ref="contextSource" />
  <constructor-arg index="1">
  <bean
    class="org.pentaho.platform.plugin.services.security.userrole.ldap.search.LdapSearchParamsFactoryImpl">
    <constructor-arg index="0" value="ou=users" />
    <constructor-arg index="1" value="objectClass=Person" />
  </bean>
  </constructor-arg>
  <constructor-arg index="2">
    <bean
      class="org.pentaho.platform.plugin.services.security.userrole.ldap.transform.SearchResultToAttrValueList">
      <constructor-arg index="0" value="uid" />
    </bean>
  </constructor-arg>

</bean>

<!-- be sure to escape ampersands -->
<bean id="allAuthoritiesSearch"
  class="org.pentaho.platform.plugin.services.security.userrole.ldap.search.GenericLdapSearch">
  <constructor-arg index="0" ref="contextSource" />
  <constructor-arg index="1">
    <bean
      class="org.pentaho.platform.plugin.services.security.userrole.ldap.search.LdapSearchParamsFactoryImpl">
      <constructor-arg index="0" value="ou=roles" />
      <constructor-arg index="1" value="objectClass=organizationalRole" />
    </bean>
  </constructor-arg>
  <constructor-arg index="2">
    <bean
      class="org.apache.commons.collections.functors.ChainedTransformer">
      <constructor-arg index="0">
        <list>
          <bean
            class="org.pentaho.platform.plugin.services.security.userrole.ldap.transform.SearchResultToAttrValueList">
            <constructor-arg index="0" value="cn" />
          </bean>
          <bean
            class="org.pentaho.platform.plugin.services.security.userrole.ldap.transform.StringToGrantedAuthority">
            <property name="rolePrefix" value="" />
            <property name="convertToUpperCase" value="false" />
          </bean>
        </list>
      </constructor-arg>
    </bean>
  </constructor-arg>
</bean>

<!-- not currently used -->
<bean id="usernamesInRoleSearch"
  class="org.pentaho.platform.plugin.services.security.userrole.ldap.search.NoOpLdapSearch">
</bean>

<bean id="ldapUserRoleListService"
  class="org.pentaho.platform.plugin.services.security.userrole.ldap.DefaultLdapUserRoleListService">
  <constructor-arg index="0" ref="contextSource" />
  <property name="allAuthoritiesSearch">
    <ref local="allAuthoritiesSearch" />
  </property>
  <property name="allUsernamesSearch">
    <ref local="allUsernamesSearch" />
  </property>
  <property name="userDetailsService">
    <ref bean="userDetailsService" />
  </property>
  <property name="usernamesInRoleSearch">
    <ref local="usernamesInRoleSearch" />
  </property>
  <property name="usernameComparator">
    <bean class="org.pentaho.platform.engine.security.DefaultUsernameComparator" />
  </property>
  <property name="grantedAuthorityComparator">
    <bean class="org.pentaho.platform.engine.security.DefaultGrantedAuthorityComparator" />
  </property>
</bean>

<bean id="pentahoUserRoleListService"
  class="org.pentaho.platform.engine.security.userrole.UserDetailsRoleListService">
  <property name="userRoleListService">
    <ref local="ldapUserRoleListService" />
  </property>
</bean>

...