Skip to content

Commit

Permalink
Merge pull request #267 from reportportal/EPMRPP-85164-AUTH
Browse files Browse the repository at this point in the history
EPMRPP-85164 || Send Create SAML user events via Rabbit MQ to DB and logs
  • Loading branch information
rkukharenka authored Aug 2, 2023
2 parents 23fbbb0 + 6ac6afc commit 12a9f78
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 4 deletions.
6 changes: 4 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ dependencies {
compile 'com.epam.reportportal:commons-rules'
compile 'com.epam.reportportal:commons-model'
} else {
compile 'com.github.reportportal:commons-dao:5c8efca'
compile 'com.github.reportportal:commons-dao:e29f869'
compile 'com.github.reportportal:commons-rules:331c402'
compile 'com.github.reportportal:commons-model:d61b714'
compile 'com.github.reportportal:commons-model:ea14e51'
}

//Fix CVE-2021-41079, CVE-2022-23181, CVE-2021-33037, CVE-2021-30640, CVE-2022-42252
Expand All @@ -76,6 +76,7 @@ dependencies {
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.springframework.boot:spring-boot-starter-actuator'
compile 'org.springframework.boot:spring-boot-starter-security'
compile 'org.springframework.boot:spring-boot-starter-amqp'

///// Security
//https://nvd.nist.gov/vuln/detail/CVE-2020-5407 AND https://nvd.nist.gov/vuln/detail/CVE-2020-5408
Expand All @@ -102,6 +103,7 @@ dependencies {
compile 'org.yaml:snakeyaml:1.32'
compile 'org.hibernate:hibernate-core:5.4.24.Final'
compile 'org.springframework:spring-core:5.3.20'
compile "com.rabbitmq:http-client:2.1.0.RELEASE"
}

processResources {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.epam.reportportal.auth.config.rabbit;

import com.epam.ta.reportportal.exception.ReportPortalException;
import com.epam.ta.reportportal.ws.model.ErrorType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.http.client.Client;
import java.net.URI;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@EnableRabbit
@Configuration
public class RabbitMqConfig {

private final ObjectMapper objectMapper;

public RabbitMqConfig(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}

@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter(objectMapper);
}

@Bean
public ConnectionFactory connectionFactory(@Value("${rp.amqp.api-address}") String apiAddress,
@Value("${rp.amqp.addresses}") URI addresses,
@Value("${rp.amqp.base-vhost}") String virtualHost) {
try {
Client client = new Client(apiAddress);
client.createVhost(virtualHost);
} catch (Exception e) {
throw new ReportPortalException(ErrorType.UNCLASSIFIED_REPORT_PORTAL_ERROR,
"Unable to create RabbitMq virtual host: " + e.getMessage()
);
}
final CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(addresses);
cachingConnectionFactory.setVirtualHost(virtualHost);
return cachingConnectionFactory;
}

@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(jsonMessageConverter());
return rabbitTemplate;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.epam.reportportal.auth.event;

import com.epam.reportportal.auth.event.activity.ActivityEvent;
import com.epam.ta.reportportal.entity.activity.Activity;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;

/**
* Activity Event Handler catch events after commit, transforms to Activity and send to queue.
*
* @author Ryhor_Kukharenka
*/
@Component
public class ActivityEventHandler {

private static final String EXCHANGE_ACTIVITY = "activity";
private final RabbitTemplate rabbitTemplate;

public ActivityEventHandler(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}

@EventListener
@TransactionalEventListener
public void onApplicationEvent(ActivityEvent event) {
Activity activity = event.toActivity();
String key = generateKey(activity);

rabbitTemplate.convertAndSend(EXCHANGE_ACTIVITY, key, activity);
}

private String generateKey(Activity activity) {
return String.format("activity.%d.%s.%s",
activity.getProjectId(),
activity.getObjectType(),
activity.getEventName());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.epam.reportportal.auth.event.activity;

import com.epam.ta.reportportal.entity.activity.Activity;

public interface ActivityEvent {

/**
* Method for transform Event to Activity.
*
* @return Activity entity
*/
Activity toActivity();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.epam.reportportal.auth.event.activity;

import com.epam.ta.reportportal.builder.ActivityBuilder;
import com.epam.ta.reportportal.entity.activity.Activity;
import com.epam.ta.reportportal.entity.activity.ActivityAction;
import com.epam.ta.reportportal.entity.activity.EventAction;
import com.epam.ta.reportportal.entity.activity.EventObject;
import com.epam.ta.reportportal.entity.activity.EventPriority;
import com.epam.ta.reportportal.entity.activity.EventSubject;

/**
* Event publish when user is created.
*
* @author Ryhor_Kukharenka
*/
public class UserCreatedEvent implements ActivityEvent {

private final Long userId;
private final String userLogin;

public UserCreatedEvent(Long userId, String userLogin) {
this.userId = userId;
this.userLogin = userLogin;
}

@Override
public Activity toActivity() {
return new ActivityBuilder()
.addCreatedNow()
.addAction(EventAction.CREATE)
.addEventName(ActivityAction.CREATE_USER.getValue())
.addPriority(EventPriority.HIGH)
.addObjectId(userId)
.addObjectName(userLogin)
.addObjectType(EventObject.USER)
.addSubjectName("Auth Service")
.addSubjectType(EventSubject.APPLICATION)
.get();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static com.epam.reportportal.auth.util.AuthUtils.CROP_DOMAIN;
import static com.epam.reportportal.auth.util.AuthUtils.NORMALIZE_STRING;

import com.epam.reportportal.auth.event.activity.UserCreatedEvent;
import com.epam.reportportal.auth.integration.AbstractUserReplicator;
import com.epam.reportportal.auth.integration.AuthIntegrationType;
import com.epam.reportportal.auth.integration.parameter.SamlParameter;
Expand All @@ -42,6 +43,7 @@
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
Expand All @@ -52,24 +54,28 @@
* @author Yevgeniy Svalukhin
*/
@Component
@Transactional
public class SamlUserReplicator extends AbstractUserReplicator {

private final IntegrationTypeRepository integrationTypeRepository;
private final IntegrationRepository integrationRepository;

private final ApplicationEventPublisher eventPublisher;

@Autowired
public SamlUserReplicator(UserRepository userRepository, ProjectRepository projectRepository,
PersonalProjectService personalProjectService, UserBinaryDataService userBinaryDataService,
IntegrationTypeRepository integrationTypeRepository,
IntegrationRepository integrationRepository, ContentTypeResolver contentTypeResolver) {
IntegrationRepository integrationRepository, ContentTypeResolver contentTypeResolver,
ApplicationEventPublisher eventPublisher) {
super(userRepository, projectRepository, personalProjectService, userBinaryDataService,
contentTypeResolver
);
this.integrationTypeRepository = integrationTypeRepository;
this.integrationRepository = integrationRepository;
this.eventPublisher = eventPublisher;
}

@Transactional
public User replicateUser(ReportPortalSamlAuthentication samlAuthentication) {
String userName = CROP_DOMAIN.apply(samlAuthentication.getPrincipal());
Optional<User> userOptional = userRepository.findByLogin(userName);
Expand Down Expand Up @@ -115,9 +121,16 @@ public User replicateUser(ReportPortalSamlAuthentication samlAuthentication) {

userRepository.save(user);

publishUserCreatedEvent(user);

return user;
}

private void publishUserCreatedEvent(User user) {
UserCreatedEvent userCreatedEvent = new UserCreatedEvent(user.getId(), user.getLogin());
eventPublisher.publishEvent(userCreatedEvent);
}

private void populateUserDetails(User user, List<Attribute> details) {
String email = NORMALIZE_STRING.apply(
findAttributeValue(details, UserAttribute.EMAIL.toString(), String.class));
Expand Down
12 changes: 12 additions & 0 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,18 @@ rp:
feature:
flags:

amqp:
addresses: amqp://${rp.amqp.user}:${rp.amqp.pass}@${rp.amqp.host}:${rp.amqp.port}
api-address: http://${rp.amqp.apiuser}:${rp.amqp.apipass}@${rp.amqp.host}:${rp.amqp.apiport}/api
base-vhost: /
host: rabbitmq
port: 5672
user:
pass:
apiport: 15672
apiuser:
apipass:

datastore:
default:
path: /data/storage
Expand Down

0 comments on commit 12a9f78

Please sign in to comment.