You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2017/06/22 17:30:06 UTC
[1/4] ambari git commit: AMBARI-21294. Setup should keep existing
connection-pool setting in ambari.properties
Repository: ambari
Updated Branches:
refs/heads/branch-feature-AMBARI-20859 b5333870a -> f760516c2
AMBARI-21294. Setup should keep existing connection-pool setting in ambari.properties
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/45a29900
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/45a29900
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/45a29900
Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 45a29900bf849678347e33c14587f8ffca855383
Parents: 5fc8ccc
Author: Attila Doroszlai <ad...@hortonworks.com>
Authored: Wed Jun 21 11:00:23 2017 +0200
Committer: Attila Doroszlai <ad...@hortonworks.com>
Committed: Thu Jun 22 16:37:58 2017 +0200
----------------------------------------------------------------------
.../ambari_server/dbConfiguration_linux.py | 34 +++++++++++++-------
1 file changed, 22 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/45a29900/ambari-server/src/main/python/ambari_server/dbConfiguration_linux.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/dbConfiguration_linux.py b/ambari-server/src/main/python/ambari_server/dbConfiguration_linux.py
index dac3141..38dfa8c 100644
--- a/ambari-server/src/main/python/ambari_server/dbConfiguration_linux.py
+++ b/ambari-server/src/main/python/ambari_server/dbConfiguration_linux.py
@@ -82,6 +82,14 @@ class LinuxDBMSConfig(DBMSConfig):
self.local_admin_user = DBMSConfig._init_member_with_prop_default(options, "local_admin_user",
properties, LOCAL_DATABASE_ADMIN_PROPERTY, "postgres")
self.database_password = getattr(options, "database_password", "")
+
+ self.jdbc_connection_pool_type = DBMSConfig._init_member_with_prop_default(options, "jdbc_connection_pool_type", properties, JDBC_CONNECTION_POOL_TYPE, "internal")
+ self.jdbc_connection_pool_acquisition_size = DBMSConfig._init_member_with_prop_default(options, "jdbc_connection_pool_acquisition_size", properties, JDBC_CONNECTION_POOL_ACQUISITION_SIZE, "5")
+ self.jdbc_connection_pool_idle_test_interval = DBMSConfig._init_member_with_prop_default(options, "jdbc_connection_pool_idle_test_interval", properties, JDBC_CONNECTION_POOL_IDLE_TEST_INTERVAL, "7200")
+ self.jdbc_connection_pool_max_idle_time = DBMSConfig._init_member_with_prop_default(options, "jdbc_connection_pool_max_idle_time", properties, JDBC_CONNECTION_POOL_MAX_IDLE_TIME, "14400")
+ self.jdbc_connection_pool_max_idle_time_excess = DBMSConfig._init_member_with_prop_default(options, "jdbc_connection_pool_max_idle_time_excess", properties, JDBC_CONNECTION_POOL_MAX_IDLE_TIME_EXCESS, "0")
+ self.jdbc_connection_pool_max_age = DBMSConfig._init_member_with_prop_default(options, "jdbc_connection_pool_max_age", properties, JDBC_CONNECTION_POOL_MAX_AGE, "0")
+
if not self.database_password:
self.database_password = DBMSConfig._read_password_from_properties(properties, options)
@@ -320,9 +328,17 @@ class LinuxDBMSConfig(DBMSConfig):
properties.process_pair(JDBC_RCA_USER_NAME_PROPERTY, self.database_username)
self._store_password_property(properties, JDBC_RCA_PASSWORD_FILE_PROPERTY, options)
+ self._store_connection_pool_properties(properties)
- # connection pooling (internal JPA by default)
- properties.process_pair(JDBC_CONNECTION_POOL_TYPE, "internal")
+ # Store set of properties for JDBC connection pooling
+ def _store_connection_pool_properties(self, properties):
+ properties.process_pair(JDBC_CONNECTION_POOL_TYPE, self.jdbc_connection_pool_type)
+ if self.jdbc_connection_pool_type == "c3p0":
+ properties.process_pair(JDBC_CONNECTION_POOL_ACQUISITION_SIZE, self.jdbc_connection_pool_acquisition_size)
+ properties.process_pair(JDBC_CONNECTION_POOL_IDLE_TEST_INTERVAL, self.jdbc_connection_pool_idle_test_interval)
+ properties.process_pair(JDBC_CONNECTION_POOL_MAX_IDLE_TIME, self.jdbc_connection_pool_max_idle_time)
+ properties.process_pair(JDBC_CONNECTION_POOL_MAX_IDLE_TIME_EXCESS, self.jdbc_connection_pool_max_idle_time_excess)
+ properties.process_pair(JDBC_CONNECTION_POOL_MAX_AGE, self.jdbc_connection_pool_max_age)
# PostgreSQL configuration and setup
@@ -582,8 +598,7 @@ class PGConfig(LinuxDBMSConfig):
properties.process_pair(JDBC_POSTGRES_SCHEMA_PROPERTY, self.postgres_schema)
properties.process_pair(JDBC_USER_NAME_PROPERTY, self.database_username)
- # connection pooling (internal JPA by default)
- properties.process_pair(JDBC_CONNECTION_POOL_TYPE, "internal")
+ self._store_connection_pool_properties(properties)
properties.process_pair(LOCAL_DATABASE_ADMIN_PROPERTY, self.local_admin_user)
@@ -1036,15 +1051,10 @@ class MySQLConfig(LinuxDBMSConfig):
:param properties: the properties object to set MySQL specific properties on
:return:
"""
- super(MySQLConfig, self)._store_remote_properties(properties, options)
-
# connection pooling (c3p0 used by MySQL by default)
- properties.process_pair(JDBC_CONNECTION_POOL_TYPE, "c3p0")
- properties.process_pair(JDBC_CONNECTION_POOL_ACQUISITION_SIZE, "5")
- properties.process_pair(JDBC_CONNECTION_POOL_IDLE_TEST_INTERVAL, "7200")
- properties.process_pair(JDBC_CONNECTION_POOL_MAX_IDLE_TIME, "14400")
- properties.process_pair(JDBC_CONNECTION_POOL_MAX_IDLE_TIME_EXCESS, "0")
- properties.process_pair(JDBC_CONNECTION_POOL_MAX_AGE, "0")
+ self.jdbc_connection_pool_type = "c3p0"
+
+ super(MySQLConfig, self)._store_remote_properties(properties, options)
def createMySQLConfig(options, properties, storage_type, dbId):
[4/4] ambari git commit: AMBARI-21216. Add support for consecutive
login failure accounting (rlevas)
Posted by rl...@apache.org.
AMBARI-21216. Add support for consecutive login failure accounting (rlevas)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/f760516c
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/f760516c
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/f760516c
Branch: refs/heads/branch-feature-AMBARI-20859
Commit: f760516c24478b19d4e579cb67702d9d43251eaa
Parents: ac5008d
Author: Robert Levas <rl...@hortonworks.com>
Authored: Thu Jun 22 13:29:51 2017 -0400
Committer: Robert Levas <rl...@hortonworks.com>
Committed: Thu Jun 22 13:29:51 2017 -0400
----------------------------------------------------------------------
.../server/audit/event/LoginAuditEvent.java | 20 ++
.../ambari/server/controller/AmbariServer.java | 2 +
.../ambari/server/orm/entities/UserEntity.java | 32 ++++
.../AmbariAuthenticationEventHandler.java | 64 +++++++
.../AmbariAuthenticationEventHandlerImpl.java | 152 +++++++++++++++
.../AmbariAuthenticationException.java | 43 +++++
.../AmbariBasicAuthenticationFilter.java | 92 ++++------
.../AmbariJWTAuthenticationFilter.java | 71 +++----
...lidUsernamePasswordCombinationException.java | 32 ++++
.../authentication/UserNotFoundException.java | 15 +-
.../AmbariKerberosAuthenticationFilter.java | 70 +++----
.../AmbariLdapAuthenticationProvider.java | 7 +-
.../AmbariLdapAuthoritiesPopulator.java | 3 +-
.../authorization/AmbariLocalUserProvider.java | 9 +-
...lidUsernamePasswordCombinationException.java | 34 ----
.../server/security/authorization/Users.java | 167 ++++++++++++++++-
.../AmbariInternalAuthenticationProvider.java | 2 +-
.../jwt/JwtAuthenticationFilter.java | 2 +-
.../main/resources/Ambari-DDL-Derby-CREATE.sql | 1 +
.../main/resources/Ambari-DDL-MySQL-CREATE.sql | 1 +
.../main/resources/Ambari-DDL-Oracle-CREATE.sql | 1 +
.../resources/Ambari-DDL-Postgres-CREATE.sql | 1 +
.../resources/Ambari-DDL-SQLAnywhere-CREATE.sql | 1 +
.../resources/Ambari-DDL-SQLServer-CREATE.sql | 1 +
.../webapp/WEB-INF/spring-security.xml | 9 +-
.../server/audit/LoginAuditEventTest.java | 36 +++-
.../AmbariBasicAuthenticationFilterTest.java | 136 ++++++++------
.../AmbariJWTAuthenticationFilterTest.java | 160 +++++++++-------
.../AmbariKerberosAuthenticationFilterTest.java | 183 ++++++++++++++-----
...ariAuthorizationProviderDisableUserTest.java | 1 +
...uthenticationProviderForDNWithSpaceTest.java | 1 +
.../AmbariLdapAuthenticationProviderTest.java | 1 +
.../AmbariLocalUserProviderTest.java | 1 +
33 files changed, 977 insertions(+), 374 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java
index 9583b84..9be216a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java
@@ -51,6 +51,11 @@ public class LoginAuditEvent extends AbstractUserAuditEvent {
private String reasonOfFailure;
/**
+ * Number of consecutive failed authentication attempts since the last successful attempt
+ */
+ private Integer consecutiveFailures;
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -73,6 +78,9 @@ public class LoginAuditEvent extends AbstractUserAuditEvent {
if (reasonOfFailure != null) {
builder.append("), Reason(")
.append(reasonOfFailure);
+
+ builder.append("), Consecutive failures(")
+ .append((consecutiveFailures == null) ? "UNKNOWN USER" : String.valueOf(consecutiveFailures));
}
builder.append(")");
}
@@ -95,6 +103,18 @@ public class LoginAuditEvent extends AbstractUserAuditEvent {
}
/**
+ * Set the number of consecutive authentication failures since the last successful authentication
+ * attempt
+ *
+ * @param consecutiveFailures the number of consecutive authentication failures
+ * @return this builder
+ */
+ public LoginAuditEventBuilder withConsecutiveFailures(Integer consecutiveFailures) {
+ this.consecutiveFailures = consecutiveFailures;
+ return this;
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 01920f8..8173655 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -98,6 +98,7 @@ import org.apache.ambari.server.security.AmbariServerSecurityHeaderFilter;
import org.apache.ambari.server.security.AmbariViewsSecurityHeaderFilter;
import org.apache.ambari.server.security.CertificateManager;
import org.apache.ambari.server.security.SecurityFilter;
+import org.apache.ambari.server.security.authentication.AmbariAuthenticationEventHandlerImpl;
import org.apache.ambari.server.security.authorization.AmbariLdapAuthenticationProvider;
import org.apache.ambari.server.security.authorization.AmbariLocalUserProvider;
import org.apache.ambari.server.security.authorization.AmbariPamAuthenticationProvider;
@@ -327,6 +328,7 @@ public class AmbariServer {
factory.registerSingleton("guiceInjector", injector);
factory.registerSingleton("ambariConfiguration", injector.getInstance(Configuration.class));
+ factory.registerSingleton("ambariAuthenticationEventHandler", injector.getInstance(AmbariAuthenticationEventHandlerImpl.class));
factory.registerSingleton("ambariUsers", injector.getInstance(Users.class));
factory.registerSingleton("passwordEncoder",
injector.getInstance(PasswordEncoder.class));
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
index 66e9003..c679fff 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UserEntity.java
@@ -42,6 +42,7 @@ import javax.persistence.TableGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
+import javax.persistence.Version;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
@@ -85,6 +86,10 @@ public class UserEntity {
@Column(name = "local_username")
private String localUsername;
+ @Version
+ @Column(name = "version")
+ private Long version;
+
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private Set<MemberEntity> memberEntities = new HashSet<>();
@@ -214,6 +219,31 @@ public class UserEntity {
this.createTime = createTime;
}
+ /**
+ * Returns the version number of the relevant data stored in the database.
+ * <p>
+ * This is used to help ensure that collisions updatin the relevant data in the database are
+ * handled properly via Optimistic locking.
+ *
+ * @return a version number
+ */
+ public Long getVersion() {
+ return version;
+ }
+
+ /**
+ * Sets the version number of the relevant data stored in the database.
+ * <p>
+ * This is used to help ensure that collisions updatin the relevant data in the database are
+ * handled properly via Optimistic locking. It is recommended that this value is <b>not</b>
+ * manually updated, else issues may occur when persisting the data.
+ *
+ * @param version a version number
+ */
+ public void setVersion(Long version) {
+ this.version = version;
+ }
+
public Set<MemberEntity> getMemberEntities() {
return memberEntities;
}
@@ -297,6 +327,7 @@ public class UserEntity {
equalsBuilder.append(consecutiveFailures, that.consecutiveFailures);
equalsBuilder.append(active, that.active);
equalsBuilder.append(createTime, that.createTime);
+ equalsBuilder.append(version, that.version);
return equalsBuilder.isEquals();
}
}
@@ -311,6 +342,7 @@ public class UserEntity {
hashCodeBuilder.append(consecutiveFailures);
hashCodeBuilder.append(active);
hashCodeBuilder.append(createTime);
+ hashCodeBuilder.append(version);
return hashCodeBuilder.toHashCode();
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandler.java
new file mode 100644
index 0000000..037fc13
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandler.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.ambari.server.security.authentication;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.core.Authentication;
+
+/**
+ * AmbariAuthenticationEventHandler is an interface to be implemented by classes used to track Ambari
+ * user authentication attempts.
+ */
+public interface AmbariAuthenticationEventHandler {
+ /**
+ * The event callback called when a successful authentication attempt has occurred.
+ *
+ * @param filter the Authentication filer used for authentication
+ * @param servletRequest the request
+ * @param servletResponse the response
+ * @param result the authentication result
+ */
+ void onSuccessfulAuthentication(AmbariAuthenticationFilter filter, HttpServletRequest servletRequest,
+ HttpServletResponse servletResponse, Authentication result);
+
+ /**
+ * The event callback called when a failed authentication attempt has occurred.
+ *
+ * @param filter the Authentication filer used for authentication
+ * @param servletRequest the request
+ * @param servletResponse the response
+ * @param cause the exception used to declare the cause for the failure
+ */
+ void onUnsuccessfulAuthentication(AmbariAuthenticationFilter filter, HttpServletRequest servletRequest,
+ HttpServletResponse servletResponse, AmbariAuthenticationException cause);
+
+ /**
+ * The event callback called just before an authentication attempt.
+ *
+ * @param filter the Authentication filer used for authentication
+ * @param servletRequest the request
+ * @param servletResponse the response
+ */
+ void beforeAttemptAuthentication(AmbariAuthenticationFilter filter, ServletRequest servletRequest,
+ ServletResponse servletResponse);
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java
new file mode 100644
index 0000000..3a5a66b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.ambari.server.security.authentication;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.LoginAuditEvent;
+import org.apache.ambari.server.security.authorization.AuthorizationHelper;
+import org.apache.ambari.server.security.authorization.PermissionHelper;
+import org.apache.ambari.server.security.authorization.Users;
+import org.apache.ambari.server.utils.RequestUtils;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * AmbariAuthenticationEventHandlerImpl is the default {@link AmbariAuthenticationEventHandler}
+ * implementation.
+ * <p>
+ * This implementation tracks authentication attempts using the Ambari {@link AuditLogger} and
+ * ensures that the relevant user's consecutive authentication failure count is properly tracked.
+ * <p>
+ * Upon an authentication failure, the user's consecutive authentication failure count is incremented
+ * by <code>1</code> and upon a successful authentication, the user's consecutive authentication failure count
+ * is reset to <code>0</code>.
+ */
+@Singleton
+public class AmbariAuthenticationEventHandlerImpl implements AmbariAuthenticationEventHandler {
+ private static final Logger LOG = LoggerFactory.getLogger(AmbariAuthenticationEventHandlerImpl.class);
+ /**
+ * Audit logger
+ */
+ @Inject
+ private AuditLogger auditLogger;
+
+ /**
+ * PermissionHelper to help create audit entries
+ */
+ @Inject
+ private PermissionHelper permissionHelper;
+
+ @Inject
+ private Users users;
+
+ @Override
+ public void onSuccessfulAuthentication(AmbariAuthenticationFilter filter, HttpServletRequest servletRequest, HttpServletResponse servletResponse, Authentication result) {
+ String username = (result == null) ? null : result.getName();
+
+ // Using the Ambari audit logger, log this event (if enabled)
+ if (auditLogger.isEnabled()) {
+ AuditEvent loginSucceededAuditEvent = LoginAuditEvent.builder()
+ .withRemoteIp(RequestUtils.getRemoteAddress(servletRequest))
+ .withUserName(username)
+ .withTimestamp(System.currentTimeMillis())
+ .withRoles(permissionHelper.getPermissionLabels(result))
+ .build();
+ auditLogger.log(loginSucceededAuditEvent);
+ }
+
+ // Reset the user's consecutive authentication failure count to 0.
+ if (!StringUtils.isEmpty(username)) {
+ LOG.debug("Successfully authenticated {}", username);
+ users.clearConsecutiveAuthenticationFailures(username);
+ } else {
+ LOG.warn("Successfully authenticated an unknown user");
+ }
+ }
+
+ @Override
+ public void onUnsuccessfulAuthentication(AmbariAuthenticationFilter filter, HttpServletRequest servletRequest, HttpServletResponse servletResponse, AmbariAuthenticationException cause) {
+ String username;
+ String message;
+ String logMessage;
+ Integer consecutiveFailures = null;
+
+ if (cause == null) {
+ username = null;
+ message = "Unknown cause";
+ } else {
+ username = cause.getUsername();
+ message = cause.getLocalizedMessage();
+ }
+
+ // Increment the user's consecutive authentication failure count.
+ if (!StringUtils.isEmpty(username)) {
+ consecutiveFailures = users.incrementConsecutiveAuthenticationFailures(username);
+ logMessage = String.format("Failed to authenticate %s (attempt #%d): %s", username, consecutiveFailures, message);
+ } else {
+ logMessage = String.format("Failed to authenticate an unknown user: %s", message);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(logMessage, cause);
+ } else {
+ LOG.info(logMessage);
+ }
+
+ // Using the Ambari audit logger, log this event (if enabled)
+ if (auditLogger.isEnabled()) {
+ AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
+ .withRemoteIp(RequestUtils.getRemoteAddress(servletRequest))
+ .withTimestamp(System.currentTimeMillis())
+ .withReasonOfFailure("Invalid username/password combination")
+ .withConsecutiveFailures(consecutiveFailures)
+ .withUserName(username)
+ .build();
+ auditLogger.log(loginFailedAuditEvent);
+ }
+ }
+
+ @Override
+ public void beforeAttemptAuthentication(AmbariAuthenticationFilter filter, ServletRequest servletRequest, ServletResponse servletResponse) {
+ HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+
+ // Using the Ambari audit logger, log this event (if enabled)
+ if (auditLogger.isEnabled() && filter.shouldApply(httpServletRequest) && (AuthorizationHelper.getAuthenticatedName() == null)) {
+ AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
+ .withRemoteIp(RequestUtils.getRemoteAddress(httpServletRequest))
+ .withTimestamp(System.currentTimeMillis())
+ .withReasonOfFailure("Authentication required")
+ .withUserName(null)
+ .build();
+ auditLogger.log(loginFailedAuditEvent);
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationException.java
new file mode 100644
index 0000000..fb18b9c
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.ambari.server.security.authentication;
+
+import org.springframework.security.core.AuthenticationException;
+
+/**
+ * AmbariAuthenticationException is an AuthenticationException implementation to be thrown
+ * when the user fails to authenticate with Ambari.
+ */
+public class AmbariAuthenticationException extends AuthenticationException {
+ private final String username;
+
+ public AmbariAuthenticationException(String username, String message) {
+ super(message);
+ this.username = username;
+ }
+
+ public AmbariAuthenticationException(String username, String message, Throwable throwable) {
+ super(message, throwable);
+ this.username = username;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java
index ac3e15f..3667012 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java
@@ -26,13 +26,7 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.ambari.server.audit.AuditLogger;
-import org.apache.ambari.server.audit.event.AuditEvent;
-import org.apache.ambari.server.audit.event.LoginAuditEvent;
import org.apache.ambari.server.security.AmbariEntryPoint;
-import org.apache.ambari.server.security.authorization.AuthorizationHelper;
-import org.apache.ambari.server.security.authorization.PermissionHelper;
-import org.apache.ambari.server.utils.RequestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
@@ -53,31 +47,25 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi
public class AmbariBasicAuthenticationFilter extends BasicAuthenticationFilter implements AmbariAuthenticationFilter {
private static final Logger LOG = LoggerFactory.getLogger(AmbariBasicAuthenticationFilter.class);
- /**
- * Audit logger
- */
- private AuditLogger auditLogger;
-
- /**
- * PermissionHelper to help create audit entries
- */
- private PermissionHelper permissionHelper;
+ private final AmbariAuthenticationEventHandler eventHandler;
/**
* Constructor.
*
- * @param authenticationManager the Spring authencation manager
+ * @param authenticationManager the Spring authentication manager
* @param ambariEntryPoint the Spring entry point
- * @param auditLogger an Audit Logger
- * @param permissionHelper a permission helper
+ * @param eventHandler the authentication event handler
*/
public AmbariBasicAuthenticationFilter(AuthenticationManager authenticationManager,
AmbariEntryPoint ambariEntryPoint,
- AuditLogger auditLogger,
- PermissionHelper permissionHelper) {
+ AmbariAuthenticationEventHandler eventHandler) {
super(authenticationManager, ambariEntryPoint);
- this.auditLogger = auditLogger;
- this.permissionHelper = permissionHelper;
+
+ if(eventHandler == null) {
+ throw new IllegalArgumentException("The AmbariAuthenticationEventHandler must not be null");
+ }
+
+ this.eventHandler = eventHandler;
}
/**
@@ -115,16 +103,9 @@ public class AmbariBasicAuthenticationFilter extends BasicAuthenticationFilter i
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
- HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
-
- if (auditLogger.isEnabled() && shouldApply(httpServletRequest) && (AuthorizationHelper.getAuthenticatedName() == null)) {
- AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
- .withRemoteIp(RequestUtils.getRemoteAddress(httpServletRequest))
- .withTimestamp(System.currentTimeMillis())
- .withReasonOfFailure("Authentication required")
- .withUserName(null)
- .build();
- auditLogger.log(loginFailedAuditEvent);
+
+ if (eventHandler != null) {
+ eventHandler.beforeAttemptAuthentication(this, servletRequest, servletResponse);
}
super.doFilter(servletRequest, servletResponse, chain);
@@ -142,14 +123,9 @@ public class AmbariBasicAuthenticationFilter extends BasicAuthenticationFilter i
protected void onSuccessfulAuthentication(HttpServletRequest servletRequest,
HttpServletResponse servletResponse,
Authentication authResult) throws IOException {
- if (auditLogger.isEnabled()) {
- AuditEvent loginSucceededAuditEvent = LoginAuditEvent.builder()
- .withRemoteIp(RequestUtils.getRemoteAddress(servletRequest))
- .withUserName(authResult.getName())
- .withTimestamp(System.currentTimeMillis())
- .withRoles(permissionHelper.getPermissionLabels(authResult))
- .build();
- auditLogger.log(loginSucceededAuditEvent);
+
+ if (eventHandler != null) {
+ eventHandler.onSuccessfulAuthentication(this, servletRequest, servletResponse, authResult);
}
}
@@ -158,28 +134,30 @@ public class AmbariBasicAuthenticationFilter extends BasicAuthenticationFilter i
*
* @param servletRequest the request
* @param servletResponse the response
- * @param authExecption the exception, if any, causing the unsuccessful authentication attempt
+ * @param authException the exception, if any, causing the unsuccessful authentication attempt
* @throws IOException
*/
@Override
protected void onUnsuccessfulAuthentication(HttpServletRequest servletRequest,
HttpServletResponse servletResponse,
- AuthenticationException authExecption) throws IOException {
- String header = servletRequest.getHeader("Authorization");
- String username = null;
- try {
- username = getUsernameFromAuth(header, getCredentialsCharset(servletRequest));
- } catch (Exception e) {
- LOG.warn("Error occurred during decoding authorization header.", e);
- }
- if (auditLogger.isEnabled()) {
- AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
- .withRemoteIp(RequestUtils.getRemoteAddress(servletRequest))
- .withTimestamp(System.currentTimeMillis())
- .withReasonOfFailure("Invalid username/password combination")
- .withUserName(username)
- .build();
- auditLogger.log(loginFailedAuditEvent);
+ AuthenticationException authException) throws IOException {
+ if (eventHandler != null) {
+ AmbariAuthenticationException cause;
+ if (authException instanceof AmbariAuthenticationException) {
+ cause = (AmbariAuthenticationException) authException;
+ } else {
+ String header = servletRequest.getHeader("Authorization");
+ String username = null;
+ try {
+ username = getUsernameFromAuth(header, getCredentialsCharset(servletRequest));
+ } catch (Exception e) {
+ LOG.warn("Error occurred during decoding authorization header.", e);
+ }
+
+ cause = new AmbariAuthenticationException(username, authException.getMessage(), authException);
+ }
+
+ eventHandler.onUnsuccessfulAuthentication(this, servletRequest, servletResponse, cause);
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java
index fca8b29..3d35578 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java
@@ -27,15 +27,9 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.ambari.server.audit.AuditLogger;
-import org.apache.ambari.server.audit.event.AuditEvent;
-import org.apache.ambari.server.audit.event.LoginAuditEvent;
import org.apache.ambari.server.configuration.Configuration;
-import org.apache.ambari.server.security.authorization.AuthorizationHelper;
-import org.apache.ambari.server.security.authorization.PermissionHelper;
import org.apache.ambari.server.security.authorization.Users;
import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationFilter;
-import org.apache.ambari.server.utils.RequestUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
@@ -51,14 +45,9 @@ import org.springframework.security.web.AuthenticationEntryPoint;
public class AmbariJWTAuthenticationFilter extends JwtAuthenticationFilter implements AmbariAuthenticationFilter {
/**
- * Audit logger
+ * Ambari authentication event handler
*/
- private AuditLogger auditLogger;
-
- /**
- * PermissionHelper to help create audit entries
- */
- private PermissionHelper permissionHelper;
+ private final AmbariAuthenticationEventHandler eventHandler;
/**
@@ -67,17 +56,19 @@ public class AmbariJWTAuthenticationFilter extends JwtAuthenticationFilter imple
* @param ambariEntryPoint the Spring entry point
* @param configuration the Ambari configuration
* @param users the Ambari users object
- * @param auditLogger an Audit Logger
- * @param permissionHelper a permission helper
+ * @param eventHandler the Ambari authentication event handler
*/
public AmbariJWTAuthenticationFilter(AuthenticationEntryPoint ambariEntryPoint,
Configuration configuration,
Users users,
- AuditLogger auditLogger,
- PermissionHelper permissionHelper) {
+ AmbariAuthenticationEventHandler eventHandler) {
super(configuration, ambariEntryPoint, users);
- this.auditLogger = auditLogger;
- this.permissionHelper = permissionHelper;
+
+ if(eventHandler == null) {
+ throw new IllegalArgumentException("The AmbariAuthenticationEventHandler must not be null");
+ }
+
+ this.eventHandler = eventHandler;
}
/**
@@ -91,16 +82,9 @@ public class AmbariJWTAuthenticationFilter extends JwtAuthenticationFilter imple
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
- HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
-
- if (auditLogger.isEnabled() && shouldApply(httpServletRequest) && (AuthorizationHelper.getAuthenticatedName() == null)) {
- AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
- .withRemoteIp(RequestUtils.getRemoteAddress(httpServletRequest))
- .withTimestamp(System.currentTimeMillis())
- .withReasonOfFailure("Authentication required")
- .withUserName(null)
- .build();
- auditLogger.log(loginFailedAuditEvent);
+
+ if (eventHandler != null) {
+ eventHandler.beforeAttemptAuthentication(this, servletRequest, servletResponse);
}
super.doFilter(servletRequest, servletResponse, chain);
@@ -108,32 +92,23 @@ public class AmbariJWTAuthenticationFilter extends JwtAuthenticationFilter imple
@Override
protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException {
- if (auditLogger.isEnabled()) {
- AuditEvent loginSucceededAuditEvent = LoginAuditEvent.builder()
- .withRemoteIp(RequestUtils.getRemoteAddress(request))
- .withUserName(authResult.getName())
- .withTimestamp(System.currentTimeMillis())
- .withRoles(permissionHelper.getPermissionLabels(authResult))
- .build();
- auditLogger.log(loginSucceededAuditEvent);
+ if (eventHandler != null) {
+ eventHandler.onSuccessfulAuthentication(this, request, response, authResult);
}
}
@Override
protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
- if (auditLogger.isEnabled()) {
- String username = null;
- if (authException instanceof UserNotFoundException) {
- username = ((UserNotFoundException) authException).getUsername();
+ if (eventHandler != null) {
+ AmbariAuthenticationException cause;
+
+ if (authException instanceof AmbariAuthenticationException) {
+ cause = (AmbariAuthenticationException) authException;
+ } else {
+ cause = new AmbariAuthenticationException(null, authException.getMessage(), authException);
}
- AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
- .withRemoteIp(RequestUtils.getRemoteAddress(request))
- .withTimestamp(System.currentTimeMillis())
- .withReasonOfFailure(authException.getLocalizedMessage())
- .withUserName(username)
- .build();
- auditLogger.log(loginFailedAuditEvent);
+ eventHandler.onUnsuccessfulAuthentication(this, request, response, cause);
}
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/InvalidUsernamePasswordCombinationException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/InvalidUsernamePasswordCombinationException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/InvalidUsernamePasswordCombinationException.java
new file mode 100644
index 0000000..cb1babd
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/InvalidUsernamePasswordCombinationException.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.ambari.server.security.authentication;
+
+public class InvalidUsernamePasswordCombinationException extends AmbariAuthenticationException {
+
+ public static final String MESSAGE = "Unable to sign in. Invalid username/password combination.";
+
+ public InvalidUsernamePasswordCombinationException(String username) {
+ super(username, MESSAGE);
+ }
+
+ public InvalidUsernamePasswordCombinationException(String username, Throwable t) {
+ super(username, MESSAGE, t);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java
index f6c4bcf..0f2fbb6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java
@@ -18,26 +18,17 @@
package org.apache.ambari.server.security.authentication;
-import org.springframework.security.core.AuthenticationException;
-
/**
* AuthenticationUserNotFoundException is an AuthenticationException implementation to be thrown
* when the user specified in an authentication attempt is not found in the Ambari user database.
*/
-public class UserNotFoundException extends AuthenticationException {
- private final String username;
+public class UserNotFoundException extends AmbariAuthenticationException {
public UserNotFoundException(String username, String message) {
- super(message);
- this.username = username;
+ super(username, message);
}
public UserNotFoundException(String username, String message, Throwable throwable) {
- super(message, throwable);
- this.username = username;
- }
-
- public String getUsername() {
- return username;
+ super(username, message, throwable);
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java
index 1b001ec..23fa171 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java
@@ -28,13 +28,10 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.ambari.server.audit.AuditLogger;
-import org.apache.ambari.server.audit.event.AuditEvent;
-import org.apache.ambari.server.audit.event.LoginAuditEvent;
import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.authentication.AmbariAuthenticationEventHandler;
+import org.apache.ambari.server.security.authentication.AmbariAuthenticationException;
import org.apache.ambari.server.security.authentication.AmbariAuthenticationFilter;
-import org.apache.ambari.server.security.authorization.AuthorizationHelper;
-import org.apache.ambari.server.security.authorization.PermissionHelper;
-import org.apache.ambari.server.utils.RequestUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -52,9 +49,9 @@ import org.springframework.security.web.authentication.AuthenticationSuccessHand
public class AmbariKerberosAuthenticationFilter extends SpnegoAuthenticationProcessingFilter implements AmbariAuthenticationFilter {
/**
- * Audit logger
+ * Ambari authentication event handler
*/
- private final AuditLogger auditLogger;
+ private final AmbariAuthenticationEventHandler eventHandler;
/**
* A Boolean value indicating whether Kerberos authentication is enabled or not.
@@ -70,30 +67,37 @@ public class AmbariKerberosAuthenticationFilter extends SpnegoAuthenticationProc
* @param authenticationManager the Spring authentication manager
* @param entryPoint the Spring entry point
* @param configuration the Ambari configuration data
- * @param auditLogger an audit logger
- * @param permissionHelper a permission helper to aid in audit logging
+ * @param eventHandler the Ambari authentication event handler
*/
- public AmbariKerberosAuthenticationFilter(AuthenticationManager authenticationManager, final AuthenticationEntryPoint entryPoint, Configuration configuration, final AuditLogger auditLogger, final PermissionHelper permissionHelper) {
+ public AmbariKerberosAuthenticationFilter(AuthenticationManager authenticationManager,
+ final AuthenticationEntryPoint entryPoint,
+ Configuration configuration,
+ final AmbariAuthenticationEventHandler eventHandler) {
AmbariKerberosAuthenticationProperties kerberosAuthenticationProperties = (configuration == null)
? null
: configuration.getKerberosAuthenticationProperties();
kerberosAuthenticationEnabled = (kerberosAuthenticationProperties != null) && kerberosAuthenticationProperties.isKerberosAuthenticationEnabled();
- this.auditLogger = auditLogger;
+ if(eventHandler == null) {
+ throw new IllegalArgumentException("The AmbariAuthenticationEventHandler must not be null");
+ }
+
+ this.eventHandler = eventHandler;
setAuthenticationManager(authenticationManager);
setFailureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
- if (auditLogger.isEnabled()) {
- AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
- .withRemoteIp(RequestUtils.getRemoteAddress(httpServletRequest))
- .withTimestamp(System.currentTimeMillis())
- .withReasonOfFailure(e.getLocalizedMessage())
- .build();
- auditLogger.log(loginFailedAuditEvent);
+ if (eventHandler != null) {
+ AmbariAuthenticationException cause;
+ if (e instanceof AmbariAuthenticationException) {
+ cause = (AmbariAuthenticationException) e;
+ } else {
+ cause = new AmbariAuthenticationException(null, e.getLocalizedMessage(), e);
+ }
+ eventHandler.onUnsuccessfulAuthentication(AmbariKerberosAuthenticationFilter.this, httpServletRequest, httpServletResponse, cause);
}
entryPoint.commence(httpServletRequest, httpServletResponse, e);
@@ -103,14 +107,8 @@ public class AmbariKerberosAuthenticationFilter extends SpnegoAuthenticationProc
setSuccessHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
- if (auditLogger.isEnabled()) {
- AuditEvent loginSucceededAuditEvent = LoginAuditEvent.builder()
- .withRemoteIp(RequestUtils.getRemoteAddress(httpServletRequest))
- .withUserName(authentication.getName())
- .withTimestamp(System.currentTimeMillis())
- .withRoles(permissionHelper.getPermissionLabels(authentication))
- .build();
- auditLogger.log(loginSucceededAuditEvent);
+ if (eventHandler != null) {
+ eventHandler.onSuccessfulAuthentication(AmbariKerberosAuthenticationFilter.this, httpServletRequest, httpServletResponse, authentication);
}
}
});
@@ -152,22 +150,10 @@ public class AmbariKerberosAuthenticationFilter extends SpnegoAuthenticationProc
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
- HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
-
- if (shouldApply(httpServletRequest)) {
- if (auditLogger.isEnabled() && (AuthorizationHelper.getAuthenticatedName() == null)) {
- AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
- .withRemoteIp(RequestUtils.getRemoteAddress(httpServletRequest))
- .withTimestamp(System.currentTimeMillis())
- .withReasonOfFailure("Authentication required")
- .withUserName(null)
- .build();
- auditLogger.log(loginFailedAuditEvent);
- }
-
- super.doFilter(servletRequest, servletResponse, filterChain);
- } else {
- filterChain.doFilter(servletRequest, servletResponse);
+ if (eventHandler != null) {
+ eventHandler.beforeAttemptAuthentication(AmbariKerberosAuthenticationFilter.this, servletRequest, servletResponse);
}
+
+ super.doFilter(servletRequest, servletResponse, filterChain);
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
index 6137b68..caff735 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
@@ -24,6 +24,7 @@ import org.apache.ambari.server.orm.dao.UserDAO;
import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
import org.apache.ambari.server.orm.entities.UserEntity;
import org.apache.ambari.server.security.ClientSecurityType;
+import org.apache.ambari.server.security.authentication.InvalidUsernamePasswordCombinationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
@@ -93,7 +94,7 @@ public class AmbariLdapAuthenticationProvider implements AuthenticationProvider
"connecting to LDAP server) are invalid.", e);
}
}
- throw new InvalidUsernamePasswordCombinationException(e);
+ throw new InvalidUsernamePasswordCombinationException(username, e);
} catch (IncorrectResultSizeDataAccessException multipleUsersFound) {
String message = configuration.isLdapAlternateUserSearchEnabled() ?
String.format("Login Failed: Please append your domain to your username and try again. Example: %s@domain", username) :
@@ -204,7 +205,7 @@ public class AmbariLdapAuthenticationProvider implements AuthenticationProvider
// lookup is case insensitive, so no need for string comparison
if (userEntity == null) {
LOG.info("user not found ('{}')", userName);
- throw new InvalidUsernamePasswordCombinationException();
+ throw new InvalidUsernamePasswordCombinationException(userName);
}
if (!userEntity.getActive()) {
@@ -221,7 +222,7 @@ public class AmbariLdapAuthenticationProvider implements AuthenticationProvider
LOG.debug("Failed to find LDAP authentication entry for {})", userName);
}
- throw new InvalidUsernamePasswordCombinationException();
+ throw new InvalidUsernamePasswordCombinationException(userName);
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java
index 5c482a1..4331f59 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java
@@ -25,6 +25,7 @@ import org.apache.ambari.server.orm.dao.PrivilegeDAO;
import org.apache.ambari.server.orm.dao.UserDAO;
import org.apache.ambari.server.orm.entities.PrivilegeEntity;
import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.security.authentication.InvalidUsernamePasswordCombinationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ldap.core.DirContextOperations;
@@ -71,7 +72,7 @@ public class AmbariLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
return Collections.emptyList();
}
if(!user.getActive()){
- throw new InvalidUsernamePasswordCombinationException();
+ throw new InvalidUsernamePasswordCombinationException(username);
}
Collection<PrivilegeEntity> privilegeEntities = users.getUserPrivileges(user);
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java
index 517efe4..2c8bf12 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java
@@ -22,6 +22,7 @@ import java.util.List;
import org.apache.ambari.server.orm.dao.UserDAO;
import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.security.authentication.InvalidUsernamePasswordCombinationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -66,17 +67,17 @@ public class AmbariLocalUserProvider extends AbstractUserDetailsAuthenticationPr
if (userEntity == null) {
LOG.info("user not found");
- throw new InvalidUsernamePasswordCombinationException();
+ throw new InvalidUsernamePasswordCombinationException(userName);
}
if (!userEntity.getActive()) {
LOG.debug("User account is disabled");
- throw new InvalidUsernamePasswordCombinationException();
+ throw new InvalidUsernamePasswordCombinationException(userName);
}
if (authentication.getCredentials() == null) {
LOG.debug("Authentication failed: no credentials provided");
- throw new InvalidUsernamePasswordCombinationException();
+ throw new InvalidUsernamePasswordCombinationException(userName);
}
List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
@@ -98,7 +99,7 @@ public class AmbariLocalUserProvider extends AbstractUserDetailsAuthenticationPr
// The user was not authenticated, fail
LOG.debug("Authentication failed: password does not match stored value");
- throw new InvalidUsernamePasswordCombinationException();
+ throw new InvalidUsernamePasswordCombinationException(userName);
}
@Override
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/InvalidUsernamePasswordCombinationException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/InvalidUsernamePasswordCombinationException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/InvalidUsernamePasswordCombinationException.java
deleted file mode 100644
index db82381..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/InvalidUsernamePasswordCombinationException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 org.apache.ambari.server.security.authorization;
-
-import org.springframework.security.core.AuthenticationException;
-
-public class InvalidUsernamePasswordCombinationException extends AuthenticationException {
-
- public static final String MESSAGE = "Unable to sign in. Invalid username/password combination.";
-
- public InvalidUsernamePasswordCombinationException() {
- super(MESSAGE);
- }
-
- public InvalidUsernamePasswordCombinationException(Throwable t) {
- super(MESSAGE, t);
- }
-}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
index 35eb255..de12a16 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
@@ -29,6 +29,7 @@ import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
+import javax.persistence.OptimisticLockException;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.hooks.HookContextFactory;
@@ -71,6 +72,11 @@ public class Users {
private static final Logger LOG = LoggerFactory.getLogger(Users.class);
+ /**
+ * The maximum number of retries when handling OptimisticLockExceptions
+ */
+ private static final int MAX_RETRIES = 10;
+
@Inject
private Provider<EntityManager> entityManagerProvider;
@@ -238,9 +244,17 @@ public class Users {
* @param active true if active; false if not active
* @throws AmbariException if user does not exist
*/
- public synchronized void setUserActive(UserEntity userEntity, boolean active) throws AmbariException {
- userEntity.setActive(active);
- userDAO.merge(userEntity);
+ public synchronized void setUserActive(UserEntity userEntity, final boolean active) throws AmbariException {
+ if(userEntity != null) {
+ Command command = new Command() {
+ @Override
+ public void perform(UserEntity userEntity) {
+ userEntity.setActive(active);
+ }
+ };
+
+ safelyUpdateUserEntity(userEntity, command, MAX_RETRIES);
+ }
}
/**
@@ -1252,13 +1266,148 @@ public class Users {
}
/**
+ * Increments the named user's consecutive authentication failure count by <code>1</code>.
+ * <p>
+ * This operation is safe when concurrent authentication attempts by the same username are made
+ * due to {@link UserEntity#version} and optimistic locking.
+ *
+ * @param username the user's username
+ * @return the updated number of consecutive authentication failures; or null if the user does not exist
+ */
+ public Integer incrementConsecutiveAuthenticationFailures(String username) {
+ return incrementConsecutiveAuthenticationFailures(getUserEntity(username));
+ }
+
+ /**
+ * Increments the named user's consecutive authentication failure count by <code>1</code>.
+ * <p>
+ * This operation is safe when concurrent authentication attempts by the same username are made
+ * due to {@link UserEntity#version} and optimistic locking.
+ *
+ * @param userEntity the user
+ * @return the updated number of consecutive authentication failures; or null if the user does not exist
+ */
+ public Integer incrementConsecutiveAuthenticationFailures(UserEntity userEntity) {
+ if (userEntity != null) {
+ Command command = new Command() {
+ @Override
+ public void perform(UserEntity userEntity) {
+ userEntity.incrementConsecutiveFailures();
+ }
+ };
+
+ userEntity = safelyUpdateUserEntity(userEntity, command, MAX_RETRIES);
+ }
+
+ return (userEntity == null) ? null : userEntity.getConsecutiveFailures();
+ }
+
+ /**
+ * Resets the named user's consecutive authentication failure count to <code>0</code>.
+ * <p>
+ * This operation is safe when concurrent authentication attempts by the same username are made
+ * due to {@link UserEntity#version} and optimistic locking.
+ *
+ * @param username the user's username
+ */
+ public void clearConsecutiveAuthenticationFailures(String username) {
+ clearConsecutiveAuthenticationFailures(getUserEntity(username));
+ }
+
+ /**
+ * Resets the named user's consecutive authentication failure count to <code>0</code>.
+ * <p>
+ * This operation is safe when concurrent authentication attempts by the same username are made
+ * due to {@link UserEntity#version} and optimistic locking.
+ *
+ * @param userEntity the user
+ */
+ public void clearConsecutiveAuthenticationFailures(UserEntity userEntity) {
+ if (userEntity != null) {
+ if (userEntity.getConsecutiveFailures() != 0) {
+ Command command = new Command() {
+ @Override
+ public void perform(UserEntity userEntity) {
+ userEntity.setConsecutiveFailures(0);
+ }
+ };
+
+ safelyUpdateUserEntity(userEntity, command, MAX_RETRIES);
+ }
+ }
+ }
+
+ /***
+ * Attempts to update the specified {@link UserEntity} while handling {@link OptimisticLockException}s
+ * by obtaining the latest version of the {@link UserEntity} and retrying the operation.
+ *
+ * If the maximum number of retries is exceeded, then the operation will fail by rethrowing the last
+ * exception encountered.
+ *
+ *
+ * @param userEntity the user entity
+ * @param command a command to perform on the user entity object that changes it state thus needing
+ * to be persisted
+ */
+ private UserEntity safelyUpdateUserEntity(UserEntity userEntity, Command command, int maxRetries) {
+ int retriesLeft = maxRetries;
+
+ do {
+ try {
+ command.perform(userEntity);
+ userDAO.merge(userEntity);
+
+ // The merge was a success, break out of this loop and return
+ return userEntity;
+ } catch (Throwable t) {
+ Throwable cause = t;
+
+ do {
+ if (cause instanceof OptimisticLockException) {
+ // An OptimisticLockException was caught, refresh the entity and retry.
+ Integer userID = userEntity.getUserId();
+
+ // Find the userEntity record to make sure the object is managed by JPA. The passed-in
+ // object may be detached, therefore calling reset on it will fail.
+ userEntity = userDAO.findByPK(userID);
+
+ if (userEntity == null) {
+ LOG.warn("Failed to find user with user id of {}. The user may have been removed. Aborting.", userID);
+ return null; // return since this user is no longer available.
+ }
+
+ retriesLeft--;
+
+ // The the number of attempts has been exhausted, re-throw the exception
+ if (retriesLeft == 0) {
+ LOG.error("Failed to update the user's ({}) consecutive failures value due to an OptimisticLockException. Aborting.",
+ userEntity.getUserName());
+ throw t;
+ } else {
+ LOG.warn("Failed to update the user's ({}) consecutive failures value due to an OptimisticLockException. {} retries left, retrying...",
+ userEntity.getUserName(), retriesLeft);
+ }
+
+ break;
+ } else {
+ // Get the cause to see if it is an OptimisticLockException
+ cause = cause.getCause();
+ }
+ } while ((cause != null) && (cause != t)); // We are out of causes
+ }
+ } while (retriesLeft > 0); // We are out of retries
+
+ return userEntity;
+ }
+
+ /**
* Validator is an interface to be implemented by authentication type specific validators to ensure
* new user authentication records meet the specific requirements for the relative authentication
* type.
*/
private interface Validator {
/**
- * Valudate the authentication type specific key meets the requirments for the relative user
+ * Validate the authentication type specific key meets the requirements for the relative user
* authentication type.
*
* @param userEntity the user
@@ -1267,4 +1416,14 @@ public class Users {
*/
void validate(UserEntity userEntity, String key) throws AmbariException;
}
+
+ /**
+ * Command is an interface used to perform operations on a {@link UserEntity} while safely updating
+ * a {@link UserEntity} object.
+ *
+ * @see #safelyUpdateUserEntity(UserEntity, Command, int)
+ */
+ private interface Command {
+ void perform(UserEntity userEntity);
+ }
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/internal/AmbariInternalAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/internal/AmbariInternalAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/internal/AmbariInternalAuthenticationProvider.java
index c57bdf1..89b6333 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/internal/AmbariInternalAuthenticationProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/internal/AmbariInternalAuthenticationProvider.java
@@ -18,7 +18,7 @@
package org.apache.ambari.server.security.authorization.internal;
-import org.apache.ambari.server.security.authorization.InvalidUsernamePasswordCombinationException;
+import org.apache.ambari.server.security.authentication.InvalidUsernamePasswordCombinationException;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
index 3c3a446..f42df6c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
@@ -73,7 +73,7 @@ public class JwtAuthenticationFilter implements AmbariAuthenticationFilter {
private List<String> audiences = null;
private String cookieName = "hadoop-jwt";
- private boolean ignoreFailure = true;
+ private boolean ignoreFailure = false;
private AuthenticationEntryPoint entryPoint;
private Users users;
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
index 0c86591..78f9aec 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
@@ -266,6 +266,7 @@ CREATE TABLE users (
display_name VARCHAR(255) NOT NULL,
local_username VARCHAR(255) NOT NULL,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ version BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_users PRIMARY KEY (user_id),
CONSTRAINT FK_users_principal_id FOREIGN KEY (principal_id) REFERENCES adminprincipal(principal_id),
CONSTRAINT UNQ_users_0 UNIQUE (user_name));
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index 83b1f48..d3a3650 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -286,6 +286,7 @@ CREATE TABLE users (
display_name VARCHAR(255) NOT NULL,
local_username VARCHAR(255) NOT NULL,
create_time TIMESTAMP DEFAULT NOW(),
+ version BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_users PRIMARY KEY (user_id),
CONSTRAINT FK_users_principal_id FOREIGN KEY (principal_id) REFERENCES adminprincipal(principal_id),
CONSTRAINT UNQ_users_0 UNIQUE (user_name));
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index 215c01d..a27bc88 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -266,6 +266,7 @@ CREATE TABLE users (
display_name VARCHAR2(255) NOT NULL,
local_username VARCHAR2(255) NOT NULL,
create_time TIMESTAMP NULL,
+ version NUMBER(19) DEFAULT 0 NOT NULL,
CONSTRAINT PK_users PRIMARY KEY (user_id),
CONSTRAINT FK_users_principal_id FOREIGN KEY (principal_id) REFERENCES adminprincipal(principal_id),
CONSTRAINT UNQ_users_0 UNIQUE (user_name));
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index 40ba709..e56cb04 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -265,6 +265,7 @@ CREATE TABLE users (
display_name VARCHAR(255) NOT NULL,
local_username VARCHAR(255) NOT NULL,
create_time TIMESTAMP DEFAULT NOW(),
+ version BIGINT DEFAULT 0 NOT NULL,
CONSTRAINT PK_users PRIMARY KEY (user_id),
CONSTRAINT FK_users_principal_id FOREIGN KEY (principal_id) REFERENCES adminprincipal(principal_id),
CONSTRAINT UNQ_users_0 UNIQUE (user_name));
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
index 35951f1..a1758e3 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
@@ -263,6 +263,7 @@ CREATE TABLE users (
display_name VARCHAR(255) NOT NULL,
local_username VARCHAR(255) NOT NULL,
create_time TIMESTAMP DEFAULT NOW(),
+ version NUMERIC(19) NOT NULL DEFAULT 0,
CONSTRAINT PK_users PRIMARY KEY (user_id),
CONSTRAINT FK_users_principal_id FOREIGN KEY (principal_id) REFERENCES adminprincipal(principal_id),
CONSTRAINT UNQ_users_0 UNIQUE (user_name));
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
index b7244ab..e794866 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -269,6 +269,7 @@ CREATE TABLE users (
display_name VARCHAR(255) NOT NULL,
local_username VARCHAR(255) NOT NULL,
create_time DATETIME DEFAULT GETDATE(),
+ version BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_users PRIMARY KEY (user_id),
CONSTRAINT FK_users_principal_id FOREIGN KEY (principal_id) REFERENCES adminprincipal(principal_id),
CONSTRAINT UNQ_users_0 UNIQUE (user_name));
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml b/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
index bdbf0de..6650f67 100644
--- a/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
+++ b/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
@@ -55,24 +55,21 @@
<beans:bean id="ambariBasicAuthenticationFilter" class="org.apache.ambari.server.security.authentication.AmbariBasicAuthenticationFilter">
<beans:constructor-arg ref="authenticationManager"/>
<beans:constructor-arg ref="ambariEntryPoint"/>
- <beans:constructor-arg ref="auditLogger"/>
- <beans:constructor-arg ref="permissionHelper"/>
+ <beans:constructor-arg ref="ambariAuthenticationEventHandler"/>
</beans:bean>
<beans:bean id="ambariJwtAuthenticationFilter" class="org.apache.ambari.server.security.authentication.AmbariJWTAuthenticationFilter">
<beans:constructor-arg ref="ambariEntryPoint"/>
<beans:constructor-arg ref="ambariConfiguration"/>
<beans:constructor-arg ref="ambariUsers"/>
- <beans:constructor-arg ref="auditLogger"/>
- <beans:constructor-arg ref="permissionHelper"/>
+ <beans:constructor-arg ref="ambariAuthenticationEventHandler"/>
</beans:bean>
<beans:bean id="ambariKerberosAuthenticationFilter" class="org.apache.ambari.server.security.authentication.kerberos.AmbariKerberosAuthenticationFilter">
<beans:constructor-arg ref="authenticationManager"/>
<beans:constructor-arg ref="ambariEntryPoint"/>
<beans:constructor-arg ref="ambariConfiguration"/>
- <beans:constructor-arg ref="auditLogger"/>
- <beans:constructor-arg ref="permissionHelper"/>
+ <beans:constructor-arg ref="ambariAuthenticationEventHandler"/>
</beans:bean>
<beans:bean id="ambariAuthorizationFilter" class="org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter">
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/test/java/org/apache/ambari/server/audit/LoginAuditEventTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/audit/LoginAuditEventTest.java b/ambari-server/src/test/java/org/apache/ambari/server/audit/LoginAuditEventTest.java
index ac79967..2cff97e 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/audit/LoginAuditEventTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/audit/LoginAuditEventTest.java
@@ -69,6 +69,7 @@ public class LoginAuditEventTest {
String testUserName = "USER1";
String testRemoteIp = "127.0.0.1";
String reason = "Bad credentials";
+ Integer consecutiveFailures = 1;
Map<String, List<String>> roles = new HashMap<>();
roles.put("a", Arrays.asList("r1", "r2", "r3"));
@@ -79,6 +80,7 @@ public class LoginAuditEventTest {
.withUserName(testUserName)
.withRoles(roles)
.withReasonOfFailure(reason)
+ .withConsecutiveFailures(consecutiveFailures)
.build();
// When
@@ -87,11 +89,41 @@ public class LoginAuditEventTest {
String roleMessage = System.lineSeparator() + " a: r1, r2, r3" + System.lineSeparator();
// Then
- String expectedAuditMessage = String.format("User(%s), RemoteIp(%s), Operation(User login), Roles(%s), Status(Failed), Reason(%s)",
- testUserName, testRemoteIp, roleMessage, reason);
+ String expectedAuditMessage = String.format("User(%s), RemoteIp(%s), Operation(User login), Roles(%s), Status(Failed), Reason(%s), Consecutive failures(%d)",
+ testUserName, testRemoteIp, roleMessage, reason, consecutiveFailures);
assertThat(actualAuditMessage, equalTo(expectedAuditMessage));
+ }
+
+ @Test
+ public void testFailedAuditMessageUnknownUser() throws Exception {
+ // Given
+ String testUserName = "USER1";
+ String testRemoteIp = "127.0.0.1";
+ String reason = "Bad credentials";
+
+ Map<String, List<String>> roles = new HashMap<>();
+ roles.put("a", Arrays.asList("r1", "r2", "r3"));
+
+ LoginAuditEvent evnt = LoginAuditEvent.builder()
+ .withTimestamp(System.currentTimeMillis())
+ .withRemoteIp(testRemoteIp)
+ .withUserName(testUserName)
+ .withRoles(roles)
+ .withReasonOfFailure(reason)
+ .withConsecutiveFailures(null)
+ .build();
+
+ // When
+ String actualAuditMessage = evnt.getAuditMessage();
+
+ String roleMessage = System.lineSeparator() + " a: r1, r2, r3" + System.lineSeparator();
+ // Then
+ String expectedAuditMessage = String.format("User(%s), RemoteIp(%s), Operation(User login), Roles(%s), Status(Failed), Reason(%s), Consecutive failures(UNKNOWN USER)",
+ testUserName, testRemoteIp, roleMessage, reason);
+
+ assertThat(actualAuditMessage, equalTo(expectedAuditMessage));
}
@Test
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilterTest.java
index 18c4cce..ed4c383 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilterTest.java
@@ -18,110 +18,134 @@
package org.apache.ambari.server.security.authentication;
import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.getCurrentArguments;
+import static org.easymock.EasyMock.newCapture;
import java.io.IOException;
-import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
-import org.apache.ambari.server.audit.AuditLogger;
-import org.apache.ambari.server.audit.event.AuditEvent;
import org.apache.ambari.server.security.AmbariEntryPoint;
-import org.apache.ambari.server.security.authorization.PermissionHelper;
+import org.easymock.Capture;
+import org.easymock.CaptureType;
import org.easymock.EasyMockSupport;
+import org.easymock.IAnswer;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.crypto.codec.Base64;
public class AmbariBasicAuthenticationFilterTest extends EasyMockSupport {
- private AmbariBasicAuthenticationFilter underTest;
-
- private AuditLogger mockedAuditLogger;
-
- private PermissionHelper permissionHelper;
+ private AmbariAuthenticationEventHandler eventHandler;
private AmbariEntryPoint entryPoint;
+ private AuthenticationManager authenticationManager;
+
@Before
public void setUp() {
- mockedAuditLogger = createMock(AuditLogger.class);
- permissionHelper = createMock(PermissionHelper.class);
+ SecurityContextHolder.getContext().setAuthentication(null);
+
+ eventHandler = createMock(AmbariAuthenticationEventHandler.class);
entryPoint = createMock(AmbariEntryPoint.class);
- underTest = new AmbariBasicAuthenticationFilter(null, entryPoint, mockedAuditLogger, permissionHelper);
+ authenticationManager = createMock(AuthenticationManager.class);
+ }
+
+ @Test (expected = IllegalArgumentException.class)
+ public void ensureNonNullEventHandler() {
+ new AmbariBasicAuthenticationFilter(authenticationManager, entryPoint, null);
}
@Test
- public void testDoFilter() throws IOException, ServletException {
- SecurityContextHolder.getContext().setAuthentication(null);
+ public void testDoFilterSuccessful() throws IOException, ServletException {
+ Capture<? extends AmbariAuthenticationFilter> captureFilter = newCapture(CaptureType.ALL);
+
// GIVEN
HttpServletRequest request = createMock(HttpServletRequest.class);
HttpServletResponse response = createMock(HttpServletResponse.class);
+ HttpSession session = createMock(HttpSession.class);
FilterChain filterChain = createMock(FilterChain.class);
- expect(request.getHeader("Authorization")).andReturn("Basic ").andReturn(null);
- expect(request.getHeader("X-Forwarded-For")).andReturn("1.2.3.4").anyTimes();
- expect(mockedAuditLogger.isEnabled()).andReturn(true).anyTimes();
- mockedAuditLogger.log(anyObject(AuditEvent.class));
- expectLastCall().times(1);
+
+ expect(request.getHeader("Authorization")).andReturn("Basic YWRtaW46YWRtaW4=").once();
+ expect(request.getRemoteAddr()).andReturn("1.2.3.4").once();
+ expect(request.getSession(false)).andReturn(session).once();
+ expect(session.getId()).andReturn("sessionID").once();
+ expect(authenticationManager.authenticate(anyObject(Authentication.class)))
+ .andAnswer(new IAnswer<Authentication>() {
+ @Override
+ public Authentication answer() throws Throwable {
+ return (Authentication) getCurrentArguments()[0];
+ }
+ })
+ .anyTimes();
+
+ eventHandler.beforeAttemptAuthentication(capture(captureFilter), eq(request), eq(response));
+ expectLastCall().once();
+ eventHandler.onSuccessfulAuthentication(capture(captureFilter), eq(request), eq(response), anyObject(Authentication.class));
+ expectLastCall().once();
+
filterChain.doFilter(request, response);
- expectLastCall();
- replayAll();
- // WHEN
- underTest.doFilter(request, response, filterChain);
- // THEN
- verifyAll();
- }
+ expectLastCall().once();
- @Test
- public void testOnSuccessfulAuthentication() throws IOException, ServletException {
- // GIVEN
- HttpServletRequest request = createMock(HttpServletRequest.class);
- HttpServletResponse response = createMock(HttpServletResponse.class);
- Authentication authentication = createMock(Authentication.class);
-
- Map<String, List<String>> roles = new HashMap<>();
- roles.put("a", Arrays.asList("r1", "r2", "r3"));
- expect(permissionHelper.getPermissionLabels(authentication))
- .andReturn(roles);
- expect(request.getHeader("X-Forwarded-For")).andReturn("1.2.3.4");
- expect(authentication.getName()).andReturn("admin");
- expect(mockedAuditLogger.isEnabled()).andReturn(true);
- mockedAuditLogger.log(anyObject(AuditEvent.class));
- expectLastCall().times(1);
replayAll();
// WHEN
- underTest.onSuccessfulAuthentication(request, response, authentication);
+ AmbariAuthenticationFilter filter = new AmbariBasicAuthenticationFilter(authenticationManager, entryPoint, eventHandler);
+ filter.doFilter(request, response, filterChain);
// THEN
verifyAll();
+
+ List<? extends AmbariAuthenticationFilter> capturedFilters = captureFilter.getValues();
+ for (AmbariAuthenticationFilter capturedFiltered : capturedFilters) {
+ Assert.assertSame(filter, capturedFiltered);
+ }
}
@Test
- public void testOnUnsuccessfulAuthentication() throws IOException, ServletException {
+ public void testDoFilterUnsuccessful() throws IOException, ServletException {
+ Capture<? extends AmbariAuthenticationFilter> captureFilter = newCapture(CaptureType.ALL);
+
// GIVEN
HttpServletRequest request = createMock(HttpServletRequest.class);
HttpServletResponse response = createMock(HttpServletResponse.class);
- AuthenticationException authEx = createMock(AuthenticationException.class);
- expect(request.getHeader("X-Forwarded-For")).andReturn("1.2.3.4");
- expect(request.getHeader("Authorization")).andReturn(
- "Basic " + new String(Base64.encode("admin:admin".getBytes("UTF-8"))));
- expect(mockedAuditLogger.isEnabled()).andReturn(true);
- mockedAuditLogger.log(anyObject(AuditEvent.class));
- expectLastCall().times(1);
+ HttpSession session = createMock(HttpSession.class);
+ FilterChain filterChain = createMock(FilterChain.class);
+
+ expect(request.getHeader("Authorization")).andReturn("Basic YWRtaW46YWRtaW4=").once();
+ expect(request.getRemoteAddr()).andReturn("1.2.3.4").once();
+ expect(request.getSession(false)).andReturn(session).once();
+ expect(session.getId()).andReturn("sessionID").once();
+ expect(authenticationManager.authenticate(anyObject(Authentication.class))).andThrow(new InvalidUsernamePasswordCombinationException("user")).once();
+
+ eventHandler.beforeAttemptAuthentication(capture(captureFilter), eq(request), eq(response));
+ expectLastCall().once();
+ eventHandler.onUnsuccessfulAuthentication(capture(captureFilter), eq(request), eq(response), anyObject(AmbariAuthenticationException.class));
+ expectLastCall().once();
+
+ entryPoint.commence(eq(request), eq(response), anyObject(AmbariAuthenticationException.class));
+ expectLastCall().once();
+
replayAll();
// WHEN
- underTest.onUnsuccessfulAuthentication(request, response, authEx);
+ AmbariAuthenticationFilter filter = new AmbariBasicAuthenticationFilter(authenticationManager, entryPoint, eventHandler);
+ filter.doFilter(request, response, filterChain);
// THEN
verifyAll();
+
+ List<? extends AmbariAuthenticationFilter> capturedFilters = captureFilter.getValues();
+ for (AmbariAuthenticationFilter capturedFiltered : capturedFilters) {
+ Assert.assertSame(filter, capturedFiltered);
+ }
}
}
[2/4] ambari git commit: Merge branch 'trunk' into
branch-feature-AMBARI-20859
Posted by rl...@apache.org.
Merge branch 'trunk' into branch-feature-AMBARI-20859
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/ac5008da
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/ac5008da
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/ac5008da
Branch: refs/heads/branch-feature-AMBARI-20859
Commit: ac5008dac895e39f0257659a270d3b231c0aee9c
Parents: b533387 45a2990
Author: Robert Levas <rl...@hortonworks.com>
Authored: Thu Jun 22 13:27:41 2017 -0400
Committer: Robert Levas <rl...@hortonworks.com>
Committed: Thu Jun 22 13:27:41 2017 -0400
----------------------------------------------------------------------
.../ambari_server/dbConfiguration_linux.py | 34 +++++++++++++-------
1 file changed, 22 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
[3/4] ambari git commit: AMBARI-21216. Add support for consecutive
login failure accounting (rlevas)
Posted by rl...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java
index 961e65d..14c1032 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java
@@ -18,8 +18,12 @@
package org.apache.ambari.server.security.authentication;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.newCapture;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
@@ -28,24 +32,31 @@ import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Calendar;
import java.util.Collections;
-import java.util.Date;
+import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.ambari.server.audit.AuditLogger;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
import org.apache.ambari.server.orm.entities.UserEntity;
import org.apache.ambari.server.security.AmbariEntryPoint;
-import org.apache.ambari.server.security.authorization.PermissionHelper;
+import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
+import org.apache.ambari.server.security.authorization.User;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
import org.apache.ambari.server.security.authorization.Users;
import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationProperties;
+import org.easymock.Capture;
+import org.easymock.CaptureType;
import org.easymock.EasyMockSupport;
+import org.junit.Assert;
+import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
@@ -58,6 +69,14 @@ public class AmbariJWTAuthenticationFilterTest extends EasyMockSupport {
private static RSAPublicKey publicKey;
private static RSAPrivateKey privateKey;
+ private AmbariAuthenticationEventHandler eventHandler;
+
+ private AmbariEntryPoint entryPoint;
+
+ private Configuration configuration;
+
+ private Users users;
+
@BeforeClass
public static void generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
@@ -67,11 +86,9 @@ public class AmbariJWTAuthenticationFilterTest extends EasyMockSupport {
privateKey = (RSAPrivateKey) keyPair.getPrivate();
}
- @Test
- public void testDoFilterSuccess() throws Exception {
- SignedJWT token = getSignedToken("foobar");
-
- AmbariEntryPoint entryPoint = createMock(AmbariEntryPoint.class);
+ @Before
+ public void setUp() {
+ SecurityContextHolder.getContext().setAuthentication(null);
JwtAuthenticationProperties properties = createMock(JwtAuthenticationProperties.class);
expect(properties.getAuthenticationProviderUrl()).andReturn("some url").once();
@@ -80,96 +97,115 @@ public class AmbariJWTAuthenticationFilterTest extends EasyMockSupport {
expect(properties.getCookieName()).andReturn("chocolate chip").once();
expect(properties.getOriginalUrlQueryParam()).andReturn("question").once();
- Configuration configuration = createMock(Configuration.class);
+ users = createMock(Users.class);
+ eventHandler = createMock(AmbariAuthenticationEventHandler.class);
+ entryPoint = createMock(AmbariEntryPoint.class);
+ configuration = createMock(Configuration.class);
+
expect(configuration.getJwtProperties()).andReturn(properties).once();
+ }
- UserEntity userEntity = createMock(UserEntity.class);
- expect(userEntity.getAuthenticationEntities()).andReturn(Collections.<UserAuthenticationEntity>emptyList()).once();
- Users users = createMock(Users.class);
- expect(users.getUserEntity("test-user")).andReturn(userEntity).once();
+ @Test (expected = IllegalArgumentException.class)
+ public void ensureNonNullEventHandler() {
+ new AmbariJWTAuthenticationFilter(entryPoint, configuration, users, null);
+ }
+
+ @Test
+ public void testDoFilterSuccessful() throws Exception {
+ Capture<? extends AmbariAuthenticationFilter> captureFilter = newCapture(CaptureType.ALL);
- AuditLogger auditLogger = createMock(AuditLogger.class);
- expect(auditLogger.isEnabled()).andReturn(false).times(2);
+ SignedJWT token = getSignedToken();
- PermissionHelper permissionHelper = createMock(PermissionHelper.class);
+ HttpServletRequest request = createMock(HttpServletRequest.class);
+ HttpServletResponse response = createMock(HttpServletResponse.class);
+ FilterChain filterChain = createMock(FilterChain.class);
Cookie cookie = createMock(Cookie.class);
expect(cookie.getName()).andReturn("chocolate chip").once();
expect(cookie.getValue()).andReturn(token.serialize()).once();
+ expect(request.getCookies()).andReturn(new Cookie[]{cookie}).once();
+
+ UserAuthenticationEntity userAuthenticationEntity = createMock(UserAuthenticationEntity.class);
+ expect(userAuthenticationEntity.getAuthenticationType()).andReturn(UserAuthenticationType.JWT).anyTimes();
- HttpServletRequest servletRequest = createMock(HttpServletRequest.class);
- expect(servletRequest.getCookies()).andReturn(new Cookie[]{cookie}).once();
+ UserEntity userEntity = createMock(UserEntity.class);
+ expect(userEntity.getAuthenticationEntities()).andReturn(Collections.singletonList(userAuthenticationEntity)).once();
- HttpServletResponse servletResponse = createMock(HttpServletResponse.class);
+ expect(users.getUserEntity("test-user")).andReturn(userEntity).once();
+ expect(users.getUserAuthorities(userEntity)).andReturn(Collections.<AmbariGrantedAuthority>emptyList()).once();
+ expect(users.getUser(userEntity)).andReturn(createMock(User.class)).once();
- FilterChain filterChain = createMock(FilterChain.class);
- filterChain.doFilter(servletRequest, servletResponse);
+ eventHandler.beforeAttemptAuthentication(capture(captureFilter), eq(request), eq(response));
+ expectLastCall().once();
+ eventHandler.onSuccessfulAuthentication(capture(captureFilter), eq(request), eq(response), anyObject(Authentication.class));
expectLastCall().once();
- replayAll();
+ filterChain.doFilter(request, response);
+ expectLastCall().once();
- AmbariJWTAuthenticationFilter filter = new AmbariJWTAuthenticationFilter(entryPoint, configuration, users, auditLogger, permissionHelper);
- filter.doFilter(servletRequest, servletResponse, filterChain);
+ replayAll();
+ // WHEN
+ AmbariJWTAuthenticationFilter filter = new AmbariJWTAuthenticationFilter(entryPoint, configuration, users, eventHandler);
+ filter.doFilter(request, response, filterChain);
+ // THEN
verifyAll();
- }
- @Test
- public void testDoFilterFailure() throws Exception {
- AmbariEntryPoint entryPoint = createMock(AmbariEntryPoint.class);
-
- JwtAuthenticationProperties properties = createMock(JwtAuthenticationProperties.class);
- expect(properties.getAuthenticationProviderUrl()).andReturn("some url").once();
- expect(properties.getPublicKey()).andReturn(publicKey).once();
- expect(properties.getAudiences()).andReturn(Collections.singletonList("foobar")).once();
- expect(properties.getCookieName()).andReturn("chocolate chip").once();
- expect(properties.getOriginalUrlQueryParam()).andReturn("question").once();
-
- Configuration configuration = createMock(Configuration.class);
- expect(configuration.getJwtProperties()).andReturn(properties).once();
+ List<? extends AmbariAuthenticationFilter> capturedFilters = captureFilter.getValues();
+ for(AmbariAuthenticationFilter capturedFiltered : capturedFilters) {
+ Assert.assertSame(filter, capturedFiltered);
+ }
+ }
- Users users = createMock(Users.class);
- AuditLogger auditLogger = createMock(AuditLogger.class);
- expect(auditLogger.isEnabled()).andReturn(false).times(2);
+ @Test
+ public void testDoFilterUnsuccessful() throws Exception {
+ Capture<? extends AmbariAuthenticationFilter> captureFilter = newCapture(CaptureType.ALL);
- PermissionHelper permissionHelper = createMock(PermissionHelper.class);
+ SignedJWT token = getSignedToken();
+ // GIVEN
+ HttpServletRequest request = createMock(HttpServletRequest.class);
+ HttpServletResponse response = createMock(HttpServletResponse.class);
+ FilterChain filterChain = createMock(FilterChain.class);
Cookie cookie = createMock(Cookie.class);
expect(cookie.getName()).andReturn("chocolate chip").once();
- expect(cookie.getValue()).andReturn("invalid token").once();
+ expect(cookie.getValue()).andReturn(token.serialize()).once();
+ expect(request.getCookies()).andReturn(new Cookie[]{cookie}).once();
- HttpServletRequest servletRequest = createMock(HttpServletRequest.class);
- expect(servletRequest.getCookies()).andReturn(new Cookie[]{cookie}).once();
+ expect(users.getUserEntity("test-user")).andReturn(null).once();
- HttpServletResponse servletResponse = createMock(HttpServletResponse.class);
+ eventHandler.beforeAttemptAuthentication(capture(captureFilter), eq(request), eq(response));
+ expectLastCall().once();
+ eventHandler.onUnsuccessfulAuthentication(capture(captureFilter), eq(request), eq(response), anyObject(AmbariAuthenticationException.class));
+ expectLastCall().once();
- FilterChain filterChain = createMock(FilterChain.class);
- filterChain.doFilter(servletRequest, servletResponse);
+ entryPoint.commence(eq(request), eq(response), anyObject(AmbariAuthenticationException.class));
expectLastCall().once();
replayAll();
-
- AmbariJWTAuthenticationFilter filter = new AmbariJWTAuthenticationFilter(entryPoint, configuration, users, auditLogger, permissionHelper);
- filter.doFilter(servletRequest, servletResponse, filterChain);
-
+ // WHEN
+ AmbariJWTAuthenticationFilter filter = new AmbariJWTAuthenticationFilter(entryPoint, configuration, users, eventHandler);
+ filter.doFilter(request, response, filterChain);
+ // THEN
verifyAll();
- }
-
- private SignedJWT getSignedToken(String audience) throws JOSEException {
- Calendar calendar = Calendar.getInstance();
- calendar.setTimeInMillis(System.currentTimeMillis());
- calendar.add(Calendar.DATE, 1); //add one day
- return getSignedToken(calendar.getTime(), audience);
+ List<? extends AmbariAuthenticationFilter> capturedFilters = captureFilter.getValues();
+ for (AmbariAuthenticationFilter capturedFiltered : capturedFilters) {
+ Assert.assertSame(filter, capturedFiltered);
+ }
}
- private SignedJWT getSignedToken(Date expirationTime, String audience) throws JOSEException {
+ private SignedJWT getSignedToken() throws JOSEException {
RSASSASigner signer = new RSASSASigner(privateKey);
+ Calendar expirationTime = Calendar.getInstance();
+ expirationTime.setTimeInMillis(System.currentTimeMillis());
+ expirationTime.add(Calendar.DATE, 1); //add one day
+
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
JWTClaimsSet claimsSet = new JWTClaimsSet();
@@ -177,9 +213,9 @@ public class AmbariJWTAuthenticationFilterTest extends EasyMockSupport {
claimsSet.setIssuer("unit-test");
claimsSet.setIssueTime(calendar.getTime());
- claimsSet.setExpirationTime(expirationTime);
+ claimsSet.setExpirationTime(expirationTime.getTime());
- claimsSet.setAudience(audience);
+ claimsSet.setAudience("foobar");
SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.RS256), claimsSet);
signedJWT.sign(signer);
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilterTest.java
index 5503fac..a0b7aca 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilterTest.java
@@ -18,35 +18,71 @@
package org.apache.ambari.server.security.authentication.kerberos;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.getCurrentArguments;
+import static org.easymock.EasyMock.newCapture;
+import java.io.IOException;
+import java.util.List;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
-import org.apache.ambari.server.audit.AuditLogger;
import org.apache.ambari.server.configuration.Configuration;
-import org.apache.ambari.server.security.authorization.PermissionHelper;
+import org.apache.ambari.server.security.AmbariEntryPoint;
+import org.apache.ambari.server.security.authentication.AmbariAuthenticationEventHandler;
+import org.apache.ambari.server.security.authentication.AmbariAuthenticationException;
+import org.apache.ambari.server.security.authentication.AmbariAuthenticationFilter;
+import org.apache.ambari.server.security.authentication.InvalidUsernamePasswordCombinationException;
+import org.easymock.Capture;
+import org.easymock.CaptureType;
import org.easymock.EasyMockSupport;
+import org.easymock.IAnswer;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
public class AmbariKerberosAuthenticationFilterTest extends EasyMockSupport {
+ private Configuration configuration;
+
+ private AuthenticationEntryPoint entryPoint;
+
+ private AuthenticationManager authenticationManager;
+
+ private AmbariAuthenticationEventHandler eventHandler;
+
+ @Before
+ public void setUp() {
+ SecurityContextHolder.getContext().setAuthentication(null);
+
+ entryPoint = createMock(AmbariEntryPoint.class);
+ configuration = createMock(Configuration.class);
+ authenticationManager = createMock(AuthenticationManager.class);
+ eventHandler = createMock(AmbariAuthenticationEventHandler.class);
+ }
+
+ @Test (expected = IllegalArgumentException.class)
+ public void ensureNonNullEventHandler() {
+ new AmbariKerberosAuthenticationFilter(authenticationManager, entryPoint, configuration, null);
+ }
+
@Test
public void shouldApplyTrue() throws Exception {
HttpServletRequest httpServletRequest = createMock(HttpServletRequest.class);
expect(httpServletRequest.getHeader("Authorization")).andReturn("Negotiate .....").once();
- AmbariKerberosAuthenticationProperties properties = createMock(AmbariKerberosAuthenticationProperties.class);
- expect(properties.isKerberosAuthenticationEnabled()).andReturn(true).once();
-
- Configuration configuration = createMock(Configuration.class);
- expect(configuration.getKerberosAuthenticationProperties()).andReturn(properties).once();
-
- AuthenticationManager authenticationManager = createMock(AuthenticationManager.class);
- AuthenticationEntryPoint entryPoint = createMock(AuthenticationEntryPoint.class);
- AuditLogger auditLogger = createMock(AuditLogger.class);
- PermissionHelper permissionHelper = createMock(PermissionHelper.class);
+ expect(configuration.getKerberosAuthenticationProperties()).andReturn(createProperties(true)).once();
replayAll();
@@ -54,8 +90,7 @@ public class AmbariKerberosAuthenticationFilterTest extends EasyMockSupport {
authenticationManager,
entryPoint,
configuration,
- auditLogger,
- permissionHelper
+ eventHandler
);
Assert.assertTrue(filter.shouldApply(httpServletRequest));
@@ -68,16 +103,7 @@ public class AmbariKerberosAuthenticationFilterTest extends EasyMockSupport {
HttpServletRequest httpServletRequest = createMock(HttpServletRequest.class);
expect(httpServletRequest.getHeader("Authorization")).andReturn(null).once();
- AmbariKerberosAuthenticationProperties properties = createMock(AmbariKerberosAuthenticationProperties.class);
- expect(properties.isKerberosAuthenticationEnabled()).andReturn(true).once();
-
- Configuration configuration = createMock(Configuration.class);
- expect(configuration.getKerberosAuthenticationProperties()).andReturn(properties).once();
-
- AuthenticationManager authenticationManager = createMock(AuthenticationManager.class);
- AuthenticationEntryPoint entryPoint = createMock(AuthenticationEntryPoint.class);
- AuditLogger auditLogger = createMock(AuditLogger.class);
- PermissionHelper permissionHelper = createMock(PermissionHelper.class);
+ expect(configuration.getKerberosAuthenticationProperties()).andReturn(createProperties(true)).once();
replayAll();
@@ -85,8 +111,7 @@ public class AmbariKerberosAuthenticationFilterTest extends EasyMockSupport {
authenticationManager,
entryPoint,
configuration,
- auditLogger,
- permissionHelper
+ eventHandler
);
Assert.assertFalse(filter.shouldApply(httpServletRequest));
@@ -98,16 +123,7 @@ public class AmbariKerberosAuthenticationFilterTest extends EasyMockSupport {
public void shouldApplyNotFalseEnabled() throws Exception {
HttpServletRequest httpServletRequest = createMock(HttpServletRequest.class);
- AmbariKerberosAuthenticationProperties properties = createMock(AmbariKerberosAuthenticationProperties.class);
- expect(properties.isKerberosAuthenticationEnabled()).andReturn(false).once();
-
- Configuration configuration = createMock(Configuration.class);
- expect(configuration.getKerberosAuthenticationProperties()).andReturn(properties).once();
-
- AuthenticationManager authenticationManager = createMock(AuthenticationManager.class);
- AuthenticationEntryPoint entryPoint = createMock(AuthenticationEntryPoint.class);
- AuditLogger auditLogger = createMock(AuditLogger.class);
- PermissionHelper permissionHelper = createMock(PermissionHelper.class);
+ expect(configuration.getKerberosAuthenticationProperties()).andReturn(createProperties(false)).once();
replayAll();
@@ -115,8 +131,7 @@ public class AmbariKerberosAuthenticationFilterTest extends EasyMockSupport {
authenticationManager,
entryPoint,
configuration,
- auditLogger,
- permissionHelper
+ eventHandler
);
Assert.assertFalse(filter.shouldApply(httpServletRequest));
@@ -125,9 +140,95 @@ public class AmbariKerberosAuthenticationFilterTest extends EasyMockSupport {
}
@Test
- public void doFilter() throws Exception {
- // Skip this test since the real work is being done by SpnegoAuthenticationProcessingFilter, which
- // is a class in the Spring libraries.
+ public void testDoFilterSuccessful() throws IOException, ServletException {
+ Capture<? extends AmbariAuthenticationFilter> captureFilter = newCapture(CaptureType.ALL);
+
+ // GIVEN
+ HttpServletRequest request = createMock(HttpServletRequest.class);
+ HttpServletResponse response = createMock(HttpServletResponse.class);
+ HttpSession session = createMock(HttpSession.class);
+ FilterChain filterChain = createMock(FilterChain.class);
+
+ expect(request.getHeader("Authorization")).andReturn("Negotiate ").once();
+ expect(request.getRemoteAddr()).andReturn("1.2.3.4").once();
+ expect(request.getSession(false)).andReturn(session).once();
+ expect(session.getId()).andReturn("sessionID").once();
+
+ expect(authenticationManager.authenticate(anyObject(Authentication.class)))
+ .andAnswer(new IAnswer<Authentication>() {
+ @Override
+ public Authentication answer() throws Throwable {
+ return (Authentication) getCurrentArguments()[0];
+ }
+ })
+ .anyTimes();
+
+ expect(configuration.getKerberosAuthenticationProperties()).andReturn(createProperties(true)).once();
+
+ eventHandler.beforeAttemptAuthentication(capture(captureFilter), eq(request), eq(response));
+ expectLastCall().once();
+ eventHandler.onSuccessfulAuthentication(capture(captureFilter), eq(request), eq(response), anyObject(Authentication.class));
+ expectLastCall().once();
+
+ filterChain.doFilter(request, response);
+ expectLastCall().once();
+
+ replayAll();
+ // WHEN
+ AmbariAuthenticationFilter filter = new AmbariKerberosAuthenticationFilter(authenticationManager, entryPoint, configuration, eventHandler);
+ filter.doFilter(request, response, filterChain);
+ // THEN
+ verifyAll();
+
+ List<? extends AmbariAuthenticationFilter> capturedFilters = captureFilter.getValues();
+ for (AmbariAuthenticationFilter capturedFiltered : capturedFilters) {
+ Assert.assertSame(filter, capturedFiltered);
+ }
}
+ @Test
+ public void testDoFilterUnsuccessful() throws IOException, ServletException {
+ Capture<? extends AmbariAuthenticationFilter> captureFilter = newCapture(CaptureType.ALL);
+
+ // GIVEN
+ HttpServletRequest request = createMock(HttpServletRequest.class);
+ HttpServletResponse response = createMock(HttpServletResponse.class);
+ HttpSession session = createMock(HttpSession.class);
+ FilterChain filterChain = createMock(FilterChain.class);
+
+ expect(request.getHeader("Authorization")).andReturn("Negotiate ").once();
+ expect(request.getRemoteAddr()).andReturn("1.2.3.4").once();
+ expect(request.getSession(false)).andReturn(session).once();
+ expect(session.getId()).andReturn("sessionID").once();
+
+ expect(authenticationManager.authenticate(anyObject(Authentication.class))).andThrow(new InvalidUsernamePasswordCombinationException("user")).once();
+
+ expect(configuration.getKerberosAuthenticationProperties()).andReturn(createProperties(true)).once();
+
+ eventHandler.beforeAttemptAuthentication(capture(captureFilter), eq(request), eq(response));
+ expectLastCall().once();
+ eventHandler.onUnsuccessfulAuthentication(capture(captureFilter), eq(request), eq(response), anyObject(AmbariAuthenticationException.class));
+ expectLastCall().once();
+
+ entryPoint.commence(eq(request), eq(response), anyObject(AmbariAuthenticationException.class));
+ expectLastCall().once();
+
+ replayAll();
+ // WHEN
+ AmbariAuthenticationFilter filter = new AmbariKerberosAuthenticationFilter(authenticationManager, entryPoint, configuration, eventHandler);
+ filter.doFilter(request, response, filterChain);
+ // THEN
+ verifyAll();
+
+ List<? extends AmbariAuthenticationFilter> capturedFilters = captureFilter.getValues();
+ for (AmbariAuthenticationFilter capturedFiltered : capturedFilters) {
+ Assert.assertSame(filter, capturedFiltered);
+ }
+ }
+
+ private AmbariKerberosAuthenticationProperties createProperties(Boolean enabled) {
+ AmbariKerberosAuthenticationProperties properties = createMock(AmbariKerberosAuthenticationProperties.class);
+ expect(properties.isKerberosAuthenticationEnabled()).andReturn(enabled).once();
+ return properties;
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java
index 33100dd..fea7fb9 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java
@@ -26,6 +26,7 @@ import org.apache.ambari.server.orm.dao.UserDAO;
import org.apache.ambari.server.orm.entities.PrincipalEntity;
import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.security.authentication.InvalidUsernamePasswordCombinationException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderForDNWithSpaceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderForDNWithSpaceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderForDNWithSpaceTest.java
index 1bf122e..fd967c2 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderForDNWithSpaceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderForDNWithSpaceTest.java
@@ -30,6 +30,7 @@ import org.apache.ambari.server.orm.GuiceJpaInitializer;
import org.apache.ambari.server.orm.dao.UserDAO;
import org.apache.ambari.server.orm.entities.UserEntity;
import org.apache.ambari.server.security.ClientSecurityType;
+import org.apache.ambari.server.security.authentication.InvalidUsernamePasswordCombinationException;
import org.apache.directory.server.annotations.CreateLdapServer;
import org.apache.directory.server.annotations.CreateTransport;
import org.apache.directory.server.core.annotations.ApplyLdifFiles;
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderTest.java
index d9eb335..a613a18 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProviderTest.java
@@ -33,6 +33,7 @@ import org.apache.ambari.server.orm.GuiceJpaInitializer;
import org.apache.ambari.server.orm.dao.UserDAO;
import org.apache.ambari.server.orm.entities.UserEntity;
import org.apache.ambari.server.security.ClientSecurityType;
+import org.apache.ambari.server.security.authentication.InvalidUsernamePasswordCombinationException;
import org.apache.directory.server.annotations.CreateLdapServer;
import org.apache.directory.server.annotations.CreateTransport;
import org.apache.directory.server.core.annotations.ApplyLdifFiles;
http://git-wip-us.apache.org/repos/asf/ambari/blob/f760516c/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java
index 65a5400..133fc9f 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java
@@ -35,6 +35,7 @@ import org.apache.ambari.server.orm.dao.UserDAO;
import org.apache.ambari.server.orm.entities.PrincipalEntity;
import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.security.authentication.InvalidUsernamePasswordCombinationException;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;