SLING-5116 - Communicate Password Change Failure Reason During Password Expiry

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1707311 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 2ccb53d..6cd7e55 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
@@ -28,6 +28,7 @@
 import java.util.List;
 import java.util.Map;
 
+import javax.jcr.SimpleCredentials;
 import javax.security.auth.login.CredentialExpiredException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletRequestEvent;
@@ -464,7 +465,7 @@
         try {
             postProcess(authInfo, request, response);
         } catch (LoginException e) {
-            handleLoginFailure(request, response, authInfo.getUser(), e);
+            handleLoginFailure(request, response, authInfo, e);
             return false;
         }
 
@@ -818,7 +819,7 @@
             // now find a way to get credentials unless the feedback handler
             // has committed a response to the client already
             if (!response.isCommitted()) {
-                return handleLoginFailure(request, response, authInfo.getUser(), re);
+                return handleLoginFailure(request, response, authInfo, re);
             }
 
         }
@@ -871,7 +872,7 @@
             } catch (LoginException re) {
 
                 // cannot login > fail login, do not try to authenticate
-                handleLoginFailure(request, response, "anonymous user", re);
+                handleLoginFailure(request, response, new AuthenticationInfo(null, "anonymous user"), re);
                 return false;
 
             }
@@ -928,9 +929,10 @@
     }
 
     private boolean handleLoginFailure(final HttpServletRequest request,
-            final HttpServletResponse response, final String user,
+            final HttpServletResponse response, final AuthenticationInfo authInfo,
             final Exception reason) {
 
+        String user = authInfo.getUser();
         boolean processRequest = false;
         if (reason.getClass().getName().contains("TooManySessionsException")) {
 
@@ -959,10 +961,19 @@
                 if (reason.getCause() instanceof CredentialExpiredException) {
                     // force failure attribute to be set so handlers can
                     // react to this special circumstance
-                    request.setAttribute(AuthenticationHandler.FAILURE_REASON_CODE,
-                            AuthenticationHandler.FAILURE_REASON_CODES.PASSWORD_EXPIRED);
-                    ensureAttribute(request, AuthenticationHandler.FAILURE_REASON,
-                            "Password expired");
+
+                    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";
+                    }
+
+                    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,
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 c97063c..a35e02a 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
@@ -119,6 +119,7 @@
     static enum FAILURE_REASON_CODES {
         INVALID_LOGIN,
         PASSWORD_EXPIRED,
+        PASSWORD_EXPIRED_AND_NEW_PASSWORD_IN_HISTORY,
         UNKNOWN;
 
         @Override