Home » Eclipse Projects » Eclipse 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  |
Eclipse User |
|
|
|
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 #1010905 is a reply to message #1010858] |
Mon, 18 February 2013 08:01   |
Eclipse User |
|
|
|
@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 #1011421 is a reply to message #1011289] |
Tue, 19 February 2013 09:51   |
Eclipse User |
|
|
|
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><fully qualified name of class>#active=true/false</code> <b>might be set in the extension point</b></li>
* <li><code><fully qualified name of class>#realm=abcde</code> <b>required</b></li>
* <li><code><fully qualified name of class>#failover=true/false</code> <b>default false</b></li>
* <li>
* <code><fully qualified name of class>#ldapDirectory=[e.g. ldap://ldap.mycompany.com:389]</code> <b>required</b></li>
* <li>
* <code><fully qualified name of class>#ldapBaseDN=[e.g. dc=mycompany,dc=com]</code> <b>required</b></li>
* <li>
* <code><fully qualified name of class>#ldapSearchFilter=[e.g. (cn=%s)]</code> <b>required</b></li>
* <li>
* <code><fully qualified name of class>#ldapSearchBindPassword=[e.g. password of LDAPReader]</code></li>
* <li>
* <code><fully qualified name of class>#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] by Moderator
|
|
| |
Goto Forum:
Current Time: Wed Jul 23 15:50:10 EDT 2025
Powered by FUDForum. Page generated in 0.04763 seconds
|