+ * 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.atlas.notification.rest; + +import org.apache.atlas.security.SecurityProperties; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.lang.StringUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * A wrapper for getting configuration entries related to HighAvailability. + */ +public final class RestHAConfiguration { + + + public static final String ATLAS_REST_SERVER_ZK_ROOT_DEFAULT = "/apache_atlas_rest"; + + private RestHAConfiguration() { + } + + public static final String ATLAS_REST_SERVER_HA_PREFIX = "atlas.rest.server.ha."; + public static final String ZOOKEEPER_PREFIX = "zookeeper."; + public static final String ATLAS_REST_SERVER_HA_ZK_ROOT_KEY = ATLAS_REST_SERVER_HA_PREFIX + ZOOKEEPER_PREFIX + "zkroot"; + public static final String ATLAS_REST_SERVER_HA_ENABLED_KEY = ATLAS_REST_SERVER_HA_PREFIX + "enabled"; + public static final String ATLAS_REST_SERVER_ADDRESS_PREFIX = "atlas.rest.server.address."; + public static final String ATLAS_REST_SERVER_IDS = "atlas.rest.server.ids"; + public static final String HA_ZOOKEEPER_CONNECT = ATLAS_REST_SERVER_HA_PREFIX + ZOOKEEPER_PREFIX + "connect"; + public static final int DEFAULT_ZOOKEEPER_CONNECT_SLEEPTIME_MILLIS = 1000; + public static final String HA_ZOOKEEPER_RETRY_SLEEPTIME_MILLIS = + ATLAS_REST_SERVER_HA_PREFIX + ZOOKEEPER_PREFIX + "retry.sleeptime.ms"; + public static final String HA_ZOOKEEPER_NUM_RETRIES = ATLAS_REST_SERVER_HA_PREFIX + ZOOKEEPER_PREFIX + "num.retries"; + public static final int DEFAULT_ZOOKEEPER_CONNECT_NUM_RETRIES = 3; + public static final String HA_ZOOKEEPER_SESSION_TIMEOUT_MS = + ATLAS_REST_SERVER_HA_PREFIX + ZOOKEEPER_PREFIX + "session.timeout.ms"; + public static final int DEFAULT_ZOOKEEPER_SESSION_TIMEOUT_MILLIS = 20000; + public static final String HA_ZOOKEEPER_ACL = ATLAS_REST_SERVER_HA_PREFIX + ZOOKEEPER_PREFIX + "acl"; + public static final String HA_ZOOKEEPER_AUTH = ATLAS_REST_SERVER_HA_PREFIX + ZOOKEEPER_PREFIX + "auth"; + + /** + * Return whether HA is enabled or not. + * + * @param configuration underlying configuration instance + * @return + */ + public static boolean isHAEnabled(Configuration configuration) { + boolean ret = false; + + if (configuration.containsKey(RestHAConfiguration.ATLAS_REST_SERVER_HA_ENABLED_KEY)) { + ret = configuration.getBoolean(ATLAS_REST_SERVER_HA_ENABLED_KEY); + } else { + String[] ids = configuration.getStringArray(RestHAConfiguration.ATLAS_REST_SERVER_IDS); + + ret = ids != null && ids.length > 1; + } + + return ret; + } + + /** + * Get the web server address that a server instance with the passed ID is bound to. + *
+ * This method uses the property {@link SecurityProperties#TLS_ENABLED} to determine whether
+ * the URL is http or https.
+ *
+ * @param configuration underlying configuration
+ * @param serverId serverId whose host:port property is picked to build the web server address.
+ * @return
+ */
+ public static String getBoundAddressForId(Configuration configuration, String serverId) {
+ String hostPort = configuration.getString(ATLAS_REST_SERVER_ADDRESS_PREFIX + serverId);
+ boolean isSecure = configuration.getBoolean(SecurityProperties.TLS_ENABLED);
+ String protocol = (isSecure) ? "https://" : "http://";
+ return protocol + hostPort;
+ }
+
+ public static List
+ * 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.atlas.notification.rest;
+
+import org.apache.atlas.ApplicationProperties;
+import org.apache.atlas.AtlasConstants;
+import org.apache.atlas.server.common.service.EmbeddedServer;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.bridge.SLF4JBridgeHandler;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Iterator;
+
+public class RestNotificationMain {
+ private static final Logger LOG = LoggerFactory.getLogger(RestNotificationMain.class);
+ private static final String APP_PATH = "app";
+ private static final String APP_PORT = "port";
+ private static final String REST_NOTIFICATION_HOME = "atlas.rest.notification.home";
+ private static final String REST_NOTIFICATION_DATA = "atlas.rest.notification.data";
+ private static final String REST_NOTIFICATION_LOG_DIR = "atlas.rest.notification.log.dir";
+ private static final String REST_SERVER_HTTPS_PORT = "atlas.rest.server.https.port";
+ private static final String REST_SERVER_HTTP_PORT = "atlas.rest.server.http.port";
+
+ private static EmbeddedServer server;
+
+ /**
+ * Prevent users from constructing this.
+ */
+ private RestNotificationMain() {
+ }
+
+ protected static CommandLine parseArgs(String[] args) throws ParseException {
+ Options options = new Options();
+ Option opt;
+
+ opt = new Option(APP_PATH, true, "Application Path");
+ opt.setRequired(false);
+ options.addOption(opt);
+
+ opt = new Option(APP_PORT, true, "Application Port");
+ opt.setRequired(false);
+ options.addOption(opt);
+
+ return new DefaultParser().parse(options, args);
+ }
+
+ public static void main(String[] args) throws Exception {
+ CommandLine cmd = parseArgs(args);
+ PropertiesConfiguration buildConfiguration = new PropertiesConfiguration("rest-notification-buildinfo.properties");
+ String appPath = "rest-notification-webapp/target/rest-notification-webapp" /*\\+ getProjectVersion(buildConfiguration)*/;
+
+ if (cmd.hasOption(APP_PATH)) {
+ appPath = cmd.getOptionValue(APP_PATH);
+ }
+
+ setApplicationHome();
+ Configuration configuration = ApplicationProperties.get();
+ final String enableTLSFlag = configuration.getString(SecurityProperties.TLS_ENABLED);
+ final String appHost = configuration.getString(SecurityProperties.BIND_ADDRESS, EmbeddedServer.REST_DEFAULT_BIND_ADDRESS);
+
+ if (!isLocalAddress(InetAddress.getByName(appHost))) {
+ String msg =
+ "Failed to start Rest Notification server. Address " + appHost
+ + " does not belong to this host. Correct configuration parameter: "
+ + SecurityProperties.BIND_ADDRESS;
+ LOG.error(msg);
+ throw new IOException(msg);
+ }
+
+ final int appPort = getApplicationPort(cmd, enableTLSFlag, configuration);
+ System.setProperty(AtlasConstants.SYSTEM_PROPERTY_APP_PORT, String.valueOf(appPort));
+ final boolean enableTLS = isTLSEnabled(enableTLSFlag, appPort);
+ configuration.setProperty(SecurityProperties.TLS_ENABLED, String.valueOf(enableTLS));
+
+ showStartupInfo(buildConfiguration, enableTLS, appPort);
+
+ server = EmbeddedServer.newServer(appHost, appPort, appPath, enableTLS);
+ installLogBridge();
+
+ server.start();
+ }
+
+ public static String getProjectVersion(PropertiesConfiguration buildConfiguration) {
+ return buildConfiguration.getString("project.version");
+ }
+
+ private static void setApplicationHome() {
+ if (System.getProperty(REST_NOTIFICATION_HOME) == null) {
+ System.setProperty(REST_NOTIFICATION_HOME, "target");
+ }
+ if (System.getProperty(REST_NOTIFICATION_DATA) == null) {
+ System.setProperty(REST_NOTIFICATION_DATA, "target/data");
+ }
+ if (System.getProperty(REST_NOTIFICATION_LOG_DIR) == null) {
+ System.setProperty(REST_NOTIFICATION_LOG_DIR, "target/logs");
+ }
+ }
+
+ private static boolean isLocalAddress(InetAddress addr) {
+ // Check if the address is any local or loop back
+ boolean local = addr.isAnyLocalAddress() || addr.isLoopbackAddress();
+
+ // Check if the address is defined on any interface
+ if (!local) {
+ try {
+ local = NetworkInterface.getByInetAddress(addr) != null;
+ } catch (SocketException e) {
+ local = false;
+ }
+ }
+ return local;
+ }
+
+
+ static int getApplicationPort(CommandLine cmd, String enableTLSFlag, Configuration configuration) {
+ String optionValue = cmd.hasOption(APP_PORT) ? cmd.getOptionValue(APP_PORT) : null;
+
+ final int appPort;
+
+ if (StringUtils.isNotEmpty(optionValue)) {
+ appPort = Integer.valueOf(optionValue);
+ } else {
+ // default : atlas.enableTLS is true
+ appPort = getPortValue(configuration, enableTLSFlag);
+ }
+
+ return appPort;
+ }
+
+
+ private static int getPortValue(Configuration configuration, String enableTLSFlag) {
+ int appPort;
+
+ assert configuration != null;
+ appPort = StringUtils.isEmpty(enableTLSFlag) || enableTLSFlag.equals("true") ?
+ configuration.getInt(REST_SERVER_HTTPS_PORT, 41443) :
+ configuration.getInt(REST_SERVER_HTTP_PORT, 41000);
+ return appPort;
+ }
+
+ private static boolean isTLSEnabled(String enableTLSFlag, int appPort) {
+ return Boolean.valueOf(StringUtils.isEmpty(enableTLSFlag) ?
+ System.getProperty(org.apache.atlas.security.SecurityProperties.TLS_ENABLED, (appPort % 1000) == 443 ? "true" : "false") : enableTLSFlag);
+ }
+
+
+ private static void showStartupInfo(PropertiesConfiguration buildConfiguration, boolean enableTLS, int appPort) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("\n############################################");
+ buffer.append("############################################");
+ buffer.append("\n Rest Notification Server (STARTUP)");
+ buffer.append("\n");
+ try {
+ final Iterator
+ * 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.atlas.notification.rest.ha;
+
+import org.apache.atlas.AtlasException;
+import org.apache.atlas.notification.rest.AtlasServerIdSelector;
+import org.apache.atlas.notification.rest.RestHAConfiguration;
+import org.apache.atlas.server.common.service.HighAvailabilityProperties;
+import org.apache.atlas.server.common.service.HighAvailability;
+import org.apache.commons.configuration.Configuration;
+import org.springframework.stereotype.Component;
+
+/**
+ * Rest-Notification specific implementation of HighAvailability.
+ * It adapts RestHAConfiguration (not standard HAConfiguration) into
+ * the common contract.
+ */
+@Component
+public class RestNotificationHighAvailabilityImpl implements HighAvailability {
+ @Override
+ public boolean isHAEnabled(Configuration configuration) {
+ return RestHAConfiguration.isHAEnabled(configuration);
+ }
+
+ @Override
+ public String selectServerId(Configuration configuration) throws AtlasException {
+ return AtlasServerIdSelector.selectServerId(configuration);
+ }
+
+ @Override
+ public String getBoundAddressForId(Configuration configuration, String serverId) {
+ return RestHAConfiguration.getBoundAddressForId(configuration, serverId);
+ }
+
+ @Override
+ public HighAvailabilityProperties getZookeeperProperties(Configuration configuration) {
+ RestHAConfiguration.ZookeeperProperties props = RestHAConfiguration.getZookeeperProperties(configuration);
+
+ return new HighAvailabilityProperties(
+ props.getConnectString(),
+ props.getZkRoot(),
+ props.getRetriesSleepTimeMillis(),
+ props.getNumRetries(),
+ props.getSessionTimeout(),
+ props.getAcl(),
+ props.getAuth());
+ }
+}
diff --git a/rest-notification-webapp/src/main/java/org/apache/atlas/notification/rest/util/CredentialProviderUtility.java b/rest-notification-webapp/src/main/java/org/apache/atlas/notification/rest/util/CredentialProviderUtility.java
new file mode 100755
index 00000000000..d50368cfa59
--- /dev/null
+++ b/rest-notification-webapp/src/main/java/org/apache/atlas/notification/rest/util/CredentialProviderUtility.java
@@ -0,0 +1,227 @@
+/*
+ * 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.atlas.notification.rest.util;
+
+import org.apache.atlas.server.common.dao.UserDao;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.alias.CredentialProvider;
+import org.apache.hadoop.security.alias.CredentialProviderFactory;
+
+import java.io.Console;
+import java.io.IOException;
+import java.util.Arrays;
+
+
+import static org.apache.atlas.notification.rest.SecurityProperties.KEYSTORE_PASSWORD_KEY;
+import static org.apache.atlas.notification.rest.SecurityProperties.SERVER_CERT_PASSWORD_KEY;
+import static org.apache.atlas.notification.rest.SecurityProperties.TRUSTSTORE_PASSWORD_KEY;
+/**
+ * A utility class for generating a credential provider containing the entries required for supporting the SSL
+ * implementation
+ * of the DGC server.
+ */
+public class CredentialProviderUtility {
+ private static final String[] KEYS = new String[] { KEYSTORE_PASSWORD_KEY, TRUSTSTORE_PASSWORD_KEY, SERVER_CERT_PASSWORD_KEY };
+ public static abstract class TextDevice {
+ public abstract void printf(String fmt, Object... params);
+
+ public abstract String readLine(String fmt, Object... args);
+
+ public abstract char[] readPassword(String fmt, Object... args);
+
+ }
+
+ private static TextDevice DEFAULT_TEXT_DEVICE = new TextDevice() {
+ Console console = System.console();
+
+ @Override
+ public void printf(String fmt, Object... params) {
+ console.printf(fmt, params);
+ }
+
+ @Override
+ public String readLine(String fmt, Object... args) {
+ return console.readLine(fmt, args);
+ }
+
+ @Override
+ public char[] readPassword(String fmt, Object... args) {
+ return console.readPassword(fmt, args);
+ }
+ };
+
+ public static TextDevice textDevice = DEFAULT_TEXT_DEVICE;
+
+ public static void main(String[] args) throws IOException {
+ try {
+ CommandLine cmd = new DefaultParser().parse(createOptions(), args);
+ boolean generatePasswordOption = cmd.hasOption("g");
+ String key = cmd.getOptionValue("k");
+ char[] cred = null;
+ String providerPath = cmd.getOptionValue("f");
+
+ if (cmd.hasOption("p")) {
+ cred = cmd.getOptionValue("p").toCharArray();
+ }
+
+ if (generatePasswordOption) {
+ String userName = cmd.getOptionValue("u");
+ String password = cmd.getOptionValue("p");
+ if (userName != null && password != null) {
+ String encryptedPassword = UserDao.encrypt(password);
+ boolean silentOption = cmd.hasOption("s");
+
+ if (silentOption) {
+ System.out.println(encryptedPassword);
+ } else {
+ System.out.println("Your encrypted password is : " + encryptedPassword);
+ }
+ } else {
+ System.out.println("Please provide username and password as input. Usage: cputil.py -g -u
+ * 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.atlas.notification.rest.web.resources;
+
+import org.apache.atlas.ApplicationProperties;
+import org.apache.atlas.AtlasClient;
+import org.apache.atlas.server.common.util.Servlets;
+import org.apache.atlas.server.common.service.ServiceState;
+import org.apache.atlas.utils.AtlasJson;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.stereotype.Service;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Jersey Resource for admin operations.
+ */
+@Path("api/atlas/admin")
+@Singleton
+@Service
+@EnableScheduling
+public class AdminResource {
+ private static final Logger LOG = LoggerFactory.getLogger(AdminResource.class);
+
+
+ private static Configuration atlasProperties;
+ private final ServiceState serviceState;
+
+ static {
+ try {
+ atlasProperties = ApplicationProperties.get();
+ } catch (Exception e) {
+ LOG.info("Failed to load application properties", e);
+ }
+ }
+
+ @Inject
+ public AdminResource(ServiceState serviceState) {
+ this.serviceState = serviceState;
+ }
+
+ /**
+ * Fetches the thread stack dump for this application.
+ *
+ * @return json representing the thread stack dump.
+ */
+ @GET
+ @Path("stack")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getThreadDump() {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> AdminResource.getThreadDump()");
+ }
+
+ ThreadGroup topThreadGroup = Thread.currentThread().getThreadGroup();
+
+ while (topThreadGroup.getParent() != null) {
+ topThreadGroup = topThreadGroup.getParent();
+ }
+ Thread[] threads = new Thread[topThreadGroup.activeCount()];
+
+ int nr = topThreadGroup.enumerate(threads);
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < nr; i++) {
+ builder.append(threads[i].getName()).append("\nState: ").
+ append(threads[i].getState()).append("\n");
+ String stackTrace = StringUtils.join(threads[i].getStackTrace(), "\n");
+ builder.append(stackTrace);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== AdminResource.getThreadDump()");
+ }
+
+ return builder.toString();
+ }
+
+
+ @GET
+ @Path("status")
+ @Produces(Servlets.JSON_MEDIA_TYPE)
+ public Response getStatus() {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> AdminResource.getStatus()");
+ }
+
+ Map
+ * 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.atlas.notification.rest.web.security;
+
+import org.apache.atlas.server.common.security.AtlasAuthenticationFailureHandler;
+import org.apache.atlas.server.common.security.AtlasAuthenticationProvider;
+import org.apache.atlas.server.common.security.AtlasAuthenticationSuccessHandler;
+import org.apache.commons.configuration.Configuration;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+
+import javax.inject.Inject;
+
+/**
+ * Spring Security configuration for the Atlas rest-notification-webapp.
+ *
+ * Why this class was created
+ * Before this commit, {@code server-common/AtlasSecurityConfig} was a concrete
+ * {@code @EnableWebSecurity} class. It also injected
+ * {@code @Qualifier("staleTransactionCleanupFilter")} — a bean that only exists
+ * in the webapp Spring context. When rest-notification-webapp started, Spring
+ * threw {@code NoSuchBeanDefinitionException} because no such bean was registered,
+ * preventing the Kerberos authentication filter chain from initializing.
+ *
+ * This class was created to be the SINGLE {@code @EnableWebSecurity} authority
+ * for rest-notification-webapp — completely separate from webapp's security config.
+ *
+ * What is intentionally ABSENT here (compared to webapp)
+ * NO {@code staleTransactionCleanupFilter} — rest-notification makes no direct
+ * JanusGraph writes and has no such bean in its context
+ * NO form login ({@code addWebUiFormLogin}) — rest-notification is a headless
+ * REST server with no browser UI, login page, or interactive sessions.
+ */
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class AtlasSecurityConfig extends org.apache.atlas.server.common.security.AtlasSecurityConfig {
+ @Inject
+ public AtlasSecurityConfig(ObjectProvider
- * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
+ * 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.
@@ -12,7 +12,7 @@
* limitations under the License. See accompanying LICENSE file.
*/
-package org.apache.atlas.web.filters;
+package org.apache.atlas.server.common.filters;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
@@ -20,217 +20,309 @@
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode;
import javax.servlet.descriptor.JspConfigDescriptor;
-
import java.io.InputStream;
+import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.Map;
import java.util.Set;
+
/**
*/
public class NullServletContext implements ServletContext {
- public String getContextPath() {
- return null;
+
+
+
+ public void setSessionTrackingModes(
+ Set
+ * 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.atlas.server.common.filters.spi;
+
+public interface ActiveInstanceStateProvider {
+ String getActiveServerAddress();
+}
diff --git a/server-common/src/main/java/org/apache/atlas/server/common/filters/spi/AtlasAuthenticationProviderBridge.java b/server-common/src/main/java/org/apache/atlas/server/common/filters/spi/AtlasAuthenticationProviderBridge.java
new file mode 100644
index 00000000000..6ef3361cbfd
--- /dev/null
+++ b/server-common/src/main/java/org/apache/atlas/server/common/filters/spi/AtlasAuthenticationProviderBridge.java
@@ -0,0 +1,34 @@
+/**
+ * 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.atlas.server.common.filters.spi;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+
+import java.util.List;
+
+public interface AtlasAuthenticationProviderBridge {
+ List
+ * 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.atlas.server.common.filters.spi;
+
+public interface ServiceStateProvider {
+ boolean isActive();
+
+ boolean isInstanceInTransition();
+
+ boolean isInstanceInMigration();
+
+ String getStateName();
+}
diff --git a/webapp/src/main/java/org/apache/atlas/web/listeners/LoginProcessor.java b/server-common/src/main/java/org/apache/atlas/server/common/listeners/LoginProcessor.java
similarity index 99%
rename from webapp/src/main/java/org/apache/atlas/web/listeners/LoginProcessor.java
rename to server-common/src/main/java/org/apache/atlas/server/common/listeners/LoginProcessor.java
index e8a198e3399..066da4329f2 100644
--- a/webapp/src/main/java/org/apache/atlas/web/listeners/LoginProcessor.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/listeners/LoginProcessor.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.atlas.web.listeners;
+package org.apache.atlas.server.common.listeners;
import org.apache.atlas.ApplicationProperties;
import org.apache.atlas.AtlasException;
diff --git a/webapp/src/main/java/org/apache/atlas/web/model/User.java b/server-common/src/main/java/org/apache/atlas/server/common/model/User.java
similarity index 98%
rename from webapp/src/main/java/org/apache/atlas/web/model/User.java
rename to server-common/src/main/java/org/apache/atlas/server/common/model/User.java
index c7bbdceb00a..be664b62e1f 100644
--- a/webapp/src/main/java/org/apache/atlas/web/model/User.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/model/User.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.atlas.web.model;
+package org.apache.atlas.server.common.model;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasADAuthenticationProvider.java b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasADAuthenticationProvider.java
similarity index 98%
rename from webapp/src/main/java/org/apache/atlas/web/security/AtlasADAuthenticationProvider.java
rename to server-common/src/main/java/org/apache/atlas/server/common/security/AtlasADAuthenticationProvider.java
index 59329a0643d..3c57b8dd73d 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasADAuthenticationProvider.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasADAuthenticationProvider.java
@@ -16,10 +16,10 @@
* limitations under the License.
*/
-package org.apache.atlas.web.security;
+package org.apache.atlas.server.common.security;
import org.apache.atlas.ApplicationProperties;
-import org.apache.atlas.web.model.User;
+import org.apache.atlas.server.common.model.User;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationConverter;
import org.slf4j.Logger;
@@ -41,6 +41,8 @@
import java.util.List;
import java.util.Properties;
+import org.apache.atlas.server.common.security.AtlasAuthenticationException;
+
@Component
public class AtlasADAuthenticationProvider extends AtlasAbstractAuthenticationProvider {
private static final Logger LOG = LoggerFactory.getLogger(AtlasADAuthenticationProvider.class);
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAbstractAuthenticationProvider.java b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAbstractAuthenticationProvider.java
similarity index 98%
rename from webapp/src/main/java/org/apache/atlas/web/security/AtlasAbstractAuthenticationProvider.java
rename to server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAbstractAuthenticationProvider.java
index cc2d1587c1b..7c3014d4e49 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAbstractAuthenticationProvider.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAbstractAuthenticationProvider.java
@@ -17,8 +17,9 @@
* under the License.
*/
-package org.apache.atlas.web.security;
+package org.apache.atlas.server.common.security;
+import org.apache.atlas.server.common.model.User;
import org.apache.atlas.utils.AuthenticationUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.hadoop.conf.Configuration;
@@ -31,7 +32,6 @@
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationException.java b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAuthenticationException.java
similarity index 95%
rename from webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationException.java
rename to server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAuthenticationException.java
index cda9fad6229..34be0fb46fa 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationException.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAuthenticationException.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.atlas.web.security;
+package org.apache.atlas.server.common.security;
import org.springframework.security.core.AuthenticationException;
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationFailureHandler.java b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAuthenticationFailureHandler.java
similarity index 93%
rename from webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationFailureHandler.java
rename to server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAuthenticationFailureHandler.java
index 514ccbc4db4..452b254869a 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationFailureHandler.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAuthenticationFailureHandler.java
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-package org.apache.atlas.web.security;
+package org.apache.atlas.server.common.security;
import org.json.simple.JSONObject;
import org.slf4j.Logger;
@@ -25,6 +25,7 @@
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
+import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -35,7 +36,7 @@ public class AtlasAuthenticationFailureHandler implements AuthenticationFailureH
private static final Logger LOG = LoggerFactory.getLogger(AtlasAuthenticationFailureHandler.class);
@Override
- public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse response, AuthenticationException e) throws IOException {
+ public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
LOG.debug("Login Failure ", e);
JSONObject json = new JSONObject();
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationProvider.java b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAuthenticationProvider.java
similarity index 81%
rename from webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationProvider.java
rename to server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAuthenticationProvider.java
index 3cff9fb8eeb..f78be18192f 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationProvider.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAuthenticationProvider.java
@@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.atlas.web.security;
+package org.apache.atlas.server.common.security;
import org.apache.atlas.ApplicationProperties;
import org.apache.commons.configuration.Configuration;
@@ -32,48 +32,56 @@
@Component
@Scope("prototype")
public class AtlasAuthenticationProvider extends AtlasAbstractAuthenticationProvider {
- private static final Logger LOG = LoggerFactory.getLogger(AtlasAuthenticationProvider.class);
+ private static final Logger LOG = LoggerFactory
+ .getLogger(AtlasAuthenticationProvider.class);
- public static final String FILE_AUTH_METHOD = "atlas.authentication.method.file";
- public static final String LDAP_AUTH_METHOD = "atlas.authentication.method.ldap";
- public static final String LDAP_TYPE = "atlas.authentication.method.ldap.type";
- public static final String PAM_AUTH_METHOD = "atlas.authentication.method.pam";
+ private boolean fileAuthenticationMethodEnabled = true;
+ private boolean pamAuthenticationEnabled = false;
+ private boolean keycloakAuthenticationEnabled;
+ private String ldapType = "NONE";
+ public static final String FILE_AUTH_METHOD = "atlas.authentication.method.file";
+ public static final String LDAP_AUTH_METHOD = "atlas.authentication.method.ldap";
+ public static final String LDAP_TYPE = "atlas.authentication.method.ldap.type";
+ public static final String PAM_AUTH_METHOD = "atlas.authentication.method.pam";
public static final String KEYCLOAK_AUTH_METHOD = "atlas.authentication.method.keycloak";
+ private boolean ssoEnabled;
+
final AtlasLdapAuthenticationProvider ldapAuthenticationProvider;
+
final AtlasFileAuthenticationProvider fileAuthenticationProvider;
+
final AtlasADAuthenticationProvider adAuthenticationProvider;
+
final AtlasPamAuthenticationProvider pamAuthenticationProvider;
- final AtlasKeycloakAuthenticationProvider atlasKeycloakAuthenticationProvider;
- private boolean fileAuthenticationMethodEnabled = true;
- private boolean pamAuthenticationEnabled;
- private boolean keycloakAuthenticationEnabled;
- private String ldapType = "NONE";
- private boolean ssoEnabled;
+ final AtlasKeycloakAuthenticationProvider atlasKeycloakAuthenticationProvider;
@Inject
public AtlasAuthenticationProvider(AtlasLdapAuthenticationProvider ldapAuthenticationProvider,
- AtlasFileAuthenticationProvider fileAuthenticationProvider, AtlasADAuthenticationProvider adAuthenticationProvider,
- AtlasPamAuthenticationProvider pamAuthenticationProvider, AtlasKeycloakAuthenticationProvider atlasKeycloakAuthenticationProvider) {
- this.ldapAuthenticationProvider = ldapAuthenticationProvider;
- this.fileAuthenticationProvider = fileAuthenticationProvider;
- this.adAuthenticationProvider = adAuthenticationProvider;
- this.pamAuthenticationProvider = pamAuthenticationProvider;
+ AtlasFileAuthenticationProvider fileAuthenticationProvider,
+ AtlasADAuthenticationProvider adAuthenticationProvider,
+ AtlasPamAuthenticationProvider pamAuthenticationProvider, AtlasKeycloakAuthenticationProvider atlasKeycloakAuthenticationProvider) {
+ this.ldapAuthenticationProvider = ldapAuthenticationProvider;
+ this.fileAuthenticationProvider = fileAuthenticationProvider;
+ this.adAuthenticationProvider = adAuthenticationProvider;
+ this.pamAuthenticationProvider = pamAuthenticationProvider;
this.atlasKeycloakAuthenticationProvider = atlasKeycloakAuthenticationProvider;
}
@Override
- public Authentication authenticate(Authentication authentication) throws AuthenticationException {
- if (ssoEnabled) {
- if (authentication != null) {
- authentication = getSSOAuthentication(authentication);
+ public Authentication authenticate(Authentication authentication)
+ throws AuthenticationException {
- if (authentication != null && authentication.isAuthenticated()) {
+ if(ssoEnabled){
+ if (authentication != null){
+ authentication = getSSOAuthentication(authentication);
+ if(authentication!=null && authentication.isAuthenticated()){
return authentication;
}
}
} else {
+
if (ldapType.equalsIgnoreCase("LDAP")) {
try {
authentication = ldapAuthenticationProvider.authenticate(authentication);
@@ -114,7 +122,6 @@ public Authentication authenticate(Authentication authentication) throws Authent
}
LOG.error("Authentication failed.");
-
throw new AtlasAuthenticationException("Authentication failed.");
}
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAuthenticationSuccessHandler.java
similarity index 94%
rename from webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
rename to server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAuthenticationSuccessHandler.java
index 5d6834fd199..755f0ddb4f3 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasAuthenticationSuccessHandler.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasAuthenticationSuccessHandler.java
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-package org.apache.atlas.web.security;
+package org.apache.atlas.server.common.security;
import org.apache.atlas.AtlasConfiguration;
import org.json.simple.JSONObject;
@@ -34,7 +34,7 @@
@Component
public class AtlasAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
- private static final Logger LOG = LoggerFactory.getLogger(AtlasAuthenticationSuccessHandler.class);
+ private static Logger LOG = LoggerFactory.getLogger(AuthenticationSuccessHandler.class);
public static final String LOCALLOGIN = "locallogin";
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasFileAuthenticationProvider.java b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasFileAuthenticationProvider.java
similarity index 96%
rename from webapp/src/main/java/org/apache/atlas/web/security/AtlasFileAuthenticationProvider.java
rename to server-common/src/main/java/org/apache/atlas/server/common/security/AtlasFileAuthenticationProvider.java
index 096ca26d837..bda282009a8 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasFileAuthenticationProvider.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasFileAuthenticationProvider.java
@@ -14,9 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.atlas.web.security;
+package org.apache.atlas.server.common.security;
-import org.apache.atlas.web.dao.UserDao;
+import org.apache.atlas.server.common.dao.UserDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.BadCredentialsException;
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasKeycloakAuthenticationProvider.java b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasKeycloakAuthenticationProvider.java
similarity index 94%
rename from webapp/src/main/java/org/apache/atlas/web/security/AtlasKeycloakAuthenticationProvider.java
rename to server-common/src/main/java/org/apache/atlas/server/common/security/AtlasKeycloakAuthenticationProvider.java
index 9839a219515..78893a0981e 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasKeycloakAuthenticationProvider.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasKeycloakAuthenticationProvider.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.atlas.web.security;
+package org.apache.atlas.server.common.security;
import org.apache.atlas.ApplicationProperties;
import org.apache.commons.configuration.Configuration;
@@ -30,7 +30,7 @@
import java.util.Map;
@Component
-public class AtlasKeycloakAuthenticationProvider extends AtlasAbstractAuthenticationProvider {
+public class AtlasKeycloakAuthenticationProvider extends org.apache.atlas.server.common.security.AtlasAbstractAuthenticationProvider {
private final boolean groupsFromUGI;
private final String groupsClaim;
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasLdapAuthenticationProvider.java b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasLdapAuthenticationProvider.java
similarity index 98%
rename from webapp/src/main/java/org/apache/atlas/web/security/AtlasLdapAuthenticationProvider.java
rename to server-common/src/main/java/org/apache/atlas/server/common/security/AtlasLdapAuthenticationProvider.java
index c401576006d..057f764fedf 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasLdapAuthenticationProvider.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasLdapAuthenticationProvider.java
@@ -16,10 +16,10 @@
* limitations under the License.
*/
-package org.apache.atlas.web.security;
+package org.apache.atlas.server.common.security;
import org.apache.atlas.ApplicationProperties;
-import org.apache.atlas.web.model.User;
+import org.apache.atlas.server.common.model.User;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationConverter;
import org.apache.commons.lang3.StringUtils;
@@ -43,6 +43,8 @@
import java.util.List;
import java.util.Properties;
+import org.apache.atlas.server.common.security.AtlasAuthenticationException;
+
@Component
public class AtlasLdapAuthenticationProvider extends AtlasAbstractAuthenticationProvider {
private static final Logger LOG = LoggerFactory.getLogger(AtlasLdapAuthenticationProvider.class);
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasPamAuthenticationProvider.java b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasPamAuthenticationProvider.java
similarity index 95%
rename from webapp/src/main/java/org/apache/atlas/web/security/AtlasPamAuthenticationProvider.java
rename to server-common/src/main/java/org/apache/atlas/server/common/security/AtlasPamAuthenticationProvider.java
index 49970129c3c..fac38d30cc9 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasPamAuthenticationProvider.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/security/AtlasPamAuthenticationProvider.java
@@ -17,10 +17,10 @@
* under the License.
*/
-package org.apache.atlas.web.security;
+package org.apache.atlas.server.common.security;
import org.apache.atlas.ApplicationProperties;
-import org.apache.atlas.web.model.User;
+import org.apache.atlas.server.common.model.User;
import org.apache.commons.configuration.ConfigurationConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -42,11 +42,14 @@
import java.util.Map;
import java.util.Properties;
+import org.apache.atlas.server.common.security.AtlasAuthenticationException;
+import org.apache.atlas.server.common.security.UserAuthorityGranter;
+
@Component
public class AtlasPamAuthenticationProvider extends AtlasAbstractAuthenticationProvider {
private static final Logger LOG = LoggerFactory.getLogger(AtlasPamAuthenticationProvider.class);
- private static final String loginModuleName = "org.apache.atlas.web.security.PamLoginModule";
+ private static final String loginModuleName = "org.apache.atlas.server.common.security.PamLoginModule";
private static final AppConfigurationEntry.LoginModuleControlFlag controlFlag = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
private final Map
+ * 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.atlas.server.common.security;
+
+import org.apache.atlas.server.common.filters.ActiveServerFilter;
+import org.apache.atlas.server.common.filters.AtlasAuthenticationFilter;
+import org.apache.atlas.server.common.filters.AtlasAuthenticationEntryPoint;
+import org.apache.atlas.server.common.filters.AtlasCSRFPreventionFilter;
+import org.apache.atlas.server.common.filters.AtlasDelegatingAuthenticationEntryPoint;
+import org.apache.atlas.server.common.filters.AtlasKnoxSSOAuthenticationFilter;
+import org.apache.atlas.server.common.filters.HeadersUtil;
+import org.apache.atlas.server.common.filters.spi.ActiveInstanceStateProvider;
+import org.apache.atlas.server.common.filters.spi.AtlasAuthenticationProviderBridge;
+import org.apache.atlas.server.common.filters.spi.ServiceStateProvider;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
+import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
+import org.springframework.security.web.header.writers.StaticHeadersWriter;
+import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
+import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+
+import javax.inject.Inject;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+import static org.apache.atlas.AtlasConstants.ATLAS_MIGRATION_MODE_FILENAME;
+
+/**
+ * Abstract base class for Atlas Spring Security configuration, shared between
+ * {@code webapp} and {@code rest-notification-webapp}.
+ *
+ * Why this class is abstract
+ * This class was previously a concrete {@code @EnableWebSecurity} class.
+ * Having {@code @EnableWebSecurity} on a class in {@code server-common} caused
+ * Spring to find TWO competing security configurations on the classpath when
+ * either webapp started — this concrete base class AND the module-specific
+ * subclass (if it existed) — causing a bean registration conflict that prevented
+ * the Kerberos filter chain from assembling correctly.
+ *
+ * Making this class {@code abstract} ensures Spring Security NEVER tries to
+ * instantiate it directly. Only the concrete subclasses in each module carry
+ * the {@code @EnableWebSecurity} annotation and are registered as the security
+ * configuration bean.
+ */
+public abstract class AtlasSecurityConfig extends WebSecurityConfigurerAdapter {
+ private static final Logger LOG = LoggerFactory.getLogger(AtlasSecurityConfig.class);
+
+ protected final AtlasAuthenticationProvider authenticationProvider;
+ protected final AtlasAuthenticationSuccessHandler successHandler;
+ protected final AtlasAuthenticationFailureHandler failureHandler;
+ protected final ObjectProvider
* The service implements leader election through Curator's
* {@link LeaderLatch} recipe. The service also implements {@link LeaderLatchListener} to get
* notified of changes to leadership state. Upon becoming leader, this instance is treated as the
@@ -49,7 +47,6 @@
* on being removed from leadership, this instance is treated as a passive instance and calls
* {@link ActiveStateChangeHandler}s to deactivate them.
*/
-
@Component
//
// This should be called the last, leaving it without the @Order(Integer.MAX_VALUE) will make it get
@@ -60,7 +57,8 @@ public class ActiveInstanceElectorService implements Service, LeaderLatchListene
private final Configuration configuration;
private final ServiceState serviceState;
private final ActiveInstanceState activeInstanceState;
- private final AtlasMetricsUtil metricsUtil;
+ private final HighAvailability highAvailability;
+ private final Set
* If Atlas High Availability configuration is disabled, this operation is a no-op.
+ *
* @throws AtlasException
*/
@Override
public void start() throws AtlasException {
- metricsUtil.onServerStart();
+ boolean haEnabled = highAvailability.isHAEnabled(configuration);
- if (!HAConfiguration.isHAEnabled(configuration)) {
- metricsUtil.onServerActivation();
+ serviceStateChangeHandlers.forEach(hook -> {
+ hook.onServerStart();
+ if (!haEnabled) {
+ hook.onServerActivation();
+ }
+ });
+ if (!haEnabled) {
LOG.info("HA is not enabled, no need to start leader election service");
-
return;
}
cacheActiveStateChangeHandlers();
-
- serverId = AtlasServerIdSelector.selectServerId(configuration);
-
+ serverId = highAvailability.selectServerId(configuration);
joinElection();
}
/**
* Leave leader election process and clean up resources on shutting down.
- *
+ *
* If Atlas High Availability configuration is disabled, this operation is a no-op.
*/
@Override
public void stop() {
- if (!HAConfiguration.isHAEnabled(configuration)) {
+ if (!highAvailability.isHAEnabled(configuration)) {
LOG.info("HA is not enabled, no need to stop leader election service");
-
return;
}
@@ -133,29 +141,29 @@ public void stop() {
/**
* Call all registered {@link ActiveStateChangeHandler}s on being elected active.
- *
+ *
* In addition, shared state information about this instance becoming active is updated
* using {@link ActiveInstanceState}.
*/
@Override
public void isLeader() {
LOG.warn("Server instance with server id {} is elected as leader", serverId);
-
serviceState.becomingActive();
-
try {
for (ActiveStateChangeHandler handler : activeStateChangeHandlers) {
handler.instanceIsActive();
}
-
activeInstanceState.update(serverId);
serviceState.setActive();
- metricsUtil.onServerActivation();
+ for (ServiceStateChangeHandler serviceStateChangeHandler : serviceStateChangeHandlers) {
+ serviceStateChangeHandler.onServerActivation();
+ }
} catch (Exception e) {
LOG.error("Got exception while activating", e);
-
notLeader();
rejoinElection();
+ } finally {
+ RequestContext.clear();
}
}
@@ -165,9 +173,7 @@ public void isLeader() {
@Override
public void notLeader() {
LOG.warn("Server instance with server id {} is removed as leader", serverId);
-
serviceState.becomingPassive();
-
for (int idx = activeStateChangeHandlers.size() - 1; idx >= 0; idx--) {
try {
activeStateChangeHandlers.get(idx).instanceIsPassive();
@@ -175,22 +181,17 @@ public void notLeader() {
LOG.error("Error while reacting to passive state.", e);
}
}
-
serviceState.setPassive();
}
private void joinElection() {
LOG.info("Starting leader election for {}", serverId);
- String zkRoot = HAConfiguration.getZookeeperProperties(configuration).getZkRoot();
-
+ String zkRoot = highAvailability.getZookeeperProperties(configuration).getZkRoot();
leaderLatch = curatorFactory.leaderLatchInstance(serverId, zkRoot);
-
leaderLatch.addListener(this);
-
try {
leaderLatch.start();
-
LOG.info("Leader latch started for {}.", serverId);
} catch (Exception e) {
LOG.info("Exception while starting leader latch for {}.", serverId, e);
@@ -212,7 +213,6 @@ private void cacheActiveStateChangeHandlers() {
private void rejoinElection() {
try {
leaderLatch.close();
-
joinElection();
} catch (IOException e) {
LOG.error("Error rejoining election", e);
diff --git a/webapp/src/main/java/org/apache/atlas/web/service/ActiveInstanceState.java b/server-common/src/main/java/org/apache/atlas/server/common/service/ActiveInstanceState.java
similarity index 75%
rename from webapp/src/main/java/org/apache/atlas/web/service/ActiveInstanceState.java
rename to server-common/src/main/java/org/apache/atlas/server/common/service/ActiveInstanceState.java
index 8e79dbe6488..e0d7e6849d5 100644
--- a/webapp/src/main/java/org/apache/atlas/web/service/ActiveInstanceState.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/service/ActiveInstanceState.java
@@ -15,14 +15,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.atlas.server.common.service;
-package org.apache.atlas.web.service;
-
-import org.apache.atlas.ApplicationProperties;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.AtlasException;
import org.apache.atlas.exception.AtlasBaseException;
-import org.apache.atlas.ha.HAConfiguration;
+import org.apache.atlas.server.common.filters.spi.ActiveInstanceStateProvider;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;
@@ -50,13 +48,14 @@
* provide for safety across multiple processes.
*/
@Component
-public class ActiveInstanceState {
+public class ActiveInstanceState implements ActiveInstanceStateProvider {
private static final Logger LOG = LoggerFactory.getLogger(ActiveInstanceState.class);
public static final String APACHE_ATLAS_ACTIVE_SERVER_INFO = "/active_server_info";
private final Configuration configuration;
private final CuratorFactory curatorFactory;
+ private final HighAvailability highAvailability;
/**
* Create a new instance of {@link ActiveInstanceState}.
@@ -64,18 +63,10 @@ public class ActiveInstanceState {
* @throws AtlasException
*/
@Inject
- public ActiveInstanceState(CuratorFactory curatorFactory) throws AtlasException {
- this(ApplicationProperties.get(), curatorFactory);
- }
-
- /**
- * Create a new instance of {@link ActiveInstanceState}.
- * @param configuration an instance of {@link Configuration} created from Atlas configuration
- * @param curatorFactory an instance of {@link CuratorFactory} to get the {@link InterProcessReadWriteLock}
- */
- public ActiveInstanceState(Configuration configuration, CuratorFactory curatorFactory) {
- this.configuration = configuration;
- this.curatorFactory = curatorFactory;
+ public ActiveInstanceState(Configuration configuration, CuratorFactory curatorFactory, HighAvailability highAvailability) {
+ this.configuration = configuration;
+ this.curatorFactory = curatorFactory;
+ this.highAvailability = highAvailability;
}
/**
@@ -87,12 +78,16 @@ public ActiveInstanceState(Configuration configuration, CuratorFactory curatorFa
* @param serverId ID of this server instance
*/
public void update(String serverId) throws AtlasBaseException {
+ if (!highAvailability.isHAEnabled(configuration)) {
+ return;
+ }
+
try {
- CuratorFramework client = curatorFactory.clientInstance();
+ CuratorFramework client = curatorFactory.clientInstance();
- HAConfiguration.ZookeeperProperties zookeeperProperties = HAConfiguration.getZookeeperProperties(configuration);
+ HighAvailabilityProperties zookeeperProperties = highAvailability.getZookeeperProperties(configuration);
- String atlasServerAddress = HAConfiguration.getBoundAddressForId(configuration, serverId);
+ String atlasServerAddress = highAvailability.getBoundAddressForId(configuration, serverId);
List
+ * 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.atlas.server.common.service;
+
+import org.apache.atlas.AtlasException;
+import org.apache.commons.configuration.Configuration;
+
+/**
+ * Interface to abstract High Availability (HA) configuration retrieval.
+ * Enables shared services in 'server-common' to operate without direct
+ * dependencies on application-specific configuration classes.
+ */
+public interface HighAvailability {
+
+ /**
+ * Determines if HA mode is active based on the provided configuration.
+ */
+ boolean isHAEnabled(Configuration configuration);
+
+ /**
+ * Resolves the unique ID for the current server instance.
+ * @throws AtlasException if the server ID cannot be resolved.
+ */
+ String selectServerId(Configuration configuration) throws AtlasException;
+
+ /**
+ * Retrieves the network address bound to a specific server ID.
+ */
+ String getBoundAddressForId(Configuration configuration, String serverId);
+
+ /**
+ * Extracts ZooKeeper connection and properties required.
+ */
+ HighAvailabilityProperties getZookeeperProperties(Configuration configuration);
+}
diff --git a/server-common/src/main/java/org/apache/atlas/server/common/service/HighAvailabilityProperties.java b/server-common/src/main/java/org/apache/atlas/server/common/service/HighAvailabilityProperties.java
new file mode 100644
index 00000000000..f6caf4f85a3
--- /dev/null
+++ b/server-common/src/main/java/org/apache/atlas/server/common/service/HighAvailabilityProperties.java
@@ -0,0 +1,79 @@
+/**
+ * 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.atlas.server.common.service;
+
+/**
+ * ZooKeeper and HA connection parameters in a form shared code can use without importing
+ * webapp-specific or rest-notification-specific configuration classes.
+ */
+public class HighAvailabilityProperties {
+ private final String connectString;
+ private final String zkRoot;
+ private final int retriesSleepTimeMillis;
+ private final int numRetries;
+ private final int sessionTimeout;
+ private final String acl;
+ private final String auth;
+
+ public HighAvailabilityProperties(String connectString, String zkRoot, int retriesSleepTimeMillis, int numRetries,
+ int sessionTimeout, String acl, String auth) {
+ this.connectString = connectString;
+ this.zkRoot = zkRoot;
+ this.retriesSleepTimeMillis = retriesSleepTimeMillis;
+ this.numRetries = numRetries;
+ this.sessionTimeout = sessionTimeout;
+ this.acl = acl;
+ this.auth = auth;
+ }
+
+ public String getConnectString() {
+ return connectString;
+ }
+
+ public String getZkRoot() {
+ return zkRoot;
+ }
+
+ public int getRetriesSleepTimeMillis() {
+ return retriesSleepTimeMillis;
+ }
+
+ public int getNumRetries() {
+ return numRetries;
+ }
+
+ public int getSessionTimeout() {
+ return sessionTimeout;
+ }
+
+ public String getAcl() {
+ return acl;
+ }
+
+ public String getAuth() {
+ return auth;
+ }
+
+ public boolean hasAcl() {
+ return acl != null;
+ }
+
+ public boolean hasAuth() {
+ return auth != null;
+ }
+}
diff --git a/webapp/src/main/java/org/apache/atlas/web/service/SecureEmbeddedServer.java b/server-common/src/main/java/org/apache/atlas/server/common/service/SecureEmbeddedServer.java
old mode 100755
new mode 100644
similarity index 99%
rename from webapp/src/main/java/org/apache/atlas/web/service/SecureEmbeddedServer.java
rename to server-common/src/main/java/org/apache/atlas/server/common/service/SecureEmbeddedServer.java
index c898861d57a..ac81bcf8cad
--- a/webapp/src/main/java/org/apache/atlas/web/service/SecureEmbeddedServer.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/service/SecureEmbeddedServer.java
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-package org.apache.atlas.web.service;
+package org.apache.atlas.server.common.service;
import org.apache.atlas.ApplicationProperties;
import org.apache.atlas.AtlasConfiguration;
diff --git a/webapp/src/main/java/org/apache/atlas/web/service/ServiceState.java b/server-common/src/main/java/org/apache/atlas/server/common/service/ServiceState.java
similarity index 57%
rename from webapp/src/main/java/org/apache/atlas/web/service/ServiceState.java
rename to server-common/src/main/java/org/apache/atlas/server/common/service/ServiceState.java
index b2e7dd705a1..6ccc1b10f0b 100644
--- a/webapp/src/main/java/org/apache/atlas/web/service/ServiceState.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/service/ServiceState.java
@@ -6,9 +6,9 @@
* 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
- *
+ *
+ * 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.
@@ -16,26 +16,18 @@
* limitations under the License.
*/
-package org.apache.atlas.web.service;
+package org.apache.atlas.server.common.service;
-import org.apache.atlas.ApplicationProperties;
-import org.apache.atlas.AtlasException;
-import org.apache.atlas.RequestContext;
-import org.apache.atlas.exception.AtlasBaseException;
-import org.apache.atlas.ha.HAConfiguration;
-import org.apache.atlas.model.audit.AtlasAuditEntry;
-import org.apache.atlas.repository.audit.AtlasAuditService;
+import org.apache.atlas.server.common.filters.spi.ServiceStateProvider;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
+import javax.inject.Inject;
import javax.inject.Singleton;
-import java.util.Date;
-
import static com.google.common.base.Preconditions.checkState;
import static org.apache.atlas.AtlasConstants.ATLAS_MIGRATION_MODE_FILENAME;
@@ -47,26 +39,29 @@
*/
@Singleton
@Component
-public class ServiceState {
+public class ServiceState implements ServiceStateProvider {
private static final Logger LOG = LoggerFactory.getLogger(ServiceState.class);
- @Autowired
- AtlasAuditService auditService;
-
- private final Configuration configuration;
+ public enum ServiceStateValue {
+ ACTIVE,
+ PASSIVE,
+ BECOMING_ACTIVE,
+ BECOMING_PASSIVE,
+ MIGRATING
+ }
+ private Configuration configuration;
private volatile ServiceStateValue state;
+ private final HighAvailability highAvailability;
- public ServiceState() throws AtlasException {
- this(ApplicationProperties.get());
- }
-
- public ServiceState(Configuration configuration) {
- this.configuration = configuration;
+ @Inject
+ public ServiceState(Configuration configuration, HighAvailability highAvailability) {
+ this.configuration = configuration;
+ this.highAvailability = highAvailability;
- state = !HAConfiguration.isHAEnabled(configuration) ? ServiceStateValue.ACTIVE : ServiceStateValue.PASSIVE;
+ state = !highAvailability.isHAEnabled(configuration) ? ServiceStateValue.ACTIVE : ServiceStateValue.PASSIVE;
- if (!StringUtils.isEmpty(configuration.getString(ATLAS_MIGRATION_MODE_FILENAME, ""))) {
+ if(!StringUtils.isEmpty(configuration.getString(ATLAS_MIGRATION_MODE_FILENAME, ""))) {
state = ServiceStateValue.MIGRATING;
}
}
@@ -75,75 +70,57 @@ public ServiceStateValue getState() {
return state;
}
- private void setState(ServiceStateValue newState) {
- checkState(HAConfiguration.isHAEnabled(configuration), "Cannot change state as requested, as HA is not enabled for this instance.");
-
- state = newState;
-
- auditServerStatus();
- }
-
public void becomingActive() {
LOG.warn("Instance becoming active from {}", state);
-
setState(ServiceStateValue.BECOMING_ACTIVE);
}
public void setActive() {
LOG.warn("Instance is active from {}", state);
-
setState(ServiceStateValue.ACTIVE);
}
public void becomingPassive() {
LOG.warn("Instance becoming passive from {}", state);
-
setState(ServiceStateValue.BECOMING_PASSIVE);
}
public void setPassive() {
LOG.warn("Instance is passive from {}", state);
-
setState(ServiceStateValue.PASSIVE);
}
+ @Override
public boolean isInstanceInTransition() {
ServiceStateValue state = getState();
-
- return state == ServiceStateValue.BECOMING_ACTIVE || state == ServiceStateValue.BECOMING_PASSIVE;
+ return state == ServiceStateValue.BECOMING_ACTIVE
+ || state == ServiceStateValue.BECOMING_PASSIVE;
}
public void setMigration() {
LOG.warn("Instance in {}", state);
-
setState(ServiceStateValue.MIGRATING);
}
+ @Override
public boolean isInstanceInMigration() {
return getState() == ServiceStateValue.MIGRATING;
}
- private void auditServerStatus() {
- if (state == ServiceState.ServiceStateValue.ACTIVE) {
- Date date = new Date();
-
- try {
- auditService.add(AtlasAuditEntry.AuditOperation.SERVER_START, EmbeddedServer.SERVER_START_TIME, date, null, null, 0);
- auditService.add(AtlasAuditEntry.AuditOperation.SERVER_STATE_ACTIVE, date, date, null, null, 0);
- } catch (AtlasBaseException e) {
- LOG.error("Exception occurred during audit", e);
- } finally {
- // In HA environment, after the server related audits are added, the request created are now cleared.
- RequestContext.clear();
- }
- }
+ @Override
+ public boolean isActive() {
+ return getState() == ServiceStateValue.ACTIVE;
}
- public enum ServiceStateValue {
- ACTIVE,
- PASSIVE,
- BECOMING_ACTIVE,
- BECOMING_PASSIVE,
- MIGRATING
+ @Override
+ public String getStateName() {
+ return getState().toString();
+ }
+
+ private void setState(ServiceStateValue newState) {
+ checkState(highAvailability.isHAEnabled(configuration),
+ "Cannot change state as requested, as HA is not enabled for this instance.");
+
+ state = newState;
}
}
diff --git a/server-common/src/main/java/org/apache/atlas/server/common/service/ServiceStateChangeHandler.java b/server-common/src/main/java/org/apache/atlas/server/common/service/ServiceStateChangeHandler.java
new file mode 100644
index 00000000000..31f065321c9
--- /dev/null
+++ b/server-common/src/main/java/org/apache/atlas/server/common/service/ServiceStateChangeHandler.java
@@ -0,0 +1,38 @@
+/**
+ * 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.atlas.server.common.service;
+
+/**
+ * A hook interface for reacting to server lifecycle events.
+ * Used to decouple core service logic.
+ */
+public interface ServiceStateChangeHandler {
+
+ /**
+ * Invoked when the server process begins its initialization.
+ */
+ default void onServerStart() {
+ }
+
+ /**
+ * Invoked when the server instance is elected as the ACTIVE instance
+ * in an HA cluster or starts up in non-HA mode.
+ */
+ default void onServerActivation() {
+ }
+}
diff --git a/webapp/src/main/java/org/apache/atlas/web/service/UserService.java b/server-common/src/main/java/org/apache/atlas/server/common/service/UserService.java
similarity index 83%
rename from webapp/src/main/java/org/apache/atlas/web/service/UserService.java
rename to server-common/src/main/java/org/apache/atlas/server/common/service/UserService.java
index e0ea2b2c02d..ab1eb820b3d 100644
--- a/webapp/src/main/java/org/apache/atlas/web/service/UserService.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/service/UserService.java
@@ -15,10 +15,10 @@
* limitations under the License.
*/
-package org.apache.atlas.web.service;
+package org.apache.atlas.server.common.service;
-import org.apache.atlas.web.dao.UserDao;
-import org.apache.atlas.web.model.User;
+import org.apache.atlas.server.common.dao.UserDao;
+import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@@ -35,7 +35,7 @@ public UserService(UserDao userDao) {
}
@Override
- public User loadUserByUsername(final String username) throws UsernameNotFoundException {
+ public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
return userDao.loadUserByUsername(username);
}
}
diff --git a/webapp/src/main/java/org/apache/atlas/web/setup/KerberosAwareListener.java b/server-common/src/main/java/org/apache/atlas/server/common/setup/KerberosAwareListener.java
similarity index 91%
rename from webapp/src/main/java/org/apache/atlas/web/setup/KerberosAwareListener.java
rename to server-common/src/main/java/org/apache/atlas/server/common/setup/KerberosAwareListener.java
index 5fb98488550..c89a7803c54 100644
--- a/webapp/src/main/java/org/apache/atlas/web/setup/KerberosAwareListener.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/setup/KerberosAwareListener.java
@@ -15,9 +15,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.atlas.web.setup;
+package org.apache.atlas.server.common.setup;
-import org.apache.atlas.web.listeners.LoginProcessor;
+import org.apache.atlas.server.common.listeners.LoginProcessor;
import org.springframework.web.context.ContextLoaderListener;
import javax.servlet.ServletContextEvent;
diff --git a/webapp/src/main/java/org/apache/atlas/web/util/DateTimeHelper.java b/server-common/src/main/java/org/apache/atlas/server/common/util/DateTimeHelper.java
old mode 100755
new mode 100644
similarity index 64%
rename from webapp/src/main/java/org/apache/atlas/web/util/DateTimeHelper.java
rename to server-common/src/main/java/org/apache/atlas/server/common/util/DateTimeHelper.java
index dbdcd98e423..f2cfb8c1844
--- a/webapp/src/main/java/org/apache/atlas/web/util/DateTimeHelper.java
+++ b/server-common/src/main/java/org/apache/atlas/server/common/util/DateTimeHelper.java
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-package org.apache.atlas.web.util;
+package org.apache.atlas.server.common.util;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
@@ -28,17 +28,20 @@
* Support function to parse and format date.
*/
public final class DateTimeHelper {
- public static final String ISO8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
- private static final String DATE_PATTERN = "(2\\d\\d\\d|19\\d\\d)-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])T" + "([0-1][0-9]|2[0-3]):([0-5][0-9])Z";
- private static final Pattern PATTERN = Pattern.compile(DATE_PATTERN);
- private static final ThreadLocal
+ * 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.atlas.web.ha; + +import org.apache.atlas.AtlasException; +import org.apache.atlas.ha.AtlasServerIdSelector; +import org.apache.atlas.ha.HAConfiguration; +import org.apache.atlas.server.common.service.HighAvailability; +import org.apache.atlas.server.common.service.HighAvailabilityProperties; +import org.apache.commons.configuration.Configuration; +import org.springframework.stereotype.Component; + +/** + * WebApp-specific implementation of HighAvailability. + * This class adapts the legacy HAConfiguration and AtlasServerIdSelector + * into the common contract required by the shared server engine. + */ +@Component +public class HighAvailabilityImpl implements HighAvailability { + @Override + public boolean isHAEnabled(Configuration configuration) { + return HAConfiguration.isHAEnabled(configuration); + } + + @Override + public String selectServerId(Configuration configuration) throws AtlasException { + return AtlasServerIdSelector.selectServerId(configuration); + } + + @Override + public String getBoundAddressForId(Configuration configuration, String serverId) { + return HAConfiguration.getBoundAddressForId(configuration, serverId); + } + + @Override + public HighAvailabilityProperties getZookeeperProperties(Configuration configuration) { + HAConfiguration.ZookeeperProperties props = HAConfiguration.getZookeeperProperties(configuration); + + return new HighAvailabilityProperties( + props.getConnectString(), + props.getZkRoot(), + props.getRetriesSleepTimeMillis(), + props.getNumRetries(), + props.getSessionTimeout(), + props.getAcl(), + props.getAuth()); + } +} diff --git a/webapp/src/main/java/org/apache/atlas/web/metrics/ServiceStateChangeAuditHandler.java b/webapp/src/main/java/org/apache/atlas/web/metrics/ServiceStateChangeAuditHandler.java new file mode 100644 index 00000000000..b944c107ecd --- /dev/null +++ b/webapp/src/main/java/org/apache/atlas/web/metrics/ServiceStateChangeAuditHandler.java @@ -0,0 +1,112 @@ +/** + * 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.atlas.web.metrics; + +import org.apache.atlas.exception.AtlasBaseException; +import org.apache.atlas.model.audit.AtlasAuditEntry.AuditOperation; +import org.apache.atlas.repository.audit.AtlasAuditService; +import org.apache.atlas.server.common.service.EmbeddedServer; +import org.apache.atlas.server.common.service.ServiceStateChangeHandler; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Date; + +/** + * Persists {@code SERVER_START} and {@code SERVER_STATE_ACTIVE} rows for Administration → Audits. + *
+ * Registered alongside {@link ServiceStateChangeMetricHandler} as a {@link ServiceStateChangeHandler} + * so lifecycle matches {@link org.apache.atlas.server.common.service.ActiveInstanceElectorService}: + * non-HA invokes both hooks in sequence; HA emits {@code SERVER_START} at process init and + * {@code SERVER_STATE_ACTIVE} when this instance becomes leader. + *
+ * Uses the eight-argument {@link AtlasAuditService#add} overload so user and client id are explicit + * and do not rely on {@link org.apache.atlas.RequestContext} during bootstrap. + */ +@Component +public class ServiceStateChangeAuditHandler implements ServiceStateChangeHandler { + private static final Logger LOG = LoggerFactory.getLogger(ServiceStateChangeAuditHandler.class); + + private static final String ADMIN_AUDIT_USER = "atlas"; + + private final AtlasAuditService auditService; + + @Inject + public ServiceStateChangeAuditHandler(AtlasAuditService auditService) { + this.auditService = auditService; + } + + @Override + public void onServerStart() { + try { + Date endTime = new Date(); + auditService.add( + ADMIN_AUDIT_USER, + AuditOperation.SERVER_START, + clientIdForAudit(), + EmbeddedServer.SERVER_START_TIME, + endTime, + null, + null, + 0); + } catch (AtlasBaseException e) { + LOG.warn("Failed to write SERVER_START admin audit", e); + } + } + + @Override + public void onServerActivation() { + try { + Date now = new Date(); + auditService.add( + ADMIN_AUDIT_USER, + AuditOperation.SERVER_STATE_ACTIVE, + clientIdForAudit(), + now, + now, + null, + null, + 0); + } catch (AtlasBaseException e) { + LOG.warn("Failed to write SERVER_STATE_ACTIVE admin audit", e); + } + } + + /** + * Aligns with {@link AtlasAuditService#add} behavior when no HTTP client is present: host:address. + */ + private static String clientIdForAudit() { + try { + InetAddress local = InetAddress.getLocalHost(); + String hostName = StringUtils.defaultString(local.getHostName()); + String hostAddress = StringUtils.defaultString(local.getHostAddress()); + if (StringUtils.isNotEmpty(hostName) && StringUtils.isNotEmpty(hostAddress)) { + return hostName + ":" + hostAddress; + } + } catch (UnknownHostException e) { + LOG.debug("Could not resolve local host for audit client id", e); + } + return "unknown"; + } +} diff --git a/webapp/src/main/java/org/apache/atlas/web/metrics/ServiceStateChangeMetricHandler.java b/webapp/src/main/java/org/apache/atlas/web/metrics/ServiceStateChangeMetricHandler.java new file mode 100644 index 00000000000..0d037110ae7 --- /dev/null +++ b/webapp/src/main/java/org/apache/atlas/web/metrics/ServiceStateChangeMetricHandler.java @@ -0,0 +1,49 @@ +/** + * 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.atlas.web.metrics;
+
+import org.apache.atlas.server.common.service.ServiceStateChangeHandler;
+import org.apache.atlas.util.AtlasMetricsUtil;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+
+/**
+ * WebApp implementation of the ServiceStateChangeHandler.
+ * This class bridges the common server lifecycle events to the
+ * WebApp-specific AtlasMetricsUtil.
+ */
+@Component
+public class ServiceStateChangeMetricHandler implements ServiceStateChangeHandler {
+ private final AtlasMetricsUtil metricsUtil;
+
+ @Inject
+ public ServiceStateChangeMetricHandler(AtlasMetricsUtil metricsUtil) {
+ this.metricsUtil = metricsUtil;
+ }
+
+ @Override
+ public void onServerStart() {
+ metricsUtil.onServerStart();
+ }
+
+ @Override
+ public void onServerActivation() {
+ metricsUtil.onServerActivation();
+ }
+}
diff --git a/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java b/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
index b092d480684..9df94d96880 100755
--- a/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
@@ -67,6 +67,9 @@
import org.apache.atlas.repository.impexp.ZipSink;
import org.apache.atlas.repository.patches.AtlasPatchManager;
import org.apache.atlas.repository.store.graph.AtlasEntityStore;
+import org.apache.atlas.server.common.filters.AtlasCSRFPreventionFilter;
+import org.apache.atlas.server.common.service.ServiceState;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.services.MetricsService;
import org.apache.atlas.services.PurgeService;
import org.apache.atlas.tasks.TaskManagement;
@@ -76,11 +79,8 @@
import org.apache.atlas.util.SearchTracker;
import org.apache.atlas.utils.AtlasJson;
import org.apache.atlas.utils.AtlasPerfTracer;
-import org.apache.atlas.web.filters.AtlasCSRFPreventionFilter;
import org.apache.atlas.web.model.DebugMetrics;
import org.apache.atlas.web.service.AtlasDebugMetricsSink;
-import org.apache.atlas.web.service.ServiceState;
-import org.apache.atlas.web.util.Servlets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
@@ -133,7 +133,7 @@
import java.util.stream.Collectors;
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
-import static org.apache.atlas.web.filters.AtlasCSRFPreventionFilter.CSRF_TOKEN;
+import static org.apache.atlas.server.common.filters.AtlasCSRFPreventionFilter.CSRF_TOKEN;
/**
* Jersey Resource for admin operations.
diff --git a/webapp/src/main/java/org/apache/atlas/web/resources/DataSetLineageResource.java b/webapp/src/main/java/org/apache/atlas/web/resources/DataSetLineageResource.java
index 0c14be19883..469c161a791 100644
--- a/webapp/src/main/java/org/apache/atlas/web/resources/DataSetLineageResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/DataSetLineageResource.java
@@ -25,13 +25,13 @@
import org.apache.atlas.model.lineage.AtlasLineageInfo;
import org.apache.atlas.model.lineage.AtlasLineageInfo.LineageDirection;
import org.apache.atlas.repository.store.graph.AtlasEntityStore;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.utils.AtlasPerfTracer;
import org.apache.atlas.v1.model.lineage.DataSetLineageResponse;
import org.apache.atlas.v1.model.lineage.SchemaResponse;
import org.apache.atlas.web.util.LineageUtils;
-import org.apache.atlas.web.util.Servlets;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java b/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java
index 7d6e829a422..ccf66c59505 100755
--- a/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java
@@ -39,6 +39,7 @@
import org.apache.atlas.repository.store.graph.AtlasEntityStore;
import org.apache.atlas.repository.store.graph.v2.AtlasEntityStream;
import org.apache.atlas.repository.store.graph.v2.AtlasGraphUtilsV2;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasType;
import org.apache.atlas.type.AtlasTypeRegistry;
@@ -50,7 +51,6 @@
import org.apache.atlas.v1.model.instance.Referenceable;
import org.apache.atlas.v1.model.instance.Struct;
import org.apache.atlas.web.rest.EntityREST;
-import org.apache.atlas.web.util.Servlets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
diff --git a/webapp/src/main/java/org/apache/atlas/web/resources/LineageResource.java b/webapp/src/main/java/org/apache/atlas/web/resources/LineageResource.java
index 61ceca3e529..6dca03e32d5 100644
--- a/webapp/src/main/java/org/apache/atlas/web/resources/LineageResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/LineageResource.java
@@ -22,12 +22,12 @@
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.lineage.AtlasLineageInfo;
import org.apache.atlas.model.lineage.AtlasLineageInfo.LineageDirection;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.utils.AtlasPerfTracer;
import org.apache.atlas.v1.model.lineage.LineageResponse;
import org.apache.atlas.v1.model.lineage.SchemaResponse;
import org.apache.atlas.web.util.LineageUtils;
-import org.apache.atlas.web.util.Servlets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
diff --git a/webapp/src/main/java/org/apache/atlas/web/resources/MetadataDiscoveryResource.java b/webapp/src/main/java/org/apache/atlas/web/resources/MetadataDiscoveryResource.java
index 280e13760ea..da6fb907400 100755
--- a/webapp/src/main/java/org/apache/atlas/web/resources/MetadataDiscoveryResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/MetadataDiscoveryResource.java
@@ -27,13 +27,13 @@
import org.apache.atlas.query.QueryParams;
import org.apache.atlas.repository.converters.AtlasInstanceConverter;
import org.apache.atlas.repository.store.graph.AtlasEntityStore;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.utils.AtlasJson;
import org.apache.atlas.utils.AtlasPerfTracer;
import org.apache.atlas.utils.ParamChecker;
import org.apache.atlas.v1.model.discovery.DSLSearchResult;
import org.apache.atlas.v1.model.discovery.FullTextSearchResult;
import org.apache.atlas.v1.model.instance.Referenceable;
-import org.apache.atlas.web.util.Servlets;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/webapp/src/main/java/org/apache/atlas/web/resources/TypesResource.java b/webapp/src/main/java/org/apache/atlas/web/resources/TypesResource.java
index 8451997fc88..b05bd4dc080 100755
--- a/webapp/src/main/java/org/apache/atlas/web/resources/TypesResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/TypesResource.java
@@ -24,13 +24,13 @@
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.typedef.AtlasTypesDef;
import org.apache.atlas.repository.converters.TypeConverterUtil;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.store.AtlasTypeDefStore;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.utils.AtlasJson;
import org.apache.atlas.utils.AtlasPerfTracer;
import org.apache.atlas.v1.model.typedef.TypesDef;
import org.apache.atlas.web.rest.TypesREST;
-import org.apache.atlas.web.util.Servlets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java
index 6f404a656ff..1719653b777 100644
--- a/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java
+++ b/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java
@@ -38,12 +38,12 @@
import org.apache.atlas.model.profile.AtlasUserSavedSearch;
import org.apache.atlas.repository.Constants;
import org.apache.atlas.repository.store.graph.v2.tasks.searchdownload.SearchResultDownloadTask;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasStructType;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.utils.AtlasJson;
import org.apache.atlas.utils.AtlasPerfTracer;
-import org.apache.atlas.web.util.Servlets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang3.StringUtils;
diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java
index 07f142d82a6..1f0e380cda3 100644
--- a/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java
+++ b/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java
@@ -45,12 +45,12 @@
import org.apache.atlas.repository.store.graph.v2.AtlasEntityStream;
import org.apache.atlas.repository.store.graph.v2.ClassificationAssociator;
import org.apache.atlas.repository.store.graph.v2.EntityStream;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.type.AtlasClassificationType;
import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.util.FileUtils;
import org.apache.atlas.utils.AtlasPerfTracer;
-import org.apache.atlas.web.util.Servlets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/GlossaryREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/GlossaryREST.java
index a9b7196674e..e83a10d16ff 100644
--- a/webapp/src/main/java/org/apache/atlas/web/rest/GlossaryREST.java
+++ b/webapp/src/main/java/org/apache/atlas/web/rest/GlossaryREST.java
@@ -32,8 +32,8 @@
import org.apache.atlas.model.glossary.relations.AtlasRelatedCategoryHeader;
import org.apache.atlas.model.glossary.relations.AtlasRelatedTermHeader;
import org.apache.atlas.model.instance.AtlasRelatedObjectId;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.utils.AtlasPerfTracer;
-import org.apache.atlas.web.util.Servlets;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;
diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/IndexRecoveryREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/IndexRecoveryREST.java
index 78ebd52c043..df379f82906 100644
--- a/webapp/src/main/java/org/apache/atlas/web/rest/IndexRecoveryREST.java
+++ b/webapp/src/main/java/org/apache/atlas/web/rest/IndexRecoveryREST.java
@@ -27,9 +27,9 @@
import org.apache.atlas.repository.graph.IndexRecoveryService;
import org.apache.atlas.repository.graphdb.AtlasGraph;
import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.server.common.util.DateTimeHelper;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.utils.AtlasPerfTracer;
-import org.apache.atlas.web.util.DateTimeHelper;
-import org.apache.atlas.web.util.Servlets;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.format.annotation.DateTimeFormat;
diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/LineageREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/LineageREST.java
index 54b62699853..ef3a94b46ef 100644
--- a/webapp/src/main/java/org/apache/atlas/web/rest/LineageREST.java
+++ b/webapp/src/main/java/org/apache/atlas/web/rest/LineageREST.java
@@ -28,10 +28,10 @@
import org.apache.atlas.model.lineage.AtlasLineageInfo.LineageDirection;
import org.apache.atlas.model.lineage.LineageOnDemandConstraints;
import org.apache.atlas.repository.store.graph.v2.AtlasGraphUtilsV2;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.utils.AtlasPerfTracer;
-import org.apache.atlas.web.util.Servlets;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/NotificationREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/NotificationREST.java
index d0c8a736fa0..6c437ea98b1 100644
--- a/webapp/src/main/java/org/apache/atlas/web/rest/NotificationREST.java
+++ b/webapp/src/main/java/org/apache/atlas/web/rest/NotificationREST.java
@@ -29,8 +29,8 @@
import org.apache.atlas.kafka.KafkaNotification;
import org.apache.atlas.notification.NotificationException;
import org.apache.atlas.notification.NotificationInterface;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.utils.AtlasJson;
-import org.apache.atlas.web.util.Servlets;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/RelationshipREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/RelationshipREST.java
index db64802d40d..6f79c3442c2 100644
--- a/webapp/src/main/java/org/apache/atlas/web/rest/RelationshipREST.java
+++ b/webapp/src/main/java/org/apache/atlas/web/rest/RelationshipREST.java
@@ -23,8 +23,8 @@
import org.apache.atlas.model.instance.AtlasRelationship;
import org.apache.atlas.model.instance.AtlasRelationship.AtlasRelationshipWithExtInfo;
import org.apache.atlas.repository.store.graph.AtlasRelationshipStore;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.utils.AtlasPerfTracer;
-import org.apache.atlas.web.util.Servlets;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;
diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/TypesREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/TypesREST.java
index e42b7627b11..47955e4f0e1 100644
--- a/webapp/src/main/java/org/apache/atlas/web/rest/TypesREST.java
+++ b/webapp/src/main/java/org/apache/atlas/web/rest/TypesREST.java
@@ -30,10 +30,10 @@
import org.apache.atlas.model.typedef.AtlasTypeDefHeader;
import org.apache.atlas.model.typedef.AtlasTypesDef;
import org.apache.atlas.repository.util.FilterUtil;
+import org.apache.atlas.server.common.util.Servlets;
import org.apache.atlas.store.AtlasTypeDefStore;
import org.apache.atlas.type.AtlasTypeUtil;
import org.apache.atlas.utils.AtlasPerfTracer;
-import org.apache.atlas.web.util.Servlets;
import org.apache.http.annotation.Experimental;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;
@@ -441,7 +441,7 @@ public void deleteAtlasTypeByName(@PathParam("typeName") final String typeName)
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TypesREST.deleteAtlasTypeByName(" + typeName + ")");
}
- typeDefStore.deleteTypeByName(typeName);
+ typeDefStore.deleteTypeByName(typeName, false);
} finally {
AtlasPerfTracer.log(perf);
}
diff --git a/webapp/src/main/java/org/apache/atlas/web/security/AtlasSecurityConfig.java b/webapp/src/main/java/org/apache/atlas/web/security/AtlasSecurityConfig.java
index 5058ebdf53d..acfaf59eaf0 100644
--- a/webapp/src/main/java/org/apache/atlas/web/security/AtlasSecurityConfig.java
+++ b/webapp/src/main/java/org/apache/atlas/web/security/AtlasSecurityConfig.java
@@ -17,16 +17,15 @@
*/
package org.apache.atlas.web.security;
-import org.apache.atlas.web.filters.ActiveServerFilter;
-import org.apache.atlas.web.filters.AtlasAuthenticationEntryPoint;
-import org.apache.atlas.web.filters.AtlasAuthenticationFilter;
-import org.apache.atlas.web.filters.AtlasCSRFPreventionFilter;
-import org.apache.atlas.web.filters.AtlasDelegatingAuthenticationEntryPoint;
-import org.apache.atlas.web.filters.AtlasKnoxSSOAuthenticationFilter;
-import org.apache.atlas.web.filters.HeadersUtil;
-import org.apache.atlas.web.filters.StaleTransactionCleanupFilter;
+import org.apache.atlas.server.common.filters.ActiveServerFilter;
+import org.apache.atlas.server.common.filters.AtlasAuthenticationEntryPoint;
+import org.apache.atlas.server.common.filters.AtlasAuthenticationFilter;
+import org.apache.atlas.server.common.filters.AtlasCSRFPreventionFilter;
+import org.apache.atlas.server.common.filters.AtlasKnoxSSOAuthenticationFilter;
+import org.apache.atlas.server.common.security.AtlasAuthenticationFailureHandler;
+import org.apache.atlas.server.common.security.AtlasAuthenticationProvider;
+import org.apache.atlas.server.common.security.AtlasAuthenticationSuccessHandler;
import org.apache.commons.configuration.Configuration;
-import org.apache.commons.lang3.StringUtils;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment;
@@ -42,28 +41,23 @@
import org.keycloak.adapters.springsecurity.filter.QueryParamPresenceRequestMatcher;
import org.keycloak.adapters.springsecurity.management.HttpSessionManager;
import org.keycloak.representations.adapters.config.AdapterConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
-import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
-import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
-import org.springframework.security.web.header.writers.StaticHeadersWriter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
@@ -71,38 +65,42 @@
import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.inject.Inject;
+import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import static org.apache.atlas.AtlasConstants.ATLAS_MIGRATION_MODE_FILENAME;
-import static org.apache.atlas.web.filters.HeadersUtil.SERVER_KEY;
-
+/**
+ * Spring Security configuration for the Atlas main webapp.
+ *
+ * Why this class was created
+ * Before this commit, {@code server-common/AtlasSecurityConfig} was a concrete
+ * {@code @EnableWebSecurity} class. That caused Spring to register TWO security
+ * configurations when the webapp started — the server-common one (found on
+ * classpath) and any module-specific one. This bean conflict prevented the
+ * Kerberos authentication filter chain from initializing correctly.
+ *
+ * This class was created as the SINGLE {@code @EnableWebSecurity} authority
+ * for the webapp, extending the now-abstract server-common base. Spring Security
+ * sees only this concrete class and builds one correct filter chain.
+ *
+ * What is webapp-specific in this class (not in base)
+ * {@code staleTransactionCleanupFilter} — cleans up open JanusGraph transactions.
+ * Only exists in webapp's Spring context; rest-notification-webapp has no
+ * JanusGraph transactions. Was previously in server-common's constructor
+ * causing {@code NoSuchBeanDefinitionException} at rest-notification startup.
+ */
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@KeycloakConfiguration
-public class AtlasSecurityConfig extends WebSecurityConfigurerAdapter {
- private static final Logger LOG = LoggerFactory.getLogger(AtlasSecurityConfig.class);
-
+public class AtlasSecurityConfig extends org.apache.atlas.server.common.security.AtlasSecurityConfig {
public static final RequestMatcher KEYCLOAK_REQUEST_MATCHER = new OrRequestMatcher(new AntPathRequestMatcher("/login.jsp"), new RequestHeaderRequestMatcher("Authorization"), new QueryParamPresenceRequestMatcher("access_token"));
- private final AtlasAuthenticationProvider authenticationProvider;
- private final AtlasAuthenticationSuccessHandler successHandler;
- private final AtlasAuthenticationFailureHandler failureHandler;
- private final AtlasKnoxSSOAuthenticationFilter ssoAuthenticationFilter;
- private final AtlasAuthenticationFilter atlasAuthenticationFilter;
- private final AtlasCSRFPreventionFilter csrfPreventionFilter;
- private final AtlasAuthenticationEntryPoint atlasAuthenticationEntryPoint;
-
- // Our own Atlas filters need to be registered as well
- private final Configuration configuration;
- private final StaleTransactionCleanupFilter staleTransactionCleanupFilter;
- private final ActiveServerFilter activeServerFilter;
- private final boolean keycloakEnabled;
+ private final boolean keycloakEnabled;
+ private final ObjectProvider
+ * 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.atlas.web.service;
+
+import org.apache.atlas.server.common.filters.spi.ActiveInstanceStateProvider;
+import org.apache.atlas.server.common.filters.spi.ServiceStateProvider;
+import org.apache.atlas.server.common.service.ActiveInstanceState;
+import org.apache.atlas.server.common.service.ServiceState;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class AtlasServiceStateProviderConfig {
+ @Bean
+ public ActiveInstanceStateProvider activeInstanceStateProvider(ActiveInstanceState activeInstanceState) {
+ return activeInstanceState::getActiveServerAddress;
+ }
+
+ @Bean
+ public ServiceStateProvider serviceStateProvider(ServiceState serviceState) {
+ return new ServiceStateProvider() {
+ @Override
+ public boolean isActive() {
+ return serviceState.getState() == ServiceState.ServiceStateValue.ACTIVE;
+ }
+
+ @Override
+ public boolean isInstanceInTransition() {
+ return serviceState.isInstanceInTransition();
+ }
+
+ @Override
+ public boolean isInstanceInMigration() {
+ return serviceState.isInstanceInMigration();
+ }
+
+ @Override
+ public String getStateName() {
+ return serviceState.getState().toString();
+ }
+ };
+ }
+}
diff --git a/webapp/src/main/java/org/apache/atlas/web/servlets/AtlasHttpServlet.java b/webapp/src/main/java/org/apache/atlas/web/servlets/AtlasHttpServlet.java
index 04566a378c2..988831eadb8 100644
--- a/webapp/src/main/java/org/apache/atlas/web/servlets/AtlasHttpServlet.java
+++ b/webapp/src/main/java/org/apache/atlas/web/servlets/AtlasHttpServlet.java
@@ -17,8 +17,8 @@
*/
package org.apache.atlas.web.servlets;
-import org.apache.atlas.web.filters.AtlasResponseRequestWrapper;
-import org.apache.atlas.web.filters.HeadersUtil;
+import org.apache.atlas.server.common.filters.AtlasResponseRequestWrapper;
+import org.apache.atlas.server.common.filters.HeadersUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/webapp/src/main/java/org/apache/atlas/web/setup/SetupSteps.java b/webapp/src/main/java/org/apache/atlas/web/setup/SetupSteps.java
index b7f5ec4a396..b789160428d 100644
--- a/webapp/src/main/java/org/apache/atlas/web/setup/SetupSteps.java
+++ b/webapp/src/main/java/org/apache/atlas/web/setup/SetupSteps.java
@@ -24,10 +24,10 @@
import org.apache.atlas.AtlasException;
import org.apache.atlas.ha.AtlasServerIdSelector;
import org.apache.atlas.ha.HAConfiguration;
+import org.apache.atlas.server.common.service.AtlasZookeeperSecurityProperties;
+import org.apache.atlas.server.common.service.CuratorFactory;
import org.apache.atlas.setup.SetupException;
import org.apache.atlas.setup.SetupStep;
-import org.apache.atlas.web.service.AtlasZookeeperSecurityProperties;
-import org.apache.atlas.web.service.CuratorFactory;
import org.apache.commons.configuration.Configuration;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
diff --git a/webapp/src/main/java/org/apache/atlas/web/util/AtlasJsonProvider.java b/webapp/src/main/java/org/apache/atlas/web/util/AtlasJsonProvider.java
index e675a364577..a34c405e950 100644
--- a/webapp/src/main/java/org/apache/atlas/web/util/AtlasJsonProvider.java
+++ b/webapp/src/main/java/org/apache/atlas/web/util/AtlasJsonProvider.java
@@ -23,6 +23,7 @@
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
+import org.apache.atlas.server.common.util.Servlets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
diff --git a/webapp/src/main/resources/spring-security.xml b/webapp/src/main/resources/spring-security.xml
index 3020690dca0..a66e34b44c7 100644
--- a/webapp/src/main/resources/spring-security.xml
+++ b/webapp/src/main/resources/spring-security.xml
@@ -54,23 +54,23 @@
+ * 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.atlas.web.metrics;
+
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.audit.AtlasAuditEntry.AuditOperation;
+import org.apache.atlas.repository.audit.AtlasAuditService;
+import org.apache.atlas.server.common.service.EmbeddedServer;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.Date;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+public class ServiceStateChangeAuditHandlerTest {
+ private static final String ATLAS_USER = "atlas";
+
+ @Mock
+ private AtlasAuditService auditService;
+
+ private ServiceStateChangeAuditHandler handler;
+
+ @BeforeMethod
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ handler = new ServiceStateChangeAuditHandler(auditService);
+ }
+
+ @Test
+ public void testOnServerStartInvokesAuditWithServerStartOperation() throws AtlasBaseException {
+ handler.onServerStart();
+
+ verify(auditService, times(1)).add(
+ eq(ATLAS_USER),
+ eq(AuditOperation.SERVER_START),
+ anyString(),
+ eq(EmbeddedServer.SERVER_START_TIME),
+ any(Date.class),
+ isNull(),
+ isNull(),
+ eq(0L));
+ }
+
+ @Test
+ public void testOnServerActivationInvokesAuditWithServerStateActiveOperation() throws AtlasBaseException {
+ handler.onServerActivation();
+
+ ArgumentCaptor
+ * Profile-gated so classpath scanning for embedded-server / full webapp tests does not import
+ * {@code test-spring-security.xml} alongside {@link AtlasSecurityConfig} (that overlap creates a
+ * circular dependency between the Knox SSO filter and {@code atlasAuthenticationProviderBridge}).
+ */
+@Configuration
+@Profile("testSpringSecurityBridge")
+@ImportResource("classpath:test-spring-security.xml")
+public class TestSpringSecurityBridgeConfig {
+ @Bean
+ public AtlasAuthenticationProviderBridge atlasAuthenticationProviderBridge(AtlasAuthenticationProvider authenticationProvider) {
+ return new AtlasAuthenticationProviderBridge() {
+ @Override
+ public List