0

I know that this question was asked many times but any answer solved my problem. I am trying to implement a custom login form using Spring Security 4 + Hibernate + Spring Data Jpa, but things don't work as I expect.

When I use in-memory credentials all work fine but I want to use my database instead.

Below the main code :

Xml security config.

    <beans:bean id="encodeurMotDePasse" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
        <beans:constructor-arg name="strength" value="12" />
    </beans:bean>

    <security:http auto-config="true" create-session="never">
        <security:intercept-url pattern="/" access="permitAll" />
        <security:intercept-url pattern="/inscription**" access="hasRole('ADMIN') or hasRole('USER')" />
        <security:intercept-url pattern="/connexion**" access="hasRole('USER') or hasRole('USER')" />
        <security:intercept-url pattern="/test**" access="hasRole('ADMIN')" />
        <security:intercept-url pattern="/dba**" access="hasRole('ADMIN')" />
        <security:form-login login-page="/login.html"
                             username-parameter="identifiant" 
                             password-parameter="motDePasse"
                             authentication-failure-url="/login.html?error=t"/>

    </security:http>

    <beans:bean id="customUserDetailsService" class="com.app.security.CustomUserDetailsService"/>
     <security:authentication-manager >
        <security:authentication-provider user-service-ref ="customUserDetailsService">
             <security:password-encoder ref="encodeurMotDePasse" />
        </security:authentication-provider> 
    </security:authentication-manager>

The UserDetailsService implementation :

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private ServicesDAO service;

    @Override
    public UserDetails loadUserByUsername( String username ) throws UsernameNotFoundException {

    T_authentification userPrincipals = service.getAuthenticatePrincipal( username );

    if ( userPrincipals == null ) {
        System.out.println( "user inexistant" );
        throw new UsernameNotFoundException( "L'utilisateur n'a pas été trouvé" );
    } else {
        System.out.println( "user trouvé" );
    }

    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

    for ( T_roles role : userPrincipals.getRoles() ) {
        System.out.println( " role dans userdetails service est :" + role.getRoleName() );
        authorities.add( new SimpleGrantedAuthority( role.getRoleName() ) );
    }

    // return new CustomUserDetails( userPrincipals );
    return new org.springframework.security.core.userdetails.User( userPrincipals.getUsername(), userPrincipals.getMotDePasse(), authorities );
 }
}

When I test the code in a controller method all credentials are well loaded from the database and I can print them on the console.

The other concern is when the login fails, Spring Security doesn't send any debug message in the console to tell the cause of this failure.

EDIT

Here my log4j.xml, I follow the configuration but any message appears in the console and the file are also empty.

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE log4j:configuration PUBLIC  "-//APACHE//DTD LOG4J 1.2//EN"    "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="true">

    <appender name="Appender1" class="org.apache.log4j.ConsoleAppender">
        <param name="Threshold" value="debug" />
       <layout class="org.apache.log4j.PatternLayout">
          <param name="ConversionPattern" value="%-7p %d [%t] %c %x - %m%n"/>
       </layout>
    </appender>

  <appender name="SpringAppender" class="org.apache.log4j.FileAppender"> 
        <param name="file" value="C:/Log4j/Spring-details.log" /> 
        <param name="Threshold" value="debug" />
        <param name="append" value="true" /> 
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                value="%d{MM/dd/yyyy HH:mm:ss}  [%t]:%c{5}.%M()%L %m%n" />
        </layout>
    </appender>

    <appender name="Appender2" class="org.apache.log4j.FileAppender">
       <param name="File" value="C:/Log4j/app.log" />
       <layout class="org.apache.log4j.PatternLayout">
          <param name="ConversionPattern" value="%-7p %d [%t] %c %x - %m%n"/>
       </layout>
    </appender>

     <category name="org.springframework">
        <priority value="ALL" />
    </category>


    <category name="org.springframework">
        <priority value="debug" />
    </category>

    <category name="org.springframework.beans">
        <priority value="debug" />
    </category>

    <category name="org.springframework.security">
        <priority value="debug" />
    </category>

    <category
        name="org.springframework.beans.CachedIntrospectionResults">
        <priority value="debug" />
    </category>

    <category name="org.springframework.jdbc.core">
        <priority value="debug" />
    </category>

    <category name="org.springframework.transaction.support.TransactionSynchronizationManager">
        <priority value="debug" />
    </category>

    <logger name="org.springframework" additivity="false">
        <level value="DEBUG"/>
        <appender-ref ref="SpringAppender"/>
    </logger>

    <root>
     <!--         <priority value="INFO"/> -->
        <level value="DEBUG"/>
        <appender-ref ref="Appender1" />
        <appender-ref ref="SpringAppender" />
        <appender-ref ref="Appender2" />
    </root>
</log4j:configuration> 

EDIT2

