Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » scout » How to integrate the LDAPSecurityFilter with a scout application
How to integrate the LDAPSecurityFilter with a scout application [message #1010781] Mon, 18 February 2013 03:21 Go to next message
Urs Beeli is currently offline Urs Beeli
Messages: 318
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Based on the information provided on the security concept page I have been able to make both the BasicSecurityFilter and the DataSourceSecurityFilter as well as extending the DataSourceSecurityFilter to add some application specific behaviour.

However, our "real" application will need to use LDAP authentication. I've searched through the concept pages, the wiki and the forum but not found any information on how to do this except for the one sentence under LDAPSecurityFilter on the security concept page.

Can anyone help me set up LDAP authentication for my scout application? Ideally I would like to have the option to either use the currently logged on windows user automatically or to show the login window, so the user can enter any username and password.

How would I go about doing this?
Re: How to integrate the LDAPSecurityFilter with a scout application [message #1010858 is a reply to message #1010781] Mon, 18 February 2013 05:52 Go to previous messageGo to next message
Boy D'Poy is currently offline Boy D'Poy
Messages: 56
Registered: October 2011
Member
take a look @ this : http://www.eclipse.org/forums/index.php/t/356576/ Wink

Once You Go Scout, You Never Come Out!
Re: How to integrate the LDAPSecurityFilter with a scout application [message #1010905 is a reply to message #1010858] Mon, 18 February 2013 08:01 Go to previous messageGo to next message
Urs Beeli is currently offline Urs Beeli
Messages: 318
Registered: October 2012
Location: Bern, Switzerland
Senior Member
@Boy D'Poy
Thanks for your pointer. Unfortunately, that doesn't help me all that much. All I found in itwith regard to LDAP authentication was the following:

org.eclipse.scout.http.servletfilter.security.AnonymousSecurityFilter#active=false
org.eclipse.scout.http.servletfilter.security.BasicSecurityFilter#active=false

org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#active=true
org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#realm=developmnet
org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#failover=false


However, with these settings I am always auto-logged on and the server shows the following message:
!MESSAGE org.eclipse.scout.http.servletfilter.helper.DevelopmentAuthFilter.createDevelopmentSubject(DevelopmentAuthFilter.java:88) +++Development security: Create Subject based on System.getProperty('user.name')


The message appears because DevelopmentAuthFilter is chained when no other SecurityFilter can be found or started.

I have managed to turn this off by adding
org.eclipse.scout.http.servletfilter.helper.DevelopmentAuthFilter#active=false

to the config.ini file.

However, that just led to another error about no user being known.

Finally I remembered the problems I had when extending the DataSourceSecurityFilter and indeed, adding LDAPSecurityFilter to the servers plugin.xml solved the problem, now the LDAPSecurityFilter is instantiated.

Looking at the source also showed me which parameters seem to be mandatory:
org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#active=true
org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#realm=abcde
org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#ldapServer=ldap://100.100.29.4
org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#ldapBaseDN=o=bsiag
org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#lDAPgroupDN=ou=bsi_baden,ou_bsi_bern
org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#lDAPgroupAttributeId=cn

I now get a login-dialog asking me for my user name and password which then throws an error because I have invalid values on the last three entries (I know the address of our LDAP server). I am now trying to find someone in our company that can tell me which values I need to add there, hopefully that will be enough to get it working.

If anyone can tell me what the "realm" parameter is for, I would appreciate it, as that does not seem to be an LDAP parameter...
Re: How to integrate the LDAPSecurityFilter with a scout application [message #1010969 is a reply to message #1010905] Mon, 18 February 2013 10:31 Go to previous messageGo to next message
Boy D'Poy is currently offline Boy D'Poy
Messages: 56
Registered: October 2011
Member
sorry, I also don't know what is the realm attribute used for, but in my office a configuration like this works:

org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#ldapServer=ldap://[yourLdapIp]:[yourLdapPort]
org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#ldapBaseDN=dc=[yourCompany],dc=[yourTld] (e.g. com, fr, net)
org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#lDAPgroupDN=ou=[yourLdapGroup]
org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter#lDAPgroupAttributeId=CN

Hop that could help Wink


Once You Go Scout, You Never Come Out!
Re: How to integrate the LDAPSecurityFilter with a scout application [message #1011253 is a reply to message #1010969] Tue, 19 February 2013 02:25 Go to previous messageGo to next message
Urs Beeli is currently offline Urs Beeli
Messages: 318
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Thanks Boy D'Poy

Currently we're trying to find out what "ourLdapGroup" needs to be, the rest is pretty clear. In a large company, finding the person to tell us this seems to be the bigger problem than actually making the code work Smile
Re: How to integrate the LDAPSecurityFilter with a scout application [message #1011280 is a reply to message #1011253] Tue, 19 February 2013 03:17 Go to previous messageGo to next message
Stathis Alexopoulos is currently offline Stathis Alexopoulos
Messages: 42
Registered: September 2010
Member
Hello Urs,

I dont know if will help you but i found in LDAPSecurityFilter.class the method getUserDN with the following doc
Quote:

...
groupDN e.g. cn=AGENTS,ou=ks,ou=lm,ou=hlg,ou=zentrale
The user DN is defined within this group
...
Re: How to integrate the LDAPSecurityFilter with a scout application [message #1011289 is a reply to message #1011280] Tue, 19 February 2013 03:47 Go to previous messageGo to next message
Urs Beeli is currently offline Urs Beeli
Messages: 318
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Thanks Stathis

I've already seen this, currently the problem is figuring out what that string needs to look like for our company. You'd think that this should be easy but ours is big enough that finding the right contact person in IT operations is a task unto itself Smile
Re: How to integrate the LDAPSecurityFilter with a scout application [message #1011421 is a reply to message #1011289] Tue, 19 February 2013 09:51 Go to previous messageGo to next message
Urs Beeli is currently offline Urs Beeli
Messages: 318
Registered: October 2012
Location: Bern, Switzerland
Senior Member
So, I've finally found somebody who could tell me the correct groupDN string. However, that still didn't work, I always got an exception about the object being unknown on the following line of the LDAPSecurityFilter:
      Attributes attrs = ldap.getAttributes(groupDN, new String[]{attributeId});


After a fair bit of debugging (and some testing with an LDAP browser) I've found out what the problem is: When our LDAP server is queried anonymously, it does not return any data at all, so the current LDAPSecurityFilter will not work in our case.

For some more testing we were able to use the dedicated LDAP server of a test project that allows anonymous queries but there the current LDAPSecurityFilter fails because it has a hard coded length of 4 and 3 (probably assuming "cn=xxxxx" to be the result, however the LDAP server in question returns "uid=xxxx" which then of course fails) on the following lines:

          dn = (String) allValues.next();
          // extract userName (e.g. "BulinskyMir")
          if (dn.length() > 4) {    
            un = dn.substring(3);   // this will fail if the DN returns "uid=BulinskyMir" instead of "cn=BulinskyMir"
            parts = un.split(",");

It would probably be cleaner to parse for the position of the equal sign and then extract the user name after its position.


We've ended up rewriting the security filter to allow for authenticated LDAP queries (relying on a "functional user" for the LDAP authentication). I'm providing it here for those interested, feel free to use it to improve the current LDAPSecurityFilter...

package org.eclipse.minicrm.server.services.custom.security;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.scout.commons.Base64Utility;
import org.eclipse.scout.commons.logger.IScoutLogger;
import org.eclipse.scout.commons.logger.ScoutLogManager;
import org.eclipse.scout.commons.security.SimplePrincipal;
import org.eclipse.scout.http.servletfilter.FilterConfigInjection;
import org.eclipse.scout.http.servletfilter.security.AbstractChainableSecurityFilter;
import org.eclipse.scout.http.servletfilter.security.PrincipalHolder;

/**
 * <h4>LDAPSecurityFilter</h4> The following properties can be set in the <code>config.ini</code> file:
 * <ul>
 * <li><code>&lt;fully qualified name of class&gt;#active=true/false</code> <b>might be set in the extension point</b></li>
 * <li><code>&lt;fully qualified name of class&gt;#realm=abcde</code> <b>required</b></li>
 * <li><code>&lt;fully qualified name of class&gt;#failover=true/false</code> <b>default false</b></li>
 * <li>
 * <code>&lt;fully qualified name of class&gt;#ldapDirectory=[e.g. ldap://ldap.mycompany.com:389]</code> <b>required</b></li>
 * <li>
 * <code>&lt;fully qualified name of class&gt;#ldapBaseDN=[e.g. dc=mycompany,dc=com]</code> <b>required</b></li>
 * <li>
 * <code>&lt;fully qualified name of class&gt;#ldapSearchFilter=[e.g. (cn=%s)]</code> <b>required</b></li>
 * <li>
 * <code>&lt;fully qualified name of class&gt;#ldapSearchBindPassword=[e.g. password of LDAPReader]</code></li>
 * <li>
 * <code>&lt;fully qualified name of class&gt;#m_searchBindDN=[e.g. cn=LDAPReader,ou=Administrators,dc=mycompany,dc=com]</code></li>
 * </ul>
 * <p>
 * based on org.eclipse.scout.http.servletfilter.security.LDAPSecurityFilter
 * 
 * @since 1.0.0 18.02.2013
 */
public class LDAPExSecurityFilter extends AbstractChainableSecurityFilter {
  private static final IScoutLogger LOG = ScoutLogManager.getLogger(LDAPExSecurityFilter.class);
  public static final String PROP_BASIC_ATTEMPT = "LDAPExSecurityFilter.basicAttempt";

  private String m_directory;
  private String m_baseDn;
  private String m_searchFilter;
  private String m_searchBindPassword;
  private String m_searchBindDN;

  @Override
  public void init(FilterConfig config0) throws ServletException {
    super.init(config0);
    FilterConfigInjection.FilterConfig config = new FilterConfigInjection(config0, getClass()).getAnyConfig();
    m_directory = getParam(config, "ldapDirectory", false);
    m_baseDn = getParam(config, "ldapBaseDN", false);
    m_searchFilter = getParam(config, "ldapSearchFilter", false);
    m_searchBindPassword = getParam(config, "ldapSearchBindPassword", true);
    m_searchBindDN = getParam(config, "ldapSearchBindDN", true);
  }

  protected String getParam(FilterConfig filterConfig, String paramName, boolean nullAllowed) throws ServletException {
    String paramValue = filterConfig.getInitParameter(paramName);
    boolean exists = false;
    if (paramValue == null && nullAllowed) { // check if parameter exists
      Enumeration initParameterNames = filterConfig.getInitParameterNames();
      while (initParameterNames.hasMoreElements() && exists == false) {
        String object = (String) initParameterNames.nextElement();
        exists = object.equals(paramName);
      }
    }
    if (paramValue == null && !exists) {
      throw new ServletException("Missing init-param with name '" + paramName + "'.");
    }
    return paramValue;
  }

  @Override
  protected int negotiate(HttpServletRequest req, HttpServletResponse resp, PrincipalHolder holder) throws IOException, ServletException {
    String h = req.getHeader("Authorization");
    if (h != null && h.matches("Basic .*")) {
      String[] a = new String(Base64Utility.decode(h.substring(6)), "ISO-8859-1").split(":", 2);
      String user = a[0].toLowerCase();
      String pass = a[1];
      if (user != null && pass != null) {
        if (login(user, pass, m_directory, m_baseDn, m_searchBindDN, m_searchBindPassword, m_searchFilter)) {
          // success
          holder.setPrincipal(new SimplePrincipal(user));
          return STATUS_CONTINUE_WITH_PRINCIPAL;
        }
      }
    }
    int attempts = getBasicAttempt(req);
    if (attempts > 2) {
      return STATUS_CONTINUE_CHAIN;
    }
    else {
      setBasicAttept(req, attempts + 1);
      resp.setHeader("WWW-Authenticate", "Basic realm=\"" + getRealm() + "\"");
      return STATUS_CONTINUE_CHAIN;
    }
  }

  private int getBasicAttempt(HttpServletRequest req) {
    int basicAtttempt = 0;
    Object attribute = req.getSession().getAttribute(PROP_BASIC_ATTEMPT);
    if (attribute instanceof Integer) {
      basicAtttempt = ((Integer) attribute).intValue();
    }
    return basicAtttempt;
  }

  private void setBasicAttept(HttpServletRequest req, int attempts) {
    req.getSession().setAttribute(PROP_BASIC_ATTEMPT, attempts);
  }

  @SuppressWarnings("unchecked")
  protected boolean login(String username, String userPassword, String directory, String baseDN, String searchBindDN, String searchBindPassword, String searchFilter) throws ServletException {
    boolean isAuthenticated = false;

    // Step 1 - authenticate with functional user to get search access
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, directory);
    env.put(Context.SECURITY_PRINCIPAL, searchBindDN);
    env.put(Context.SECURITY_CREDENTIALS, searchBindPassword);

    try {
      DirContext ctx = new InitialDirContext(env);
      SearchControls constraints = new SearchControls();
      constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
      String search = String.format(searchFilter, username);

      NamingEnumeration<SearchResult> results = ctx.search(baseDN, search, constraints);

      SearchResult sr = null;

      // Step 2 - authenticate with entered user credentials
      if (results != null && results.hasMore()) {
        sr = results.next();

        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        if (sr.isRelative()) {
          env.put(Context.SECURITY_PRINCIPAL, sr.getName() + "," + baseDN);
        }
        else {
          env.put(Context.SECURITY_PRINCIPAL, sr.getName());
        }
        env.put(Context.SECURITY_CREDENTIALS, userPassword);

        try {
          new InitialDirContext(env);
          isAuthenticated = true;
        } catch (NamingException ne) {
          isAuthenticated = false;
        }
      }
      else {
        isAuthenticated = false;
      }
    }
    catch (NamingException ne) {
      LOG.error("Exception in getting user DN from LDAP: " + ne);
      throw new SecurityException(ne.getMessage(), ne);
    }
    return isAuthenticated;
  }

}


The parameters in config.ini look something like this:
org.eclipse.minicrm.server.services.custom.security.LDAPExSecurityFilter#active=true
org.eclipse.minicrm.server.services.custom.security.LDAPExSecurityFilter#realm=LDAP
org.eclipse.minicrm.server.services.custom.security.LDAPExSecurityFilter#ldapDirectory=ldap://ldapi.mycompany.com:389
org.eclipse.minicrm.server.services.custom.security.LDAPExSecurityFilter#ldapBaseDN=dc=mycompany,dc=com
org.eclipse.minicrm.server.services.custom.security.LDAPExSecurityFilter#ldapSearchFilter=(cn=%s)
org.eclipse.minicrm.server.services.custom.security.LDAPExSecurityFilter#ldapSearchBindDN=cn=LDAPReader,ou=Administrators,dc=mycompany,dc=ch
org.eclipse.minicrm.server.services.custom.security.LDAPExSecurityFilter#ldapSearchBindPassword=pass1234
org.eclipse.minicrm.server.services.custom.security.LDAPExSecurityFilter#failover=false

[Updated on: Tue, 19 February 2013 10:35]

Report message to a moderator

Re: How to integrate the LDAPSecurityFilter with a scout application [message #1011826 is a reply to message #1011421] Wed, 20 February 2013 05:20 Go to previous message
Urs Beeli is currently offline Urs Beeli
Messages: 318
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Deleted post because my idea of silently authenticating the current user wouldn't work. It used the "current user on the server" instead of the current user on the client... I'll need to look into this a little more.

[Updated on: Thu, 21 February 2013 08:31]

Report message to a moderator

Previous Topic:Swing discrepancies when using Rayo
Next Topic:Menu bar missing on OS X build
Goto Forum:
  


Current Time: Thu Jul 24 09:08:57 EDT 2014

Powered by FUDForum. Page generated in 0.02119 seconds