Skip to content
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
6 changes: 6 additions & 0 deletions internal/scan-manager/core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@
<artifactId>powermock-api-mockito</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>${com.sun.mail.javax.mail}</version>
</dependency>
</dependencies>

<build>
Expand Down Expand Up @@ -235,6 +240,7 @@
</org.wso2.security.tools.scanmanager.common.version>
<org.hibernate.core.version>5.4.14.Final</org.hibernate.core.version>
<tomcat.http.port>8081</tomcat.http.port>
<com.sun.mail.javax.mail>1.6.2</com.sun.mail.javax.mail>
</properties>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import org.wso2.security.tools.scanmanager.core.exception.ScanManagerException;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static org.wso2.security.tools.scanmanager.core.util.Constants.DEFAULT_LOG_PAGE_SIZE;
Expand All @@ -36,12 +38,28 @@ public class ScanManagerConfiguration {
private Integer scanPageSize;
private Integer logPageSize;

// Email notification related configurations
private Boolean isNotificationEnabled;
private String notificationSubject;
private String smtpServerHost;
private Integer smtpServerPort;
private String smtpUserName;
private String emailFromaddress;
private List<String> emailCCaddress;

private static final String SCAN_MANAGER_HOST_KEY = "scanManagerHost";
private static final String SCAN_MANAGER_PORT_KEY = "scanManagerPort";
private static final String SCANNER_SERVICE_HOST_KEY = "scannerServiceHost";
private static final String SCANNER_SERVICE_PORT_KEY = "scannerServicePort";
private static final String SCAN_PAGE_SIZE = "scanPageSize";
private static final String LOG_PAGE_SIZE = "logPageSize";
private static final String SMTP_SERVERHOST_KEY = "smtpServerHost";
private static final String SMTP_SERVERPORT_KEY = "smtpServerPort";
private static final String SMTP_USERNAME = "smtpUsername";
private static final String SMTP_EMAIL_FROM_ADDRESS = "emailFromaddress";
private static final String SMTP_EMAIL_CC_ADDRESS = "emailCCaddress";
private static final String IS_NOTIFICATION_ENABLED = "isNotificationEnabled";
private static final String NOTIFICATION_SUBJECT = "notificationSubject";

private static final ScanManagerConfiguration scanManagerConfiguration = new ScanManagerConfiguration();

Expand All @@ -63,6 +81,13 @@ public void initScanConfiguration(Map<String, Object> configObjectMap) throws Sc
Integer scanManagerPort = (Integer) configObjectMap.get(SCAN_MANAGER_PORT_KEY);
String scannerServiceHost = (String) configObjectMap.get(SCANNER_SERVICE_HOST_KEY);
Integer scannerServicePort = (Integer) configObjectMap.get(SCANNER_SERVICE_PORT_KEY);
String smtpServerHost = (String) configObjectMap.get(SMTP_SERVERHOST_KEY);
Integer smtpServerPort = (Integer) configObjectMap.get(SMTP_SERVERPORT_KEY);
String smtpUserName = (String) configObjectMap.get(SMTP_USERNAME);
String smtpEmailFromAddress = (String) configObjectMap.get(SMTP_EMAIL_FROM_ADDRESS);
String smtpEmailCCAddress = (String) configObjectMap.get(SMTP_EMAIL_CC_ADDRESS);
Boolean isNotificationEnabled = (Boolean) configObjectMap.get(IS_NOTIFICATION_ENABLED);
String notificiationSubject = (String) configObjectMap.get(NOTIFICATION_SUBJECT);

if (scanManagerHost != null) {
this.scanManagerHost = scanManagerHost;
Expand All @@ -77,17 +102,36 @@ public void initScanConfiguration(Map<String, Object> configObjectMap) throws Sc
if (scannerServiceHost != null) {
this.scannerServiceHost = scannerServiceHost;
} else {
throw new ScanManagerException("Unable to find scaner service host configuration");
throw new ScanManagerException("Unable to find scanner service host configuration");
}
if (scannerServicePort != null) {
this.scannerServicePort = scannerServicePort;
} else {
throw new ScanManagerException("Unable to find scaner service port configuration");
}
if (smtpServerHost != null || smtpServerPort != null || smtpUserName != null) {
this.smtpServerHost = smtpServerHost;
this.smtpServerPort = smtpServerPort;
this.smtpUserName = smtpUserName;
} else {
throw new ScanManagerException("Unable to find email notification related configuration");
}
if (smtpEmailFromAddress != null) {
this.emailFromaddress = smtpEmailFromAddress;
} else {
throw new ScanManagerException("Unable to find valid email address of sender");
}

// CC email addresses are not mandatory.
if (smtpEmailCCAddress != null) {
this.emailCCaddress = Arrays.asList(smtpEmailCCAddress.trim().split(","));
}

// Not mandatory as there are default values.
this.scanPageSize = (Integer) configObjectMap.get(SCAN_PAGE_SIZE);
this.logPageSize = (Integer) configObjectMap.get(LOG_PAGE_SIZE);
this.isNotificationEnabled = isNotificationEnabled;
this.notificationSubject = notificiationSubject;
}

public String getScanManagerHost() {
Expand Down Expand Up @@ -119,4 +163,32 @@ public Integer getLogPageSize() {
}
return logPageSize;
}

public Boolean getNotificationEnabled() {
return isNotificationEnabled;
}

public String getNotificationSubject() {
return notificationSubject;
}

public String getSmtpServerHost() {
return smtpServerHost;
}

public Integer getSmtpServerPort() {
return smtpServerPort;
}

public String getSmtpUserName() {
return smtpUserName;
}

public String getEmailFromaddress() {
return emailFromaddress;
}

public List<String> getEmailCCaddress() {
return emailCCaddress;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -166,27 +166,26 @@ private Scanner validateScanRequest(ScanManagerScanRequest scanRequest) throws I
/**
* Get the list of available scans by page.
*
* @param page required page number
* @param product product name
* @param page required page number
* @return the requested scans page
*/
@GetMapping(path = "scans")
@ResponseBody
public ResponseEntity<ScanManagerScansResponse> getScans(@RequestParam(name = "page", required = false)
Integer page) {
@GetMapping(path = "scans") @ResponseBody
public ResponseEntity<ScanManagerScansResponse> getScans(@RequestParam("product") String product,
@RequestParam(name = "page", required = false) Integer page) {
Integer scanPageSize = ScanManagerConfiguration.getInstance().getScanPageSize();
if (page == null) {
page = 1; // Initialize to first page if no page number is defined.
}

// Internal page indexing starts at 0
Page<Scan> scansPage = scanService.getAll(page - 1, scanPageSize);
List<ScanExternal> scanExternalList =
scansPage.getContent().parallelStream()
.map(ScanExternal::new)
.collect(Collectors.toList());
return new ResponseEntity<>(new ScanManagerScansResponse(scanExternalList, scansPage.getTotalPages(),
page, scansPage.getSize(), scansPage.hasNext(), scansPage.hasPrevious(), scansPage.isFirst(),
scansPage.isLast()), HttpStatus.OK);
Page<Scan> scansPage = scanService.getScanByProduct(page - 1, scanPageSize, product);
List<ScanExternal> scanExternalList = scansPage.getContent().parallelStream().map(ScanExternal::new)
.collect(Collectors.toList());
return new ResponseEntity<>(
new ScanManagerScansResponse(scanExternalList, scansPage.getTotalPages(), page, scansPage.getSize(),
scansPage.hasNext(), scansPage.hasPrevious(), scansPage.isFirst(), scansPage.isLast()),
HttpStatus.OK);
}

/**
Expand Down Expand Up @@ -258,9 +257,8 @@ public ResponseEntity<List<ScanExternal>> getScansByState(@PathVariable("status"
* @throws ScanManagerException when an error occurs while updating the priority of the scan
* @throws ResourceNotFoundException when unable to find a scan for the given job id
*/
@PostMapping(value = "scans/{jobId}")
public ResponseEntity updateScanPriority(@PathVariable("jobId") String jobId,
@RequestBody ScanPriorityUpdateRequest scanPriorityUpdateRequest)
@PostMapping(value = "scans/{jobId}") public ResponseEntity updateScanPriority(@PathVariable("jobId") String jobId,
@RequestBody ScanPriorityUpdateRequest scanPriorityUpdateRequest)
throws ResourceNotFoundException, ScanManagerException {
Scan scan = scanService.getByJobId(jobId);
if (scan != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,13 @@ public interface ScanDAO extends PagingAndSortingRepository<Scan, String> {
/**
* Get all scans.
*
* @param product product name
* @param pageable page request object
* @return page containing the list of requested scans
*/
public Page<Scan> getAllByOrderBySubmittedTimestampDesc(Pageable pageable);
@Query("select o from Scan o where o.product = :product")
public Page<Scan> getScanByProductByOrderBySubmittedTimestampDesc(@Param("product") String product,
Pageable pageable);

/**
* Get scan by job id.
Expand Down Expand Up @@ -112,4 +115,16 @@ public interface ScanDAO extends PagingAndSortingRepository<Scan, String> {
@Query("select o from Scan o where o.status in :statuses and o.scanner = :scanner and o.product = :product")
public List<Scan> getByStatusInAndScannerAndProduct(@Param("statuses") List<ScanStatus> statuses, @Param(
"scanner") Scanner scanner, @Param("product") String product);

// /**
// * Get logs by scan.
// *
// * @param product scan details
// * @param pageable page information
// * @return list of logs for a given scan
// */
// public Page<Scan> getByScanOrderByTimeStampDesc(String product, Pageable pageable);

@Query("select o from Scan o where o.product = :product")
public List<Scan> getByProduct(@Param("product") String product);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public interface UserDAO extends PagingAndSortingRepository<User, Integer> {
* @param id user id assigned for a user
* @return user object for the given user id
*/
public User getById(String id);
public User getById(int id);

/**
* Get User by username.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
*
* Copyright (c) 2020, WSO2 Inc., WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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 org.wso2.security.tools.scanmanager.core.handler;

import org.wso2.security.tools.scanmanager.common.external.model.Scan;
import org.wso2.security.tools.scanmanager.core.config.ScanManagerConfiguration;
import org.wso2.security.tools.scanmanager.core.config.ScanMangerConfigurationBuilder;
import org.wso2.security.tools.scanmanager.core.exception.ResourceNotFoundException;
import org.wso2.security.tools.scanmanager.core.exception.ScanManagerException;
import org.wso2.security.tools.scanmanager.core.model.Email;
import org.wso2.security.tools.scanmanager.core.util.Util;

import java.util.Arrays;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import static org.wso2.security.tools.scanmanager.core.util.Constants.SMTP_PASSWORD;

/**
* This class provides the implementation for the email notification operations.
*/
public class EmailNotificationHandler implements NotificationHandler {

private static final String EMAIL_TEMPLATE = "emailTemplate.html";

// Place holders used for email template.
private static final String EMAIL_TEMPLATE_SCAN_TITLE_PLACEHOLDER = "{scanTitle}";
private static final String EMAIL_TEMPLATE_JOBID_PLACEHOLDER = "{jobId}";
private static final String EMAIL_TEMPLATE_PRODUCT_NAME_PLACEHOLDER = "{productName}";
private static final String EMAIL_TEMPLATE_USER_NAME_PLACEHOLDER = "{launchedBy}";
private static final String EMAIL_TEMPLATE_SCAN_TYPE_PLACEHOLDER = "{ScannerId}";
private static final String EMAIL_TEMPLATE_SCAN_STATUS_PLACEHOLDER = "{scanStatus}";

@Override public void sendNotification(Scan scan, String toAddress) throws ScanManagerException {

// Set smtp configurations.
Properties props = new Properties();
props.setProperty("mail.smtp.host", ScanManagerConfiguration.getInstance().getSmtpServerHost());
props.setProperty("mail.smtp.port", String.valueOf(ScanManagerConfiguration.getInstance().getSmtpServerPort()));
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.smtp.starttls.enable", "true");
props.setProperty("mail.smtp.ssl.trust", ScanManagerConfiguration.getInstance().getSmtpServerHost());
props.setProperty("mail.debug", "true");

char[] password = ((String) ScanMangerConfigurationBuilder.getConfiguration().get(SMTP_PASSWORD)).toCharArray();
Session session = getSession(props, password);

// Clear credential.
Arrays.fill(password, '0');
try {
Email email = assembleEmail(scan, toAddress);
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(ScanManagerConfiguration.getInstance().getEmailFromaddress()));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(toAddress));

if (email.getCcList() != null && !email.getCcList().isEmpty()) {
for (String ccAddress : email.getCcList()) {
message.addRecipient(Message.RecipientType.CC, new InternetAddress((String) ccAddress));
}
}
message.setSubject(email.getSubject());
message.setContent(email.getBody(), "text/html");
Transport.send(message);
} catch (MessagingException | ResourceNotFoundException e) {
throw new ScanManagerException("Mail sending failed", e);
}
}

/**
* This method use to form complete email.
*
* @param scan object which represents scan
* @param toAddress email address of scan launcher
* @return email object
* @throws ResourceNotFoundException error occurred if email template in not found
*/
private Email assembleEmail(Scan scan, String toAddress) throws ResourceNotFoundException {
Email email = new Email();
email.setFromAddress(ScanManagerConfiguration.getInstance().getEmailFromaddress());
email.setCcList(ScanManagerConfiguration.getInstance().getEmailCCaddress());
email.setSubject(ScanManagerConfiguration.getInstance().getNotificationSubject().concat(" " + scan.getJobId()));
email.setBody(buildEmailBody(scan, scan.getStatus().name(), toAddress));
return email;
}

/**
* This method is used to build email body. This method reads the email template file and replace the relevant
* information from scan object.
*
* @param scan object which represents scan
* @param status status of scan
* @param toAddress email address of scan launcher
* @return email body
* @throws ResourceNotFoundException error occurred if email template file is not found
*/
private String buildEmailBody(Scan scan, String status, String toAddress) throws ResourceNotFoundException {
String htmlTemplate = Util.readHTMLEmailTemplate(EMAIL_TEMPLATE);
String htmlwithContent = htmlTemplate.replace(EMAIL_TEMPLATE_SCAN_TITLE_PLACEHOLDER, scan.getName())
.replace(EMAIL_TEMPLATE_JOBID_PLACEHOLDER, scan.getJobId())
.replace(EMAIL_TEMPLATE_PRODUCT_NAME_PLACEHOLDER, scan.getProduct())
.replace(EMAIL_TEMPLATE_USER_NAME_PLACEHOLDER, toAddress)
.replace(EMAIL_TEMPLATE_SCAN_TYPE_PLACEHOLDER, scan.getScanner().getName())
.replace(EMAIL_TEMPLATE_SCAN_STATUS_PLACEHOLDER, status);
return htmlwithContent;
}

private static Session getSession(Properties props, char[] password) {
return Session.getInstance(props, new Authenticator() {
@Override protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(ScanManagerConfiguration.getInstance().getSmtpUserName(),
String.valueOf(password));
}
});
}
}
Loading