SLING-5141 - Expose Oak's Login Failures in Authenticator Reason (applied patch from Dominique Jaeggi thanks!)

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1708557 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java b/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
index 6cd7e55..dfc3d5e 100644
--- a/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
+++ b/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
@@ -29,6 +29,8 @@
 import java.util.Map;
 
 import javax.jcr.SimpleCredentials;
+import javax.security.auth.login.AccountLockedException;
+import javax.security.auth.login.AccountNotFoundException;
 import javax.security.auth.login.CredentialExpiredException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletRequestEvent;
@@ -958,30 +960,32 @@
                 // request authentication information and send 403 (Forbidden)
                 // if no handler can request authentication information.            
 
+                AuthenticationHandler.FAILURE_REASON_CODES code = AuthenticationHandler.FAILURE_REASON_CODES.INVALID_LOGIN;
+                String message = "User name and password do not match";
+
                 if (reason.getCause() instanceof CredentialExpiredException) {
                     // force failure attribute to be set so handlers can
                     // react to this special circumstance
-
-                    AuthenticationHandler.FAILURE_REASON_CODES code = AuthenticationHandler.FAILURE_REASON_CODES.PASSWORD_EXPIRED;
-                    String message = "Password expired";
-
                     Object creds = authInfo.get("user.jcr.credentials");
                     if (creds instanceof SimpleCredentials && ((SimpleCredentials) creds).getAttribute("PasswordHistoryException") != null) {
                         code = AuthenticationHandler.FAILURE_REASON_CODES.PASSWORD_EXPIRED_AND_NEW_PASSWORD_IN_HISTORY;
                         message = "Password expired and new password found in password history";
+                    } else {
+                        code = AuthenticationHandler.FAILURE_REASON_CODES.PASSWORD_EXPIRED;
+                        message = "Password expired";
                     }
-
-                    request.setAttribute(AuthenticationHandler.FAILURE_REASON_CODE, code);
-                    ensureAttribute(request, AuthenticationHandler.FAILURE_REASON, message);
-
-                } else {
-                    // preset a reason for the login failure (if not done already)
-                    request.setAttribute(AuthenticationHandler.FAILURE_REASON_CODE,
-                            AuthenticationHandler.FAILURE_REASON_CODES.INVALID_LOGIN);
-                    ensureAttribute(request, AuthenticationHandler.FAILURE_REASON,
-                            "User name and password do not match");
+                } else if (reason.getCause() instanceof AccountLockedException) {
+                    code = AuthenticationHandler.FAILURE_REASON_CODES.ACCOUNT_LOCKED;
+                    message = "Account is locked";
+                } else if (reason.getCause() instanceof AccountNotFoundException) {
+                    code = AuthenticationHandler.FAILURE_REASON_CODES.ACCOUNT_NOT_FOUND;
+                    message = "Account was not found";
                 }
 
+                // preset a reason for the login failure
+                request.setAttribute(AuthenticationHandler.FAILURE_REASON_CODE, code);
+                ensureAttribute(request, AuthenticationHandler.FAILURE_REASON, message);
+
                 doLogin(request, response);
             }
 
diff --git a/src/main/java/org/apache/sling/auth/core/spi/AuthenticationHandler.java b/src/main/java/org/apache/sling/auth/core/spi/AuthenticationHandler.java
index a35e02a..5d9b848 100644
--- a/src/main/java/org/apache/sling/auth/core/spi/AuthenticationHandler.java
+++ b/src/main/java/org/apache/sling/auth/core/spi/AuthenticationHandler.java
@@ -109,18 +109,21 @@
     /**
      * This enum indicates the supported detailed login failure reason codes:
      * <ul>
-     *     <li><code>invalid_login</code>:</li> indicates username/password mismatch.
-     *     <li><code>password_expired</code>:</li> indicates password has expired or was never set and
-     *     change initial password is enabled
-     *     <li><code>unknown</code>:</li> an unknown reason for the login failure was encountered.
+     *     <li><code>invalid_login</code>: indicates username/password mismatch.</li>
+     *     <li><code>password_expired</code>: indicates password has expired or was never set and
+     *     change initial password is enabled</li>
+     *     <li><code>account_locked</code>: the account was disabled or locked</li>
+     *     <li><code>account_not_found</code>: the account was not found (not the same as username password mismatch)</li>
      * </ul>
      * @since 1.1.0
      */
-    static enum FAILURE_REASON_CODES {
+    enum FAILURE_REASON_CODES {
         INVALID_LOGIN,
         PASSWORD_EXPIRED,
         PASSWORD_EXPIRED_AND_NEW_PASSWORD_IN_HISTORY,
-        UNKNOWN;
+        UNKNOWN,
+        ACCOUNT_LOCKED,
+        ACCOUNT_NOT_FOUND;
 
         @Override
         public String toString() {