Page 1 of 1

LDAP / AD authentication

PostPosted: Mon Oct 16, 2006 11:45 am
by Svenson
Hi.

Would it by possible to have LDAP User authentication ?
It would be awesome if Subsonic could authenticate users against Active Directory.


Thanks,
Svenni

PostPosted: Mon Oct 16, 2006 6:56 pm
by sindre_mehus
Thanks for the suggestion, I'll consider it. It all depends on how hard it is to implement, and how user-friendly it will be.

Sindre

PostPosted: Sun Dec 30, 2007 1:07 pm
by thofmann
Hi,

I've found out about subsonic only a few weeks ago and I really love it.

I also wanted to use Active Directory (AD) for authentication and authorization. After playing around with the source a bit I found out that using AD for authentication is no problem. Authorization would also work based on group memberships but unfortunately subsonic does not use the GrantedAuthority instances available in acegi for all decisions that involve roles. Instead, the information is taken from the net.sourceforge.subsonic.domain.User which is populated from the role information in the database.

So supporting LDAP authorization would require some more code changes. Authentication on the other hand is pretty easy to do with the following changes to applicationContext-security.xml:


Code: Select all
    <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
        <property name="providers">
            <list>
                <!-- add the following line for LDAP authentication -->
               <ref local="activeDirectoryAuthenticationProvider"/>
                <!-- comment out the following line to disable database authentication -->
                <!--  <ref local="daoAuthenticationProvider"/> -->
                <bean class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
                    <property name="key" value="subsonic"/>
                </bean>
                <bean class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
                    <property name="key" value="subsonic"/>
                </bean>
            </list>
        </property>
    </bean>


Add the following bean definitions:

Code: Select all
   <bean id="initialDirContextFactory"
      class="org.acegisecurity.ldap.DefaultInitialDirContextFactory">
      <constructor-arg
         value="ldap://domain.com.hostname:389/cn=Users,dc=domain,dc=com" />
      <property name="managerDn">
         <value>
            <!-- the DN of a user that is able to read data from LDAP -->
            <![CDATA[CN=LDAP,CN=Users,DC=domain,DC=com]]>
         </value>
      </property>
      <property name="managerPassword">
         <!-- the password of the DN set above -->
         <value>secretpassword</value>
      </property>
      <property name="extraEnvVars">
         <map>
            <entry>
               <key>
                  <value>java.naming.referral</value>
               </key>
               <value>follow</value>
            </entry>
         </map>
      </property>
   </bean>

   <bean id="activeDirectoryAuthenticationProvider"
      class="org.acegisecurity.providers.ldap.LdapAuthenticationProvider">
      <constructor-arg>
         <ref local="bindAuthenticator" />
      </constructor-arg>
      <constructor-arg>
         <ref local="userDetailsServiceBasedAuthoritiesPopulator" />
      </constructor-arg>
   </bean>

   <bean id="bindAuthenticator"
      class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">
      <constructor-arg>
         <ref local="initialDirContextFactory" />
      </constructor-arg>
      <property name="userSearch">
         <ref local="userSearch" />
      </property>
   </bean>

   <bean id="userDetailsServiceBasedAuthoritiesPopulator"
      class="net.sourceforge.subsonic.ldap.UserDetailsServiceBasedAuthoritiesPopulator">
      <property name="userDetailsService" ref="securityService"/>
   </bean>

   <bean id="userSearch"
      class="org.acegisecurity.ldap.search.FilterBasedLdapUserSearch">
      <constructor-arg>
         <value></value>
      </constructor-arg>
      <constructor-arg>
         <value>(sAMAccountName={0})</value>
      </constructor-arg>
      <constructor-arg>
         <ref local="initialDirContextFactory" />
      </constructor-arg>
      <property name="searchSubtree">
         <value>true</value>
      </property>
      <property name="derefLinkFlag">
         <value>true</value>
      </property>
   </bean>


In addition to these configuration settings a new class needs to be added to the WEB-INF classes directory compiled from this source:
Code: Select all
package net.sourceforge.subsonic.ldap;

import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.ldap.LdapDataAccessException;
import org.acegisecurity.providers.ldap.LdapAuthoritiesPopulator;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;

