mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-08 15:04:29 +00:00
[Backend] Websocket implementation added (#5440)
* [Backend] Websocket implementation added * [Backend] Websocket implementation added [google formatter fix] * [backend] Updated Reiew Comments * [backend] Updated CheckStyle
This commit is contained in:
parent
0a9e36f1b4
commit
be18feb928
@ -390,6 +390,21 @@
|
||||
<groupId>org.jeasy</groupId>
|
||||
<artifactId>easy-rules-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.socket</groupId>
|
||||
<artifactId>socket.io-server</artifactId>
|
||||
<version>4.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.socket</groupId>
|
||||
<artifactId>engine.io-server-jetty</artifactId>
|
||||
<version>6.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-server</artifactId>
|
||||
<version>9.4.46.v20220331</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -32,6 +32,8 @@ import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
|
||||
import io.github.maksymdolgykh.dropwizard.micrometer.MicrometerBundle;
|
||||
import io.github.maksymdolgykh.dropwizard.micrometer.MicrometerHttpFilter;
|
||||
import io.github.maksymdolgykh.dropwizard.micrometer.MicrometerJdbiTimingCollector;
|
||||
import io.socket.engineio.server.EngineIoServerOptions;
|
||||
import io.socket.engineio.server.JettyWebSocketHandler;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
@ -39,13 +41,18 @@ import java.util.EnumSet;
|
||||
import java.util.Optional;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.FilterRegistration;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.ws.rs.container.ContainerRequestFilter;
|
||||
import javax.ws.rs.container.ContainerResponseFilter;
|
||||
import javax.ws.rs.core.Response;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.jetty.http.pathmap.ServletPathSpec;
|
||||
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
|
||||
import org.glassfish.jersey.media.multipart.MultiPartFeature;
|
||||
import org.glassfish.jersey.server.ServerProperties;
|
||||
import org.jdbi.v3.core.Jdbi;
|
||||
@ -74,12 +81,17 @@ import org.openmetadata.catalog.security.policyevaluator.PolicyEvaluator;
|
||||
import org.openmetadata.catalog.security.policyevaluator.RoleEvaluator;
|
||||
import org.openmetadata.catalog.slack.SlackPublisherConfiguration;
|
||||
import org.openmetadata.catalog.slack.SlackWebhookEventPublisher;
|
||||
import org.openmetadata.catalog.socket.FeedServlet;
|
||||
import org.openmetadata.catalog.socket.SocketAddressFilter;
|
||||
import org.openmetadata.catalog.socket.WebSocketManager;
|
||||
|
||||
/** Main catalog application */
|
||||
@Slf4j
|
||||
public class CatalogApplication extends Application<CatalogApplicationConfig> {
|
||||
private Authorizer authorizer;
|
||||
|
||||
private SocketAddressFilter socketAddressFilter = null;
|
||||
|
||||
@Override
|
||||
public void run(CatalogApplicationConfig catalogConfig, Environment environment)
|
||||
throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException,
|
||||
@ -151,6 +163,7 @@ public class CatalogApplication extends Application<CatalogApplicationConfig> {
|
||||
FilterRegistration.Dynamic micrometerFilter =
|
||||
environment.servlets().addFilter("MicrometerHttpFilter", new MicrometerHttpFilter());
|
||||
micrometerFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
|
||||
intializeWebsockets(environment);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@ -201,7 +214,11 @@ public class CatalogApplication extends Application<CatalogApplicationConfig> {
|
||||
InstantiationException {
|
||||
AuthorizerConfiguration authorizerConf = catalogConfig.getAuthorizerConfiguration();
|
||||
AuthenticationConfiguration authenticationConfiguration = catalogConfig.getAuthenticationConfiguration();
|
||||
// to authenticate request while opening websocket connections
|
||||
if (authorizerConf != null) {
|
||||
if (authorizerConf.getEnableSecureSocketConnection()) {
|
||||
socketAddressFilter = new SocketAddressFilter(authenticationConfiguration, authorizerConf);
|
||||
}
|
||||
authorizer =
|
||||
Class.forName(authorizerConf.getClassName()).asSubclass(Authorizer.class).getConstructor().newInstance();
|
||||
String filterClazzName = authorizerConf.getContainerRequestFilter();
|
||||
@ -261,6 +278,29 @@ public class CatalogApplication extends Application<CatalogApplicationConfig> {
|
||||
environment.getApplicationContext().setErrorHandler(eph);
|
||||
}
|
||||
|
||||
private void intializeWebsockets(Environment environment) {
|
||||
EngineIoServerOptions eioOptions = EngineIoServerOptions.newFromDefault();
|
||||
eioOptions.setAllowedCorsOrigins(null);
|
||||
WebSocketManager.WebSocketManagerBuilder.build(eioOptions);
|
||||
environment.getApplicationContext().setContextPath("/");
|
||||
if (socketAddressFilter != null)
|
||||
environment
|
||||
.getApplicationContext()
|
||||
.addFilter(new FilterHolder(socketAddressFilter), "/api/v1/push/feed/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
environment.getApplicationContext().addServlet(new ServletHolder(new FeedServlet()), "/api/v1/push/feed/*");
|
||||
// Upgrade connection to websocket from Http
|
||||
try {
|
||||
WebSocketUpgradeFilter webSocketUpgradeFilter =
|
||||
WebSocketUpgradeFilter.configureContext(environment.getApplicationContext());
|
||||
webSocketUpgradeFilter.addMapping(
|
||||
new ServletPathSpec("/api/v1/push/feed/*"),
|
||||
(servletUpgradeRequest, servletUpgradeResponse) ->
|
||||
new JettyWebSocketHandler(WebSocketManager.getInstance().getEngineIoServer()));
|
||||
} catch (ServletException ex) {
|
||||
LOG.error("Websocket Upgrade Filter error : ", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
CatalogApplication catalogApplication = new CatalogApplication();
|
||||
catalogApplication.run(args);
|
||||
|
||||
@ -18,6 +18,7 @@ import static org.openmetadata.catalog.type.EventType.ENTITY_SOFT_DELETED;
|
||||
import static org.openmetadata.catalog.type.EventType.ENTITY_UPDATED;
|
||||
import static org.openmetadata.common.utils.CommonUtil.listOrEmpty;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -36,6 +37,7 @@ import org.openmetadata.catalog.entity.feed.Thread;
|
||||
import org.openmetadata.catalog.jdbi3.CollectionDAO;
|
||||
import org.openmetadata.catalog.jdbi3.FeedRepository;
|
||||
import org.openmetadata.catalog.resources.feeds.MessageParser.EntityLink;
|
||||
import org.openmetadata.catalog.socket.WebSocketManager;
|
||||
import org.openmetadata.catalog.type.ChangeDescription;
|
||||
import org.openmetadata.catalog.type.ChangeEvent;
|
||||
import org.openmetadata.catalog.type.EntityReference;
|
||||
@ -48,10 +50,12 @@ import org.openmetadata.catalog.util.RestUtil;
|
||||
public class ChangeEventHandler implements EventHandler {
|
||||
private CollectionDAO dao;
|
||||
private FeedRepository feedDao;
|
||||
private ObjectMapper mapper;
|
||||
|
||||
public void init(CatalogApplicationConfig config, Jdbi jdbi) {
|
||||
this.dao = jdbi.onDemand(CollectionDAO.class);
|
||||
this.feedDao = new FeedRepository(dao);
|
||||
this.mapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
public Void process(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
|
||||
@ -100,6 +104,8 @@ public class ChangeEventHandler implements EventHandler {
|
||||
}
|
||||
EntityLink about = EntityLink.parse(thread.getAbout());
|
||||
feedDao.create(thread, entity.getId(), owner, about);
|
||||
String json = mapper.writeValueAsString(thread);
|
||||
WebSocketManager.getInstance().broadCastMessageToClients(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ public class AuthorizerConfiguration {
|
||||
@NotEmpty @Getter @Setter private Set<String> botPrincipals;
|
||||
@NotEmpty @Getter @Setter private String principalDomain;
|
||||
@NotEmpty @Getter @Setter private Boolean enforcePrincipalDomain;
|
||||
@NotEmpty @Getter @Setter private Boolean enableSecureSocketConnection;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
@ -56,7 +56,6 @@ public class JwtFilter implements ContainerRequestFilter {
|
||||
public static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
public static final String TOKEN_PREFIX = "Bearer";
|
||||
public static final String BOT_CLAIM = "isBot";
|
||||
|
||||
private List<String> jwtPrincipalClaims;
|
||||
private JwkProvider jwkProvider;
|
||||
private String principalDomain;
|
||||
@ -104,10 +103,33 @@ public class JwtFilter implements ContainerRequestFilter {
|
||||
String tokenFromHeader = extractToken(headers);
|
||||
LOG.debug("Token from header:{}", tokenFromHeader);
|
||||
|
||||
DecodedJWT jwt = validateAndReturnDecodedJwtToken(tokenFromHeader);
|
||||
|
||||
Map<String, Claim> claims = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
claims.putAll(jwt.getClaims());
|
||||
|
||||
String userName = validateAndReturnUsername(claims);
|
||||
|
||||
// validate bot token
|
||||
if (claims.containsKey(BOT_CLAIM) && claims.get(BOT_CLAIM).asBoolean()) {
|
||||
validateBotToken(tokenFromHeader, userName);
|
||||
}
|
||||
|
||||
// Setting Security Context
|
||||
CatalogPrincipal catalogPrincipal = new CatalogPrincipal(userName);
|
||||
String scheme = requestContext.getUriInfo().getRequestUri().getScheme();
|
||||
CatalogSecurityContext catalogSecurityContext =
|
||||
new CatalogSecurityContext(catalogPrincipal, scheme, SecurityContext.DIGEST_AUTH);
|
||||
LOG.debug("SecurityContext {}", catalogSecurityContext);
|
||||
requestContext.setSecurityContext(catalogSecurityContext);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public DecodedJWT validateAndReturnDecodedJwtToken(String token) {
|
||||
// Decode JWT Token
|
||||
DecodedJWT jwt;
|
||||
try {
|
||||
jwt = JWT.decode(tokenFromHeader);
|
||||
jwt = JWT.decode(token);
|
||||
} catch (JWTDecodeException e) {
|
||||
throw new AuthenticationException("Invalid token", e);
|
||||
}
|
||||
@ -127,10 +149,12 @@ public class JwtFilter implements ContainerRequestFilter {
|
||||
} catch (RuntimeException runtimeException) {
|
||||
throw new AuthenticationException("Invalid token");
|
||||
}
|
||||
return jwt;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public String validateAndReturnUsername(Map<String, Claim> claims) {
|
||||
// Get username from JWT token
|
||||
Map<String, Claim> claims = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
claims.putAll(jwt.getClaims());
|
||||
String jwtClaim =
|
||||
jwtPrincipalClaims.stream()
|
||||
.filter(claims::containsKey)
|
||||
@ -141,6 +165,7 @@ public class JwtFilter implements ContainerRequestFilter {
|
||||
() ->
|
||||
new AuthenticationException(
|
||||
"Invalid JWT token, none of the following claims are present " + jwtPrincipalClaims));
|
||||
|
||||
String userName;
|
||||
String domain;
|
||||
if (jwtClaim.contains("@")) {
|
||||
@ -158,18 +183,7 @@ public class JwtFilter implements ContainerRequestFilter {
|
||||
String.format("Not Authorized! Email does not match the principal domain %s", principalDomain));
|
||||
}
|
||||
}
|
||||
|
||||
// validate bot token
|
||||
if (claims.containsKey(BOT_CLAIM) && claims.get(BOT_CLAIM).asBoolean()) {
|
||||
validateBotToken(tokenFromHeader, userName);
|
||||
}
|
||||
// Setting Security Context
|
||||
CatalogPrincipal catalogPrincipal = new CatalogPrincipal(userName);
|
||||
String scheme = requestContext.getUriInfo().getRequestUri().getScheme();
|
||||
CatalogSecurityContext catalogSecurityContext =
|
||||
new CatalogSecurityContext(catalogPrincipal, scheme, SecurityContext.DIGEST_AUTH);
|
||||
LOG.debug("SecurityContext {}", catalogSecurityContext);
|
||||
requestContext.setSecurityContext(catalogSecurityContext);
|
||||
return userName;
|
||||
}
|
||||
|
||||
protected static String extractToken(MultivaluedMap<String, String> headers) {
|
||||
@ -185,6 +199,18 @@ public class JwtFilter implements ContainerRequestFilter {
|
||||
throw new AuthenticationException("Not Authorized! Token not present");
|
||||
}
|
||||
|
||||
public static String extractToken(String tokenFromHeader) {
|
||||
LOG.debug("Request Token:{}", tokenFromHeader);
|
||||
if (Strings.isNullOrEmpty(tokenFromHeader)) {
|
||||
throw new AuthenticationException("Not Authorized! Token not present");
|
||||
}
|
||||
// Extract the bearer token
|
||||
if (tokenFromHeader.startsWith(TOKEN_PREFIX)) {
|
||||
return tokenFromHeader.substring(TOKEN_PREFIX.length() + 1);
|
||||
}
|
||||
throw new AuthenticationException("Not Authorized! Token not present");
|
||||
}
|
||||
|
||||
private void validateBotToken(String tokenFromHeader, String userName) throws IOException {
|
||||
EntityRepository<User> userRepository = Entity.getEntityRepository(Entity.USER);
|
||||
User user = userRepository.getByName(null, userName, new EntityUtil.Fields(List.of("authenticationMechanism")));
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed 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.openmetadata.catalog.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@WebServlet("/api/v1/push/feed/*")
|
||||
public class FeedServlet extends HttpServlet {
|
||||
public FeedServlet() {}
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
WebSocketManager.getInstance()
|
||||
.getEngineIoServer()
|
||||
.handleRequest(
|
||||
new HttpServletRequestWrapper(request) {
|
||||
@Override
|
||||
public boolean isAsyncSupported() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
response);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed 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.openmetadata.catalog.socket;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
public class HeaderRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
public HeaderRequestWrapper(HttpServletRequest request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
private Map<String, String> headerMap = new HashMap<>();
|
||||
|
||||
public void addHeader(String name, String value) {
|
||||
headerMap.put(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
String headerValue = super.getHeader(name);
|
||||
if (headerMap.containsKey(name)) {
|
||||
headerValue = headerMap.get(name);
|
||||
}
|
||||
return headerValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getHeaderNames() {
|
||||
List<String> names = Collections.list(super.getHeaderNames());
|
||||
names.addAll(headerMap.keySet());
|
||||
return Collections.enumeration(names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getHeaders(String name) {
|
||||
List<String> values = Collections.list(super.getHeaders(name));
|
||||
if (headerMap.containsKey(name)) {
|
||||
values.add(headerMap.get(name));
|
||||
}
|
||||
return Collections.enumeration(values);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed 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.openmetadata.catalog.socket;
|
||||
|
||||
import com.auth0.jwt.interfaces.Claim;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.openmetadata.catalog.security.AuthenticationConfiguration;
|
||||
import org.openmetadata.catalog.security.AuthorizerConfiguration;
|
||||
import org.openmetadata.catalog.security.JwtFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SocketAddressFilter implements Filter {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SocketAddressFilter.class);
|
||||
private JwtFilter jwtFilter;
|
||||
|
||||
public SocketAddressFilter(
|
||||
AuthenticationConfiguration authenticationConfiguration, AuthorizerConfiguration authorizerConf) {
|
||||
jwtFilter = new JwtFilter(authenticationConfiguration, authorizerConf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||
String tokenWithType = httpServletRequest.getHeader("Authorization");
|
||||
|
||||
HeaderRequestWrapper requestWrapper = new HeaderRequestWrapper(httpServletRequest);
|
||||
requestWrapper.addHeader("RemoteAddress", request.getRemoteAddr());
|
||||
requestWrapper.addHeader("Authorization", tokenWithType);
|
||||
|
||||
String token = JwtFilter.extractToken(tokenWithType);
|
||||
// validate token
|
||||
DecodedJWT jwt = jwtFilter.validateAndReturnDecodedJwtToken(token);
|
||||
// validate Domain and Username
|
||||
Map<String, Claim> claims = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
claims.putAll(jwt.getClaims());
|
||||
jwtFilter.validateAndReturnUsername(claims);
|
||||
// Goes to default servlet.
|
||||
chain.doFilter(requestWrapper, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package org.openmetadata.catalog.socket;
|
||||
|
||||
import io.socket.engineio.server.EngineIoServer;
|
||||
import io.socket.engineio.server.EngineIoServerOptions;
|
||||
import io.socket.socketio.server.SocketIoNamespace;
|
||||
import io.socket.socketio.server.SocketIoServer;
|
||||
import io.socket.socketio.server.SocketIoSocket;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class WebSocketManager {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WebSocketManager.class);
|
||||
private static WebSocketManager INSTANCE;
|
||||
private final EngineIoServer mEngineIoServer;
|
||||
private final SocketIoServer mSocketIoServer;
|
||||
private final String feedBroadcastChannel = "activityFeed";
|
||||
private final Map<String, SocketIoSocket> activityFeedEndpoints = new ConcurrentHashMap<>();
|
||||
|
||||
private WebSocketManager(EngineIoServerOptions eiOptions) {
|
||||
mEngineIoServer = new EngineIoServer(eiOptions);
|
||||
mSocketIoServer = new SocketIoServer(mEngineIoServer);
|
||||
intilizateHandlers();
|
||||
}
|
||||
|
||||
private void intilizateHandlers() {
|
||||
SocketIoNamespace ns = mSocketIoServer.namespace("/");
|
||||
// On Connection
|
||||
ns.on(
|
||||
"connection",
|
||||
args -> {
|
||||
SocketIoSocket socket = (SocketIoSocket) args[0];
|
||||
LOG.info(
|
||||
"Client :"
|
||||
+ socket.getId()
|
||||
+ "with Remote Address :"
|
||||
+ socket.getInitialHeaders().get("RemoteAddress")
|
||||
+ "connected.");
|
||||
activityFeedEndpoints.put(socket.getId(), socket);
|
||||
});
|
||||
}
|
||||
|
||||
public static WebSocketManager getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public SocketIoServer getSocketIoServer() {
|
||||
return mSocketIoServer;
|
||||
}
|
||||
|
||||
public EngineIoServer getEngineIoServer() {
|
||||
return mEngineIoServer;
|
||||
}
|
||||
|
||||
public Map<String, SocketIoSocket> getActivityFeedEndpoints() {
|
||||
return activityFeedEndpoints;
|
||||
}
|
||||
|
||||
public void broadCastMessageToClients(String message) {
|
||||
for (Map.Entry<String, SocketIoSocket> endpoints : activityFeedEndpoints.entrySet()) {
|
||||
endpoints.getValue().send(feedBroadcastChannel, message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class WebSocketManagerBuilder {
|
||||
public static void build(EngineIoServerOptions eiOptions) {
|
||||
INSTANCE = new WebSocketManager(eiOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -129,6 +129,8 @@ authorizerConfiguration:
|
||||
botPrincipals:
|
||||
- "ingestion-bot"
|
||||
principalDomain: "open-metadata.org"
|
||||
enforcePrincipalDomain: false
|
||||
enableSecureSocketConnection: false
|
||||
|
||||
authenticationConfiguration:
|
||||
provider: "openID"
|
||||
|
||||
@ -133,6 +133,7 @@ authorizerConfiguration:
|
||||
botPrincipals: ${AUTHORIZER_INGESTION_PRINCIPALS:-[ingestion-bot]}
|
||||
principalDomain: ${AUTHORIZER_PRINCIPAL_DOMAIN:-"openmetadata.org"}
|
||||
enforcePrincipalDomain: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
|
||||
enableSecureSocketConnection : ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
|
||||
|
||||
authenticationConfiguration:
|
||||
provider: ${AUTHENTICATION_PROVIDER:-no-auth}
|
||||
|
||||
@ -65,6 +65,7 @@ services:
|
||||
AUTHORIZER_INGESTION_PRINCIPALS: ${AUTHORIZER_INGESTION_PRINCIPALS:-[ingestion-bot]}
|
||||
AUTHORIZER_PRINCIPAL_DOMAIN: ${AUTHORIZER_PRINCIPAL_DOMAIN:-""}
|
||||
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
|
||||
AUTHORIZER_ENABLE_SECURE_SOCKET: ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
|
||||
AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-no-auth}
|
||||
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
|
||||
AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEY:-[https://www.googleapis.com/oauth2/v3/certs]}
|
||||
|
||||
@ -54,6 +54,7 @@ services:
|
||||
AUTHORIZER_INGESTION_PRINCIPALS: ${AUTHORIZER_INGESTION_PRINCIPAL:-[ingestion-bot]}
|
||||
AUTHORIZER_PRINCIPAL_DOMAIN: ${AUTHORIZER_PRINCIPAL_DOMAIN:-""}
|
||||
AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
|
||||
AUTHORIZER_ENABLE_SECURE_SOCKET: ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false}
|
||||
AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-no-auth}
|
||||
CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
|
||||
AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEY:-[https://www.googleapis.com/oauth2/v3/certs]}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user