Home » Eclipse Projects » Eclipse Scout » How to integrate the LDAPSecurityFilter with a scout application
| |
Re: How to integrate the LDAPSecurityFilter with a scout application [message #1010905 is a reply to message #1010858] |
Mon, 18 February 2013 13:01 |
Urs Beeli Messages: 573 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 #1011421 is a reply to message #1011289] |
Tue, 19 February 2013 14:51 |
Urs Beeli Messages: 573 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><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 15:35] Report message to a moderator
|
|
| |
Goto Forum:
Current Time: Sat Sep 21 05:28:57 GMT 2024
Powered by FUDForum. Page generated in 0.04729 seconds
|