Skip to content

Commit 5352d90

Browse files
committed
Merge remote-tracking branch 'origin/v11' into backlog/extend-visualization-creation-flow-to-include-SQL
# Conflicts: # backend/src/main/resources/config/liquibase/master.xml
2 parents 022a050 + 5f17d81 commit 5352d90

37 files changed

Lines changed: 1243 additions & 749 deletions

CHANGELOG.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# UTMStack 11.1.4 – Release Notes
1+
# UTMStack 11.1.5 – Release Notes
22

3-
The **UTMStack v11.1.4** update delivers important fixes and usability improvements to enhance stability and user experience.
3+
The **UTMStack v11.1.5** update delivers important fixes and usability improvements to enhance stability and user experience.
44

55
## Improvements & Fixes
6-
- Refined the styling of download links to improve clarity and accessibility.
7-
- Resolved a syntax error in the UTMStack installation command, ensuring smoother setup.
8-
- Corrected the display of pipeline card statuses and improved accuracy of event processing counts.
6+
- Standardized `utm_visualization` field names by replacing legacy O365 keys with new conventions.
7+
- Enhanced responsive behavior for TFA enrollment components based on viewport height.
8+

backend/src/main/java/com/park/utmstack/config/Constants.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ public final class Constants {
166166
// Application version file
167167
public static final String APP_VERSION_FILE = "/updates/version.json";
168168

169+
public static final String ADMIN_EMAIL = "admin@localhost";
170+
171+
169172
private Constants() {
170173
}
171174
}

backend/src/main/java/com/park/utmstack/security/jwt/TokenProvider.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,10 @@ public boolean validateToken(String authToken) {
121121
}
122122

123123
public boolean shouldBypassTfa(HttpServletRequest request) {
124-
boolean bypassSwagger = Boolean.parseBoolean(request.getHeader(Constants.TFA_EXEMPTION_HEADER));
125-
126124
boolean forceTfaAuth = Boolean.parseBoolean(
127125
Optional.ofNullable(System.getenv(Constants.ENV_TFA_ENABLE)).orElse("true")
128126
);
129-
130-
return bypassSwagger || !forceTfaAuth;
127+
return !forceTfaAuth;
131128
}
132129

133130
}

backend/src/main/java/com/park/utmstack/security/saml/Saml2LoginSuccessHandler.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.park.utmstack.security.saml;
22

3+
import com.park.utmstack.domain.User;
34
import com.park.utmstack.repository.UserRepository;
45
import com.park.utmstack.security.jwt.TokenProvider;
56
import lombok.RequiredArgsConstructor;
@@ -21,6 +22,7 @@
2122
import java.net.URI;
2223
import java.util.Collection;
2324
import java.util.Objects;
25+
import java.util.Optional;
2426

2527
import static com.park.utmstack.config.Constants.FRONT_BASE_URL;
2628

