Announcement Announcement Module
Collapse
No announcement yet.
Overriding messages.properties Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Overriding messages.properties

    I am overriding the messages.properties so that I can show custom messages. For example, I have replaced all occurrences of "Bad credentials" with "Login information is invalid. Please try again." If I enter a valid user name and invalid password, I get my custom message. However, if I enter an invalid user name with a password, I still get "Bad credentials".

    Any thoughts on why I would still get the "Bad credentials" message? I'm using LDAP authentication.

    Thanks in advance for your help.

  • #2
    Hi logic

    I had a similar problem when I tried to customize these messages.
    Perhaps this post could help you.

    I wasn´t using LDAP authentication, but I think I shouldn´t matter.

    Regards

    Comment


    • #3
      Thanks for the reply EmilioSpring. Unfortunately, I tried your solution and it still did not work. Specifically, I did this

      Code:
           <bean id="messageSource"   
            class="org.springframework.context.support.ResourceBundleMessageSource">  
            <property name="basenames">  
                <list>
                    <value>classpath:/resources/messages</value>
                </list>
            </property>
          </bean>
      When I do that, I get a WARN message from Spring Security noting that it cannot find the messages and will default to the standard messages.

      I think you had a slightly different issue in that you were not getting any of your custom messages to show. In my case, I get my custom messages to show (if I change the value back to messages) except in the one scenario that I mentioned above.

      So, I know that the message.properties file is being used in all but this scenario. In this scenario, it appears that Spring Security either has the message hard coded or that it references a message that is in another file (I'm overriding all message.properties).

      Comment


      • #4
        The fact that you are getting the customization for flow and not another makes me think you might be missing some of the keys. Did you ensure to add keys from the BindAuthenticator/PasswordComparisonAuthenticator (i.e. BindAuthenticator.badCredentials, PasswordComparisonAuthenticator.badCredentials)? Ensure you copy the entire file from Spring Security and look for the error message you are getting and replace it with the one you desire.

        You could probably enable debug logging to see what key you are missing too (i.e. see where the stack trace of the exception that is internationalized is coming from).

        Comment


        • #5
          Thanks rwinch. I verified that those two entries are overridden in my messages.properties. The exception is this:

          979718 DEBUG UsernamePasswordAuthenticationFilter - Authentication request failed: org.springframework.security.authentication.BadCre dentialsException: Bad credentials

          I've looked a bit in the code but have not been able to determine where it's pulling the message. Here's my message.properties for reference. I constructed this by copying the one from Spring Security and doing a find and replace on Bad credentials.

          Code:
          AuthByAdapterProvider.incorrectKey=The presented AuthByAdapter implementation does not contain the expected key
          BasicAclEntryAfterInvocationProvider.noPermission=Authentication {0} has NO permissions at all to the domain object {1}
          BasicAclEntryAfterInvocationProvider.insufficientPermission=Authentication {0} has ACL permissions to the domain object, but not the required ACL permission to the domain object {1}
          ConcurrentSessionControllerImpl.exceededAllowed=Maximum sessions of {0} for this principal exceeded
          ProviderManager.providerNotFound=No AuthenticationProvider found for {0}
          AnonymousAuthenticationProvider.incorrectKey=The presented AnonymousAuthenticationToken does not contain the expected key
          CasAuthenticationProvider.incorrectKey=The presented CasAuthenticationToken does not contain the expected key
          CasAuthenticationProvider.noServiceTicket=Failed to provide a CAS service ticket to validate
          NamedCasProxyDecider.untrusted=Nearest proxy {0} is untrusted
          RejectProxyTickets.reject=Proxy tickets are rejected
          AbstractSecurityInterceptor.authenticationNotFound=An Authentication object was not found in the SecurityContext
          AbstractUserDetailsAuthenticationProvider.onlySupports=Only UsernamePasswordAuthenticationToken is supported
          AbstractUserDetailsAuthenticationProvider.locked=User account is locked
          AbstractUserDetailsAuthenticationProvider.disabled=User is disabled
          AbstractUserDetailsAuthenticationProvider.expired=User account has expired
          AbstractUserDetailsAuthenticationProvider.credentialsExpired=User credentials have expired
          AbstractUserDetailsAuthenticationProvider.badCredentials=Login information is invalid. Please try again.
          X509AuthenticationProvider.certificateNull=Certificate is null
          DaoX509AuthoritiesPopulator.noMatching=No matching pattern was found in subjectDN: {0}
          RememberMeAuthenticationProvider.incorrectKey=The presented RememberMeAuthenticationToken does not contain the expected key
          RunAsImplAuthenticationProvider.incorrectKey=The presented RunAsUserToken does not contain the expected key
          DigestProcessingFilter.missingMandatory=Missing mandatory digest value; received header {0}
          DigestProcessingFilter.missingAuth=Missing mandatory digest value for 'auth' QOP; received header {0}
          DigestProcessingFilter.incorrectRealm=Response realm name {0} does not match system realm name of {1}
          DigestProcessingFilter.nonceExpired=Nonce has expired/timed out
          DigestProcessingFilter.nonceEncoding=Nonce is not encoded in Base64; received nonce {0}
          DigestProcessingFilter.nonceNotTwoTokens=Nonce should have yielded two tokens but was {0}
          DigestProcessingFilter.nonceNotNumeric=Nonce token should have yielded a numeric first token, but was {0}
          DigestProcessingFilter.nonceCompromised=Nonce token compromised {0}
          DigestProcessingFilter.usernameNotFound=Username {0} not found
          DigestProcessingFilter.incorrectResponse=Incorrect response
          JdbcDaoImpl.notFound=User {0} not found
          JdbcDaoImpl.noAuthority=User {0} has no GrantedAuthority
          SwitchUserProcessingFilter.noCurrentUser=No current user associated with this request
          SwitchUserProcessingFilter.noOriginalAuthentication=Could not find original Authentication object
          SwitchUserProcessingFilter.usernameNotFound=Username {0} not found
          SwitchUserProcessingFilter.locked=User account is locked
          SwitchUserProcessingFilter.disabled=User is disabled
          SwitchUserProcessingFilter.expired=User account has expired
          SwitchUserProcessingFilter.credentialsExpired=User credentials have expired
          AbstractAccessDecisionManager.accessDenied=Access is denied
          LdapAuthenticationProvider.emptyUsername=Empty username not allowed
          LdapAuthenticationProvider.emptyPassword=Login information is invalid. Please try again.
          DefaultIntitalDirContextFactory.communicationFailure=Unable to connect to LDAP server
          DefaultIntitalDirContextFactory.badCredentials=Login information is invalid. Please try again.
          DefaultIntitalDirContextFactory.unexpectedException=Failed to obtain InitialDirContext due to unexpected exception
          PasswordComparisonAuthenticator.badCredentials=Login information is invalid. Please try again.
          BindAuthenticator.badCredentials=Login information is invalid. Please try again.
          BindAuthenticator.failedToLoadAttributes=Login information is invalid. Please try again.
          UserDetailsService.locked=User account is locked
          UserDetailsService.disabled=User is disabled
          UserDetailsService.expired=User account has expired
          UserDetailsService.credentialsExpired=User credentials have expired

          Comment


          • #6
            What version of Spring and Spring Security are you using? How are you obtaining the message (i.e. SPRING_SECURITY_LAST_EXCEPTION.message)? Do you by chance have message.properties on your classpath twice and one of them does not have all the resources overriden? Can you post your Spring Security configuration?

            Comment


            • #7
              Thanks for your help rwinch. Here are the answers to your questions.

              I am using version Spring Security 3.0.0 and Spring 3.0.2.

              In the login jsp page, I obtain the message via

              Code:
              <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/>
              I did a file search for message.properties and only found one message.properties (besides the one in the spring security core jar).

              Here's my spring (applicationContext.xml) config file:

              Code:
              <?xml version="1.0" encoding="UTF-8"?>
              <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
              
              <beans>    
                   <bean id="messageSource"   
                    class="org.springframework.context.support.ResourceBundleMessageSource">  
                    <property name="basenames">  
                        <list>
                            <value>messages</value>
                        </list>
                    </property>
                  </bean>
              </beans>
              It's referenced in the web.xml as follows:
              Code:
                  <context-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>
                    classpath:applicationContext-processor.xml
                    /WEB-INF/applicationContext-security.xml
                    /WEB-INF/applicationContext.xml
                  </param-value>
                </context-param>

              Comment


              • #8
                What type of ldap authentication are you doing (i.e. custom, Bind, Password compare, etc)? I assume you haven't customized Spring Security at all? When you say invalid username do you mean a username that does not exist? Can you give an example? Can you post the Spring Security configuration / web.xml?

                PS: You might checkout the contacts sample application from master git. It demonstrates setting up i18n (but not customizing it).
                Last edited by Rob Winch; Aug 19th, 2010, 05:32 PM. Reason: added define invalid username

                Comment


                • #9
                  Correct, I have not customized Spring Security beyond what is provided in the applicationContext-security.xml file. Here are the contents of that file:

                  Code:
                  <?xml version="1.0" encoding="UTF-8"?>
                  
                  <beans:beans xmlns="http://www.springframework.org/schema/security"
                      xmlns:beans="http://www.springframework.org/schema/beans"
                      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                      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.0.xsd">
                     
                       <http use-expressions="false" auto-config="true">
                          <intercept-url pattern="/html/login.jsp" filters="none"/>
                          <intercept-url pattern="/html/css/**" filters="none" />
                          <intercept-url pattern="/html/images/**" filters="none" />
                          <intercept-url pattern="/html/js/**" filters="none" />
                          <intercept-url pattern="/**" access="ROLE_MYGROUP" />
                          <access-denied-handler error-page="/html/login.jsp?login_error=2"/>
                          <form-login default-target-url="/html/" always-use-default-target="true" 
                                      login-page="/html/login.jsp" authentication-failure-url="/html/login.jsp?login_error=1"/>
                          <logout logout-success-url="/html/login.html" />
                      </http>
                  
                      <ldap-server url="ldap://myldapserver:389"
                                   manager-dn="cn=My Manager,cn=Users,dc=myorg,dc=local"
                                   manager-password="password"/>
                      
                       <authentication-manager>
                          <ldap-authentication-provider user-search-base="cn=Users,dc=myorg,dc=local" user-search-filter="(sAMAccountName={0})"
                            group-search-base="cn=MyGroup,cn=Users,dc=myorg,dc=local" role-prefix="ROLE_" group-search-filter="(member={0})"/>
                      </authentication-manager> 
                  
                  </beans:beans>
                  Here's the web.xml
                  Code:
                  <?xml version="1.0" encoding="ISO-8859-1"?>
                  <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                      xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
                      
                    <display-name>Web Application</display-name>
                      <context-param>
                      <param-name>contextConfigLocation</param-name>
                      <param-value>
                        classpath:applicationContext-processor.xml
                        /WEB-INF/applicationContext-security.xml
                        /WEB-INF/applicationContext.xml
                      </param-value>
                    </context-param>
                    
                    <context-param>
                      <param-name>log4jConfigLocation</param-name>
                      <param-value>/WEB-INF/log4j.properties</param-value>
                    </context-param>
                    
                    <listener>
                      <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
                    </listener>
                    
                    <listener>
                      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
                    </listener>
                  
                    <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>
                  
                      
                    <servlet>
                      <servlet-name>myservlet</servlet-name>
                      <servlet-class>
                        org.springframework.web.servlet.DispatcherServlet
                      </servlet-class>
                      <load-on-startup>1</load-on-startup>
                    </servlet>
                    
                    <servlet-mapping>
                      <servlet-name>myservlet</servlet-name>
                      <url-pattern>*.x</url-pattern>
                    </servlet-mapping>
                    
                    <session-config>
                      <session-timeout>1</session-timeout>
                    </session-config>
                    
                  </web-app>
                  Yes, by invalid username, I mean that the username does not exist. For example, this produces Bad credentials message..

                  username: bob
                  password: 123

                  The username bob is does not exist. These username password combinations do not produce the Bad credentials message but instead show my custom message..

                  // username does not exist and no password provided
                  username: bob
                  password:

                  // username does exist and no password provided
                  username: fred
                  password:

                  // username does exist and password is incorrect
                  username: fred
                  password: abc

                  Thanks for the links. I'll take a look and see if they can help.

                  Comment


                  • #10
                    Your spring security configuration was enough for me to know where the exception was being thrown. Looks like you found an i18n key that is not defined in message.properties of spring-core. I have logged a JIRA for this. In the meantime, try adding a key for LdapAuthenticationProvider.badCredentials and see if that helps.

                    Comment


                    • #11
                      As you suggested, I added the key to my message.properties and set the corresponding value to my custom message.

                      Code:
                      LdapAuthenticationProvider.badCredentials=Login information is incorrect.
                      That works great. The "Bad credentials" message no longer shows in the situation that I described.

                      I had been looking through the Spring Security code to see if I could spot a solution without much luck. So, many thanks for your help.

                      Comment

                      Working...
                      X