I got this exception when I try to @Autowire this bean <beans:bean id="customUserDetailsService" class="com.app.security.CustomUserDetailsService"/> in a java class.

Why this error occured?

ERROR javax.enterprise.web.core - ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'inscriptionController': Unsatisfied dependency expressed through field 'customUserDetailsService'; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'customUserDetailsService' is expected to be of type 'com.app.security.CustomUserDetailsService' but was actually of type 'com.sun.proxy.$Proxy323' at org.apache.catalina.core.StandardContext.start(StandardContext.java:5985)

Many thanks for your clarifications and sorry for my bad English.

akuma8
  • 4,160
  • 5
  • 46
  • 82
  • 1
    remove the `authentication-failure-url="/login.html?error=t"/>`, the exception will return directly then you can post the error here, and what's `encodeurMotDePasse` for `passwordEncoder` ? – chaoluo Dec 25 '16 at 13:58
  • I commented `authentication-failure-url="/login.html?error=t"` but nothing appear in the console. `encodeurMotDePasse` is my 'BCryptPasswordEncoder' bean. – akuma8 Dec 25 '16 at 15:19
  • the exception will return in response,not console. or you can enable the log to debug level. – chaoluo Dec 26 '16 at 01:31
  • How can I enable the log? I have a log4j.xml in the classpath how can I enable it ? – akuma8 Dec 26 '16 at 09:58
  • you can search it on stackoverflow.and what's the error message in response? – chaoluo Dec 26 '16 at 10:03
  • I edit and add the log4j.xml configuration. – akuma8 Dec 26 '16 at 14:09
  • add `` to security config. BTW, spring security use the common log, and if you want to change to SLF4J(log4j or logback), following this [document](http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/overview.html#overview-not-using-commons-logging) – chaoluo Dec 26 '16 at 14:24
  • I added ``, followed the link to add SLF4J + Log4J and copied information [here](http://stackoverflow.com/questions/7840088/debugging-spring-configuration) but still have the same issue. – akuma8 Dec 27 '16 at 22:46
  • 3 days now and I don't find any solution :(! – akuma8 Dec 27 '16 at 22:51
  • why `create-session="never"` for form login, Could you upload your simple project to github? – chaoluo Dec 28 '16 at 01:11
  • `create-session="never"` is to avoid that the framework creates a session, I want to do it myself. I add my project to [github](https://github.com/akuma8/chicowaProject.git) as you asked, it is on development so it is a little dirty. I need some help because I'm totally stuck. Many thanks. – akuma8 Dec 29 '16 at 00:57
  • `` `` this will send the error message in response directly. – chaoluo Dec 29 '16 at 02:15
  • I added this but it changed anything. I also added a `jdbc-user-service` authentication and it works well. So I don't know why only the `UserDetailsService` doesn't work. The most frustrating is that I can't see the error message after a logging failure. – akuma8 Dec 29 '16 at 19:01
  • Another idea? thanks a lot – akuma8 Dec 29 '16 at 20:48
  • I can't find any config to scan `com.chicowa.services`, but your `userDetailService` is depend on that. – chaoluo Dec 30 '16 at 01:39
  • In the file ´/WEB-INF/spring/servlet-config.xml´ I scan all the packages like this ´´ I will put the package explicitly to see if it changes something. – akuma8 Dec 30 '16 at 10:10
  • Hi, I am back cause I didn't yet solve my problem :( ! Now I can see the log message sent by spring security and it seems that the method which loads data from database sends `NULL`. I don't know why in the other classes this same method works fine and not in the class which implements `UserDetailsService`. It seems that the '@Autowired' here `@Autowired private ServicesDAO service;` doesn't work as expected. Any suggestion? Thanks – akuma8 Jan 05 '17 at 22:58
  • what do you mean "it seems that the method which loads data from database sends NULL" ? and Could you post the log ? – chaoluo Jan 06 '17 at 01:27
  • I mean that when I called my `ServicesDAO` method (`service.getAuthenticatePrincipal( username );`) to load data from database, the result was `null`. I found the reason of this strange behavior (for me it's strange) see the answer. – akuma8 Jan 06 '17 at 10:49
  • I solved the main problem but now when I want to `@Autowired` the bean defined in `spring-security.xml` in a .java class I have an exception (see EDIT2) – akuma8 Jan 06 '17 at 11:13

1 Answers1

0

I found the reason of this strange behavior.

I suppose that the spring security listener org.springframework.security.web.session.HttpSessionEventPublisherdoesn't share the same context as the servlet dispatcher. So, all beans defined in the mvc context are inaccessible for the security part.

To solve this, I had to add the <context:component-scan base-package=.... in the root context as all beans defined here are accessible everywhere.

I lost 2 weeks to find the reason of my problem :( !

akuma8
  • 4,160
  • 5
  • 46
  • 82