Переглянути джерело

Use subuser on Sendgrid instead of delegate service

pull/61/head
Kristijan Mitrovic 4 роки тому
джерело
коміт
8c03b0e1ec
7 змінених файлів з 164 додано та 8 видалено
  1. +5
    -0
      bubble-server/pom.xml
  2. +13
    -0
      bubble-server/src/main/java/bubble/cloud/CloudServiceDriver.java
  3. +116
    -0
      bubble-server/src/main/java/bubble/cloud/email/SendgridSmtpEmailDriver.java
  4. +22
    -4
      bubble-server/src/main/java/bubble/cloud/email/SmtpEmailDriver.java
  5. +2
    -3
      bubble-server/src/main/java/bubble/dao/account/AccountDAO.java
  6. +5
    -0
      bubble-server/src/main/java/bubble/model/cloud/CloudService.java
  7. +1
    -1
      bubble-server/src/main/resources/models/defaults/cloudService.json

+ 5
- 0
bubble-server/pom.xml Переглянути файл

@@ -276,6 +276,11 @@
</exclusions>
</dependency>

<dependency>
<groupId>com.sendgrid</groupId>
<artifactId>sendgrid-java</artifactId>
<version>4.6.5</version>
</dependency>
</dependencies>

<build>


+ 13
- 0
bubble-server/src/main/java/bubble/cloud/CloudServiceDriver.java Переглянути файл

