Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
4e9f284
Fix cors
strug May 29, 2025
5ee0e47
Fix cors
strug May 29, 2025
ca988c8
Fix cors
strug May 29, 2025
53ec0d0
Fix cors
strug May 29, 2025
c2cad39
Fix cors
strug May 29, 2025
22edc4a
Fix cors
strug May 29, 2025
97230e2
Fix cors
strug May 30, 2025
3d5109f
Fix tests
strug May 30, 2025
be832ef
After review
strug Jun 3, 2025
3127732
Merge remote-tracking branch 'origin/master' into ft/up-libs
strug Aug 5, 2025
e7b0713
Fix security
strug Aug 5, 2025
24752b8
Fix secure
strug Aug 5, 2025
60a9f7e
Fix secure
strug Aug 5, 2025
ce93aa1
Fix secure
strug Aug 5, 2025
ad64ef9
Fix secure
strug Aug 5, 2025
a1ebb99
Fix secure
strug Aug 5, 2025
44abc46
Merge remote-tracking branch 'origin/master' into ft/security
strug Aug 5, 2025
d2f2ca5
Fix secure
strug Aug 6, 2025
176ab3c
Fix secure
strug Aug 6, 2025
9ca6cc2
Fix secure
strug Aug 6, 2025
5e6d907
Fix secure
strug Aug 6, 2025
740c5f6
Fix secure
strug Aug 6, 2025
615ac95
Fix secure
strug Aug 6, 2025
9d3bb1b
Fix secure
strug Aug 6, 2025
ba28add
Fix secure
strug Aug 6, 2025
c3d0dac
Fix secure
strug Aug 6, 2025
37708eb
Fix secure
strug Aug 6, 2025
f76cef5
Fix secure
strug Aug 6, 2025
7a7abbf
Fix secure
strug Aug 6, 2025
04e4212
Fix sec
strug Aug 11, 2025
2d4268d
Merge
strug Aug 27, 2025
ec319ef
Merge remote-tracking branch 'origin/master' into epic/sec-test
strug Aug 29, 2025
36ea011
Bump libs
strug Aug 29, 2025
467eba9
Bump libs
strug Aug 29, 2025
2aefce2
Bump libs
strug Aug 29, 2025
37b2d97
Bump libs
strug Aug 29, 2025
fcffd30
Bump libs
strug Aug 29, 2025
e1c896d
Bump libs
strug Aug 29, 2025
72c38ec
Bump libs
strug Aug 29, 2025
0a9d7dd
Bump libs
strug Aug 29, 2025
d9f636d
Bump libs
strug Aug 29, 2025
65725d2
Bump libs
strug Aug 29, 2025
58760b2
Bump libs
strug Aug 29, 2025
6ea9b8f
Bump libs
strug Aug 29, 2025
5be5907
Bump libs
strug Aug 29, 2025
ea29b58
Bump libs
strug Aug 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:
branches:
- 'master'
- 'ft/up-woody'
- 'epic/*'

jobs:
build-and-deploy:
Expand Down
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

<!--kafka-->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.vality.fraudbusters.management.config;

