Spring Security, LDAP & Active Directory

Sunday, July 31, 2011 Posted by Suresh Payankannur 0 comments
Earlier this year, I had to integrate the spring-security with Active Directory, for authentication and authorization. Eventhough there were some documentation available, I had to struggle a bit to get this working. So it will be a good idea to share my findings here. I have been looking for the minimal configuration that accomplishes the goal.

Notes:

  • The sAMAccountName attribute in AD stores the user login.
  • The persion tag will populate the the details of the user in org.springframework.security.ldap.userdetails.Person class. This is handy if one needs to get more than the username like first name, last name etc.
  • A number of ldap related tags are not documented well. Refer to the package org.springframework.security.config.ldap for details of the possible tags that can be used in the spring context.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:s="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemalocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.1.xsd">

  
  <s:http>
    <s:intercept-url access="IS_AUTHENTICATED_REMEMBERED" pattern="/secure/**">
      <s:form-login login-page="login.html"
                    default-target-url="/secure/homepage.do"
                    always-use-default-target="true"/>
    <s:logout/>
    </s:intercept-url>
 </s:http>

 <s:ldap-server id="ldap-server"
                url="ldap://host:389/"
                root=""
                manager-dn="cn=xxx,ou=xxx,DC=corp,dc=xxx,dc=com"
                manager-password="xxx"/>

  <s:authentication-manager alias="authenticationManager">
    <s:ldap-authentication-provider
        user-search-filter="(&amp;(objectclass=user)(sAMAccountName={0}))"
        user-search-base="dc=corp,dc=xxx,dc=com"
        group-search-filter="(&amp;(objectclass=group)(member={0}))"
        group-search-base="ou=xxx,dc=corp,dc=xxx,dc=com"
        user-details-class="person"
        role-prefix="none"
        />
  </s:authentication-manager>
</beans>
For example, if one wants to extract the full name of the user:
import org.springframework.security.ldap.userdetails.Person;

    public String getFullName() {
        Person person = (Person) getAuthentication().getPrincipal();
        String[] cn = person.getCn();

        StringBuilder sbuf = new StringBuilder("");
        if (cn != null  &&  cn.length > 0) {
            for (String s : cn) {
                sbuf.append(s).append(" ");
            }
        }
        return sbuf.toString().trim();
    }

Unit Testing

import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;

import static org.mockito.Mockito.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:spring-security-context.xml"})
public class AuthenticationTest {
    @Test
    public void testAuth() {
        // Authentication auth = mock(Authentication.class);
        // when(auth.getPrincipal()).thenReturn("rod");
        // when(auth.getCredentials()).thenReturn("koala");
        // Cannot mock authenticator as the ProviderManager checks for
        // an instance of UsrenamePasswordAuthenticationToken. So create
        // a concrete instance.
        Authentication auth = new UsernamePasswordAuthenticationToken("rod",
                                                                      "koala");
        auth = authenticationManager.authenticate(auth);
        assertTrue(auth.isAuthenticated());
    }

    @Autowired
    private AuthenticationManager authenticationManager;
}

Using embedded ldap server

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:s="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemalocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.1.xsd">

  <s:http>
    <s:intercept-url pattern="/secure/**" 
                     access="IS_AUTHENTICATED_REMEMBERED" />
    <s:form-login login-page="/login.html"
                  default-target-url="/secure/homepage.do" 
                  always-use-default-target="true"/>
    <s:logout />
  </s:http>

  <s:ldap-server ldif="classpath:users.ldif" port="33389"/>

  <s:authentication-manager alias="authenticationManager">
    <s:ldap-authentication-provider
        group-search-filter="member={0}"
        group-search-base="ou=groups"
        user-search-base="ou=people"
        user-search-filter="uid={0}"
        user-details-class="person"
        role-prefix="none"/>
  </s:authentication-manager>
</beans>
Labels: ,

DD-WRT and NetGear WNDR3700

Posted by Suresh Payankannur 0 comments
Flashing DD-WRT on WNDR3700 was quite easy. Follow the standard instructions:

  1. Download the latest version of DD-WRT
  2. Connect using a LAN cable
  3. Use stock firmware's GUI to upload the latet version of DD-WRT
  4. No Need to do a 30/30/30 reset
