Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OP-21175: Publish user details as events to rabbitmq. #424

Open
wants to merge 1 commit into
base: v4.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion gate-web/gate-web.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ dependencies {


implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-openfeign', version: '2.2.4.RELEASE'

implementation 'org.apache.camel:camel-core:3.14.1'
implementation 'org.apache.camel:camel-rabbitmq:3.14.1'
implementation 'org.apache.camel:camel-jackson:3.14.1'

runtimeOnly "io.spinnaker.kork:kork-runtime"
runtimeOnly "org.springframework.boot:spring-boot-properties-migrator"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2015 OpsMx, Inc.
*
* 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 com.netflix.spinnaker.gate.config;

import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.impl.DefaultCamelContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
@ConditionalOnExpression("${message-broker.enabled:true}")
public class CamelConfig {

@Autowired private UserActivityRouteBuilder userActivityRouteBuilder;

@Bean
public CamelContext camelContext() throws Exception {
CamelContext camelContext = new DefaultCamelContext();
camelContext.addRoutes(userActivityRouteBuilder);
camelContext.getShutdownStrategy().setShutdownNowOnTimeout(true);
camelContext.getShutdownStrategy().setTimeout(5);
camelContext.getShutdownStrategy().setTimeUnit(TimeUnit.SECONDS);
camelContext.start();
return camelContext;
}

@Bean
public ProducerTemplate producerTemplate(CamelContext camelContext) {
return camelContext.createProducerTemplate();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2015 OpsMx, Inc.
*
* 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 com.netflix.spinnaker.gate.config;

public interface CamelRouteConfig {
String getUserActivityQueueEndPoint();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2015 OpsMx, Inc.
*
* 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 com.netflix.spinnaker.gate.config;

import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Data
@Configuration
@ConfigurationProperties(prefix = "message-broker")
@ConditionalOnExpression("${message-broker.enabled:true}")
@EnableConfigurationProperties({
MessageBrokerProperties.class,
MessageBrokerProperties.Endpoint.class
})
public class MessageBrokerProperties {

private boolean enabled;
private String username;
private String password;
private String host;
private String port;
private Endpoint endpoint;

@Data
@Configuration
@ConditionalOnExpression("${message-broker.enabled:true}")
@ConfigurationProperties(prefix = "message-broker.endpoint")
public static class Endpoint {
private String name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2015 OpsMx, Inc.
*
* 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 com.netflix.spinnaker.gate.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConditionalOnExpression("${message-broker.enabled:true}")
@ConditionalOnProperty(value = "message-broker.endpoint.name", havingValue = "rabbitmq")
public class RabbitMQConfig implements CamelRouteConfig {

@Autowired private MessageBrokerProperties messageBrokerProperties;
private static final String isdExchange = "isd.userLoginDetails";
private String directUserActivity = "userLoginDetails";

@Override
public String getUserActivityQueueEndPoint() {
return messageBrokerProperties.getEndpoint().getName()
+ ":"
+ isdExchange
+ "?queue="
+ directUserActivity
+ "&autoDelete=false&routingKey="
+ directUserActivity
+ "&declare=true&durable=true&exchangeType=direct&hostname="
+ messageBrokerProperties.getHost()
+ "&portNumber="
+ messageBrokerProperties.getPort()
+ "&username="
+ messageBrokerProperties.getUsername()
+ "&password="
+ messageBrokerProperties.getPassword();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2015 OpsMx, Inc.
*
* 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 com.netflix.spinnaker.gate.config;

import static com.opsmx.spinnaker.gate.constant.CamelEndpointConstant.directUserActivity;

import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConditionalOnExpression("${message-broker.enabled:true}")
public class UserActivityRouteBuilder extends RouteBuilder {

private final String userActivity = "userActivity";
@Autowired private CamelRouteConfig camelRouteConfig;

@Override
public void configure() throws Exception {

from(directUserActivity)
.id(userActivity)
.to(camelRouteConfig.getUserActivityQueueEndPoint())
.end();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@

public interface AuditHandler {

void publishEvent(AuditEventType auditEventType, Object auditData);
String publishEvent(AuditEventType auditEventType, Object auditData);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

package com.opsmx.spinnaker.gate.audit;

import com.google.gson.Gson;
import com.opsmx.spinnaker.gate.enums.AuditEventType;
import com.opsmx.spinnaker.gate.feignclient.AuditService;
import com.opsmx.spinnaker.gate.model.OesAuditModel;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.cloud.openfeign.EnableFeignClients;
Expand All @@ -28,16 +30,21 @@
@Component
@EnableFeignClients(basePackageClasses = AuditService.class)
@ConditionalOnExpression("${services.auditservice.enabled:true}")
@Slf4j
public class AuditRestApiHandler implements AuditHandler {

@Autowired private AuditService auditService;
Gson gson = new Gson();

@Override
public void publishEvent(AuditEventType auditEventType, Object auditData) {
public String publishEvent(AuditEventType auditEventType, Object auditData) {
OesAuditModel oesAuditModel = new OesAuditModel();
oesAuditModel.setEventId(UUID.randomUUID().toString());
oesAuditModel.setAuditData(auditData);
oesAuditModel.setEventType(auditEventType);
auditService.publishAuditData(oesAuditModel, "OES");
String model = gson.toJson(oesAuditModel, OesAuditModel.class);
log.debug("model: {}", model);
return model;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@

package com.opsmx.spinnaker.gate.audit;

import com.google.gson.Gson;
import com.opsmx.spinnaker.gate.constant.CamelEndpointConstant;
import com.opsmx.spinnaker.gate.enums.AuditEventType;
import com.opsmx.spinnaker.gate.model.AuditData;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import com.opsmx.spinnaker.gate.model.OesAuditModel;
import java.util.*;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.camel.ProducerTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.security.AbstractAuthenticationAuditListener;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.security.authentication.AbstractAuthenticationToken;
Expand All @@ -38,6 +41,9 @@
public class AuthenticationAuditListener extends AbstractAuthenticationAuditListener {

@Autowired private AuditHandler auditHandler;
@Autowired @Lazy private ProducerTemplate template;

Gson gson = new Gson();

@Async
@Override
Expand All @@ -56,11 +62,15 @@ public void onApplicationEvent(AbstractAuthenticationEvent event) {
if (event.getAuthentication().isAuthenticated()
&& event instanceof AuthenticationSuccessEvent) {
log.debug("publishEvent AuthenticationSuccessEvent");
auditHandler.publishEvent(AuditEventType.AUTHENTICATION_SUCCESSFUL_AUDIT, event);
template.asyncSendBody(
CamelEndpointConstant.directUserActivity,
auditHandler.publishEvent(AuditEventType.AUTHENTICATION_SUCCESSFUL_AUDIT, event));
} else if (!event.getAuthentication().isAuthenticated()
&& event instanceof AbstractAuthenticationFailureEvent) {
log.debug("publishEvent AbstractAuthenticationFailureEvent");
auditHandler.publishEvent(AuditEventType.AUTHENTICATION_FAILURE_AUDIT, event);
template.asyncSendBody(
CamelEndpointConstant.directUserActivity,
auditHandler.publishEvent(AuditEventType.AUTHENTICATION_FAILURE_AUDIT, event));
} else if (event instanceof LogoutSuccessEvent) {
if (event
.getAuthentication()
Expand All @@ -73,10 +83,16 @@ public void onApplicationEvent(AbstractAuthenticationEvent event) {
}
log.debug("publishEvent LogoutSuccessEvent");
auditHandler.publishEvent(AuditEventType.SUCCESSFUL_USER_LOGOUT_AUDIT, event);
AbstractAuthenticationToken auth = (AbstractAuthenticationToken) event.getAuthentication();
String name = auth.getName();
template.asyncSendBody(
CamelEndpointConstant.directUserActivity,
getOesAuditModel(
name, event.getTimestamp(), AuditEventType.SUCCESSFUL_USER_LOGOUT_AUDIT));
}

} catch (Exception e) {
log.error("Exception occured while capturing audit events : {}", e);
log.error("Exception occurred while capturing audit events : {}", e);
}
}

Expand All @@ -88,7 +104,23 @@ private void handleAuthenticationEvent(
Optional.ofNullable(auth.getAuthorities()).orElse(new ArrayList<>()).stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());
AuditData data = new AuditData(name, roles);
AuditData data = new AuditData(name, roles, event.getTimestamp());
auditHandler.publishEvent(eventType, data);
template.asyncSendBody(
CamelEndpointConstant.directUserActivity,
getOesAuditModel(name, event.getTimestamp(), eventType));
}

private String getOesAuditModel(String name, Long timestamp, AuditEventType eventType) {
OesAuditModel oesAuditModel = new OesAuditModel();
Map<String, Object> date = new HashMap<>();
date.put("userName", name);
date.put("timestamp", timestamp);
oesAuditModel.setEventId(UUID.randomUUID().toString());
oesAuditModel.setAuditData(date);
oesAuditModel.setEventType(eventType);
String model = gson.toJson(oesAuditModel, OesAuditModel.class);
log.debug("model: {}", model);
return model;
}
}
Loading
Loading