import dev.vality.fraudbusters.management.config.converter.JwtAuthConverter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
Expand All @@ -11,8 +12,6 @@
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
Expand All @@ -27,24 +26,14 @@
public class SecurityConfig {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtAuthConverter jwtAuthConverter)
throws Exception {
return http.authorizeHttpRequests(
(authorize) -> authorize
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.requestMatchers(HttpMethod.POST, "/**").authenticated()
.requestMatchers(HttpMethod.PUT, "/**").authenticated()
.requestMatchers(HttpMethod.GET, "/**").authenticated()
.requestMatchers(HttpMethod.DELETE, "/**").authenticated()
.requestMatchers(HttpMethod.GET, "/health/liveness").permitAll()
.requestMatchers(HttpMethod.GET, "/health/readiness").permitAll()
.requestMatchers(HttpMethod.GET, "/actuator/prometheus").permitAll()
.requestMatchers(HttpMethod.GET, "/actuator/health").permitAll()
.requestMatchers(HttpMethod.POST, "/**").authenticated()
.requestMatchers(HttpMethod.PUT, "/**").authenticated()
.requestMatchers(HttpMethod.DELETE, "/**").authenticated()
.anyRequest().authenticated())
.csrf(csrf -> csrf.requireCsrfProtectionMatcher(new KeycloakCsrfRequestMatcher()))
.anyRequest().permitAll())
.csrf((csrf) -> csrf.requireCsrfProtectionMatcher(new KeycloakCsrfRequestMatcher()))
.cors(c -> c.configurationSource(corsConfigurationSource()))
.oauth2ResourceServer(server -> server.jwt(token -> token.jwtAuthenticationConverter(jwtAuthConverter)))
.exceptionHandling(exceptions -> exceptions
.authenticationEntryPoint(new CustomAuthenticationEntryPoint())
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package dev.vality.fraudbusters.management.config.converter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Component
public class JwtAuthConverter implements Converter<Jwt, AbstractAuthenticationToken> {

private static final String principleAttribute = "preferred_username";
private static final String resourceAttribute = "resource_access";

@Override
public AbstractAuthenticationToken convert(Jwt jwt) {
return new JwtAuthenticationToken(
jwt,
new HashSet<>(extractResourceRoles(jwt)),
getPrincipleClaimName(jwt)
);
}

private Collection<? extends GrantedAuthority> extractResourceRoles(Jwt token) {
if (token.getClaim(resourceAttribute) == null) {
return Set.of();
}
Map<String, Object> resourceAccess = token.getClaim(resourceAttribute);
if (resourceAccess.isEmpty()) {
return Set.of();
}

return resourceAccess.values().stream()
.map(resourceAccessInfo -> (Map<String, Object>) resourceAccessInfo)
.flatMap(resourceAccessInfo -> ((Collection<String>) resourceAccessInfo.get("roles")).stream())
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toSet());
}

private String getPrincipleClaimName(Jwt jwt) {
return jwt.getClaim(principleAttribute);
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
package dev.vality.fraudbusters.management.utils;

import dev.vality.fraudbusters.management.config.converter.JwtAuthConverter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.security.Principal;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserInfoService {

private final JwtAuthConverter jwtAuthConverter;

public static final String UNKNOWN = "UNKNOWN";

public String getUserName() {
var authentication = SecurityContextHolder.getContext().getAuthentication();
log.info("authentication: {}", authentication);
if (authentication == null || authentication.getPrincipal() == null) {
return UNKNOWN;
}
return ((Principal) authentication.getPrincipal()).getName();
}

public String getUserName(Principal principal) {
if (principal == null || !StringUtils.hasText(principal.getName())) {
return UNKNOWN;
}
return principal.getName();
return jwtAuthConverter.convert((org.springframework.security.oauth2.jwt.Jwt) authentication.getPrincipal())
.getName();
}
}
9 changes: 9 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ spring:
output:
ansi:
enabled: always
security:
oauth2:
resourceserver:
url: https://auth.domain
jwt:
realm: internal
issuer-uri: >
${spring.security.oauth2.resourceserver.url}/auth/realms/
${spring.security.oauth2.resourceserver.jwt.realm}
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: org.postgresql.Driver
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import dev.vality.damsel.wb_list.ListType;
import dev.vality.dao.DaoException;
import dev.vality.fraudbusters.management.config.converter.JwtAuthConverter;
import dev.vality.fraudbusters.management.converter.candidate.ChargebacksToFraudDataCandidatesConverter;
import dev.vality.fraudbusters.management.converter.candidate.WbListCandidateToWbListRecordConverter;
import dev.vality.fraudbusters.management.converter.payment.*;
Expand Down Expand Up @@ -32,6 +33,7 @@
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
Expand Down Expand Up @@ -60,7 +62,8 @@
CountInfoUtils.class, CountInfoApiUtils.class, CsvPaymentCountInfoParser.class,
WbListRecordsModelToWbListRecordConverter.class, PaymentsListsService.class, ListRowValidator.class})
@EnableAutoConfiguration(exclude = {FlywayAutoConfiguration.class, JooqAutoConfiguration.class,
ManagementWebSecurityAutoConfiguration.class, SecurityAutoConfiguration.class})
ManagementWebSecurityAutoConfiguration.class, SecurityAutoConfiguration.class,
OAuth2ResourceServerAutoConfiguration.class})
public class ExceptionApplicationTest {

public static final String ID_TEST = "42";
Expand All @@ -72,9 +75,12 @@ public class ExceptionApplicationTest {

@Value("${kafka.topic.wblist.event.sink}")
public String topicEventSink;

@MockitoBean
public AuditService auditService;
@MockitoBean
public JwtAuthConverter jwtAuthConverter;
@MockitoBean
public WbListCommandService wbListCommandService;
@MockitoBean
public PaymentListRecordToRowConverter paymentListRecordToRowConverter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
Expand All @@ -49,7 +50,7 @@
FlywayAutoConfiguration.class,
JooqAutoConfiguration.class,
ManagementWebSecurityAutoConfiguration.class,
SecurityAutoConfiguration.class})
SecurityAutoConfiguration.class, OAuth2ResourceServerAutoConfiguration.class})
public class WbListApplicationTest {

public static final String BASE_URL = "http://localhost:";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
Expand All @@ -30,7 +31,8 @@
@SpringBootTest
@AutoConfigureMockMvc
@EnableAutoConfiguration(exclude = {FlywayAutoConfiguration.class, JooqAutoConfiguration.class,
ManagementWebSecurityAutoConfiguration.class, SecurityAutoConfiguration.class})
ManagementWebSecurityAutoConfiguration.class, SecurityAutoConfiguration.class,
OAuth2ResourceServerAutoConfiguration.class})
class AuditResourceTest {

private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateTimeUtils.YYYY_MM_DD_HH_MM_SS);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.vality.fraudbusters.management.resource;

