Spring security not intercepting request

springspring-mvcspring-security

I'm trying to do a basic spring security D/B authentication program.I tried this by two ways i.e.

Method 1 : Using custom tables for Spring Security authentication.
Method 2 : Using Spring security specific database tables for user authentication and authorization.

File Locations:
1. index.jsp -> webapp/index.jsp
2. welcome.jsp -> webapp/pages/welcome.jsp
3. login.jsp -> webapp/pages/login.jsp

For method 1,Spring security was not intercepting request and i didn't see errors in console.Instead of intercepting the request i was directly taken to welcome.jsp.

P.S – Since i was not trying authorization, i didn't use 'authorities-by-username-query' attribute below in security context xml. I'm not sure if its mandatory to create a table for authorization as well.

Below is my security-context.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:jee="http://www.springframework.org/schema/jee"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/security
      http://www.springframework.org/schema/security/spring-security-3.1.xsd
      http://www.springframework.org/schema/tx 
      http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

<security:http auto-config="true">
    <security:intercept-url pattern="/welcome.html" />
    <security:form-login login-page="/login.html"
        default-target-url="/welcome.html" authentication-failure-url="/loginfailed.html" />
    <security:logout logout-success-url="/logout.html" />
</security:http>

<security:authentication-manager>
    <security:authentication-provider>
        <security:jdbc-user-service data-source-ref="dataSource"
         users-by-username-query="select FIRST_NAME,LAST_NAME,PASSWORD from USER_AUTHENTICATION where FIRST_NAME=?" />
    </security:authentication-provider>
</security:authentication-manager>

web.xml:

 <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-  app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
 <display-name>SpringPOC</display-name>
 <servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
        /WEB-INF/applicationContextDirect.xml
        /WEB-INF/applicationContext-security.xml
    </param-value>
</context-param>
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

BaseController

//@RequestMapping(value="/login", method = RequestMethod.GET)
@RequestMapping("/login")
public ModelAndView login(Model model) {
    //System.out.println("Inside /login...");
    return new ModelAndView("login");
}
/*public String login(ModelMap model) {

    System.out.println("Inside /login...");
    return "login";

}*/

@RequestMapping(value="/loginfailed", method = RequestMethod.GET)
public String loginerror(ModelMap model) {

    model.addAttribute("error", "true");
    return "login";

}

@RequestMapping(value="/logout", method = RequestMethod.GET)
public String logout(ModelMap model) {

    return "login";

}

