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

adding possibility to add SMTP configuration #122

Merged
merged 6 commits into from
Jun 14, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
15 changes: 15 additions & 0 deletions example/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ resource "keycloak_realm" "test" {
enabled = true
display_name = "foo"

smtp_server {
host = "mysmtphost.com"
port = 25
from_display_name = "Tom"
from = "[email protected]"
reply_to_display_name = "Tom"
reply_to = "[email protected]"
auth = true
user = "tom"
password = "tom"
ssl = true
starttls = true
envelope_from= "[email protected]"
}

account_theme = "base"

access_code_lifespan = "30m"
Expand Down
26 changes: 26 additions & 0 deletions keycloak/realm.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ type Realm struct {
LoginWithEmailAllowed bool `json:"loginWithEmailAllowed"`
DuplicateEmailsAllowed bool `json:"duplicateEmailsAllowed"`

//SMTP Server
SmtpServer SmtpServer `json:"smtpServer"`

// Themes
LoginTheme string `json:"loginTheme,omitempty"`
AccountTheme string `json:"accountTheme,omitempty"`
Expand All @@ -42,6 +45,21 @@ type Realm struct {
ActionTokenGeneratedByAdminLifespan int `json:"actionTokenGeneratedByAdminLifespan,omitempty"`
}

type SmtpServer struct {
StartTls string `json:"starttls,omitempty"`
Auth string `json:"auth,omitempty"`
Port string `json:"port,omitempty"`
Host string `json:"host,omitempty"`
ReplyTo string `json:"replyTo,omitempty"`
ReplyToDisplayName string `json:"replyToDisplayName,omitempty"`
From string `json:"from,omitempty"`
FromDisplayName string `json:"fromDisplayName,omitempty"`
EnvelopeFrom string `json:"envelopeFrom,omitempty"`
Ssl string `json:"ssl,omitempty"`
User string `json:"user,omitempty"`
Password string `json:"password,omitempty"`
}

func (keycloakClient *KeycloakClient) NewRealm(realm *Realm) error {
_, _, err := keycloakClient.post("/realms", realm)

Expand Down Expand Up @@ -92,6 +110,14 @@ func (keycloakClient *KeycloakClient) ValidateRealm(realm *Realm) error {
return err
}

if (SmtpServer{}) != realm.SmtpServer && realm.SmtpServer.Host == "" {
return fmt.Errorf("validation error: Smtp Server Host is a required field when Smtp Server is being set up")
}

if (SmtpServer{}) != realm.SmtpServer && realm.SmtpServer.From == "" {
return fmt.Errorf("validation error: Smtp Server From is a required field when Smtp Server is being set up")
}

if realm.LoginTheme != "" && !serverInfo.ThemeIsInstalled("login", realm.LoginTheme) {
return fmt.Errorf("validation error: theme \"%s\" does not exist on the server", realm.LoginTheme)
}
Expand Down
113 changes: 113 additions & 0 deletions provider/resource_keycloak_realm.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,70 @@ func resourceKeycloakRealm() *schema.Resource {
Computed: true,
},

//Smtp server

"smtp_server": {
Type: schema.TypeSet,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"starttls": {
Type: schema.TypeString,
Optional: true,
},
"auth": {
Type: schema.TypeString,
Optional: true,
},
"port": {
Type: schema.TypeString,
Optional: true,
},
"host": {
Type: schema.TypeString,
Optional: true,
},
"reply_to": {
Type: schema.TypeString,
Optional: true,
},
"reply_to_display_name": {
Type: schema.TypeString,
Optional: true,
},
"from": {
Type: schema.TypeString,
Optional: true,
},
"from_display_name": {
Type: schema.TypeString,
Optional: true,
},
"envelope_from": {
Type: schema.TypeString,
Optional: true,
},
"ssl": {
Type: schema.TypeString,
Optional: true,
},
"user": {
Type: schema.TypeString,
Optional: true,
},
"password": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
DiffSuppressFunc: func(_, remoteBindCredential, _ string, _ *schema.ResourceData) bool {
return remoteBindCredential == "**********"
},
},
},
},
},

// Themes