/**
* An {@link LdapAuthoritiesPopulator} that retrieves the roles from the
* database using the {@link UserDetailsService} instead of retrieving the roles
* from LDAP. An instance of this class can be configured for the
* {@link org.acegisecurity.providers.ldap.LdapAuthenticationProvider} when
* authentication should be done using LDAP and authorization using the
* information stored in the database.
*
* @author Thomas M. Hofmann
*/
public class UserDetailsServiceBasedAuthoritiesPopulator implements
      LdapAuthoritiesPopulator {

   private UserDetailsService userDetailsService;

   public GrantedAuthority[] getGrantedAuthorities(LdapUserDetails userDetails)
         throws LdapDataAccessException {
      return userDetailsService.loadUserByUsername(userDetails.getUsername())
            .getAuthorities();
   }

   public void setUserDetailsService(UserDetailsService userDetailsService) {
      this.userDetailsService = userDetailsService;
   }
}


When you make these changes you will need to make sure that the user is added both in AD and in subsonic. The roles / user rights are stilled defined in subsonic only. Only the password / credentials are taken from LDAP so that your users do not need to change there passwords at several places / applications.

Thomas

PostPosted: Wed Jan 02, 2008 12:55 pm
by sindre_mehus
Hi Thomas,

Thanks for posting this! I'll consider adding LDAP support as part of the official release, but I need to fulfill the following requirements:

o It should be possible to enable/disable/edit LDAP settings dynamically from the web UI.
o It should be configurable on a per-user basis whether that user is authenticated by LDAP or by Subsonic's internal database.
o It should not be necessary to know the LDAP manager username/password.
o It should work with other LDAP servers, not only AD.

I'll have a look and see how difficult this would be.

Thanks again,
Sindre

PostPosted: Mon Jan 07, 2008 7:29 am
by sindre_mehus
I'm happy to inform you that LDAP authentication has been implemented for the 3.4 release.

Sindre

PostPosted: Mon Jan 21, 2008 12:55 am
by Svenson
Yehh, this is great news !

Will there be a beta version of 3.4 soon ?
I would really like to give it a try :)

PostPosted: Fri Feb 01, 2008 9:45 pm
by mistaox
hmm...well this is half of what i expected....

LDAP auth seems pointless if it is still dependant on a local Subsonic user account.
Also, having to create identical user names between Subsonic and AD seems rather redundant.

This feature should allow for Users to be managed exclusively by AD and the roles should be handled by Subsonic.

Subsonic should be able to pull user names from a AD Security Group and allow the Subsonic Admin to create even more granular permissions within Subsonic.

So if I add user "jsmith" to my "Subsonic-Users" Security group, Subsonic should then allow me to specify what roles or permissions he should have.

PostPosted: Fri Feb 01, 2008 11:00 pm
by sindre_mehus
mistaox wrote:This feature should allow for Users to be managed exclusively by AD and the roles should be handled by Subsonic.

It does.

PostPosted: Mon Feb 04, 2008 3:32 pm
by mistaox
NOICE!!!

PostPosted: Tue Apr 08, 2008 5:46 pm
by Svenson
Hi Sindre.
This is looking really good.

But the current LDAP lookup does not support BindDN and password.
And many LDAP / AD servers do not support anonymous bind.

Is it possible to give option to supply Bind user and password ?

Cheers !


ps . Here is an example of the error I get.

Code: Select all
[2008-04-03 13:39:31,850] INFO SubsonicLdapBindAuthenticator - Failed to authenticate user 'testuser' in LDAP.
org.acegisecurity.ldap.LdapDataAccessException: LdapCallback;[LDAP: error code 1 - 00000000: LdapErr: DSID-0C090627, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, vece]; nested exception is javax.naming.NamingException: [LDAP: error code 1 - 00000000: LdapErr: DSID-0C090627, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, vece]; remaining name ''
Caused by: javax.naming.NamingException: [LDAP: error code 1 - 00000000: LdapErr: DSID-0C090627, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, vece]; remaining name ''

PostPosted: Tue Apr 08, 2008 7:08 pm
by sindre_mehus
Svenson,

Yeah, I'll add that in the next 3.4 release.

Thanks for pointing it out!

PostPosted: Wed Apr 09, 2008 12:13 pm
by sindre_mehus
Can someone pls let me know if authentication in Active Directory works? I don't have an AD available for testing.

Cheers,
Sindre

PostPosted: Wed Apr 09, 2008 3:09 pm
by Svenson
It is at least not working for me ;-)
See the error in previous post.

Thank you it works with AD

PostPosted: Mon May 26, 2008 7:55 pm
by thofmann
Hi Sindre,

thanks a lot for integrating LDAP authentication. I had no problems with my AD.

Well, almost no problems.

If I try to authenticate through the WAP interface only without having a session the authentication fails.

If I log on to the normal UI and then switch to the WAP UI it works.

Regards,

Thomas