login.jsp

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
          <html>
         <head>
         <title>Login Page</title>
         <style>
         .errorblock {
    color: #ff0000;
    background-color: #ffEEEE;
    border: 3px solid #ff0000;
    padding: 8px;
    margin: 16px;
     }
     </style>
     </head>
     <body onload='document.f.j_username.focus();'>
    <h3>Login with Username and Password (Authentication with Database)</h3>

    <c:if test="${not empty error}">
        <div class="errorblock">
            Your login attempt was not successful, try again.<br /> Caused :
            ${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
        </div>
    </c:if>

    <form name='f' action="<c:url value='j_spring_security_check' />"
        method='POST'>

        <table>
            <tr>
                <td>User:</td>
                <td><input type='text' name='j_username' value=''>
                </td>
            </tr>
            <tr>
                <td>Password:</td>
                <td><input type='password' name='j_password' />
                </td>
            </tr>
            <tr>
                <td colspan='2'><input name="submit" type="submit"
                    value="submit" />
                </td>
            </tr>
            <tr>
                <td colspan='2'><input name="reset" type="reset" />
                </td>
            </tr>
        </table>

    </form>

index.jsp

    <body>
    <div id="content">
   <h1>Home Page</h1>
   <p>
   Anyone can view this page.
   </p>
   <p><a href="welcome.html">Login page</a></p>
   </div>
   </body>

For method 2, i created spring specific database tables in the name of “USERS” and “AUTHORITIES” after following the below link. Here SQL query is not used in xml as shown below.

 http://www.raistudies.com/spring-security-tutorial/authentication-authorization-spring-security-mysql-database/

Every thing remains same except for security-context.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:jee="http://www.springframework.org/schema/jee"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/security
      http://www.springframework.org/schema/security/spring-security-3.1.xsd
      http://www.springframework.org/schema/tx 
      http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

<security:http realm="Project Realm" auto-config="true">
    <security:intercept-url pattern="/welcome.html" access="ROLE_USER"/>
    <security:form-login login-page="/login.html"
        default-target-url="/welcome.html" authentication-failure-url="/loginfailed.html" />
    <security:logout logout-success-url="/logout.html" />   
</security:http>

<security:authentication-manager>
    <security:authentication-provider>
    <security:password-encoder hash="md5"/>
    <security:jdbc-user-service data-source-ref="dataSource"/>
    </security:authentication-provider>
</security:authentication-manager>
    </beans>

when i tried the above way, even though i enter correct user name & password, i was getting 'bad credentials' message [But yes, in this case spring security is intercepting the request]. I'm using Oracle database.

[Update]: I enabled spring debug logging to find the root cause of errors in both methods. I couldn't figure out or understand what exactly is wrong from logs, so i compared logs i got after trying both methods.As,for method 1 Spring security was not intercepting request and for method 2 i was able to login (Spring security was atleast intercepting request) but i was getting 'Bad credential' message even after entering correct username & password.

Below is the code snippet for method 2[ Here i get login page,but authentication is failing]

            firing Filter: 'FilterSecurityInterceptor'
        DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/welcome.html'; against 

        '/welcome.html'
        DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: 

        /welcome.html; Attributes: [ROLE_USER]
        DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: 

        org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: 

        [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: 

        RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
        DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: 

        org.springframework.security.access.vote.RoleVoter@19432e0, returned: -1
        DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: 

        org.springframework.security.access.vote.AuthenticatedVoter@9830bc, returned: 0
        DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Access is denied (user is anonymous); 

        redirecting to authentication entry point
        org.springframework.security.access.AccessDeniedException: Access is denied
            at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
            at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation

        (AbstractSecurityInterceptor.java:206)
            at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke

        (FilterSecurityInterceptor.java:115)
            at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter

        (FilterSecurityInterceptor.java:84)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter

        (AnonymousAuthenticationFilter.java:113)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter

        (SecurityContextHolderAwareRequestFilter.java:54)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter

        (BasicAuthenticationFilter.java:150)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter

        (AbstractAuthenticationProcessingFilter.java:183)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter

        (SecurityContextPersistenceFilter.java:87)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
            at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
            at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
            at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
            at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
            at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
            at java.lang.Thread.run(Thread.java:662)
        DEBUG: org.springframework.security.web.savedrequest.HttpSessionRequestCache - DefaultSavedRequest added to Session: 

        DefaultSavedRequest[http://localhost:8080/itrade-web/welcome.html]
        DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Calling Authentication entry point.
        DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to 'http://localhost:8080/itrade-

        web/login.html;jsessionid=3FD72892F4F4EF2E65B0C90ABE115354'
        DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents 

        are anonymous - context will not be stored in HttpSession.
        DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as 

        request processing completed
        DEBUG: org.springframework.security.web.FilterChainProxy - /login.html at position 1 of 10 in additional filter chain; 

        firing Filter: 'SecurityContextPersistenceFilter'
        DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
        firing Filter: 'UsernamePasswordAuthenticationFilter'
        ...
        DEBUG: org.springframework.security.web.FilterChainProxy - /login.html at position 7 of 10 in additional filter chain; 

        firing Filter: 'AnonymousAuthenticationFilter'
        DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with 

        anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@6fa8940c: Principal: 

        anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: 

        org.springframework.security.web.authentication.WebAuthenticationDetails@fffde5d4: RemoteIpAddress: 0:0:0:0:0:0:0:1; 

        SessionId: 3FD72892F4F4EF2E65B0C90ABE115354; Granted Authorities: ROLE_ANONYMOUS'
                    ...
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Request is to process 

        authentication
        DEBUG: org.springframework.security.authentication.ProviderManager - Authentication attempt using 

        org.springframework.security.authentication.dao.DaoAuthenticationProvider
        DEBUG: org.springframework.security.provisioning.JdbcUserDetailsManager - Query returned no results for user 'admin'
        DEBUG: org.springframework.security.authentication.dao.DaoAuthenticationProvider - User 'admin' not found
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Authentication request 

        failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Updated SecurityContextHolder 

        to contain null Authentication
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Delegating to authentication 

        failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@1882c1a
        DEBUG: org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler - Redirecting to 

        /loginfailed.html
        DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to '/itrade-web/loginfailed.html'
        DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents 

        are anonymous - context will not be stored in HttpSession.
        DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as 

        request processing completed

[Update] For method 1 ,i added 'authorities-by-username-query' tag after creating a custom table for 'authorization'. Now i'm getting login screen, so i got to know inorder for spring security to intercept i need to have 'authorities-by-username-query' tag .But after entering user name and password i get following error mesage :

 Caused : PreparedStatementCallback; uncategorized SQLException for SQL [select          FIRST_NAME,LAST_NAME,PASSWORD from USER_AUTHENTICATION where FIRST_NAME=?]; SQL state   [null]; error code [17059]; Fail to convert to internal representation; nested exception is   java.sql.SQLException: Fail to convert to internal representation 

i see following lines in debug mode :

            DEBUG: org.springframework.security.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
        INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Authentication request failed: org.springframework.security.authentication.AuthenticationServiceException: PreparedStatementCallback; uncategorized SQLException for SQL [select FIRST_NAME,LAST_NAME,PASSWORD from USER_AUTHENTICATION where FIRST_NAME=?]; SQL state [null]; error code [17059]; Fail to convert to internal representation; nested exception is java.sql.SQLException: Fail to convert to internal representation
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Updated SecurityContextHolder to contain null Authentication
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@e7736c
        DEBUG: org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler - Redirecting to /loginfailed.html
        DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to '/itrade-web/loginfailed.html'

[Update]: Now for both methods i'm getting same error though i enter correct user name & password.Also,since i could fetch data from D/B i'm sure that I'm not going wrong because of data not present in D/B.

 DEBUG: org.springframework.security.provisioning.JdbcUserDetailsManager - Query returned no results for user 'user'

I feel there should be any other reason behind this error.

[Edit] Now I've following 'users_detail' table in D/B :

USER_ID INTEGER

USERNAME VARCHAR2 (50 Byte)

PASSWORD VARCHAR2 (50 Byte)

ENABLED INTEGER

Data in the 'users_detail' table :

USER_ID USERNAME PASSWORD ENABLED

100 user 123456 1

My query is in security-context.xml :

  "select username,password, enabled from users_detail where username=?"

when i execute the query manually i.e. select username,password,enabled from users_detail where username='user'. i get the resultsets.

Where am i going wrong ? Why is it that JdbcUserDetailsManager class always return 'Query returned no results for user 'user' ' even though there is an entry for the same in D/B.

Debug mode doesn't show which method of JdbcUserDetailsManager class is being executed when i get the above error. How can i know that? Also, does spring internally do any encryption/decryption technique while saving password field?

Best Answer

The log message "User 'admin' not found" seems pretty clear as a reason for authentication failure, when using the default schema. Why not just execute the command manually and see if it returns the user data?

Also, whether the login screen is shown doesn't depend on whether you set "'authorities-by-username-query" or not. It only depends on whether what intercept-url values apply for the URL you request. The only exception would be if you have customized the access-denied behaviour (for an authenticated user with insufficient rights) to show the login page (not the case here).

Your SQL exception is probably due to your custom table having the wrong column types. You need to end up with something compatible with the result set obtained from the standard schema. Better to stick with the default unless you have a good reason not to.

Better still, forget about Oracle completely until you can get the basics working with a simple test database like HSQLDB.

Related Topic