You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by en...@apache.org on 2018/09/18 23:06:52 UTC
[sling-org-apache-sling-auth-core] branch master updated:
SLING-7939 SlingAuthenticator should post an event for login failures
This is an automated email from the ASF dual-hosted git repository.
enorman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-core.git
The following commit(s) were added to refs/heads/master by this push:
new c81d411 SLING-7939 SlingAuthenticator should post an event for login failures
c81d411 is described below
commit c81d411a6bbd691e1c9bad6f7581a417eee06ab3
Author: Eric Norman <en...@apache.org>
AuthorDate: Tue Sep 18 16:06:43 2018 -0700
SLING-7939 SlingAuthenticator should post an event for login failures
---
.../org/apache/sling/auth/core/AuthConstants.java | 8 ++
.../sling/auth/core/impl/SlingAuthenticator.java | 95 ++++++++++++++++++----
.../org/apache/sling/auth/core/package-info.java | 4 +-
3 files changed, 87 insertions(+), 20 deletions(-)
diff --git a/src/main/java/org/apache/sling/auth/core/AuthConstants.java b/src/main/java/org/apache/sling/auth/core/AuthConstants.java
index 43631f7..a809b26 100644
--- a/src/main/java/org/apache/sling/auth/core/AuthConstants.java
+++ b/src/main/java/org/apache/sling/auth/core/AuthConstants.java
@@ -115,6 +115,14 @@ public final class AuthConstants {
public static final String TOPIC_LOGIN = "org/apache/sling/auth/core/Authenticator/LOGIN";
/**
+ * The topic for the OSGi event which is sent when a user has logged in successfully.
+ * The event contains at least the {@link org.apache.sling.api.SlingConstants#PROPERTY_USERID}
+ * and the {@link org.apache.sling.auth.core.spi.AuthenticationInfo#AUTH_TYPE}
+ * properties.
+ */
+ public static final String TOPIC_LOGIN_FAILED = "org/apache/sling/auth/core/Authenticator/LOGIN_FAILED";
+
+ /**
* Any OSGi service may provide a {@code sling.auth.requirements} registration property which is used
* to dynamically extend the authentication requirements for the {@code AuthenticationSupport}.
* This may for example be set by AuthenticationHandler implementations providing
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 7a78f89..89f124c 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
@@ -30,6 +30,7 @@ import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+
import javax.jcr.SimpleCredentials;
import javax.security.auth.login.AccountLockedException;
import javax.security.auth.login.AccountNotFoundException;
@@ -40,6 +41,7 @@ import javax.servlet.ServletRequestListener;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -486,6 +488,8 @@ public class SlingAuthenticator implements Authenticator,
try {
postProcess(authInfo, request, response);
} catch (LoginException e) {
+ postLoginFailedEvent(request, authInfo, e);
+
handleLoginFailure(request, response, authInfo, e);
return false;
}
@@ -833,6 +837,7 @@ public class SlingAuthenticator implements Authenticator,
return processRequest;
} catch (LoginException re) {
+ postLoginFailedEvent(request, authInfo, re);
// handle failure feedback before proceeding to handling the
// failed login internally
@@ -1011,26 +1016,26 @@ public class SlingAuthenticator implements Authenticator,
// 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
- 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";
- }
- } else if (reason.getCause() instanceof AccountLockedException) {
- code = AuthenticationHandler.FAILURE_REASON_CODES.ACCOUNT_LOCKED;
+ AuthenticationHandler.FAILURE_REASON_CODES code = getFailureReasonFromException(authInfo, reason);
+ String message = null;
+ switch (code) {
+ case ACCOUNT_LOCKED:
message = "Account is locked";
- } else if (reason.getCause() instanceof AccountNotFoundException) {
- code = AuthenticationHandler.FAILURE_REASON_CODES.ACCOUNT_NOT_FOUND;
+ break;
+ case ACCOUNT_NOT_FOUND:
message = "Account was not found";
+ break;
+ case PASSWORD_EXPIRED:
+ message = "Password expired";
+ break;
+ case PASSWORD_EXPIRED_AND_NEW_PASSWORD_IN_HISTORY:
+ message = "Password expired and new password found in password history";
+ break;
+ case UNKNOWN:
+ case INVALID_LOGIN:
+ default:
+ message = "User name and password do not match";
+ break;
}
// preset a reason for the login failure
@@ -1061,6 +1066,39 @@ public class SlingAuthenticator implements Authenticator,
}
/**
+ * Try to determine the failure reason from the thrown exception
+ */
+ private AuthenticationHandler.FAILURE_REASON_CODES getFailureReasonFromException(final AuthenticationInfo authInfo, Exception reason) {
+ AuthenticationHandler.FAILURE_REASON_CODES code = null;
+ if (reason.getClass().getName().contains("TooManySessionsException")) {
+ // not a login failure just unavailable service
+ code = null;
+ } else if (reason instanceof LoginException) {
+ if (reason.getCause() instanceof CredentialExpiredException) {
+ // force failure attribute to be set so handlers can
+ // react to this special circumstance
+ 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;
+ } else {
+ code = AuthenticationHandler.FAILURE_REASON_CODES.PASSWORD_EXPIRED;
+ }
+ } else if (reason.getCause() instanceof AccountLockedException) {
+ code = AuthenticationHandler.FAILURE_REASON_CODES.ACCOUNT_LOCKED;
+ } else if (reason.getCause() instanceof AccountNotFoundException) {
+ code = AuthenticationHandler.FAILURE_REASON_CODES.ACCOUNT_NOT_FOUND;
+ }
+
+ if (code == null) {
+ // default to invalid login as the reason
+ code = AuthenticationHandler.FAILURE_REASON_CODES.INVALID_LOGIN;
+ }
+ }
+
+ return code;
+ }
+
+ /**
* Tries to request credentials from the client. The following mechanisms
* are implemented by this method:
* <ul>
@@ -1491,6 +1529,27 @@ public class SlingAuthenticator implements Authenticator,
}
/**
+ * Post an event to let subscribers know that a login failure has occurred. For examples, subscribers
+ * to the {@link AuthConstants#TOPIC_LOGIN_FAILED} event topic may be used to implement a failed login throttling solution.
+ */
+ private void postLoginFailedEvent(final HttpServletRequest request, final AuthenticationInfo authInfo, Exception reason) {
+ // The reason for the failure may be useful to downstream subscribers.
+ AuthenticationHandler.FAILURE_REASON_CODES reason_code = getFailureReasonFromException(authInfo, reason);
+ //if reason_code is null, it is problem some non-login related failure, so don't send the event
+ if (reason_code != null) {
+ final Dictionary<String, Object> properties = new Hashtable<String, Object>();
+ properties.put(SlingConstants.PROPERTY_USERID, authInfo.getUser());
+ properties.put(AuthenticationInfo.AUTH_TYPE, authInfo.getAuthType());
+ properties.put("reason_code", reason_code.name());
+
+ EventAdmin localEA = this.eventAdmin;
+ if (localEA != null) {
+ localEA.postEvent(new Event(AuthConstants.TOPIC_LOGIN_FAILED, properties));
+ }
+ }
+ }
+
+ /**
* Ensures the cookie value is properly quoted for transmission to the
* client.
* <p>
diff --git a/src/main/java/org/apache/sling/auth/core/package-info.java b/src/main/java/org/apache/sling/auth/core/package-info.java
index bc1ab49..66dee4f 100755
--- a/src/main/java/org/apache/sling/auth/core/package-info.java
+++ b/src/main/java/org/apache/sling/auth/core/package-info.java
@@ -22,9 +22,9 @@
* of utility functions in the {@link org.apache.sling.auth.core.AuthUtil}
* class.
*
- * @version 1.3.2
+ * @version 1.4.0
*/
-@org.osgi.annotation.versioning.Version("1.3.2")
+@org.osgi.annotation.versioning.Version("1.4.0")
package org.apache.sling.auth.core;