0

I am developing a web application with spring mvc framework and java. I am using active directory user authentication in the application.

Now i want to assign role to these users from a sql database. So the whole authentication process will be done by taking information from two sources: [ user id & password from active directory & roles of user from sql database ].

I have searched on internet to get any tutorial/samples to do so but I'm unable to get any useful stuff. So any help on the issue will be appreciated.

Here is the current code of my spring security file,

<bean id="adAuthenticationProvider"
      class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
    <constructor-arg value="abbl.org"/>
    <constructor-arg value="LDAP://abbl.org"/>
    <property name="convertSubErrorCodesToExceptions" value="true"/>
    <property name="useAuthenticationRequestCredentials" value="true"/>
</bean>

<bean id="customAuthenticationProvider"
      class="org.abbl.exhbp.templates.CustomAuthorityProvider">
    <constructor-arg ref="adAuthenticationProvider"/>
</bean>

<security:authentication-manager>
    <security:authentication-provider ref="customAuthenticationProvider"/>
</security:authentication-manager>

my authenticate function in AuthenticationProvider class,

public Authentication authenticate(Authentication authentication) {

    final Authentication a = delegate.authenticate(authentication);

    // Load additional authorities and create an Authentication object
    final List<GrantedAuthority> authorities = getGrantedAuthorities(a.getName());

    return new AbstractAuthenticationToken(authorities) {
        @Override
        public Object getCredentials() {
            //return null;  //To change body of implemented methods use File | Settings | File Templates.
            throw new UnsupportedOperationException();
        }

        @Override
        public Object getPrincipal() {
            //return null; //To change body of implemented methods use File | Settings | File Templates.
            return a.getPrincipal();
        }
    };
}

After login , i am getting this exception,

java.lang.UnsupportedOperationException
org.abbl.exhbp.templates.CustomAuthorityProvider$1.getCredentials(CustomAuthorityProvider.java:41)
org.springframework.security.authentication.AbstractAuthenticationToken.eraseCredentials(AbstractAuthenticationToken.java:108)
org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:186)
org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:195)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)

What modification or implementation I need to do here to achieve what i mentioned above?

Junaid
  • 1,179
  • 2
  • 18
  • 35
  • Have a look at [this answer](http://stackoverflow.com/a/9235912/241990). – Shaun the Sheep Apr 10 '14 at 11:19
  • possible duplicate of [Spring Security 3 Active Directory Authentication, Database Authorization](http://stackoverflow.com/questions/9228932/spring-security-3-active-directory-authentication-database-authorization) – Shaun the Sheep Apr 10 '14 at 11:20
  • I was just looking at that answer when you posted your comment. Actually i am new to spring framework. So far worked finding reference and samples from internet. So it will be very helpful for me if you can provide me any sample project or guideline exactly how i can achieve what i intended to do. I understood your custom AuthenticationProvider class pretty much. What i am not getting exactly how it will communicate with my sql database and in what format database will keep users and its roles track. Looking forward if you can help me on this ... – Junaid Apr 10 '14 at 11:33
  • You can store the users/roles any way you want. The function `loadRolesFromDatabaseHere` in that link would just load the roles for that user, based on their name, for example. You would write the SQL yourself. Something like the code from [this FAQ](http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/faq.html#faq-ldap-authorities) would do it. – Shaun the Sheep Apr 11 '14 at 14:48
  • @ Luke Taylor : I have made necessary modification according to suggestion and refrences. But after loging , i am getting avobe exception. can you tell me exactly what i am doing wrong here ? :-/ – Junaid Apr 15 '14 at 06:30

1 Answers1

0

Finally i achieved what i aimed for by using UsernamePasswordAuthenticationToken instead of AbstractAuthenticationToken. Solution is given below,

1) spring-security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:security="http://www.springframework.org/schema/security"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/security
   http://www.springframework.org/schema/security/spring-security.xsd">


<security:http auto-config="true" use-expressions="true">
    <security:anonymous enabled="false"/>
    <security:form-login login-page="/login" default-target-url="/home"
                         login-processing-url="/j_spring_security_check"
                         authentication-failure-url="/loginfailed"/>
    <security:logout logout-success-url="/logout"/>
</security:http>

<bean id="adAuthenticationProvider"
      class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
    <constructor-arg value="DOMAIN"/>
    <constructor-arg value="URL"/>
    <property name="convertSubErrorCodesToExceptions" value="true"/>
    <property name="useAuthenticationRequestCredentials" value="true"/>
</bean>

<bean id="customAuthenticationProvider"
      class="org.abbl.exhbp.templates.CustomAuthorityProvider">
    <constructor-arg ref="adAuthenticationProvider"/>
</bean>

<security:authentication-manager>
    <security:authentication-provider ref="customAuthenticationProvider"/>
</security:authentication-manager>

2) CustomAuthorityProvider.class

public class CustomAuthorityProvider implements AuthenticationProvider {

private AuthenticationProvider delegate;

public CustomAuthorityProvider(AuthenticationProvider delegate) {
    this.delegate = delegate;
}

public Authentication authenticate(Authentication authentication) {

    final Authentication a = delegate.authenticate(authentication);

    // Load additional authorities and create an Authentication object
    final List<GrantedAuthority> authorities = getGrantedAuthorities(a.getName());

    return new UsernamePasswordAuthenticationToken(a.getPrincipal(),a.getCredentials(),authorities);
}

@Override
public boolean supports(Class<?> authentication) {
    return delegate.supports(authentication);
}

List<GrantedAuthority> getGrantedAuthorities(String username) {
    JdbcTemplateDataSource ds = new JdbcTemplateDataSource();
    List<GrantedAuthority> roles = ds.getJdbcTemplate().query("select r.Role from Users u join UserRole ur on u.UserId = "
            + "ur.UserId join Roles r on r.RoleId = ur.RoleId where Username = ?",
            new String[]{username},
            new RowMapper<GrantedAuthority>() {
                public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException {
                    return new SimpleGrantedAuthority(rs.getString(1));
                }
            });
    return roles;
}
}
Junaid
  • 1,179
  • 2
  • 18
  • 35