How-to...‎ > ‎

JasperReports Server CE V4.7.0 with Active Directory

posted Sep 21, 2012, 2:04 PM by Andrés Arenas Vélez   [ updated Sep 22, 2012, 7:26 AM ]
 
 JasperReports Server is one of my favorite projects.  If you are not familiar with Jasper Reports I will give a short description of what this is all about.

First, it is the report designer:  iReport Designer

With this great program you can create reports in a friendly and fairly intuitive way.  If you have used Crystal Reports or MS Access reports in the past you will get used to this tool easily.  The result of your design will be a .jxml file with the report description.

The link between iReport Designer and JasperReports Server is the JasperReports library.  This java library uses the jxml file to render the report to various formats including PDF, HTML, XLS, Etc.  It generates a complied file .jasper that can be used in any java application.  I’m really not a java programmer, so I prefer to view my reports on the next tool.

The JasperReports Server.

This is a java web application running on a Tomcat Server that works as a repository of reports.  Users login on the web application to see their reports from there.  Reports can be exported to various formats and you can even make the server to mail the reports on a schedule.  It is a very powerful and mature application.

One thing to have in mind is that these 3 applications are separate projects and they move at different paces.  It is very important to make sure that the library used in iReport is the same supported library on the server.  At the moment of this writing all projects are in sync in version 4.7.0.

So, be careful upgrading iReport to find out your server cannot display the reports it produces due to new incompatible features.

The great part is that all these applications are cross-platform so if you prefer to install all or some of them on Windows or Linux you will have no problems.

To make things easier, JasperReports Server can be installed as a bundle with its own Tomcat + PostgreSQL included in the installation package so it will make it a click and go setup.

What I have is, I think is, a typical scenario:  Windows Server + MSSQL Server, Windows Clients and a Linux Server for other tasks.

JasperReports support AD integration but I must confess it’s a little tricky; I spent like a week or more to get this working the way I wanted.

I will assume you have your JasperReports Server up and running at this point.  That part is easy and well documented on the project site.  This is my setup:

Windows Server 2003
+ MSSQL 2005

Centos 6.3 Server
+ Apache Tomcat 7.029
+ PostgreSQL 9.2
+ Jasper Reports Server 4.7.0 CE

The build-in security model in Jasper Reports uses the PostgreSQL database to store the roles and the users.  Every element on the server can assign specific permission to the roles.

No Access
Administer
Read Only
Read + Delete
Read + Write + Delete
Execute Only


Ex. On the Annual Sales (Branch 1)  report these could be the permissions to each role:

ROLE_USER        No Access
ROLE_Sales_B1    Read Only
ROLE_Sales_B2    No Access
ROLE_Management  Administer


A user can have one or more roles at a time having by default ROLE_USER.

What we want to accomplish is Jasper Reports using the users from Active Directory to authenticate against the server and use AD Groups as roles to assign the permissions.

You can leave the default jaspeadmin user, or any other local admin user, for troubleshooting purposes. The mechanism Jasper Reports Server uses to integrate with AD works like this:

□    The user send credentials on the login page using a username / password combination
□    The username / password combination is verified against AD and the local database.
□    If the authentication is successful, the server will retrieve the groups the user belongs to
□    The server will create the user on the local database if its not created already
□    All the groups will be created as roles on the local databases ( group1 -> ROLE_group1 )
□    The local user will be assigned to the corresponding roles

So as AD users start to login on the server it will populate the local users,roles and user-role tables; then you can use those roles to assign permissions to the reports.

I found some glitches on the process but I’m going to describe the solutions to have it working as you expect.

First, edit the applicationContext-security.xml file located on the webapps/jasperserver/WEB-INF directory of your tomcat installation.


<bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
  <property name="providers">
    <list>
       <ref local="ldapAuthenticationProvider"/>
       <ref bean="${bean.daoAuthenticationProvider}"/>
       <!--ref bean="anonymousAuthenticationProvider"/-->
       <!--ref local="jaasAuthenticationProvider"/-->
    </list>
  </property>
</bean>


Uncomment the ldap authentication provider and comment the anonymous login.

Next, on the same document you will find also commented a section for ldap authentication.  It should end looking like this:


<!--   For LDAP authentication     -->

<bean id="ldapContextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
  <constructor-arg value="ldap://192.168.5.10:389/DC=COMPANY,DC=COM"/>
  <property name="userDn"><value>CN=administrator,CN=Users,DC=COMPANY,DC=COM</value></property>
  <property name="password"><value>admin-password</value></property>
</bean>