"login_theme": {
Expand Down Expand Up @@ -187,6 +251,28 @@ func getRealmFromData(data *schema.ResourceData) (*keycloak.Realm, error) {
DuplicateEmailsAllowed: data.Get("duplicate_emails_allowed").(bool),
}

//smtp
if v, ok := data.GetOk("smtp_server"); ok {
smtpSettings := v.(*schema.Set).List()[0].(map[string]interface{})

smtpServer := keycloak.SmtpServer{
StartTls: smtpSettings["starttls"].(string),
Auth: smtpSettings["auth"].(string),
Port: smtpSettings["port"].(string),
Host: smtpSettings["host"].(string),
ReplyTo: smtpSettings["reply_to"].(string),
ReplyToDisplayName: smtpSettings["reply_to_display_name"].(string),
From: smtpSettings["from"].(string),
FromDisplayName: smtpSettings["from_display_name"].(string),
EnvelopeFrom: smtpSettings["envelope_from"].(string),
Ssl: smtpSettings["ssl"].(string),
User: smtpSettings["user"].(string),
Password: smtpSettings["password"].(string),
}

realm.SmtpServer = smtpServer
}

// Themes

if loginTheme, ok := data.GetOk("login_theme"); ok {
Expand Down Expand Up @@ -322,6 +408,28 @@ func setRealmData(data *schema.ResourceData, realm *keycloak.Realm) {
data.Set("login_with_email_allowed", realm.LoginWithEmailAllowed)
data.Set("duplicate_emails_allowed", realm.DuplicateEmailsAllowed)

// Smtp Config

if (keycloak.SmtpServer{}) == realm.SmtpServer {
data.Set("smtp_server", nil)
} else {
smtpSettings := make(map[string]interface{})

smtpSettings["starttls"] = realm.SmtpServer.StartTls
smtpSettings["auth"] = realm.SmtpServer.Auth
smtpSettings["port"] = realm.SmtpServer.Port
smtpSettings["host"] = realm.SmtpServer.Host
smtpSettings["reply_to"] = realm.SmtpServer.ReplyTo
smtpSettings["reply_to_display_name"] = realm.SmtpServer.ReplyToDisplayName
smtpSettings["from"] = realm.SmtpServer.From
smtpSettings["from_display_name"] = realm.SmtpServer.FromDisplayName
smtpSettings["envelope_from"] = realm.SmtpServer.EnvelopeFrom
smtpSettings["ssl"] = realm.SmtpServer.Ssl
smtpSettings["user"] = realm.SmtpServer.User
smtpSettings["password"] = realm.SmtpServer.Password
data.Set("smtp_server", schema.NewSet(func(i interface{}) int { return 1 }, []interface{}{smtpSettings}))
}

// Themes
data.Set("login_theme", realm.LoginTheme)
data.Set("account_theme", realm.AccountTheme)
Expand Down Expand Up @@ -375,6 +483,11 @@ func resourceKeycloakRealmRead(data *schema.ResourceData, meta interface{}) erro
return handleNotFoundError(err, data)
}

if v, ok := data.GetOk("smtp_server"); ok {
// we can't trust the API to set this field correctly since it just responds with "**********" this implies a 'password only' change will not detected
smtpSettings := v.(*schema.Set).List()[0].(map[string]interface{})
realm.SmtpServer.Password = smtpSettings["password"].(string)
}
setRealmData(data, realm)

return nil
Expand Down
83 changes: 83 additions & 0 deletions provider/resource_keycloak_realm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,46 @@ func TestAccKeycloakRealm_import(t *testing.T) {
})
}

func TestAccKeycloakRealm_SmtpServer(t *testing.T) {
realm := "terraform-" + acctest.RandString(10)

resource.Test(t, resource.TestCase{
Providers: testAccProviders,
PreCheck: func() { testAccPreCheck(t) },
CheckDestroy: testAccCheckKeycloakRealmDestroy(),
Steps: []resource.TestStep{
{
Config: testKeycloakRealm_WithSmtpServer(realm, "myhost.com", "My Host"),
Check: testAccCheckKeycloakRealmSmtp("keycloak_realm.realm", "myhost.com", "My Host"),
},
{
Config: testKeycloakRealm_basic(realm, realm),
Check: testAccCheckKeycloakRealmSmtp("keycloak_realm.realm", "", ""),
},
},
})
}

func TestAccKeycloakRealm_SmtpServerInValid(t *testing.T) {
realm := "terraform-" + acctest.RandString(10)

resource.Test(t, resource.TestCase{
Providers: testAccProviders,
PreCheck: func() { testAccPreCheck(t) },
CheckDestroy: testAccCheckKeycloakRealmDestroy(),
Steps: []resource.TestStep{
{
Config: testKeycloakRealm_WithSmtpServer(realm, "", "My Host"),
ExpectError: regexp.MustCompile("validation error: Smtp Server Host is a required field when Smtp Server is being set up"),
},
{
Config: testKeycloakRealm_WithSmtpServer(realm, "myhost.com", ""),
ExpectError: regexp.MustCompile("validation error: Smtp Server From is a required field when Smtp Server is being set up"),
},
},
})
}

func TestAccKeycloakRealm_themes(t *testing.T) {
realmOne := &keycloak.Realm{
Realm: "terraform-" + acctest.RandString(10),
Expand Down Expand Up @@ -381,6 +421,25 @@ func testAccCheckKeycloakRealmDisplayName(resourceName string, displayName strin
}
}

func testAccCheckKeycloakRealmSmtp(resourceName string, host string, from string) resource.TestCheckFunc {
return func(s *terraform.State) error {
realm, err := getRealmFromState(s, resourceName)
if err != nil {
return err
}

if realm.SmtpServer.Host != host {
return fmt.Errorf("expected realm %s to have smtp host set to %s, but was %s", realm.Realm, host, realm.SmtpServer.Host)
}

if realm.SmtpServer.From != from {
return fmt.Errorf("expected realm %s to have smtp from set to %s, but was %s", realm.Realm, from, realm.SmtpServer.From)
}

return nil
}
}

func testAccCheckKeycloakRealmDestroy() resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
Expand Down Expand Up @@ -429,6 +488,30 @@ resource "keycloak_realm" "realm" {
`, realm, realmDisplayName)
}

func testKeycloakRealm_WithSmtpServer(realm, host string, from string) string {
return fmt.Sprintf(`
resource "keycloak_realm" "realm" {
realm = "%s"
enabled = true
display_name = "%s"
smtp_server {
host = "%s"
port = 25
from_display_name = "Tom"
from = "%s"
reply_to_display_name = "Tom"
reply_to = "[email protected]"
auth = true
user = "tom"
password = "tom"
ssl = true
starttls = true
envelope_from= "[email protected]"
}
}
`, realm, realm, host, from)
}

func testKeycloakRealm_themes(realm *keycloak.Realm) string {
return fmt.Sprintf(`
resource "keycloak_realm" "realm" {
Expand Down