@@ -10,6 +10,7 @@ import bubble.model.cloud.CloudService;
import bubble.server.BubbleConfiguration;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.jknack.handlebars.Handlebars;
import lombok.NonNull;
import org.cobbzilla.util.handlebars.HandlebarsUtil;
import org.cobbzilla.util.http.HttpResponseBean;
import org.cobbzilla.util.http.HttpUtil;
@@ -28,6 +29,18 @@ public interface CloudServiceDriver {

default boolean disableDelegation () { return false; }

@NonNull default CloudService setupDelegatedCloudService(@NonNull final BubbleConfiguration configuration,
@NonNull final CloudService parentService,
@NonNull final CloudService delegatedService) {
return delegatedService.setDelegated(parentService.getUuid())
.setCredentials(CloudCredentials.delegate(configuration.getThisNode(), configuration))
.setTemplate(false);
}

default void postServiceDelete(@NonNull final CloudService service) {
// noop
}

void setConfig(JsonNode json, CloudService cloudService);

static <T extends CloudServiceDriver> T setupDriver(BubbleConfiguration configuration, T driver) {


+ 116
- 0
bubble-server/src/main/java/bubble/cloud/email/SendgridSmtpEmailDriver.java Переглянути файл

@@ -0,0 +1,116 @@
package bubble.cloud.email;

import bubble.dao.account.AccountDAO;
import bubble.dao.cloud.CloudServiceDAO;
import bubble.model.account.Account;
import bubble.model.cloud.CloudCredentials;
import bubble.model.cloud.CloudService;
import bubble.server.BubbleConfiguration;
import com.sendgrid.Method;
import com.sendgrid.Request;
import com.sendgrid.Response;
import com.sendgrid.SendGrid;
import lombok.*;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;

import static bubble.cloud.storage.StorageCryptStream.MIN_DISTINCT_LENGTH;
import static bubble.cloud.storage.StorageCryptStream.MIN_KEY_LENGTH;
import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
import static java.net.HttpURLConnection.HTTP_OK;
import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.json.JsonUtil.EMPTY_JSON;
import static org.cobbzilla.util.json.JsonUtil.json;
import static org.cobbzilla.util.security.CryptoUtil.generatePassword;
import static org.cobbzilla.util.string.StringUtil.repeat;

public class SendgridSmtpEmailDriver extends SmtpEmailDriver {

private static final String PARAM_PARENT_SERVICE = "parentService";

@Autowired private AccountDAO accountDAO;
@Autowired private CloudServiceDAO serviceDAO;

@Override protected boolean isServiceCompatible() { return this.config.getHost().equals(SENDGRID_SMTP); }

/**
* Build username which will be used for Subuser created on SendGrid's service for specified Account's object.
*/
@NonNull private String sgUsername(@NonNull final CloudService delegatedService) {
return delegatedService.getShortId();
}

@Override @NonNull public CloudService setupDelegatedCloudService(@NonNull final BubbleConfiguration configuration,
@NonNull final CloudService parentService,
@NonNull final CloudService delegatedService) {
final CloudCredentials parentCredentials = parentService.getCredentials();
if (parentService.delegated() || !parentCredentials.getParam(PARAM_HOST).contains(".sendgrid.net")) {
return super.setupDelegatedCloudService(configuration, parentService, delegatedService);
}

final SendGrid sg = new SendGrid(parentCredentials.getParam(PARAM_PASSWORD));
final Account accountWithDelegate = accountDAO.findByUuid(delegatedService.getAccount());
final String user = sgUsername(delegatedService);
String password = generatePassword(MIN_KEY_LENGTH, MIN_DISTINCT_LENGTH);
final CreateSubuserRequest data = new CreateSubuserRequest(user, accountWithDelegate.getEmail(), password,
new String[]{});
final Request req = new Request();
req.setMethod(Method.POST);
req.setEndpoint("subusers");
req.setBody(json(data));

final Response res;
try {
res = sg.api(req);
} catch (IOException e) {
return die("Cannot create SendGrid Subuser", e);
}
if (res.getStatusCode() != HTTP_OK) {
return die("Wrong response when creating SendGrid Subuser: " + res.getStatusCode() + " : " + res.getBody());
}

delegatedService.setDelegated(null).setTemplate(false);
delegatedService.getCredentials()
.setParam(PARAM_USER, user)
.setParam(PARAM_PASSWORD, password)
.setParam(PARAM_PARENT_SERVICE, parentService.getUuid());
password = repeat("x", MIN_KEY_LENGTH); // Override password (in memory) just in case
return delegatedService;
}

@Override public void postServiceDelete(@NonNull final CloudService service) {
final String parentServiceUuid = service.getCredentials().getParam(PARAM_PARENT_SERVICE);
if (parentServiceUuid == null) return;

final CloudService parentService = serviceDAO.findByUuid(parentServiceUuid);
if (parentService == null) return;

final SendGrid sg = new SendGrid(parentService.getCredentials().getParam(PARAM_PASSWORD));
final String sgUserToDelete = sgUsername(service);

final Request req = new Request();
req.setMethod(Method.DELETE);
req.setEndpoint("subusers/" + sgUserToDelete);
req.setBody(EMPTY_JSON);

final Response res;
try {
res = sg.api(req);
} catch (IOException e) {
die("Cannot delete SendGrid Subuser " + sgUserToDelete, e);
return;
}
if (res.getStatusCode() != HTTP_NO_CONTENT) {
die("Wrong response when creating SendGrid Subuser: " + res.getStatusCode() + " : " + res.getBody());
}
}

@AllArgsConstructor @NoArgsConstructor
private class CreateSubuserRequest {
@Getter @Setter private String username;
@Getter @Setter private String email;
@Getter @Setter private String password;
@Getter @Setter private String[] ips;
}
}

+ 22
- 4
bubble-server/src/main/java/bubble/cloud/email/SmtpEmailDriver.java Переглянути файл

@@ -10,19 +10,30 @@ import bubble.cloud.email.mock.MockMailSender;
import bubble.model.account.Account;
import bubble.model.account.AccountContact;
import bubble.model.account.message.AccountMessage;
import bubble.model.cloud.CloudService;
import bubble.server.BubbleConfiguration;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.mail.sender.SmtpMailSender;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;

import static org.cobbzilla.util.daemon.ZillaRuntime.die;

@Slf4j
public class SmtpEmailDriver extends CloudServiceDriverBase<EmailDriverConfig> implements EmailServiceDriver {
protected static final String SENDGRID_SMTP = "smtp.sendgrid.net";

private static final List<String> SEPARATE_DRIVERS_SMTPS = new ArrayList<>();
static { SEPARATE_DRIVERS_SMTPS.add(SENDGRID_SMTP); }

private static final String PARAM_USER = "user";
private static final String PARAM_PASSWORD = "password";
private static final String PARAM_HOST = "host";
private static final String PARAM_PORT = "port";
protected static final String PARAM_USER = "user";
protected static final String PARAM_PASSWORD = "password";
protected static final String PARAM_HOST = "host";
protected static final String PARAM_PORT = "port";

@Autowired @Getter protected BubbleConfiguration configuration;

@@ -38,6 +49,13 @@ public class SmtpEmailDriver extends CloudServiceDriverBase<EmailDriverConfig> i
return smtpSender;
}

@Override public void setConfig(JsonNode json, CloudService cloudService) {
super.setConfig(json, cloudService);
if (!isServiceCompatible()) die("Specified SmtpEmailDriver is not compatible with given config");
}

protected boolean isServiceCompatible() { return !SEPARATE_DRIVERS_SMTPS.contains(this.config.getHost()); }

@Override public boolean send(Account account, AccountMessage message, AccountContact contact) {
return EmailServiceDriver.send(this, account, message, contact);
}


+ 2
- 3
bubble-server/src/main/java/bubble/dao/account/AccountDAO.java Переглянути файл

@@ -229,12 +229,11 @@ public class AccountDAO extends AbstractCRUDDAO<Account> implements SqlViewSearc
.setTemplate(false);

} else {
return accountEntity.setDelegated(parentEntity.getUuid())
.setCredentials(CloudCredentials.delegate(configuration.getThisNode(), configuration))
.setTemplate(false);
return driver.setupDelegatedCloudService(configuration, parentEntity, accountEntity);
}
}
}

@Override public void postCreate(CloudService parentEntity, CloudService accountEntity) {
clouds.put(parentEntity.getUuid(), accountEntity);
}


+ 5
- 0
bubble-server/src/main/java/bubble/model/cloud/CloudService.java Переглянути файл

@@ -25,6 +25,7 @@ import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.cobbzilla.util.collection.ArrayUtil;
@@ -342,4 +343,8 @@ public class CloudService extends IdentifiableBaseParentEntity implements Accoun
}
return errors;
}

@PostRemove void onPostRemove(@NonNull final CloudService service) {
service.getDriver().postServiceDelete(service);
}
}

+ 1
- 1
bubble-server/src/main/resources/models/defaults/cloudService.json Переглянути файл

@@ -72,7 +72,7 @@
{
"name": "SmtpServer",
"type": "email",
"driverClass": "bubble.cloud.email.SmtpEmailDriver",
"driverClass": "{{BUBBLE_SMTP_DRIVER}}",
"driverConfig": {
"tlsEnabled": true
},


Завантаження…
Відмінити
Зберегти