<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
  <constructor-arg index="0"><value></value></constructor-arg>
  <constructor-arg index="1"><value>(sAMAccountName={0})</value></constructor-arg>
  <constructor-arg index="2"><ref local="ldapContextSource" /></constructor-arg>
  <property name="searchSubtree"><value>true</value></property>
</bean>


<bean id="ldapAuthenticationProvider" class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
  <constructor-arg>
    <bean class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
      <constructor-arg><ref local="ldapContextSource"/></constructor-arg>
      <property name="userSearch" ref="userSearch"/>
    </bean>
  </constructor-arg>
  <constructor-arg>
    <bean class="org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator">
      <constructor-arg index="0"><ref local="ldapContextSource"/></constructor-arg>
      <constructor-arg index="1"><value>OU= GROUPS</value></constructor-arg>
      <property name="groupRoleAttribute"><value>CN</value></property>
      <property name="convertToUpperCase"><value>true</value></property>
      <property name="rolePrefix"><value>ROLE_</value></property>
      <property name="groupSearchFilter">
        <value>(&amp;(member={0})(objectclass=group)(cn=JASPER_*))</value>
      </property>
      <property name="defaultRole"><value>ROLE_USER</value></property>
      <property name="searchSubtree"><value>true</value></property>
     </bean>
  </constructor-arg>
</bean>


On the first bean, put the server and the user to browse the AD.  I use administrator to avoid issues, but you better try with a less sensitive user when you get things working.

Next, we want the users be mapped using the sANAccountName which is the short user login name on AD.  The next bean will search for the groups on the OU you specify here.  I filter here the groups beginning with JASPER_ so only those groups are going to be imported to the server.  I found it better that way, since a user can belong to a lot of groups that have noting to do with the reports and I will never use those group to assign permissions.  All you need to do is to create your groups on the Active Directory with this prefix and filter them here. That way, a group called JASPER_MANAGEMENT will be created as ROLE_JASPER_MANAGEMENT on the server.

Now, the last step is to allow the server to log the logins to check everything is OK.

Edit webapps/jasperserver/WEB-INF/log4j.properties and modify this line:

   log4j.rootLogger=WARN, stdout, fileout

That way on the tomcat log it will have detailed data on the login process.

Well, let’s test test it.

Create some groups on your OU=GROUPS like JASPER_SALES, assign some users to the group and check the results.  On your tomcat logs/catalina.out you should see something like this:

2012-09-21 15:46:42,572  WARN LoggerListener,http-bio-8080-exec-3:60 - Authentication event AuthenticationSuccessEvent: username; details: org.springframework.security.ui.WebAuthenticationDetails@1c07a: RemoteIpAddress: 192.168.5.27; SessionId: 106B002787102DD98C55A760A897CA74
2012-09-21 15:46:42,576  WARN LoggerListener,http-bio-8080-exec-3:60 - Authentication event InteractiveAuthenticationSuccessEvent: username; details: org.springframework.security.ui.WebAuthenticationDetails@1c07a: RemoteIpAddress: 192.168.5.27; SessionId: 106B002787102DD98C55A760A897CA74
2012-09-21 15:46:42,618  WARN UserAuthorityServiceImpl,http-bio-8080-exec-3:899 - Added following external roles to: username
ROLE_USER

2012-09-21 15:46:42,621  WARN UserAuthorityServiceImpl,http-bio-8080-exec-3:935 - Updated user: username. Roles are now:
ROLE_USER
ROLE_JASPER_SALES
ROLE_JASPER_MANAGEMENT



2012-09-21 15:46:42,653  WARN UserAuthorityServiceImpl,http-bio-8080-exec-3:941 - Updated user: username. Roles are now:
ROLE_USER
ROLE_JASPER_SALES
ROLE_JASPER_MANAGEMENT


Now the roles are created.  Login with the local admin and give the created roles permissions to the reports.  As other users belonging to those groups login in the future they will be added automatically.

I wrote a little script to check when user login to the server:

#!/bin/sh
cat /usr/share/apache-tomcat-7.0.29/logs/catalina.out | grep InteractiveAuthenticationSuccessEvent | cut -d: -f1,2,3,5 | cut -d" " -f1,2,6


This two lines script will list the date/time and the user that successfully logged on the server.

Finally, AD is not case sensitive, so user, User, UsEr are all the same to AD; but not for Jasper Server, so every time the user enters the name in different caps those users will be added creating duplicates on the local database.

To prevent this, edit the file:

webapps/jasperserver/WEB-INF/jsp/templates/login.jsp

Change line 70:

<input id="j_username" name="j_username" type="text" style="text-transform:lowercase;" onkeyup="javascript:this.value=this.value.toLowerCase();" autocomplete="off"/>

That's it!

Hope this helps someone out there. Enjoy!
Comments