@@ -50,33 +52,25 @@ public void onAuthenticationSuccess(HttpServletRequest request,
5052
String frontBaseUrl = scheme + "://" + host;
5153

5254
Saml2AuthenticatedPrincipal samlUser = (Saml2AuthenticatedPrincipal) authentication.getPrincipal();
53-
var roles = samlUser.getAttribute("roles");
54-
5555
String username = samlUser.getName();
5656

57-
if (roles == null || ((Collection<?>) roles).isEmpty() || userRepository.findOneByLogin(username).isEmpty()) {
58-
log.error("{}: Attempted SAML2 login with invalid roles or non-existing user account.", username);
59-
failureHandler.onAuthenticationFailure(request, response,
60-
new BadCredentialsException("The provided credentials do not match any active user account or the account lacks required roles."));
61-
return;
62-
}
57+
User user = userRepository.findOneByLogin(username)
58+
.orElseThrow(() -> new BadCredentialsException("The provided credentials do not match any active user account."));
6359

64-
Collection<? extends GrantedAuthority> authorities = Objects.requireNonNull(samlUser.getAttribute("roles"))
60+
Collection<? extends GrantedAuthority> authorities = Objects.requireNonNull(user.getAuthorities())
6561
.stream()
6662
.map(Objects::toString)
6763
.filter(r -> r.startsWith("ROLE_"))
6864
.map(SimpleGrantedAuthority::new)
6965
.toList();
7066

7167
UsernamePasswordAuthenticationToken auth =
72-
new UsernamePasswordAuthenticationToken(username, null, authorities);
68+
new UsernamePasswordAuthenticationToken((Object) username, null, authorities);
7369

7470
SecurityContextHolder.getContext().setAuthentication(auth);
7571

76-
// Generate JWT
7772
String token = tokenProvider.createToken(auth, false, true);
7873

79-
// Redirect to frontend with token
8074
URI redirectUri = UriComponentsBuilder.fromUriString(frontBaseUrl)
8175
.path("/")
8276
.queryParam("token", token)

backend/src/main/java/com/park/utmstack/service/dto/jwt/LoginResponseDTO.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ public class LoginResponseDTO {
1414
private String method;
1515
private String token;
1616
private long tfaExpiresInSeconds;
17+
boolean firstLogin;
1718
}
1819

backend/src/main/java/com/park/utmstack/service/threat_management/AdversaryAlertsService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ public class AdversaryAlertsService {
2727
private final ElasticsearchService elasticsearchService;
2828

2929
public List<AdversaryAlertsResponseDto> fetchAdversaryAlerts(List<FilterType> filters){
30+
31+
if(!elasticsearchService.indexExist(V11_ALERTS_INDEX_PATTERN)) {
32+
return Collections.emptyList();
33+
}
34+
3035
SearchRequest request = SearchRequest.of(s -> s
3136
.index(V11_ALERTS_INDEX_PATTERN)
3237
.query(SearchUtil.toQuery(filters))

backend/src/main/java/com/park/utmstack/web/rest/UserJWTController.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import javax.validation.Valid;
4343
import java.util.Map;
4444

45+
import static com.park.utmstack.config.Constants.ADMIN_EMAIL;
46+
4547
/**
4648
* Controller to authenticate users.
4749
*/
@@ -94,7 +96,7 @@ public ResponseEntity<LoginResponseDTO> authorize(@Valid @RequestBody LoginVM lo
9496

9597
boolean isTfaSetup = isTfaEnabled && user.getTfaMethod() != null && !user.getTfaMethod().isEmpty() && !isAuth;
9698
Map<String, Object> args = logContextBuilder.buildArgs(request);
97-
Long tfaExpiresInSeconds = 0L;
99+
long tfaExpiresInSeconds = 0L;
98100

99101
if (isTfaSetup) {
100102
tfaExpiresInSeconds = tfaService.generateChallenge(user);
@@ -120,6 +122,7 @@ public ResponseEntity<LoginResponseDTO> authorize(@Valid @RequestBody LoginVM lo
120122
.tfaConfigured(isTfaSetup)
121123
.forceTfa(!isAuth)
122124
.tfaExpiresInSeconds(tfaExpiresInSeconds)
125+
.firstLogin(user.getEmail().equals(ADMIN_EMAIL))
123126
.build();
124127

125128
return ResponseEntity.ok(response);

backend/src/main/java/com/park/utmstack/web/rest/threat_management/AdversaryAlertsResource.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class AdversaryAlertsResource {
2424

2525
@PostMapping("/alerts")
2626
public ResponseEntity<List<AdversaryAlertsResponseDto>> search(@RequestBody(required = false) List<FilterType> filters) {
27+
2728
List<AdversaryAlertsResponseDto> responseDto = adversaryAlertsService.fetchAdversaryAlerts(filters);
2829

2930
if (responseDto.isEmpty())
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<databaseChangeLog
3+
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
6+
7+
<changeSet id="20251218001" author="Manuel Abascal">
8+
9+
<sql dbms="postgresql" splitStatements="true" stripComments="true">
10+
<![CDATA[
11+
12+
UPDATE utm_visualization
13+
SET
14+
filters = REPLACE(
15+
REPLACE(
16+
REPLACE(
17+
REPLACE(
18+
REPLACE(filters, 'log.o365.Operation.keyword', 'action.keyword'),
19+
'log.o365.ClientIP.keyword', 'log.clientIP.keyword'
20+
),
21+
'log.o365.UserId.keyword', 'origin.user.keyword'
22+
),
23+
'log.o365.ResultStatus.keyword', 'actionResult.keyword'
24+
),
25+
'log.o365.LogonError.keyword', 'log.logonError.keyword'
26+
)
27+
WHERE filters IS NOT NULL;
28+
29+
UPDATE utm_visualization
30+
SET
31+
aggregation = REPLACE(
32+
REPLACE(
33+
REPLACE(
34+
REPLACE(
35+
REPLACE(aggregation, 'log.o365.Operation.keyword', 'action.keyword'),
36+
'log.o365.ClientIP.keyword', 'log.clientIP.keyword'
37+
),
38+
'log.o365.UserId.keyword', 'origin.user.keyword'
39+
),
40+
'log.o365.ResultStatus.keyword', 'actionResult.keyword'
41+
),
42+
'log.o365.LogonError.keyword', 'log.logonError.keyword'
43+
)
44+
WHERE aggregation IS NOT NULL;
45+
46+
47+
48+
UPDATE utm_visualization
49+
SET
50+
filters = REPLACE(
51+
REPLACE(
52+
REPLACE(
53+
REPLACE(
54+
REPLACE(
55+
REPLACE(filters, 'log.o365.Workload.keyword', 'log.Workload.keyword'),
56+
'log.o365.Workload', 'log.Workload'
57+
),
58+
'log.o365.Verdict.keyword', 'emailVerdict.keyword'
59+
),
60+
'log.o365.SenderIp.keyword', 'origin.ip.keyword'
61+
),
62+
'log.o365.Recipients.keyword', 'log.Recipients.keyword'
63+
),
64+
'log.o365.Subject.keyword', 'log.Subject.keyword'
65+
)
66+
WHERE filters IS NOT NULL;
67+
68+
UPDATE utm_visualization
69+
SET
70+
aggregation = REPLACE(
71+
REPLACE(
72+
REPLACE(
73+
REPLACE(
74+
REPLACE(
75+
REPLACE(aggregation, 'log.o365.Workload.keyword', 'log.Workload.keyword'),
76+
'log.o365.Workload', 'log.Workload'
77+
),
78+
'log.o365.Verdict.keyword', 'emailVerdict.keyword'
79+
),
80+
'log.o365.SenderIp.keyword', 'origin.ip.keyword'
81+
),
82+
'log.o365.Recipients.keyword', 'log.Recipients.keyword'
83+
),
84+
'log.o365.Subject.keyword', 'log.Subject.keyword'
85+
)
86+
WHERE aggregation IS NOT NULL;
87+
88+
]]>
89+
</sql>
90+
</changeSet>
91+
</databaseChangeLog>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<databaseChangeLog
3+
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
6+
7+
<changeSet id="20251218002" author="Manuel Abascal">
8+
9+
<sql dbms="postgresql" splitStatements="true" stripComments="true">
10+
<![CDATA[
11+
12+
UPDATE utm_dashboard
13+
SET filters = REPLACE(filters, '"indexPattern":"log-o365-', '"indexPattern":"v11-log-o365-');
14+
15+
UPDATE utm_dashboard
16+
SET filters = REPLACE(filters, '"indexPattern":"alert-', '"indexPattern":"v11-alert-');
17+
18+
UPDATE utm_dashboard
19+
SET filters = REPLACE(filters, '"indexPattern":"log-firewall-meraki-', '"indexPattern":"v11-log-firewall-meraki-');
20+
21+
UPDATE utm_dashboard
22+
SET filters = REPLACE(filters, '"indexPattern":"log-wineventlog-', '"indexPattern":"v11-log-wineventlog-');
23+
24+
UPDATE utm_dashboard
25+
SET filters = REPLACE(filters, '"indexPattern":"log-linux-', '"indexPattern":"v11-log-linux-');
26+
27+
UPDATE utm_dashboard
28+
SET filters = REPLACE(filters, '"indexPattern":"log-cisco-switch-', '"indexPattern":"v11-log-cisco-switch-');
29+
30+
UPDATE utm_dashboard
31+
SET filters = REPLACE(filters, '"indexPattern":"log-firewall-cisco-asa-', '"indexPattern":"v11-log-firewall-cisco-asa-');
32+
33+
UPDATE utm_dashboard
34+
SET filters = REPLACE(filters, '"indexPattern":"log-aws-', '"indexPattern":"v11-log-aws-');
35+
36+
UPDATE utm_dashboard
37+
SET filters = REPLACE(filters, '"field":"ogx.wineventlog.event_data.SubjectUserName.keyword"', '"field":"log.winlogEventDataSubjectUserName"');
38+
39+
UPDATE utm_dashboard
40+
SET filters = REPLACE(filters, '"field":"logx.tenant.keyword"', '"field":"tenantId.keyword"');
41+
42+
UPDATE utm_dashboard
43+
SET filters = REPLACE(filters, '"field":"logx.o365.UserId.keyword"', '"field":"origin.user.keyword"');
44+
45+
UPDATE utm_dashboard
46+
SET filters = REPLACE(filters, '"field":"logx.linux.host.name.keyword"', '"field":"origin.host.keyword"');
47+
48+
UPDATE utm_dashboard
49+
SET filters = REPLACE(filters, '"field":"logx.wineventlog.event_data.TargetUserName.keyword"', '"field":"target.user.keyword"');
50+
51+
UPDATE utm_dashboard
52+
SET filters = REPLACE(filters, '"field":"log.winlogEventDataSubjectUserName"', '"field":"log.winlogEventDataSubjectUserName.keyword"');
53+
54+
]]>
55+
</sql>
56+
</changeSet>
57+
</databaseChangeLog>

0 commit comments

Comments
 (0)