move scm-auth-ldap-plugin to its own repository at https://bitbucket.org/tludewig/scm-auth-ldap-plugin

This commit is contained in:
Sebastian Sdorra
2011-07-04 08:29:19 +02:00
parent 41f0a5d1ca
commit 48c67bd65f
8 changed files with 0 additions and 1606 deletions

View File

@@ -17,7 +17,6 @@
<modules>
<module>scm-activedirectory-auth-plugin</module>
<module>scm-auth-ldap-plugin</module>
<!-- core plugins -->
<module>scm-hg-plugin</module>
<module>scm-git-plugin</module>

View File

@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>scm-plugins</artifactId>
<groupId>sonia.scm.plugins</groupId>
<version>1.5-SNAPSHOT</version>
</parent>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-auth-ldap-plugin</artifactId>
<packaging>jar</packaging>
<version>1.4-SNAPSHOT</version>
<name>${project.artifactId}</name>
<description>plugin description</description>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<!-- test scope -->
<dependency>
<groupId>sonia.scm</groupId>
<artifactId>scm-test</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>maven.scm-manager.org</id>
<name>scm-manager release repository</name>
<url>http://maven.scm-manager.org/nexus/content/groups/public</url>
</repository>
</repositories>
</project>

View File

@@ -1,704 +0,0 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.auth.ldap;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.SCMContextProvider;
import sonia.scm.plugin.ext.Extension;
import sonia.scm.store.Store;
import sonia.scm.store.StoreFactory;
import sonia.scm.user.User;
import sonia.scm.util.AssertUtil;
import sonia.scm.util.Util;
import sonia.scm.web.security.AuthenticationHandler;
import sonia.scm.web.security.AuthenticationResult;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author Thorsten Ludewig
*/
@Singleton
@Extension
public class LDAPAuthenticationHandler implements AuthenticationHandler
{
/** Field description */
public static final String ATTRIBUTE_GROUP_NAME = "cn";
/** Field description */
public static final String FILTER_GROUP =
"(&(objectClass=groupOfUniqueNames)(uniqueMember={0}))";
/** Field description */
public static final String SEARCHTYPE_GROUP = "group";
/** Field description */
public static final String SEARCHTYPE_USER = "user";
/** Field description */
public static final String TYPE = "ldap";
/** the logger for PAMAuthenticationHandler */
private static final Logger logger =
LoggerFactory.getLogger(LDAPAuthenticationHandler.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param factory
*/
@Inject
public LDAPAuthenticationHandler(StoreFactory factory)
{
store = factory.getStore(LDAPConfig.class, TYPE);
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param request
* @param response
* @param username
* @param password
*
* @return
*/
@Override
public AuthenticationResult authenticate(HttpServletRequest request,
HttpServletResponse response, String username, String password)
{
AuthenticationResult result = AuthenticationResult.NOT_FOUND;
if (config.isEnabled())
{
AssertUtil.assertIsNotEmpty(username);
AssertUtil.assertIsNotEmpty(password);
result = authenticate(username, password);
}
else if (logger.isWarnEnabled())
{
logger.warn("ldap plugin is disabled");
}
return result;
}
/**
* Method description
*
*
* @throws IOException
*/
@Override
public void close() throws IOException
{
// do nothing
}
/**
* Method description
*
*
* @param context
*/
@Override
public void init(SCMContextProvider context)
{
config = store.get();
if (config == null)
{
config = new LDAPConfig();
store.set(config);
}
buildLdapProperties();
}
/**
* Method description
*
*/
public void storeConfig()
{
store.set(config);
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public LDAPConfig getConfig()
{
return config;
}
/**
* Method description
*
*
* @return
*/
@Override
public String getType()
{
return TYPE;
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
* @param config
*/
public void setConfig(LDAPConfig config)
{
this.config = config;
buildLdapProperties();
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param list
* @param attribute
*/
private void appendAttribute(List<String> list, String attribute)
{
if (Util.isNotEmpty(attribute))
{
list.add(attribute);
}
}
/**
* Method description
*
*
* @param username
* @param password
*
* @return
*/
private AuthenticationResult authenticate(String username, String password)
{
AuthenticationResult result = AuthenticationResult.NOT_FOUND;
DirContext bindContext = null;
try
{
bindContext = createBindContext();
if (bindContext != null)
{
SearchResult searchResult = getUserSearchResult(bindContext, username);
if (searchResult != null)
{
result = AuthenticationResult.FAILED;
String userDN = searchResult.getNameInNamespace();
if (authenticateUser(userDN, password))
{
Attributes attributes = searchResult.getAttributes();
User user = createUser(attributes);
Set<String> groups = new HashSet<String>();
fetchGroups(bindContext, groups, userDN);
getGroups(attributes, groups);
result = new AuthenticationResult(user, groups);
} // password wrong ?
} // user not found
} // no bind context available
}
finally
{
LdapUtil.close(bindContext);
}
return result;
}
/**
* Method description
*
*
* @param userDN
* @param password
*
* @return
*/
private boolean authenticateUser(String userDN, String password)
{
boolean authenticated = false;
Hashtable<String, String> userProperties = new Hashtable<String,
String>(ldapProperties);
userProperties.put(Context.SECURITY_PRINCIPAL, userDN);
userProperties.put(Context.SECURITY_CREDENTIALS, password);
DirContext userContext = null;
try
{
userContext = new InitialDirContext(userProperties);
authenticated = true;
if (logger.isDebugEnabled())
{
logger.debug("user {} successfully authenticated", userDN);
}
}
catch (NamingException ex)
{
if (logger.isTraceEnabled())
{
logger.trace("authentication failed for user ".concat(userDN), ex);
}
else if (logger.isWarnEnabled())
{
logger.debug("authentication failed for user {}", userDN);
}
}
finally
{
LdapUtil.close(userContext);
}
return authenticated;
}
/**
* Method description
*
*/
private void buildLdapProperties()
{
ldapProperties = new Hashtable<String, String>();
ldapProperties.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
ldapProperties.put(Context.PROVIDER_URL, config.getHostUrl());
ldapProperties.put(Context.SECURITY_AUTHENTICATION, "simple");
ldapProperties.put(Context.SECURITY_PRINCIPAL, config.getConnectionDn());
ldapProperties.put(Context.SECURITY_CREDENTIALS,
config.getConnectionPassword());
ldapProperties.put("java.naming.ldap.version", "3");
}
/**
* Method description
*
*
* @return
*/
private DirContext createBindContext()
{
DirContext context = null;
try
{
context = new InitialDirContext(ldapProperties);
}
catch (NamingException ex)
{
logger.error(
"could not bind to ldap with dn ".concat(config.getConnectionDn()),
ex);
}
return context;
}
/**
* Method description
*
*
* @return
*/
private String createGroupSearchBaseDN()
{
return createSearchBaseDN(SEARCHTYPE_GROUP, config.getUnitGroup());
}
/**
* Method description
*
*
* @param type
* @param prefix
*
* @return
*/
private String createSearchBaseDN(String type, String prefix)
{
String dn = null;
if (Util.isNotEmpty(config.getBaseDn()))
{
if (Util.isNotEmpty(prefix))
{
dn = prefix.concat(",").concat(config.getBaseDn());
}
else
{
if (logger.isDebugEnabled())
{
logger.debug("no prefix for {} defined, using basedn for search",
type);
}
dn = config.getBaseDn();
}
if (logger.isDebugEnabled())
{
logger.debug("saarch base for {} search: {}", type, dn);
}
}
else
{
logger.error("no basedn defined");
}
return dn;
}
/**
* Method description
*
*
* @param attributes
*
* @return
*/
private User createUser(Attributes attributes)
{
User user = new User();
user.setName(LdapUtil.getAttribute(attributes,
config.getAttributeNameId()));
user.setDisplayName(LdapUtil.getAttribute(attributes,
config.getAttributeNameFullname()));
user.setMail(LdapUtil.getAttribute(attributes,
config.getAttributeNameMail()));
user.setType(TYPE);
return user;
}
/**
* Method description
*
*
* @return
*/
private String createUserSearchBaseDN()
{
return createSearchBaseDN(SEARCHTYPE_USER, config.getUnitPeople());
}
/**
* Method description
*
*
* @param username
*
* @return
*/
private String createUserSearchFilter(String username)
{
String filter = null;
if (Util.isNotEmpty(config.getSearchFilter()))
{
filter = MessageFormat.format(config.getSearchFilter(), username);
if (logger.isDebugEnabled())
{
logger.debug("search-filter for user search: {}", filter);
}
}
else
{
logger.error("search filter not defined");
}
return filter;
}
/**
* Method description
*
*
* @param context
* @param groups
* @param userDN
*/
private void fetchGroups(DirContext context, Set<String> groups,
String userDN)
{
NamingEnumeration<SearchResult> searchResultEnm = null;
try
{
// read group of unique names
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
searchControls.setReturningAttributes(new String[] { "cn" });
String filter = MessageFormat.format(FILTER_GROUP, userDN);
if (logger.isDebugEnabled())
{
logger.debug("using filter {} for group search", filter);
}
String searchDN = createGroupSearchBaseDN();
searchResultEnm = context.search(searchDN, filter, searchControls);
while (searchResultEnm.hasMore())
{
SearchResult searchResult = searchResultEnm.next();
Attributes groupAttributes = searchResult.getAttributes();
String name = LdapUtil.getAttribute(groupAttributes,
ATTRIBUTE_GROUP_NAME);
if (Util.isNotEmpty(name))
{
groups.add(name);
}
}
}
catch (NamingException ex)
{
logger.debug("groupOfUniqueNames not found", ex);
}
finally
{
LdapUtil.close(searchResultEnm);
}
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param attributes
* @param groups
*
*/
private void getGroups(Attributes attributes, Set<String> groups)
{
NamingEnumeration<?> userGroupsEnm = null;
try
{
Attribute groupsAttribute =
attributes.get(config.getAttributeNameGroup());
if (groupsAttribute != null)
{
userGroupsEnm = (NamingEnumeration<?>) groupsAttribute.getAll();
while (userGroupsEnm.hasMore())
{
groups.add((String) userGroupsEnm.next());
}
}
else
{
logger.info("user has no group attributes assigned");
}
}
catch (NamingException ex)
{
logger.error("could not read group attribute", ex);
}
finally
{
LdapUtil.close(userGroupsEnm);
}
}
/**
* Method description
*
*
* @return
*/
private String[] getReturnAttributes()
{
List<String> list = new ArrayList<String>();
appendAttribute(list, config.getAttributeNameId());
appendAttribute(list, config.getAttributeNameFullname());
appendAttribute(list, config.getAttributeNameMail());
appendAttribute(list, config.getAttributeNameMail());
return list.toArray(new String[list.size()]);
}
/**
* Method description
*
*
* @param bindContext
* @param username
*
* @return
*/
private SearchResult getUserSearchResult(DirContext bindContext,
String username)
{
SearchResult result = null;
if (bindContext != null)
{
NamingEnumeration<SearchResult> searchResultEnm = null;
try
{
SearchControls searchControls = new SearchControls();
int scope = LdapUtil.getSearchScope(config.getSearchScope());
if (logger.isDebugEnabled())
{
logger.debug("using scope {} for user search",
LdapUtil.getSearchScope(scope));
}
searchControls.setSearchScope(scope);
searchControls.setCountLimit(1);
searchControls.setReturningAttributes(getReturnAttributes());
String filter = createUserSearchFilter(username);
if (filter != null)
{
String baseDn = createUserSearchBaseDN();
if (baseDn != null)
{
searchResultEnm = bindContext.search(baseDn, filter,
searchControls);
if (searchResultEnm.hasMore())
{
result = searchResultEnm.next();
}
else if (logger.isWarnEnabled())
{
logger.warn("no user with username {} found", username);
}
}
}
}
catch (NamingException ex)
{
logger.error("exception occured during user search", ex);
}
finally
{
LdapUtil.close(searchResultEnm);
}
}
return result;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private LDAPConfig config;
/** Field description */
private Hashtable<String, String> ldapProperties;
/** Field description */
private Store<LDAPConfig> store;
}

View File

@@ -1,263 +0,0 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.auth.ldap;
//~--- JDK imports ------------------------------------------------------------
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Thorsten Ludewig
*/
@XmlRootElement(name = "ldap-config")
@XmlAccessorType(XmlAccessType.FIELD)
public class LDAPConfig
{
/**
* Method description
*
*
* @return
*/
public String getAttributeNameFullname()
{
return attributeNameFullname;
}
/**
* Method description
*
*
* @return
*/
public String getAttributeNameGroup()
{
return attributeNameGroup;
}
/**
* Method description
*
*
* @return
*/
public String getAttributeNameId()
{
return attributeNameId;
}
/**
* Method description
*
*
* @return
*/
public String getAttributeNameMail()
{
return attributeNameMail;
}
/**
* Method description
*
*
* @return
*/
public String getBaseDn()
{
return baseDn;
}
/**
* Method description
*
*
* @return
*/
public String getConnectionDn()
{
return connectionDn;
}
/**
* Method description
*
*
* @return
*/
public String getConnectionPassword()
{
return connectionPassword;
}
/**
* Method description
*
*
* @return
*/
public String getHostUrl()
{
return hostUrl;
}
/**
* Method description
*
*
* @return
*/
public String getSearchFilter()
{
return searchFilter;
}
/**
* Method description
*
*
* @return
*/
public String getSearchScope()
{
return searchScope;
}
/**
* Method description
*
*
* @return
*/
public String getUnitGroup()
{
return unitGroup;
}
/**
* Method description
*
*
* @return
*/
public String getUnitPeople()
{
return unitPeople;
}
/**
* Method description
*
*
* @return
*/
public boolean isEnabled()
{
return enabled;
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
*
* @param enabled
*/
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
@XmlElement(name = "attribute-name-fullname")
private String attributeNameFullname = "cn";
/** Field description */
@XmlElement(name = "attribute-name-group")
private String attributeNameGroup = "group";
/** Field description */
@XmlElement(name = "attribute-name-id")
private String attributeNameId = "uid";
/** Field description */
@XmlElement(name = "attribute-name-mail")
private String attributeNameMail = "mail";
/** Field description */
@XmlElement(name = "base-dn")
private String baseDn = "dc=scm-manager,dc=org";
/** Field description */
@XmlElement(name = "connection-dn")
private String connectionDn = "cn=Directory Manager";
/** Field description */
@XmlElement(name = "connection-password")
private String connectionPassword = "password";
/** Field description */
@XmlElement(name = "host-url")
private String hostUrl = "ldap://localhost:389";
/** Field description */
@XmlElement(name = "search-filter")
private String searchFilter = "(&(uid={0})(objectClass=posixAccount))";
/** Field description */
@XmlElement(name = "search-scope")
private String searchScope = "one";
/** Field description */
@XmlElement(name = "unit-groups")
private String unitGroup = "ou=Groups";
/** Field description */
@XmlElement(name = "unit-people")
private String unitPeople = "ou=People";
/** Field description */
@XmlElement(name = "enabled")
private boolean enabled = false;
}

View File

@@ -1,119 +0,0 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.auth.ldap;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Singleton;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
/**
*
* @author Thorsten Ludewig
*/
@Singleton
@Path("config/auth/ldap")
public class LDAPConfigResource
{
/**
* Constructs ...
*
*
* @param authenticationHandler
*/
@Inject
public LDAPConfigResource(LDAPAuthenticationHandler authenticationHandler)
{
this.authenticationHandler = authenticationHandler;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public LDAPConfig getConfig()
{
return authenticationHandler.getConfig();
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
* @param uriInfo
* @param config
*
* @return
*
* @throws IOException
*/
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response setConfig(@Context UriInfo uriInfo, LDAPConfig config)
throws IOException
{
authenticationHandler.setConfig(config);
authenticationHandler.storeConfig();
return Response.created(uriInfo.getRequestUri()).build();
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private LDAPAuthenticationHandler authenticationHandler;
}

View File

@@ -1,217 +0,0 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.auth.ldap;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
/**
*
* @author Sebastian Sdorra
*/
public class LdapUtil
{
/** Field description */
public static final String SCOPE_OBJECT = "object";
/** Field description */
public static final String SCOPE_ONE = "one";
/** Field description */
public static final String SCOPE_SUB = "sub";
/** the logger for LdapUtil */
private static final Logger logger = LoggerFactory.getLogger(LdapUtil.class);
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param context
*/
public static void close(Context context)
{
if (context != null)
{
try
{
context.close();
}
catch (NamingException ex)
{
logger.error(ex.getMessage(), ex);
}
}
}
/**
* Method description
*
*
* @param enm
*/
public static void close(NamingEnumeration<?> enm)
{
if (enm != null)
{
try
{
enm.close();
}
catch (NamingException ex)
{
logger.error(ex.getMessage(), ex);
}
}
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param attributes
* @param name
*
* @return
*
*/
public static String getAttribute(Attributes attributes, String name)
{
String value = null;
try
{
if (Util.isNotEmpty(name))
{
Attribute attribute = attributes.get(name);
if (attribute != null)
{
value = (String) attribute.get();
}
}
}
catch (NamingException ex)
{
logger.warn("could not fetch attribute ".concat(name), ex);
}
return value;
}
/**
* Method description
*
*
* @param scopeString
*
* @return
*/
public static int getSearchScope(String scopeString)
{
int scope = SearchControls.SUBTREE_SCOPE;
if (Util.isNotEmpty(scopeString))
{
scopeString = scopeString.trim();
if (SCOPE_SUB.equalsIgnoreCase(scopeString))
{
scope = SearchControls.SUBTREE_SCOPE;
}
else if (SCOPE_ONE.equalsIgnoreCase(scopeString))
{
scope = SearchControls.ONELEVEL_SCOPE;
}
else if (SCOPE_OBJECT.equalsIgnoreCase(scopeString))
{
scope = SearchControls.OBJECT_SCOPE;
}
else if (logger.isWarnEnabled())
{
logger.warn("unknown scope {}, using subtree scope", scopeString);
}
}
else if (logger.isWarnEnabled())
{
logger.warn("no search scope defined, using subtree scope");
}
return scope;
}
/**
* Method description
*
*
* @param scope
*
* @return
*/
public static String getSearchScope(int scope)
{
String scopeString = SCOPE_SUB;
switch (scope)
{
case SearchControls.ONELEVEL_SCOPE :
scopeString = SCOPE_ONE;
break;
case SearchControls.OBJECT_SCOPE :
scopeString = SCOPE_OBJECT;
}
return scopeString;
}
}

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<information>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<name>${project.name}</name>
<description>SCM-Manager LDAP Plugin</description>
<author>Thorsten Ludewig</author>
</information>
<packages>
<package>sonia.scm.auth.ldap</package>
</packages>
<resources>
<script>/sonia/scm/auth/ldap/sonia.ldap.js</script>
</resources>
</plugin>

View File

@@ -1,232 +0,0 @@
/* *
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
Ext.ns("Sonia.ldap");
Sonia.ldap.ConfigPanel = Ext.extend(Sonia.config.ConfigForm, {
titleText: 'LDAP Authentication',
idAttributeText: 'ID Attribute Name',
fullnameAttributeText: 'Fullname Attribute Name',
mailAttributeText: 'Mail Attribute Name',
groupAttributeText: 'Group Attribute Name',
baseDNText: 'Base DN',
connectionDNText: 'Connection DN',
connectionPasswordText: 'Connection Password',
hostURLText: 'Host URL',
searchFilterText: 'Search Filter',
searchScopeText: 'Search Scope',
groupsUnitText: 'Groups Unit',
peopleUnitText: 'People Unit',
enabledText: 'Enabled',
// help texts
idAttributeHelpText: 'The name of the ldap attribute which contains the username',
fullnameAttributeHelpText: 'The name of the ldap attribute which contains the displayname of the user',
mailAttributeHelpText: 'The name of the ldap attribute which contains the e-mail address of the user',
// TODO improve
groupAttributeHelpText: 'The name of the ldap attribute which contains the group names of the user',
baseDNHelpText: 'The basedn for example: dc=example,dc=com',
connectionDNHelpText: 'The complete dn of the connection user. <strong>Note:<strong> \n\
This user needs read an search privileges for the id, mail and fullname attributes.',
connectionPasswordHelpText: 'The password for connection user.',
hostURLHelpText: 'The url for the ldap server. For example: ldap://localhost:389/',
searchFilterHelpText: 'The search filter to find the users. <strong>Note:</strong>\n\
{0} will be replaced by the username.',
searchScopeHelpText: 'The scope for the user search.',
peopleUnitHelpText: 'The relative location of the users. For example: ou=People',
groupsUnitHelpText: 'The relative location of the users. For example: ou=Groups',
enabledHelpText: 'Enables or disables the ldap authentication',
initComponent: function(){
var config = {
title : this.titleText,
items : [{
xtype : 'textfield',
fieldLabel : this.idAttributeText,
name : 'attribute-name-id',
allowBlank : true,
helpText: this.idAttributeHelpText
},{
xtype : 'textfield',
fieldLabel : this.fullnameAttributeText,
name : 'attribute-name-fullname',
allowBlank : true,
helpText: this.fullnameAttributeHelpText
},{
xtype : 'textfield',
fieldLabel : this.mailAttributeText,
name : 'attribute-name-mail',
allowBlank : true,
helpText: this.mailAttributeHelpText
},{
xtype : 'textfield',
fieldLabel : this.groupAttributeText,
name : 'attribute-name-group',
allowBlank : true,
helpText: this.groupAttributeHelpText
},{
xtype : 'textfield',
fieldLabel : this.baseDNText,
name : 'base-dn',
allowBlank : true,
helpText: this.baseDNHelpText
},{
xtype : 'textfield',
fieldLabel : this.connectionDNText,
name : 'connection-dn',
allowBlank : true,
helpText: this.connectionDNHelpText
},{
xtype : 'textfield',
inputType: 'password',
fieldLabel : this.connectionPasswordText,
name : 'connection-password',
allowBlank : true,
helpText: this.connectionPasswordHelpText
},{
xtype : 'textfield',
fieldLabel : this.hostURLText,
name : 'host-url',
allowBlank : true,
helpText: this.hostURLHelpText
},{
xtype : 'textfield',
fieldLabel : this.searchFilterText,
name : 'search-filter',
allowBlank : true,
helpText: this.searchFilterHelpText
},{
xtype : 'combo',
fieldLabel : this.searchScopeText,
name : 'search-scope',
allowBlank : true,
helpText: this.searchScopeHelpText,
valueField: 'scope',
displayField: 'scope',
typeAhead: false,
editable: false,
triggerAction: 'all',
mode: 'local',
store: new Ext.data.SimpleStore({
fields: ['scope'],
data: [
['object'],
['one'],
['sub']
]
})
},{
xtype : 'textfield',
fieldLabel : this.peopleUnitText,
name : 'unit-people',
allowBlank : true,
helpText: this.peopleUnitHelpText
},{
xtype : 'textfield',
fieldLabel : this.groupsUnitText,
name : 'unit-groups',
allowBlank : true,
helpText: this.groupsUnitHelpText
},{
xtpye: 'checkbox',
fieldLabel : this.enabledText,
name: 'enabled',
helpText: this.enabledHelpText
}]
}
Ext.apply(this, Ext.apply(this.initialConfig, config));
Sonia.ldap.ConfigPanel.superclass.initComponent.apply(this, arguments);
},
onSubmit: function(values){
this.el.mask(this.submitText);
Ext.Ajax.request({
url: restUrl + 'config/auth/ldap.json',
method: 'POST',
jsonData: values,
scope: this,
disableCaching: true,
success: function(response){
this.el.unmask();
},
failure: function(){
this.el.unmask();
}
});
},
onLoad: function(el){
var tid = setTimeout( function(){el.mask(this.loadingText);}, 100);
Ext.Ajax.request({
url: restUrl + 'config/auth/ldap.json',
method: 'GET',
scope: this,
disableCaching: true,
success: function(response){
var obj = Ext.decode(response.responseText);
this.load(obj);
clearTimeout(tid);
el.unmask();
},
failure: function(){
el.unmask();
clearTimeout(tid);
alert('failure');
}
});
}
});
// register xtype
Ext.reg("ldapConfigPanel", Sonia.ldap.ConfigPanel);
// i18n
if ( i18n != null && i18n.country == 'de' ){
Ext.override(Sonia.ldap.ConfigPanel, {
// TODO
});
}
// regist config panel
registerGeneralConfigPanel({
id: 'ldapConfigPanel',
xtype: 'ldapConfigPanel'
});