浏览代码

Additional event when user not found. Contributed by Karel Miarka.

Ben Alex 21 年之前
父节点
当前提交
da5469fed0

+ 2 - 1
contributors.txt

@@ -30,7 +30,8 @@ contributions to the Acegi Security System for Spring project:
 
 * Ray Krueger is a current member of the development team.
 
-* Karel Miarka contributed a fix for EH-CACHE NPEs.
+* Karel Miarka contributed a fix for EH-CACHE NPEs and additional event
+  handling for DaoAuthenticationProvider.
 
 * Anyone else I've forgotten (please let me know so I can correct this).
 

+ 15 - 1
core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java

@@ -20,12 +20,14 @@ import net.sf.acegisecurity.AuthenticationException;
 import net.sf.acegisecurity.AuthenticationServiceException;
 import net.sf.acegisecurity.BadCredentialsException;
 import net.sf.acegisecurity.DisabledException;
+import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.UserDetails;
 import net.sf.acegisecurity.providers.AuthenticationProvider;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
 import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureDisabledEvent;
 import net.sf.acegisecurity.providers.dao.event.AuthenticationFailurePasswordEvent;
+import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureUsernameNotFoundEvent;
 import net.sf.acegisecurity.providers.dao.event.AuthenticationSuccessEvent;
 import net.sf.acegisecurity.providers.encoding.PasswordEncoder;
 import net.sf.acegisecurity.providers.encoding.PlaintextPasswordEncoder;
@@ -190,7 +192,19 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
 
         if (user == null) {
             cacheWasUsed = false;
-            user = getUserFromBackend(username);
+
+            try {
+                user = getUserFromBackend(username);
+            } catch (BadCredentialsException ex) {
+                if (this.context != null) {
+                    context.publishEvent(new AuthenticationFailureUsernameNotFoundEvent(
+                            authentication,
+                            new User(username, "*****", false,
+                                new GrantedAuthority[0])));
+                }
+
+                throw ex;
+            }
         }
 
         if (!user.isEnabled()) {

+ 40 - 0
core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailureUsernameNotFoundEvent.java

@@ -0,0 +1,40 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.providers.dao.event;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.UserDetails;
+
+
+/**
+ * Application event which indicates authentication failure due to nonexistent
+ * username. <code>AuthenticationFailureUsernameNotFoundEvent.getUser()</code>
+ * returns an instance of <code>User</code>, where the username is filled by
+ * the <code>String</code> provided at login attempt. The other properties are
+ * set to non-<code>null</code> values without any meaning.
+ *
+ * @author Karel Miarka
+ */
+public class AuthenticationFailureUsernameNotFoundEvent
+    extends AuthenticationEvent {
+    //~ Constructors ===========================================================
+
+    //  ~ Constructors ===========================================================
+    public AuthenticationFailureUsernameNotFoundEvent(
+        Authentication authentication, UserDetails user) {
+        super(authentication, user);
+    }
+}

+ 13 - 1
core/src/main/java/org/acegisecurity/providers/dao/event/LoggerListener.java

@@ -45,7 +45,8 @@ public class LoggerListener implements ApplicationListener {
             AuthenticationFailurePasswordEvent authEvent = (AuthenticationFailurePasswordEvent) event;
 
             if (logger.isWarnEnabled()) {
-                logger.warn("Authentication failed due to incorrect password for user: "
+                logger.warn(
+                    "Authentication failed due to incorrect password for user: "
                     + authEvent.getUser().getUsername() + "; details: "
                     + authEvent.getAuthentication().getDetails());
             }
@@ -62,6 +63,17 @@ public class LoggerListener implements ApplicationListener {
             }
         }
 
+        if (event instanceof AuthenticationFailureUsernameNotFoundEvent) {
+            AuthenticationFailureUsernameNotFoundEvent authEvent = (AuthenticationFailureUsernameNotFoundEvent) event;
+
+            if (logger.isWarnEnabled()) {
+                logger.warn(
+                    "Authentication failed due to nonexistent username: "
+                    + authEvent.getUser().getUsername() + "; details: "
+                    + authEvent.getAuthentication().getDetails());
+            }
+        }
+
         if (event instanceof AuthenticationSuccessEvent) {
             AuthenticationSuccessEvent authEvent = (AuthenticationSuccessEvent) event;
 

+ 14 - 6
docs/reference/src/index.xml

@@ -1018,22 +1018,31 @@
           <listitem>
             <para><literal>AuthenticationFailureDisabledEvent</literal> is
             published when an authentication request is unsuccessful because
-            the returned <literal>User</literal> is disabled. This is normally
-            the case when an account is locked.</para>
+            the returned <literal>UserDetails</literal> is disabled. This is
+            normally the case when an account is locked.</para>
+          </listitem>
+
+          <listitem>
+            <para><literal>AuthenticationFailureUsernameNotFoundEvent</literal>
+            is published when an authentication request is unsuccessful
+            because the <literal>AuthenticationDao</literal> could not locate
+            the <literal>UserDetails</literal>.</para>
           </listitem>
 
           <listitem>
             <para><literal>AuthenticationFailurePasswordEvent</literal> is
             published when an authentication request is unsuccessful because
             the presented password did not match that in the
-            <literal>User</literal>.</para>
+            <literal>UserDetails</literal>.</para>
           </listitem>
         </itemizedlist>
 
         <para>Each event contains two objects: the
         <literal>Authentication</literal> object that represented the
         authentication request, and the <literal>UserDetails</literal> object
-        that was found in response to the authentication request. The
+        that was found in response to the authentication request (clearly the
+        latter will be a dummy object in the case of
+        <literal>AuthenticationFailureUsernameNotFoundEvent</literal>). The
         <literal>Authentication</literal> interface provides a
         <literal>getDetails()</literal> method which often includes
         information that event consumers may find useful (eg the TCP/IP
@@ -1150,8 +1159,7 @@
           <title>JaasAuthenticationProvider</title>
 
           <para>The <literal>JaasAuthenticationProvider</literal> attempts to
-          authenticate a user’s principal and credentials through JAAS.
-          </para>
+          authenticate a user’s principal and credentials through JAAS.</para>
 
           <para>Let’s assume we have a JAAS login configuration file,
           <literal>/WEB-INF/login.conf</literal>, with the following