diff --git a/CHANGELOG.md b/CHANGELOG.md index fcb1573ea..181eb85b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ -# UTMStack 11.1.0 +# UTMStack 11.1.1 -These are the release notes for **UTMStack v11.1.0**, highlighting new features, bug fixes, and performance improvements. +These are the release notes for **UTMStack v11.1.1**, highlighting new features, bug fixes, and performance improvements. -## Features +## Fixes +- Improved the module activation and deactivation process to handle missing modules more robustly and prevent errors when activating integrations. -- Introduced SQL query support in LogExplorer, enabling users to execute SQL queries on OpenSearch indices directly from the user interface. -- Added an interactive Adversary View to the Threat Management module, providing a graphical, filterable visualization of relationships between Adversaries, their generated Alerts, and associated Echoes. +## Features +- Enabled inline expand/collapse functionality for alert echo rows. diff --git a/agent/logservice/processor.go b/agent/logservice/processor.go index deda9015e..537e8f922 100644 --- a/agent/logservice/processor.go +++ b/agent/logservice/processor.go @@ -174,8 +174,16 @@ func (l *LogProcessor) CleanCountedLogs() { for range ticker.C { dataRetention, err := GetDataRetention() if err != nil { - utils.Logger.ErrorF("error getting data retention: %s", err) - continue + utils.Logger.ErrorF("error getting data retention: %s, creating default retention file", err) + if err := SetDataRetention(""); err != nil { + utils.Logger.ErrorF("error creating default data retention: %s", err) + continue + } + dataRetention, err = GetDataRetention() + if err != nil { + utils.Logger.ErrorF("error reading newly created data retention: %s", err) + continue + } } l.db.Lock() _, err = l.db.DeleteOld(&models.Log{}, dataRetention) diff --git a/backend/src/main/java/com/park/utmstack/event_processor/EventProcessorManagerService.java b/backend/src/main/java/com/park/utmstack/event_processor/EventProcessorManagerService.java index 2736efaf3..96c3b51d7 100644 --- a/backend/src/main/java/com/park/utmstack/event_processor/EventProcessorManagerService.java +++ b/backend/src/main/java/com/park/utmstack/event_processor/EventProcessorManagerService.java @@ -4,6 +4,8 @@ import com.park.utmstack.domain.application_modules.UtmModule; import com.park.utmstack.domain.application_modules.UtmModuleGroup; import com.park.utmstack.domain.application_modules.enums.ModuleName; +import com.park.utmstack.service.dto.application_modules.ModuleDTO; +import com.park.utmstack.service.dto.application_modules.UtmModuleMapper; import com.park.utmstack.service.web_clients.rest_template.RestTemplateService; import com.park.utmstack.util.CipherUtil; import lombok.RequiredArgsConstructor; @@ -34,7 +36,7 @@ public class EventProcessorManagerService { System.getenv(Constants.ENV_EVENT_PROCESSOR_HOST) + ":" + System.getenv(Constants.ENV_EVENT_PROCESSOR_PORT); - public void updateModule(UtmModule module) { + public void updateModule(ModuleDTO module) { final String ctx = CLASSNAME + ".updateModule"; String url = UriComponentsBuilder @@ -60,10 +62,19 @@ public void updateModule(UtmModule module) { public void decryptModuleConfig (UtmModule module){ Set groups = module.getModuleGroups(); + decryptModuleGroupsConfig(groups, module.getModuleName()); + } + + public void decryptModuleConfig (ModuleDTO moduleDTO){ + Set groups = moduleDTO.getModuleGroups(); + decryptModuleGroupsConfig(groups, moduleDTO.getModuleName()); + } + + private void decryptModuleGroupsConfig(Set groups, ModuleName moduleName) { groups.forEach((gp) -> { gp.getModuleGroupConfigurations().forEach((gpc) -> { if ((gpc.getConfDataType().equals(Constants.CONF_TYPE_PASSWORD) && StringUtils.hasText(gpc.getConfValue())) - || (gpc.getConfDataType().equals(Constants.CONF_TYPE_FILE) && StringUtils.hasText(gpc.getConfValue())) && typeFileNeedsDecryptList.contains(module.getModuleName())) { + || (gpc.getConfDataType().equals(Constants.CONF_TYPE_FILE) && StringUtils.hasText(gpc.getConfValue())) && typeFileNeedsDecryptList.contains(moduleName)) { gpc.setConfValue(CipherUtil.decrypt(gpc.getConfValue(), System.getenv(Constants.ENV_ENCRYPTION_KEY))); } }); diff --git a/backend/src/main/java/com/park/utmstack/repository/application_modules/UtmModuleRepository.java b/backend/src/main/java/com/park/utmstack/repository/application_modules/UtmModuleRepository.java index bab778349..274b3b355 100644 --- a/backend/src/main/java/com/park/utmstack/repository/application_modules/UtmModuleRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/application_modules/UtmModuleRepository.java @@ -10,6 +10,7 @@ import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Optional; /** @@ -19,8 +20,8 @@ @Repository public interface UtmModuleRepository extends JpaRepository, JpaSpecificationExecutor { - @EntityGraph(attributePaths = {"moduleGroups", "moduleGroups.moduleGroupConfigurations"}) - UtmModule findByServerIdAndModuleName(Long serverId, ModuleName shortName); + @EntityGraph(attributePaths = {"server", "filters", "moduleGroups", "moduleGroups.moduleGroupConfigurations"}) + Optional findByServerIdAndModuleName(Long serverId, ModuleName shortName); Integer countAllByModuleNameAndModuleActiveIsTrue(ModuleName shortName); diff --git a/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleGroupConfigurationService.java b/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleGroupConfigurationService.java index b5823b743..1311b5f4d 100644 --- a/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleGroupConfigurationService.java +++ b/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleGroupConfigurationService.java @@ -8,8 +8,9 @@ import com.park.utmstack.repository.application_modules.UtmModuleRepository; import com.park.utmstack.event_processor.EventProcessorManagerService; import com.park.utmstack.util.CipherUtil; +import com.park.utmstack.util.exceptions.ApiException; import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.SerializationUtils; +import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @@ -53,11 +54,11 @@ public void createConfigurationKeys(List keys) thro * @param keys List of configuration keys to save * @throws Exception In case of any error */ - public void updateConfigurationKeys(Long moduleId, List keys) throws Exception { + public UtmModule updateConfigurationKeys(Long moduleId, List keys) throws Exception { final String ctx = CLASSNAME + ".updateConfigurationKeys"; try { if (CollectionUtils.isEmpty(keys)) - return; + throw new ApiException("No configuration keys were provided to update", HttpStatus.BAD_REQUEST); for (UtmModuleGroupConfiguration key : keys) { if (key.getConfRequired() && !StringUtils.hasText(key.getConfValue())) throw new Exception(String.format("No value was found for required configuration: %1$s (%2$s)", key.getConfName(), key.getConfKey())); @@ -67,14 +68,14 @@ public void updateConfigurationKeys(Long moduleId, List needRestartModules = Arrays.asList(ModuleName.AWS_IAM_USER, ModuleName.AZURE, - ModuleName.GCP, ModuleName.SOPHOS); + ModuleName.GCP, ModuleName.SOPHOS); - moduleRepository.findById(moduleId).ifPresent(module -> { - module.setNeedsRestart(needRestartModules.contains(module.getModuleName())); - moduleRepository.save(module); - UtmModule detached = SerializationUtils.clone(module); - eventProcessorManagerService.updateModule(detached); - }); + return moduleRepository.findById(moduleId) + .map(module -> { + module.setNeedsRestart(needRestartModules.contains(module.getModuleName())); + return moduleRepository.save(module); + }) + .orElseThrow(() -> new ApiException(String.format("Module with ID %1$s not found", moduleId), HttpStatus.NOT_FOUND)); } catch (Exception e) { throw new Exception(ctx + ": " + e.getMessage()); } diff --git a/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleService.java b/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleService.java index 4ff889fdb..65c978fe3 100644 --- a/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleService.java +++ b/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleService.java @@ -8,12 +8,10 @@ import com.park.utmstack.repository.UtmModuleGroupRepository; import com.park.utmstack.repository.application_modules.UtmModuleRepository; import com.park.utmstack.service.UtmMenuService; -import com.park.utmstack.event_processor.EventProcessorManagerService; import com.park.utmstack.service.dto.application_modules.ModuleActivationDTO; import com.park.utmstack.service.index_pattern.UtmIndexPatternService; import com.park.utmstack.service.logstash_filter.UtmLogstashFilterService; import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.SerializationUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; @@ -24,7 +22,6 @@ import java.util.List; import java.util.NoSuchElementException; -import java.util.Objects; import java.util.Optional; /** @@ -43,7 +40,6 @@ public class UtmModuleService { private final UtmIndexPatternService indexPatternService; private final UtmLogstashFilterService logstashFilterService; private final UtmModuleGroupRepository moduleGroupRepository; - private final EventProcessorManagerService eventProcessorManagerService; /** @@ -56,30 +52,29 @@ public class UtmModuleService { public UtmModule activateDeactivate(ModuleActivationDTO moduleActivationDTO) { final String ctx = CLASSNAME + ".activateDeactivate"; - long serverId = moduleActivationDTO.getServerId(); - ModuleName nameShort = moduleActivationDTO.getModuleName(); - boolean activationStatus = moduleActivationDTO.getActivationStatus(); + long serverId = moduleActivationDTO.getServerId(); + ModuleName nameShort = moduleActivationDTO.getModuleName(); + boolean activationStatus = moduleActivationDTO.getActivationStatus(); - UtmModule module = moduleRepository.findByServerIdAndModuleName(serverId, nameShort); + return moduleRepository.findByServerIdAndModuleName(serverId, nameShort) + .map(module -> { + module.setModuleActive(activationStatus); + module = moduleRepository.save(module); - if (Objects.isNull(module)) - throw new NoSuchElementException(String.format("Definition of the module %1$s not found for the server ID %2$s", nameShort.name(), serverId)); + List nonRemovableConf = List.of(ModuleName.SOC_AI); - module.setModuleActive(activationStatus); - module = moduleRepository.save(module); + if (!activationStatus && !nonRemovableConf.contains(nameShort)) + moduleGroupRepository.deleteAllByModuleId(module.getId()); - List nonRemovableConf = List.of(ModuleName.SOC_AI); + enableDisableModuleMenus(nameShort, activationStatus); + enableDisableModuleIndexPatterns(nameShort, activationStatus); + enableDisableModuleFilter(nameShort, activationStatus); - if (!activationStatus && !nonRemovableConf.contains(nameShort)) - moduleGroupRepository.deleteAllByModuleId(module.getId()); - - enableDisableModuleMenus(nameShort, activationStatus); - enableDisableModuleIndexPatterns(nameShort, activationStatus); - enableDisableModuleFilter(nameShort, activationStatus); - UtmModule detached = SerializationUtils.clone(module); - eventProcessorManagerService.updateModule(detached); - - return module; + return module; + }) + .orElseThrow(() -> new NoSuchElementException( + String.format("Definition of the module %1$s not found for the server ID %2$s", nameShort.name(), serverId) + )); } private void enableDisableModuleMenus(ModuleName nameShort, Boolean activationStatus) { @@ -186,11 +181,12 @@ public Optional findOne(Long id) { public UtmModule findByServerIdAndModuleName(Long serverId, ModuleName shortName) { final String ctx = CLASSNAME + ".findByServerIdAndModuleName"; - try { - return moduleRepository.findByServerIdAndModuleName(serverId, shortName); - } catch (Exception e) { - throw new RuntimeException(ctx + ": " + e.getMessage()); - } + + return moduleRepository.findByServerIdAndModuleName(serverId, shortName) + .orElseThrow(() -> new NoSuchElementException( + String.format("%s: The module %s not found for the server ID %s", ctx, shortName.name(), serverId) + )); + } public boolean isModuleActive(ModuleName shortName) { diff --git a/backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleGroupConfigurationResource.java b/backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleGroupConfigurationResource.java index 8a7026bbd..b5daf4548 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleGroupConfigurationResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleGroupConfigurationResource.java @@ -2,10 +2,14 @@ import com.park.utmstack.aop.logging.AuditEvent; import com.park.utmstack.domain.application_events.enums.ApplicationEventType; +import com.park.utmstack.domain.application_modules.UtmModule; import com.park.utmstack.domain.application_modules.UtmModuleGroupConfiguration; +import com.park.utmstack.event_processor.EventProcessorManagerService; import com.park.utmstack.service.application_events.ApplicationEventService; import com.park.utmstack.service.application_modules.UtmModuleGroupConfigurationService; import com.park.utmstack.service.dto.application_modules.GroupConfigurationDTO; +import com.park.utmstack.service.dto.application_modules.ModuleDTO; +import com.park.utmstack.service.dto.application_modules.UtmModuleMapper; import com.park.utmstack.web.rest.util.HeaderUtil; import lombok.RequiredArgsConstructor; import org.slf4j.Logger; @@ -27,6 +31,8 @@ public class UtmModuleGroupConfigurationResource { private final Logger log = LoggerFactory.getLogger(UtmModuleGroupConfigurationResource.class); private final UtmModuleGroupConfigurationService moduleGroupConfigurationService; private final ApplicationEventService applicationEventService; + private final UtmModuleMapper utmModuleMapper; + private final EventProcessorManagerService eventProcessorManagerService; @PutMapping("/module-group-configurations/update") @@ -39,7 +45,10 @@ public class UtmModuleGroupConfigurationResource { public ResponseEntity updateConfiguration(@Valid @RequestBody GroupConfigurationDTO body) { final String ctx = CLASSNAME + ".updateConfiguration"; try { - moduleGroupConfigurationService.updateConfigurationKeys(body.getModuleId(), body.getKeys()); + UtmModule module = moduleGroupConfigurationService.updateConfigurationKeys(body.getModuleId(), body.getKeys()); + ModuleDTO moduleDTO = utmModuleMapper.toDto(module, false); + eventProcessorManagerService.updateModule(moduleDTO); + return ResponseEntity.ok().build(); } catch (Exception e) { String msg = ctx + ": " + e.getMessage(); diff --git a/backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleResource.java b/backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleResource.java index 6870a60c3..1fe1ef8ae 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleResource.java @@ -13,15 +13,10 @@ import com.park.utmstack.service.application_modules.UtmModuleQueryService; import com.park.utmstack.service.application_modules.UtmModuleService; import com.park.utmstack.event_processor.EventProcessorManagerService; -import com.park.utmstack.service.dto.application_modules.CheckRequirementsResponse; -import com.park.utmstack.service.dto.application_modules.ModuleActivationDTO; -import com.park.utmstack.service.dto.application_modules.ModuleDTO; -import com.park.utmstack.service.dto.application_modules.UtmModuleCriteria; +import com.park.utmstack.service.dto.application_modules.*; import com.park.utmstack.util.ResponseUtil; import com.park.utmstack.web.rest.util.PaginationUtil; -import lombok.Getter; import lombok.RequiredArgsConstructor; -import lombok.Setter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; @@ -48,8 +43,8 @@ public class UtmModuleResource { private final UtmModuleQueryService utmModuleQueryService; private final ApplicationEventService eventService; private final UtmServerRepository utmServerRepository; - // List of configurations of type 'file' that needs content decryption private final EventProcessorManagerService eventProcessorManagerService; + private final UtmModuleMapper utmModuleMapper; @@ -60,14 +55,19 @@ public class UtmModuleResource { successMessage = "Module activated/deactivated successfully" ) @PutMapping("/utm-modules/activateDeactivate") - public ResponseEntity activateDeactivate(@RequestParam Long serverId, + public ResponseEntity activateDeactivate(@RequestParam Long serverId, @RequestParam ModuleName nameShort, @RequestParam Boolean activationStatus) { - return ResponseEntity.ok(moduleService.activateDeactivate(ModuleActivationDTO.builder() - .serverId(serverId) - .moduleName(nameShort) - .activationStatus(activationStatus) - .build())); + + UtmModule module = moduleService.activateDeactivate(ModuleActivationDTO.builder() + .serverId(serverId) + .moduleName(nameShort) + .activationStatus(activationStatus) + .build()); + ModuleDTO moduleDTO = utmModuleMapper.toDto(module, false); + eventProcessorManagerService.updateModule(moduleDTO); + + return ResponseEntity.ok(moduleDTO); } /** diff --git a/frontend/src/app/data-management/adversary-management/adversary-alerts-graph/adversary-alerts-graph.component.html b/frontend/src/app/data-management/adversary-management/adversary-alerts-graph/adversary-alerts-graph.component.html index 571cbe9df..3ab70dbb3 100644 --- a/frontend/src/app/data-management/adversary-management/adversary-alerts-graph/adversary-alerts-graph.component.html +++ b/frontend/src/app/data-management/adversary-management/adversary-alerts-graph/adversary-alerts-graph.component.html @@ -1,4 +1,4 @@ -
+
+
+
+
+
+
+ {{ alertDetail.name }} +
+
+ + +
+
+ + +
+
diff --git a/frontend/src/app/data-management/adversary-management/adversary-alerts-graph/adversary-alerts-graph.component.ts b/frontend/src/app/data-management/adversary-management/adversary-alerts-graph/adversary-alerts-graph.component.ts index 72e66bc8d..b2163cb91 100644 --- a/frontend/src/app/data-management/adversary-management/adversary-alerts-graph/adversary-alerts-graph.component.ts +++ b/frontend/src/app/data-management/adversary-management/adversary-alerts-graph/adversary-alerts-graph.component.ts @@ -1,5 +1,8 @@ -import {Component, EventEmitter, Input, OnChanges, OnInit, Output} from '@angular/core'; +import {Component, Input, OnChanges} from '@angular/core'; import {ECharts} from 'echarts'; +import {UtmAlertType} from '../../../shared/types/alert/utm-alert.type'; +import {Side} from '../../../shared/types/event/event'; +import {EventDataTypeEnum} from '../../alert-management/shared/enums/event-data-type.enum'; import {AdversaryAlerts} from '../models'; @Component({ @@ -13,6 +16,9 @@ export class AdversaryAlertsGraphComponent implements OnChanges { baseHeight = 600; nodeGap = 6; option: any; + viewAlertDetail = false; + alertDetail: UtmAlertType; + EventDataTypeEnum = EventDataTypeEnum; ngOnChanges(): void { if (this.data) { @@ -20,7 +26,7 @@ export class AdversaryAlertsGraphComponent implements OnChanges { } } - onChartInit(chart: ECharts) { + onChartInit(chart: any) { chart.on('mouseover', (params) => { if (params.dataType === 'node') { @@ -35,11 +41,72 @@ export class AdversaryAlertsGraphComponent implements OnChanges { }); chart.on('click', (params) => { - if (params.dataType === 'node') { + if (params.componentType === 'series' + && params.seriesType === 'sankey' + && (params.dataType === 'node' || params.dataType === 'label' || params.dataType === 'edge')) { + this.alertDetail = params.data.meta.alert || null; + this.viewAlertDetail = !!this.alertDetail; } }); } + private getGraphicElements() { + const sankey = { + left: 10, + right: 180, + top: 20, + bottom: 40 + }; + + const chartElement = document.querySelector('.chart-container'); + const chartContainerWidth = chartElement ? chartElement.clientWidth : 1000; + const columnWidth = chartContainerWidth / 3; + + const depthPositions = [ + { left: sankey.left, width: columnWidth }, + { left: sankey.left + columnWidth, width: columnWidth }, + { left: sankey.left + (columnWidth * 2), width: columnWidth } + ]; + + const graphicElements: any[] = []; + const labels = ['Adversary', 'Alerts', 'Echoes']; + const colors = [ + { fill: 'rgba(31, 119, 180, 0.06)', text: '#1F77B4' }, + { fill: 'rgba(255, 127, 14, 0.06)', text: '#FF7F0E' }, + { fill: 'rgba(44, 160, 44, 0.06)', text: '#2CA02C' } + ]; + + depthPositions.forEach((pos, index) => { + const color = colors[index]; + + graphicElements.push({ + type: 'rect', + left: pos.left, + top: sankey.top, + shape: { width: pos.width - 10, height: this.chartHeight - sankey.top - sankey.bottom }, + style: { + fill: color.fill, + stroke: 'none' + } + }); + + graphicElements.push({ + type: 'text', + left: pos.left + (pos.width / 2), + top: 0, + style: { + text: labels[index], + fontSize: 12, + fontWeight: 'bold', + fill: color.text, + textAlign: 'center' + } + }); + }); + + return graphicElements; + } + private buildOption(adversaryAlerts: AdversaryAlerts[]): any { const nodes: any[] = []; const links: any[] = []; @@ -112,6 +179,10 @@ export class AdversaryAlertsGraphComponent implements OnChanges { depth: 1, symbolSize: getNodeSize(childCount), meta: { + alert: { + ...alert, + hasChildren: true + }, severity: alert.severityLabel, timestamp: alert.timestamp, dataSource: alert.dataSource @@ -133,7 +204,7 @@ export class AdversaryAlertsGraphComponent implements OnChanges { alertWithChildren.children.forEach(child => { const childKey = nodeKey(child.id, child.name); - const childLabel = truncate(child.name); + const childLabel = truncate(this.getLabel(child)); const childSeverityColor = severityColors[child.severityLabel.toLowerCase()] || severityColors.default; if (!nodeSet.has(childKey)) { @@ -149,6 +220,7 @@ export class AdversaryAlertsGraphComponent implements OnChanges { depth: 2, symbolSize: getNodeSize(1), meta: { + alert: child, severity: child.severityLabel, timestamp: child.timestamp, dataSource: child.dataSource @@ -165,6 +237,9 @@ export class AdversaryAlertsGraphComponent implements OnChanges { color: gradientColor(severityColor, childSeverityColor), opacity: 0.5, curveness: 0.2 + }, + meta: { + alert: child, } }); }); @@ -190,6 +265,7 @@ export class AdversaryAlertsGraphComponent implements OnChanges { `; } }, + graphic: this.getGraphicElements(), series: [{ type: 'sankey', orient: 'horizontal', @@ -214,9 +290,10 @@ export class AdversaryAlertsGraphComponent implements OnChanges { layoutIterations: 32, left: 20, right: 180, - top: 20, - bottom: 40, + top: 30, + bottom: 50, label: { + show: true, position: 'right', fontSize: 10, formatter: (params: any) => params.name.split('::')[1] || params.name @@ -224,4 +301,24 @@ export class AdversaryAlertsGraphComponent implements OnChanges { }] }; } + + private getLabel(alert: UtmAlertType) { + if (alert.target) { + const target: any = alert.target as Side; + if (target.ip) { + return target.ip; + } else if (target.host) { + return target.host; + } else if (target.user) { + return target.user; + } + } else { + return alert.dataSource; + } + } + + closeDetail() { + this.alertDetail = null; + this.viewAlertDetail = false; + } } diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-description/alert-description.component.html b/frontend/src/app/data-management/alert-management/shared/components/alert-description/alert-description.component.html index 649e7cab1..eda12ec34 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-description/alert-description.component.html +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-description/alert-description.component.html @@ -1,4 +1,4 @@ -
+
Summary:

diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-echoes-timeline/alert-echoes-timeline.component.ts b/frontend/src/app/data-management/alert-management/shared/components/alert-echoes-timeline/alert-echoes-timeline.component.ts index a3d73ca80..5828950f6 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-echoes-timeline/alert-echoes-timeline.component.ts +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-echoes-timeline/alert-echoes-timeline.component.ts @@ -85,7 +85,6 @@ export class AlertEchoesTimelineComponent implements OnInit { group.startTimestamp = Math.floor(timestamps.reduce((sum, t) => sum + t, 0) / timestamps.length); const rep = group.items[0] || ({} as any); // representative item - console.log('group', group, rep); seriesData.push({ value: [ group.startTimestamp, // 0: timestamp (start of minute) diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-echoes/alert-echoes.component.html b/frontend/src/app/data-management/alert-management/shared/components/alert-echoes/alert-echoes.component.html index 40d8f6292..b5e2630f2 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-echoes/alert-echoes.component.html +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-echoes/alert-echoes.component.html @@ -15,29 +15,29 @@ - - - + + + - - - - - + + + + + - - -
- - -
- - + + +
+ + +
+ +
@@ -58,14 +58,28 @@
- + - + + + + + + + + + diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-echoes/alert-echoes.component.ts b/frontend/src/app/data-management/alert-management/shared/components/alert-echoes/alert-echoes.component.ts index 581be64eb..998692c10 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-echoes/alert-echoes.component.ts +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-echoes/alert-echoes.component.ts @@ -2,7 +2,7 @@ import {HttpResponse} from '@angular/common/http'; import {Component, Input, OnInit} from '@angular/core'; import {UtmToastService} from '../../../../../shared/alert/utm-toast.service'; import { - ALERT_ADVERSARY_FIELD, ALERT_ECHOES_FIELDS, ALERT_PARENT_ID, + ALERT_ADVERSARY_FIELD, ALERT_ECHOES_FIELDS, ALERT_FIELDS, ALERT_PARENT_ID, ALERT_STATUS_FIELD_AUTO, ALERT_TAGS_FIELD, ALERT_TARGET_FIELD, ALERT_TIMESTAMP_FIELD, FALSE_POSITIVE_OBJECT } from '../../../../../shared/constants/alert/alert-field.constant'; @@ -94,4 +94,8 @@ export class AlertEchoesComponent implements OnInit { this.itemsPerPage = $event; this.loadChildrenAlerts(); } + + protected viewDetail(alert: UtmAlertType) { + alert.expanded = !alert.expanded; + } } diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-view-detail/alert-view-detail.component.html b/frontend/src/app/data-management/alert-management/shared/components/alert-view-detail/alert-view-detail.component.html index 201fcd787..01e704b1c 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-view-detail/alert-view-detail.component.html +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-view-detail/alert-view-detail.component.html @@ -97,7 +97,7 @@
-
+
Tags: 
-
+
Incident response:  (); ALERT_NAME = ALERT_NAME_FIELD; diff --git a/frontend/src/app/shared/components/utm/util/utm-console-check/utm-console-check.component.ts b/frontend/src/app/shared/components/utm/util/utm-console-check/utm-console-check.component.ts index c47f685ff..322d3a7f5 100644 --- a/frontend/src/app/shared/components/utm/util/utm-console-check/utm-console-check.component.ts +++ b/frontend/src/app/shared/components/utm/util/utm-console-check/utm-console-check.component.ts @@ -22,11 +22,13 @@ export class UtmConsoleCheckComponent implements OnInit { } ngOnInit() { - this.getAgent(this.hostname).then(value => { - this.agent = value; - this.canConnect = this.agent.status === AgentStatusEnum.ONLINE; - this.emptyValue.emit(!this.canConnect); - }); + this.getAgent(this.hostname) + .then(value => { + this.agent = value; + this.canConnect = this.agent && this.agent.status === AgentStatusEnum.ONLINE; + this.emptyValue.emit(!this.canConnect); + }) + .catch(error => this.canConnect = false); } getAgent(hostname: string): Promise { diff --git a/installer/templates/front-end.go b/installer/templates/front-end.go index c64a5f2a5..52be99b6a 100644 --- a/installer/templates/front-end.go +++ b/installer/templates/front-end.go @@ -15,9 +15,19 @@ const FrontEnd string = `server { set $utmstack_agent_manager http://agentmanager:8080; set $utmstack_backend_auth http://backend:8080/api/authenticate; set $utmstack_ws http://backend:8080/ws; + set $utmstack_saml2 http://backend:8080/login/saml2/; set $shared_key {{.SharedKey}}; set $shared_key_header $http_x_shared_key; + location /login/saml2/ { + proxy_pass $utmstack_saml2 + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + location /api { proxy_pass $utmstack_backend; proxy_set_header Host $host;