diff --git a/plugins/scm-auth-ldap-plugin/pom.xml b/plugins/scm-auth-ldap-plugin/pom.xml index 92a3205900..65e4420914 100644 --- a/plugins/scm-auth-ldap-plugin/pom.xml +++ b/plugins/scm-auth-ldap-plugin/pom.xml @@ -6,7 +6,7 @@ scm-plugins sonia.scm.plugins - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins @@ -30,7 +30,7 @@ sonia.scm scm-test - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT test diff --git a/plugins/scm-auth-ldap-plugin/src/main/java/sonia/scm/auth/ldap/LDAPAuthenticationHandler.java b/plugins/scm-auth-ldap-plugin/src/main/java/sonia/scm/auth/ldap/LDAPAuthenticationHandler.java index 028ff45d04..4230946bb2 100644 --- a/plugins/scm-auth-ldap-plugin/src/main/java/sonia/scm/auth/ldap/LDAPAuthenticationHandler.java +++ b/plugins/scm-auth-ldap-plugin/src/main/java/sonia/scm/auth/ldap/LDAPAuthenticationHandler.java @@ -29,6 +29,8 @@ * */ + + package sonia.scm.auth.ldap; //~--- non-JDK imports -------------------------------------------------------- @@ -51,8 +53,22 @@ import sonia.scm.web.security.AuthenticationResult; import java.io.IOException; +import java.text.MessageFormat; + +import java.util.Properties; + +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +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; +import sonia.scm.user.User; /** * @@ -105,6 +121,90 @@ public class LDAPAuthenticationHandler implements AuthenticationHandler AssertUtil.assertIsNotEmpty(password); AuthenticationResult result = AuthenticationResult.NOT_FOUND; + DirContext context = null; + + try + { + context = new InitialDirContext(ldapProperties); + + SearchControls searchControls = new SearchControls(); + + searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); + searchControls.setCountLimit(1); + searchControls.setReturningAttributes(new String[] { + config.getAttributeNameId(), + config.getAttributeNameFullname(), config.getAttributeNameMail() }); + + String filter = MessageFormat.format(config.getSearchFilter(), username); + String baseDn = config.getUnitPeople() + "," + config.getBaseDn(); + NamingEnumeration searchResult = context.search(baseDn, + filter, searchControls); + + if (searchResult.hasMore()) + { + result = AuthenticationResult.FAILED; + + SearchResult sr = searchResult.next(); + String userDn = sr.getName() + "," + baseDn; + Properties userProperties = new Properties(ldapProperties); + + userProperties.put(Context.SECURITY_PRINCIPAL, userDn); + userProperties.put(Context.SECURITY_CREDENTIALS, password); + + DirContext userContext = null; + + try + { + userContext = new InitialDirContext(userProperties); + + User user = new User(); + Attributes userAttributes = sr.getAttributes(); + user.setName((String)userAttributes.get(config.getAttributeNameId()).get()); + user.setDisplayName((String)userAttributes.get(config.getAttributeNameFullname()).get()); + user.setMail((String)userAttributes.get(config.getAttributeNameMail()).get()); + user.setType(TYPE); + result = new AuthenticationResult(user); + } + catch (NamingException ex) + { + logger.trace(ex.getMessage(), ex); + } + finally + { + if (userContext != null) + { + try + { + userContext.close(); + } + catch (NamingException ex) + { + logger.error(ex.getMessage(), ex); + } + } + } + } + + searchResult.close(); + } + catch (NamingException ex) + { + logger.error(ex.getMessage(), ex); + } + finally + { + if (context != null) + { + try + { + context.close(); + } + catch (NamingException ex) + { + logger.error(ex.getMessage(), ex); + } + } + } return result; } @@ -138,6 +238,8 @@ public class LDAPAuthenticationHandler implements AuthenticationHandler config = new LDAPConfig(); store.set(config); } + + buildLdapProperties(); } /** @@ -185,14 +287,45 @@ public class LDAPAuthenticationHandler implements AuthenticationHandler public void setConfig(LDAPConfig config) { this.config = config; + buildLdapProperties(); } + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + */ + private void buildLdapProperties() + { + ldapProperties = new Properties(); + ldapProperties.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + ldapProperties.put(Context.PROVIDER_URL, config.getHostUrl()); + ldapProperties.put(Context.SECURITY_AUTHENTICATION, "simple"); + + /* + * if( contextSecurityProtocol.equalsIgnoreCase( "ssl" ) ) + * { + * ldapContextProperties.put( Context.SECURITY_PROTOCOL, "ssl" ); + * ldapContextProperties.put( "java.naming.ldap.factory.socket", + * "sonia.net.ssl.SSLSocketFactory" ); + * } + */ + ldapProperties.put(Context.SECURITY_PRINCIPAL, config.getConnectionDn()); + ldapProperties.put(Context.SECURITY_CREDENTIALS, + config.getConnectionPassword()); + ldapProperties.put("java.naming.ldap.version", "3"); + } //~--- fields --------------------------------------------------------------- /** Field description */ private LDAPConfig config; + /** Field description */ + private Properties ldapProperties; + /** Field description */ private Store store; } diff --git a/plugins/scm-auth-ldap-plugin/src/main/java/sonia/scm/auth/ldap/LDAPConfig.java b/plugins/scm-auth-ldap-plugin/src/main/java/sonia/scm/auth/ldap/LDAPConfig.java index f8ad66d5c6..e2431bed1f 100644 --- a/plugins/scm-auth-ldap-plugin/src/main/java/sonia/scm/auth/ldap/LDAPConfig.java +++ b/plugins/scm-auth-ldap-plugin/src/main/java/sonia/scm/auth/ldap/LDAPConfig.java @@ -325,7 +325,7 @@ public class LDAPConfig /** Field description */ @XmlElement(name = "search-filter") - private String searchFilter = "objectClass=posixAccount"; + private String searchFilter = "(&(uid={0})(objectClass=posixAccount))"; /** Field description */ @XmlElement(name = "search-scope") diff --git a/plugins/scm-auth-ldap-plugin/src/main/resources/META-INF/scm/plugin.xml b/plugins/scm-auth-ldap-plugin/src/main/resources/META-INF/scm/plugin.xml index c2f77990d1..9b1228a219 100644 --- a/plugins/scm-auth-ldap-plugin/src/main/resources/META-INF/scm/plugin.xml +++ b/plugins/scm-auth-ldap-plugin/src/main/resources/META-INF/scm/plugin.xml @@ -6,11 +6,8 @@ ${project.artifactId} ${project.version} ${project.name} - ${project.description} - + SCM-Manager LDAP Plugin + Thorsten Ludewig diff --git a/plugins/scm-auth-ldap-plugin/src/main/resources/sonia/scm/auth/ldap/sonia.ldap.js b/plugins/scm-auth-ldap-plugin/src/main/resources/sonia/scm/auth/ldap/sonia.ldap.js index 1c78176334..5dc6021193 100644 --- a/plugins/scm-auth-ldap-plugin/src/main/resources/sonia/scm/auth/ldap/sonia.ldap.js +++ b/plugins/scm-auth-ldap-plugin/src/main/resources/sonia/scm/auth/ldap/sonia.ldap.js @@ -33,22 +33,104 @@ registerGeneralConfigPanel({ xtype : 'configForm', - title : 'PAM Authentication', + title : 'LDAP Authentication', items : [{ xtype : 'textfield', - fieldLabel : 'Service name', - name : 'service-name', - allowBlank : false + fieldLabel : 'Admin NSRole DN', + name : 'admin-nsrole-dn', + allowBlank : true },{ xtype : 'textfield', fieldLabel : 'Admin Groups', name : 'admin-groups', allowBlank : true - },{ + } + ,{ xtype : 'textfield', fieldLabel : 'Admin Users', name : 'admin-users', allowBlank : true + } + ,{ + xtype : 'textfield', + fieldLabel : 'Fullname Attribute Name', + name : 'attribute-name-fullname', + allowBlank : true + } + ,{ + xtype : 'textfield', + fieldLabel : 'ID Attribute Name', + name : 'attribute-name-id', + allowBlank : true + } + ,{ + xtype : 'textfield', + fieldLabel : 'Mail Attribute Name', + name : 'attribute-name-mail', + allowBlank : true + } + ,{ + xtype : 'textfield', + fieldLabel : 'Base DN', + name : 'base-dn', + allowBlank : true + } + ,{ + xtype : 'textfield', + fieldLabel : 'Connection DN', + name : 'connection-dn', + allowBlank : true + } + ,{ + xtype : 'textfield', + inputType: 'password', + fieldLabel : 'Connection Password', + name : 'connection-password', + allowBlank : true + } + ,{ + xtype : 'textfield', + fieldLabel : 'Host URL', + name : 'host-url', + allowBlank : true + } + ,{ + xtype : 'textfield', + fieldLabel : 'Search Filter', + name : 'search-filter', + allowBlank : true + } + ,{ + xtype : 'combo', + fieldLabel : 'Search Scope', + name : 'search-scope', + allowBlank : true, + 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 : 'Groups Unit', + name : 'unit-groups', + allowBlank : true + } + ,{ + xtype : 'textfield', + fieldLabel : 'Groups People', + name : 'unit-people', + allowBlank : true }], onSubmit: function(values){