Once the DD-WRT was flashed, the ath1 (5G) was only connecting at 130 Mbs. Where as the stock firmware was able to connect a a rate of 300 Mbs. After poking around a while, the following settings worked and I was able to connect at 300 Mbs.
  1. In the Advanced settings for wireless on the DD-WRT GUI, select Wireless Network Mode as N Only (5 GHz)
  2. This will enable setting higher channel width. Select Turbo (40 MHz) in the Channel Width
Labels: ,

Confluence + Tomcat + Ubuntu + MySQL

Posted by Suresh Payankannur 0 comments
To install the EAR/WAR version of Confluence follow these steps. This assumes basic knowledge on Ubuntu, MySQL, Tomcat etc.
  1. Download the latest EAR/WAR version
  2. Unpack the distribution
        % sudo tar xvf confluence-3.4.6.tar -C /opt
    
  3. Create symlink wiki for the confluence distribution
        % cd /opt
        % sudo ln -s confluence-3.4.6 wiki
        % sudo chown -R tomcat6:tomcat6 wiki
      
  4. Create the data directory
        % sudo mkdir /var/data/wiki
        % sudo chown -R tomcat6:tomcat6 /var/data/wiki
      
  5. Edit the /opt/wiki/confluence/WEB-INF/classes/confluence-init.properties and set the value of variable confluence.home to /opt/wiki/confluence
  6. Edit /etc/default/tomcat6 and adjust the JVM settings
    JAVA_OPTS="-Djava.awt.headless=true -Xmx640m -XX:+UseConcMarkSweepGC -XX:MaxPermSize=256m"
    
  7. Modify /opt/wiki/confluence/WEB-INF/classes/log4j.properties so that the log files will be produced under /var/log/tomcat6
    • Comment the line for ConfluenceHomeLogAppender
    • Uncomment the line for RollingFileAppender
    • Set the log location to /var/log/tomcat6/atlassian-confluence.log
    • Set the debug threshold to WARN
  8. Create a confluence database
        % mysqladmin -u root -p create wiki
        % mysql -u root -p
        % mysql> grant all privileges on wiki.* to 'wikiuser'@'localhost' identified by 'wikipass' with grant option;
        % mysql> commit;
        % mysql> flush all privileges;
      
  9. Setup the confluence context: In the /var/lib/tomcat6/conf/Catalina/localhost directory, create a file called confluence.xml with the following contents:
    <Context path="/wiki" docBase="/opt/wiki/confluence" debug="0" reloadable="0"/>
    
  10. Restart tomcat
        % sudo /etc/init.d/tomcat6 restart
    

  11. Point the browser to localhost:8080/wiki and follow the instructions

Install VMWareTools on Ubuntu Server

Posted by Suresh Payankannur 0 comments
I have been running Ubuntu Server Guest OS on OSX. Ubuntu server is installed without any X support. So to install VMWare Tools, which will allow to share folders between the Guest OS and host, follow these instructions:

  1. Upgrade the server
        % sudo apt-get update
        % sudo apt-get dist-upgrade
      
  2. Install the required packages to compile VMWare Tools
        sudo apt-get install build-essential linux-headers`uname -r` psmic
      
  3. Reboot the server
        % sudo reboot now
      
  4. Go to the menu bar Virtual Machine -> CD/DVD -> Choose Disk Image. Choose the file /Library/Application Support/VMWare Fusion/isoimages/linux.so
  5. Mount the CDROM on the Ubuntu Server
         % sudo mount /dev/cdrom /media/cdrom
       
  6. Copy the VMWare Tools from CDROM to the local
        % cp /media/cdrom/VMWareTools-8.4.5-332101.tar.gz ~/tmp
      
  7. Unpack VMWare Tools
        % tar xvf VMWareTools-8.4.5-332101.tar.gz
      
  8. Install the VMWareTools. Provide default values for all the questions.
        % cd ~/tmp/vmware-tools-distrib
        % ./vmware-install.pl
      
  9. Reboot the server
        % sudo reboot now
      
Labels: ,

Get a list of installed packages on Ubuntu

Posted by Suresh Payankannur 0 comments
  dpkg --get-selections
Labels:

Installing Apache + Tomcat on Ubuntu