import dev.vality.fraudbusters.management.config.converter.JwtAuthConverter;
import dev.vality.fraudbusters.management.converter.payment.TemplateModelToTemplateConverterImpl;
import dev.vality.fraudbusters.management.dao.GroupDao;
import dev.vality.fraudbusters.management.dao.TemplateDao;
Expand All @@ -26,6 +27,7 @@
import org.springframework.boot.test.autoconfigure.jooq.JooqTest;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.bean.override.mockito.MockitoBean;

import java.time.LocalDateTime;
import java.util.ArrayList;
Expand Down Expand Up @@ -58,6 +60,8 @@ public class PaymentEmulateResourceTest {
PaymentReferenceDao referenceDao;
@Autowired
TemplateDao templateDao;
@MockitoBean
JwtAuthConverter jwtAuthConverter;

@Test
void getRulesByPartyAndShop() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
Expand All @@ -35,7 +36,8 @@
@SpringBootTest
@AutoConfigureMockMvc
@EnableAutoConfiguration(exclude = {FlywayAutoConfiguration.class, JooqAutoConfiguration.class,
ManagementWebSecurityAutoConfiguration.class, SecurityAutoConfiguration.class})
ManagementWebSecurityAutoConfiguration.class, SecurityAutoConfiguration.class,
OAuth2ResourceServerAutoConfiguration.class})
class PaymentDataSetsResourceTest {

@Autowired
Expand All @@ -57,8 +59,8 @@ void getCheckedDataSet() throws Exception {
.andExpect(status().isOk())
.andExpect(content()
.json("{\"id\":\"null\",\"testDataSetId\":\"null\",\"template\":null," +
"\"rows\":[],\"createdAt\":null,\"checkingTimestamp\":null," +
"\"initiator\":null,\"merchantInfo\":{\"partyId\":null,\"shopId\":null}}"));
"\"rows\":[],\"createdAt\":null,\"checkingTimestamp\":null," +
"\"initiator\":null,\"merchantInfo\":{\"partyId\":null,\"shopId\":null}}"));

verify(paymentsDataSetService, times(1)).getCheckedDataSet(id);
}
Expand All @@ -72,8 +74,8 @@ void filterDataSets() throws Exception {
.andExpect(status().isOk())
.andExpect(content()
.json("{\"continuationId\":null,\"result\":" +
"[{\"id\":null,\"name\":null,\"rows\":[]," +
"\"lastModificationAt\":null,\"lastModificationInitiator\":null}]}"));
"[{\"id\":null,\"name\":null,\"rows\":[]," +
"\"lastModificationAt\":null,\"lastModificationInitiator\":null}]}"));

verify(paymentsDataSetService, times(1)).filterDataSets(any(), any(), any());
}
Expand All @@ -87,7 +89,7 @@ void getDataSet() throws Exception {
.andExpect(status().isOk())
.andExpect(content()
.json("{\"id\":null,\"name\":null,\"rows\":[]," +
"\"lastModificationAt\":null,\"lastModificationInitiator\":null}"));
"\"lastModificationAt\":null,\"lastModificationInitiator\":null}"));

verify(paymentsDataSetService, times(1)).getDataSet(id);
}
Expand Down
Loading
Loading