/* * Copyright 2011 NCHOVY * * 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.krakenapps.siem.engine; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; import org.apache.felix.ipojo.annotations.Component; import org.apache.felix.ipojo.annotations.Invalidate; import org.apache.felix.ipojo.annotations.Provides; import org.apache.felix.ipojo.annotations.Requires; import org.apache.felix.ipojo.annotations.Validate; import org.krakenapps.api.PrimitiveConverter; import org.krakenapps.confdb.Config; import org.krakenapps.confdb.ConfigCollection; import org.krakenapps.confdb.ConfigDatabase; import org.krakenapps.confdb.ConfigIterator; import org.krakenapps.confdb.Predicates; import org.krakenapps.event.api.Event; import org.krakenapps.siem.ConfigManager; import org.krakenapps.siem.model.EventResponseMapping; import org.krakenapps.siem.model.ResponseActionInstance; import org.krakenapps.siem.response.ResponseAction; import org.krakenapps.siem.response.ResponseActionManager; import org.krakenapps.siem.response.ResponseActionManagerEventListener; import org.krakenapps.siem.response.ResponseServer; import org.krakenapps.siem.response.ResponseServerEventListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component(name = "siem-response-mapper") @Provides public class EventResponseMapperImpl implements EventResponseMapper, ResponseServerEventListener, ResponseActionManagerEventListener { private final Logger logger = LoggerFactory.getLogger(EventResponseMapperImpl.class.getName()); private ConcurrentMap<ResponseKey, CopyOnWriteArraySet<ResponseAction>> actionMap; @Requires private ResponseServer responseServer; @Requires private ConfigManager configManager; @Validate public void start() { responseServer.addEventListener(this); for (ResponseActionManager manager : responseServer.getResponseActionManagers()) { managerAdded(manager); } actionMap = new ConcurrentHashMap<ResponseKey, CopyOnWriteArraySet<ResponseAction>>(); loadActions(); responseServer.setResponseMapper(this); } @Invalidate public void stop() { if (responseServer != null) { responseServer.removeEventListener(this); responseServer.setResponseMapper(null); } } private void loadActions() { ConfigCollection col = getCol(); ConfigIterator it = col.findAll(); while (it.hasNext()) { Config c = it.next(); ResponseActionInstance instance = PrimitiveConverter.parse(ResponseActionInstance.class, c.getDocument()); for (EventResponseMapping mapping : instance.getEventMappings()) { ResponseActionManager manager = responseServer.getResponseActionManager(instance.getManager()); if (manager == null) { logger.trace("kraken siem: manager [{}] not found, preloading deferred", instance.getManager()); continue; } ResponseAction action = manager.getAction(instance.getNamespace(), instance.getName()); if (action == null) { logger.trace("kraken siem: action [{}] not found, preloading deferred", instance.getNamespace() + "\\" + instance.getName()); continue; } loadResponse(new ResponseKey(mapping.getCategory(), mapping.getEventSource()), action); logger.trace("kraken siem: event [category={}, source={}] to response [{}] mapping loaded", new Object[] { mapping.getCategory(), mapping.getEventSource(), action.getNamespace() + "\\" + action.getName() }); } } } @Override public Collection<ResponseAction> getActions(ResponseKey key) { CopyOnWriteArraySet<ResponseAction> c = actionMap.get(key); if (c == null) return null; return Collections.unmodifiableCollection(c); } @Override public Collection<ResponseKey> getKeys() { return Collections.unmodifiableCollection(actionMap.keySet()); } @Override public Collection<ResponseAction> getActions(Event e) { return actionMap.get(new ResponseKey(e.getCategory(), e.getKey().getSource())); } @Override public void addResponse(ResponseKey key, ResponseAction action) { loadResponse(key, action); addResponseConfig(key, action); logger.trace("kraken siem: added response mapping, key [{}], action [{}]", key, action.toString()); } @Override public void removeResponse(ResponseKey key, ResponseAction action) { unloadResponse(key, action); removeResponseConfig(key, action); logger.trace("kraken siem: removed response mapping, key [{}], action [{}]", key, action.toString()); } private void loadResponse(ResponseKey key, ResponseAction action) { CopyOnWriteArraySet<ResponseAction> actions = new CopyOnWriteArraySet<ResponseAction>(); CopyOnWriteArraySet<ResponseAction> old = actionMap.putIfAbsent(key, actions); if (old != null) actions = old; actions.add(action); } /** * add response mapping to specific event type * * @param key * the event type * @param action * the response action */ private void addResponseConfig(ResponseKey key, ResponseAction action) { ConfigCollection col = getCol(); Config c = getResponseActionInstance(action); ResponseActionInstance instance = PrimitiveConverter.parse(ResponseActionInstance.class, c.getDocument()); EventResponseMapping mapping = new EventResponseMapping(key.getCategory(), key.getEventSource()); List<EventResponseMapping> mappings = instance.getEventMappings(); if (!mappings.contains(mapping)) mappings.add(mapping); c.setDocument(PrimitiveConverter.serialize(instance)); col.update(c); } private void unloadResponse(ResponseKey key, ResponseAction action) { CopyOnWriteArraySet<ResponseAction> actions = actionMap.get(key); if (actions == null) return; actions.remove(action); } private void removeResponseConfig(ResponseKey key, ResponseAction action) { ConfigCollection col = getCol(); Config c = getResponseActionInstance(action); ResponseActionInstance instance = PrimitiveConverter.parse(ResponseActionInstance.class, c); EventResponseMapping mapping = new EventResponseMapping(key.getCategory(), key.getEventSource()); instance.getEventMappings().remove(mapping); if (instance.getEventMappings().size() == 0) col.remove(c); else { c.setDocument(PrimitiveConverter.serialize(instance)); col.update(c); } } private Config getResponseActionInstance(ResponseAction action) { ConfigCollection col = getCol(); Config c = col.findOne(Predicates.and( // Predicates.field("manager", action.getManager().getName()), // Predicates.field("namespace", action.getNamespace()), // Predicates.field("name", action.getName()))); // if (c == null) throw new IllegalStateException("response instance configuration not found: " + action.getNamespace() + "\\" + action.getName()); return c; } @Override public void managerAdded(ResponseActionManager manager) { if (manager == null) return; manager.addEventListener(this); for (ResponseAction action : manager.getActions()) { actionCreated(manager, action); } } @Override public void managerRemoved(ResponseActionManager manager) { if (manager == null) return; manager.removeEventListener(this); } @Override public void actionCreated(ResponseActionManager manager, ResponseAction action) { try { Config c = getResponseActionInstance(action); ResponseActionInstance instance = PrimitiveConverter.parse(ResponseActionInstance.class, c.getDocument()); for (EventResponseMapping mapping : instance.getEventMappings()) { loadResponse(new ResponseKey(mapping.getCategory(), mapping.getEventSource()), action); } } catch (Exception e) { // ignore if not exists } } @Override public void actionRemoved(ResponseActionManager manager, ResponseAction action) { try { Config c = getResponseActionInstance(action); ResponseActionInstance instance = PrimitiveConverter.parse(ResponseActionInstance.class, c.getDocument()); for (EventResponseMapping mapping : instance.getEventMappings()) { unloadResponse(new ResponseKey(mapping.getCategory(), mapping.getEventSource()), action); } } catch (Exception e) { // ignore if not exists } } private ConfigCollection getCol() { ConfigDatabase db = configManager.getDatabase(); return db.ensureCollection("response_action_instance"); } }