Posted by Suresh Payankannur 0 comments
  1. Install the packages
        sudo apt-get update
        sudo apt-get dist-upgrade
        sudo apt-get install apache2
        sudo apt-get install tomcat6
        sudo apt-get install libapache2-mod-jk
      
  2. Adjust the startup parameters like heap space, permgen etc. by modifying the file /etc/default/tomcat6
  3. Uncomment the AJP connector from the server configuration by modifying /var/lib/tomcat6/conf/server.xml
  4. Add the jk worker properties file by creating a new file /etc/apache2/jk_workers.properties with the following content:
        # List of workers
        worker.list = local, status
    
        # Local worker
        worker.local.type=ajp13
        worker.local.host=localhost
        worker.local.port=8009
    
        # Status worker
        worker.status.type=status
      
  5. Add a new file /etc/apache2/mods_available/jk.conf with the following content:
        JkWorkersFile /etc/apache2/jk_workers.properties
        JkShmFile     /var/log/apache2/mod_jk.shm
        JkLogFile     /var/log/apache2/mod_jk.log
        JkLogLevel    info
        JkLogStampFormat "[%a %b %H:%M:%S %Y]"
      
  6. Enable the mods
          % cd /etc/apache2/mods-enabled
          % sudo ln -s ../mods-available/jk.conf jk.conf
        
  7. Edit /etc/apache2/sites-available/default and add the JK Mount points. At the end of the file, in the same virtual host definition, add the following:
        JkMount /servlet* local
        JkMount /tomcat-status status
      
  8. Reboot the server
          % sudo reboot now
        
Labels: , ,

Install Java6 on Ubuntu

Posted by Suresh Payankannur 0 comments
Java6 is not available from standard repositories. In order to install Java6, a new repository should be added. In addition, some new packages needs to be installed.

  1. Get additional packages
    sudo apt-get install python-software-properties
    
  2. Add new repository
    sudo add-apt-repository "deb http://archive.canonical.com/ lucid partner"
    
  3. Update
    sudo apt-get update
    
  4. Install Java
    sudo apt-get install sun-java6-jdk
    
  5. Set JAVA_HOME
    export JAVA_HOME=/usr/lib/jvm/java-6-sun
    
Labels: ,

Redmine Burndown Charts

Posted by Suresh Payankannur 3 comments
I have been searching for a good burndown chart based on Redmine, a wonderful tracking plaform. There are a few plugins but not quite there yet. What I have been looking for is to use the Version concept of Redmine as the iteration and have a simple daily burndown.

Then I found Redmine Charts Plugin has the features I have been looking for. Especially, burndown with velocity. But found a couple of issues with the latest implementation:

  1. Start of the iteration is the version creation date. This is not practical. A version can be created ahead of time, and scheduled later.
  2. The ideal burndown chart should be a single straightline, starting from the version-start-date to version-end-date. But the ideal burndown is not a straight line with this plugin.

A couple of minor changes will fix these issues and I was able to get get a good burndown chart.

Getting an iteration start date


  1. Login as adminstrator and create a new custom field called Start Date
  2. Select the project and modify the version. Set the Start Date of the version to the actual iteration start date.
  3. Make the following change to $REDMINE_ROOT/vendor/plugins/redmine_charts/app/controller/charts_burndown2_controller.rb

      # start_date = version.created_on.to_date
      c_value = CustomValue.find_by_sql(["SELECT value from custom_values WHERE customized_type = 'Version' AND customized_id = ? LIMIT 1", version.id])
      s_date = c_value.empty? ? nil : c_value.first.value
      s_date = (s_date.nil?  ||  s_date.empty?) ? nil : s_date.to_date
      
      start_date = s_date==nil ? version.created_on.to_date : s_date
    

Making the ideal burndown a straightline


The reason the ideal burndown is not a straightline is that the total number of days used in the calculation is not correct. To fix this issue, modify the file $REDMINE_ROOT/vendor/plugins/redmine_charts/app/controller/charts_burndown2_controller.rb with the following change:
  # daily_velocity = total_estimated.to_f/@range[:keys].size
  daily_velocity = total_estimated.to_f/(@range[:keys].size - 1

Restart the redmine server.
Labels: ,

Bash Tips

Tuesday, July 26, 2011 Posted by Suresh Payankannur 0 comments
Debugging a bash script
% bash -x myscript.sh
Setting variables like CLASSPATH etc. using a script

Typically when setting variables with in a script and executing the script (% setenv.sh) makes these variables available only within the sub-process that executing the script. Once the script execution is done, these variables are not passed back to the parent shell. In order to achieve this, one has to 'source' it.

Suppose you have a shell script which contains the following line:
CLASSPATH="/opt/jars:/usr/lib/jars"
export CLASSPATH
In order for this variable to be available to the parent shell:
% source setenv.sh
Then the variable will be available in the parent shell
% env | grep -i classpath
Will show the set values.


Labels: