Repository: mrparkers/terraform-provider-keycloak
Pull request #342 (2020-07-10 14:35:26)

Adds attribute saml.encrypt to keycloak_saml_client
Adding the configuration option "Encrypt Assertions" to SAML client.


Patch:
diff --git a/docs/index.md b/docs/index.md
index a9f403e..cf691c8 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -59,6 +59,7 @@ The following provider attributes are supported:
 - `client_timeout` (Optional) - Sets the timeout of the client when addressing Keycloak, in seconds. Defaults to environment variable `KEYCLOAK_CLIENT_TIMEOUT`, or 5 is the environment variable is not specified.
 - `tls_insecure_skip_verify` (Optional) - Allows ignoring insecure certificates when set to true. Defaults to false. Disabling security check is dangerous and should be avoided.
 - `root_ca_certificate` (Optional) - Allows x509 calls using an unknown CA certificate (for development purposes)
+- `base_path` (Optional) - The base path used for accessing the Keycloak REST API.  Defaults to `/auth`
 
 #### Example (client credentials)
 
diff --git a/docs/resources/keycloak_saml_client.md b/docs/resources/keycloak_saml_client.md
index 63eb7b0..104d493 100644
--- a/docs/resources/keycloak_saml_client.md
+++ b/docs/resources/keycloak_saml_client.md
@@ -40,6 +40,7 @@ The following arguments are supported:
 - `include_authn_statement` - (Optional) When `true`, an `AuthnStatement` will be included in the SAML response.
 - `sign_documents` - (Optional) When `true`, the SAML document will be signed by Keycloak using the realm's private key.
 - `sign_assertions` - (Optional) When `true`, the SAML assertions will be signed by Keycloak using the realm's private key, and embedded within the SAML XML Auth response.
+- `encrypt_assertions` - (Optional) When `true`, the SAML assertions will be encrypted by Keycloak using the client's public key.
 - `client_signature_required` - (Optional) When `true`, Keycloak will expect that documents originating from a client will be signed using the certificate and/or key configured via `signing_certificate` and `signing_private_key`.
 - `force_post_binding` - (Optional) When `true`, Keycloak will always respond to an authentication request via the SAML POST Binding.
 - `front_channel_logout` - (Optional) When `true`, this client will require a browser redirect in order to perform a logout.
@@ -49,6 +50,7 @@ The following arguments are supported:
 - `valid_redirect_uris` - (Optional) When specified, Keycloak will use this list to validate given Assertion Consumer URLs specified in the authentication request.
 - `base_url` - (Optional) When specified, this URL will be used whenever Keycloak needs to link to this client.
 - `master_saml_processing_url` - (Optional) When specified, this URL will be used for all SAML requests.
+- `encryption_certificate` - (Optional) If assertions for the client are encrypted, this certificate will be used for encryption.
 - `signing_certificate` - (Optional) If documents or assertions from the client are signed, this certificate will be used to verify the signature.
 - `signing_private_key` - (Optional) If documents or assertions from the client are signed, this private key will be used to verify the signature.
 - `idp_initiated_sso_url_name` - (Optional) URL fragment name to reference client when you want to do IDP Initiated SSO.
diff --git a/keycloak/keycloak_client.go b/keycloak/keycloak_client.go
index ee8638b..bc6f66a 100644
--- a/keycloak/keycloak_client.go
+++ b/keycloak/keycloak_client.go
@@ -40,11 +40,11 @@ type ClientCredentials struct {
 }
 
 const (
-	apiUrl   = "/auth/admin"
-	tokenUrl = "%s/auth/realms/%s/protocol/openid-connect/token"
+	apiUrl   = "/admin"
+	tokenUrl = "%s/realms/%s/protocol/openid-connect/token"
 )
 
-func NewKeycloakClient(baseUrl, clientId, clientSecret, realm, username, password string, initialLogin bool, clientTimeout int, caCert string, tlsInsecureSkipVerify bool, userAgent string) (*KeycloakClient, error) {
+func NewKeycloakClient(url, basePath, clientId, clientSecret, realm, username, password string, initialLogin bool, clientTimeout int, caCert string, tlsInsecureSkipVerify bool, userAgent string) (*KeycloakClient, error) {
 	cookieJar, err := cookiejar.New(&cookiejar.Options{
 		PublicSuffixList: publicsuffix.List,
 	})
@@ -87,7 +87,7 @@ func NewKeycloakClient(baseUrl, clientId, clientSecret, realm, username, passwor
 	}
 
 	keycloakClient := KeycloakClient{
-		baseUrl:           baseUrl,
+		baseUrl:           url + basePath,
 		clientCredentials: clientCredentials,
 		httpClient:        httpClient,
 		initialLogin:      initialLogin,
@@ -122,6 +122,9 @@ func (keycloakClient *KeycloakClient) login() error {
 	if err != nil {
 		return err
 	}
+	if accessTokenResponse.StatusCode != http.StatusOK {
+		return fmt.Errorf("error sending POST request to %s: %s", accessTokenUrl, accessTokenResponse.Status)
+	}
 
 	defer accessTokenResponse.Body.Close()
 
diff --git a/keycloak/saml_client.go b/keycloak/saml_client.go
index 51bb7d5..538d404 100644
--- a/keycloak/saml_client.go
+++ b/keycloak/saml_client.go
@@ -8,6 +8,7 @@ type SamlClientAttributes struct {
 	IncludeAuthnStatement   *string `json:"saml.authnstatement"`
 	SignDocuments           *string `json:"saml.server.signature"`
 	SignAssertions          *string `json:"saml.assertion.signature"`
+	EncryptAssertions       *string `json:"saml.encrypt"`
 	ClientSignatureRequired *string `json:"saml.client.signature"`
 	ForcePostBinding        *string `json:"saml.force.post.binding"`
 	ForceNameIdFormat       *string `json:"saml_force_name_id_format"`
@@ -15,6 +16,7 @@ type SamlClientAttributes struct {
 	NameIdFormat                    string  `json:"saml_name_id_format"`
 	SigningCertificate              *string `json:"saml.signing.certificate,omitempty"`
 	SigningPrivateKey               *string `json:"saml.signing.private.key"`
+	EncryptionCertificate           *string `json:"saml.encryption.certificate"`
 	IDPInitiatedSSOURLName          string  `json:"saml_idp_initiated_sso_url_name"`
 	IDPInitiatedSSORelayState       string  `json:"saml_idp_initiated_sso_relay_state"`
 	AssertionConsumerPostURL        string  `json:"saml_assertion_consumer_url_post"`
diff --git a/provider/provider.go b/provider/provider.go
index 145f3ba..e334c17 100644
--- a/provider/provider.go
+++ b/provider/provider.go
@@ -142,6 +142,11 @@ func KeycloakProvider() *schema.Provider {
 				Description: "Allows ignoring insecure certificates when set to true. Defaults to false. Disabling security check is dangerous and should be avoided.",
 				Default:     false,
 			},
+			"base_path": {
+				Optional: true,
+				Type:     schema.TypeString,
+				Default:  "/auth",
+			},
 		},
 	}
 
@@ -163,6 +168,7 @@ func KeycloakProvider() *schema.Provider {
 
 func configureKeycloakProvider(data *schema.ResourceData, userAgent string) (interface{}, error) {
 	url := data.Get("url").(string)
+	basePath := data.Get("base_path").(string)
 	clientId := data.Get("client_id").(string)
 	clientSecret := data.Get("client_secret").(string)
 	username := data.Get("username").(string)
@@ -173,5 +179,5 @@ func configureKeycloakProvider(data *schema.ResourceData, userAgent string) (int
 	tlsInsecureSkipVerify := data.Get("tls_insecure_skip_verify").(bool)
 	rootCaCertificate := data.Get("root_ca_certificate").(string)
 
-	return keycloak.NewKeycloakClient(url, clientId, clientSecret, realm, username, password, initialLogin, clientTimeout, rootCaCertificate, tlsInsecureSkipVerify, userAgent)
+	return keycloak.NewKeycloakClient(url, basePath, clientId, clientSecret, realm, username, password, initialLogin, clientTimeout, rootCaCertificate, tlsInsecureSkipVerify, userAgent)
 }
diff --git a/provider/resource_keycloak_saml_client.go b/provider/resource_keycloak_saml_client.go
index 6d49ac6..6e8de85 100644
--- a/provider/resource_keycloak_saml_client.go
+++ b/provider/resource_keycloak_saml_client.go
@@ -62,6 +62,11 @@ func resourceKeycloakSamlClient() *schema.Resource {
 				Optional: true,
 				Computed: true,
 			},
+			"encrypt_assertions": {
+				Type:     schema.TypeBool,
+				Optional: true,
+				Computed: true,
+			},
 			"client_signature_required": {
 				Type:     schema.TypeBool,
 				Optional: true,
@@ -106,11 +111,18 @@ func resourceKeycloakSamlClient() *schema.Resource {
 				Type:     schema.TypeString,
 				Optional: true,
 			},
+			"encryption_certificate": {
+				Type:     schema.TypeString,
+				Optional: true,
+				DiffSuppressFunc: func(_, old, new string, _ *schema.ResourceData) bool {
+					return old == formatCertificate(new)
+				},
+			},
 			"signing_certificate": {
 				Type:     schema.TypeString,
 				Optional: true,
 				DiffSuppressFunc: func(_, old, new string, _ *schema.ResourceData) bool {
-					return old == formatSigningCertificate(new)
+					return old == formatCertificate(new)
 				},
 			},
 			"signing_private_key": {
@@ -153,7 +165,7 @@ func resourceKeycloakSamlClient() *schema.Resource {
 	}
 }
 
-func formatSigningCertificate(signingCertificate string) string {
+func formatCertificate(signingCertificate string) string {
 	r := strings.NewReplacer(
 		"-----BEGIN CERTIFICATE-----", "",
 		"-----END CERTIFICATE-----", "",
@@ -192,8 +204,13 @@ func mapToSamlClientFromData(data *schema.ResourceData) *keycloak.SamlClient {
 		LogoutServiceRedirectBindingURL: data.Get("logout_service_redirect_binding_url").(string),
 	}
 
+	if encryptionCertificate, ok := data.GetOkExists("encryption_certificate"); ok {
+		encryptionCertificateString := formatCertificate(encryptionCertificate.(string))
+		samlAttributes.EncryptionCertificate = &encryptionCertificateString
+	}
+
 	if signingCertificate, ok := data.GetOkExists("signing_certificate"); ok {
-		signingCertificateString := formatSigningCertificate(signingCertificate.(string))
+		signingCertificateString := formatCertificate(signingCertificate.(string))
 		samlAttributes.SigningCertificate = &signingCertificateString
 	}
 
@@ -222,6 +239,11 @@ func mapToSamlClientFromData(data *schema.ResourceData) *keycloak.SamlClient {
 		samlAttributes.SignAssertions = &signAssertionsString
 	}
 
+	if encryptAssertions, ok := data.GetOkExists("encrypt_assertions"); ok {
+		encryptAssertionsString := strconv.FormatBool(encryptAssertions.(bool))
+		samlAttributes.EncryptAssertions = &encryptAssertionsString
+	}
+
 	if clientSignatureRequired, ok := data.GetOkExists("client_signature_required"); ok {
 		clientSignatureRequiredString := strconv.FormatBool(clientSignatureRequired.(bool))
 		samlAttributes.ClientSignatureRequired = &clientSignatureRequiredString
@@ -289,6 +311,15 @@ func mapToDataFromSamlClient(data *schema.ResourceData, client *keycloak.SamlCli
 		data.Set("sign_assertions", signAssertions)
 	}
 
+	if client.Attributes.EncryptAssertions != nil {
+		encryptAssertions, err := strconv.ParseBool(*client.Attributes.EncryptAssertions)
+		if err != nil {
+			return err
+		}
+
+		data.Set("encrypt_assertions", encryptAssertions)
+	}
+
 	if client.Attributes.ClientSignatureRequired != nil {
 		clientSignatureRequired, err := strconv.ParseBool(*client.Attributes.ClientSignatureRequired)
 		if err != nil {
@@ -307,6 +338,10 @@ func mapToDataFromSamlClient(data *schema.ResourceData, client *keycloak.SamlCli
 		data.Set("force_post_binding", forcePostBinding)
 	}
 
+	if _, exists := data.GetOkExists("encryption_certificate"); client.Attributes.EncryptionCertificate != nil && exists {
+		data.Set("encryption_certificate", client.Attributes.EncryptionCertificate)
+	}
+
 	if _, exists := data.GetOkExists("signing_certificate"); client.Attributes.SigningCertificate != nil && exists {
 		data.Set("signing_certificate", *client.Attributes.SigningCertificate)
 	}


Test patch:
diff --git a/keycloak/keycloak_client_test.go b/keycloak/keycloak_client_test.go
index 57a0deb..5925402 100644
--- a/keycloak/keycloak_client_test.go
+++ b/keycloak/keycloak_client_test.go
@@ -51,7 +51,7 @@ func TestAccKeycloakApiClientRefresh(t *testing.T) {
 		t.Fatal("KEYCLOAK_CLIENT_TIMEOUT must be an integer")
 	}
 
-	keycloakClient, err := NewKeycloakClient(os.Getenv("KEYCLOAK_URL"), os.Getenv("KEYCLOAK_CLIENT_ID"), os.Getenv("KEYCLOAK_CLIENT_SECRET"), os.Getenv("KEYCLOAK_REALM"), os.Getenv("KEYCLOAK_USER"), os.Getenv("KEYCLOAK_PASSWORD"), true, clientTimeout, "", false, "")
+	keycloakClient, err := NewKeycloakClient(os.Getenv("KEYCLOAK_URL"), "/auth", os.Getenv("KEYCLOAK_CLIENT_ID"), os.Getenv("KEYCLOAK_CLIENT_SECRET"), os.Getenv("KEYCLOAK_REALM"), os.Getenv("KEYCLOAK_USER"), os.Getenv("KEYCLOAK_PASSWORD"), true, clientTimeout, "", false, "")
 	if err != nil {
 		t.Fatalf("%s", err)
 	}
diff --git a/provider/provider_test.go b/provider/provider_test.go
index f4a4244..f1d1916 100644
--- a/provider/provider_test.go
+++ b/provider/provider_test.go
@@ -26,7 +26,7 @@ func init() {
 		"keycloak": testAccProvider,
 	}
 
-	keycloakClient, _ = keycloak.NewKeycloakClient(os.Getenv("KEYCLOAK_URL"), os.Getenv("KEYCLOAK_CLIENT_ID"), os.Getenv("KEYCLOAK_CLIENT_SECRET"), os.Getenv("KEYCLOAK_REALM"), "", "", true, 5, "", false, httpclient.TerraformUserAgent(testAccProvider.TerraformVersion))
+	keycloakClient, _ = keycloak.NewKeycloakClient(os.Getenv("KEYCLOAK_URL"), "/auth", os.Getenv("KEYCLOAK_CLIENT_ID"), os.Getenv("KEYCLOAK_CLIENT_SECRET"), os.Getenv("KEYCLOAK_REALM"), "", "", true, 5, "", false, httpclient.TerraformUserAgent(testAccProvider.TerraformVersion))
 }
 
 func TestProvider(t *testing.T) {
diff --git a/provider/resource_keycloak_saml_client_test.go b/provider/resource_keycloak_saml_client_test.go
index c7c086d..b732751 100644
--- a/provider/resource_keycloak_saml_client_test.go
+++ b/provider/resource_keycloak_saml_client_test.go
@@ -128,6 +128,8 @@ func TestAccKeycloakSamlClient_updateInPlace(t *testing.T) {
 	frontChannelLogout := randomBool()
 	clientSignatureRequired := "true"
 
+	encryptionCertificateBefore := acctest.RandString(20)
+	encryptionCertificateAfter := acctest.RandString(20)
 	signingCertificateBefore := acctest.RandString(20)
 	signingCertificateAfter := acctest.RandString(20)
 	signingPrivateKeyBefore := acctest.RandString(20)
@@ -156,10 +158,12 @@ func TestAccKeycloakSamlClient_updateInPlace(t *testing.T) {
 			IncludeAuthnStatement:           randomBoolAsStringPointer(),
 			SignDocuments:                   randomBoolAsStringPointer(),
 			SignAssertions:                  randomBoolAsStringPointer(),
+			EncryptAssertions:               randomBoolAsStringPointer(),
 			ClientSignatureRequired:         &clientSignatureRequired,
 			ForcePostBinding:                randomBoolAsStringPointer(),
 			ForceNameIdFormat:               randomBoolAsStringPointer(),
 			NameIdFormat:                    randomStringInSlice(keycloakSamlClientNameIdFormats),
+			EncryptionCertificate:           &encryptionCertificateBefore,
 			SigningCertificate:              &signingCertificateBefore,
 			SigningPrivateKey:               &signingPrivateKeyBefore,
 			IDPInitiatedSSOURLName:          acctest.RandString(20),
@@ -192,10 +196,12 @@ func TestAccKeycloakSamlClient_updateInPlace(t *testing.T) {
 			IncludeAuthnStatement:           randomBoolAsStringPointer(),
 			SignDocuments:                   randomBoolAsStringPointer(),
 			SignAssertions:                  randomBoolAsStringPointer(),
+			EncryptAssertions:               randomBoolAsStringPointer(),
 			ClientSignatureRequired:         &clientSignatureRequired,
 			ForcePostBinding:                randomBoolAsStringPointer(),
 			ForceNameIdFormat:               randomBoolAsStringPointer(),
 			NameIdFormat:                    randomStringInSlice(keycloakSamlClientNameIdFormats),
+			EncryptionCertificate:           &encryptionCertificateAfter,
 			SigningCertificate:              &signingCertificateAfter,
 			SigningPrivateKey:               &signingPrivateKeyAfter,
 			IDPInitiatedSSOURLName:          acctest.RandString(20),
@@ -237,7 +243,7 @@ func TestAccKeycloakSamlClient_certificateAndKey(t *testing.T) {
 				Config: testKeycloakSamlClient_signingCertificateAndKey(realmName, clientId),
 				Check: resource.ComposeTestCheckFunc(
 					testAccCheckKeycloakSamlClientExistsWithCorrectProtocol("keycloak_saml_client.saml_client"),
-					testAccCheckKeycloakSamlClientHasCertificate("keycloak_saml_client.saml_client"),
+					testAccCheckKeycloakSamlClientHasSigningCertificate("keycloak_saml_client.saml_client"),
 					testAccCheckKeycloakSamlClientHasPrivateKey("keycloak_saml_client.saml_client"),
 				),
 			},
@@ -245,7 +251,7 @@ func TestAccKeycloakSamlClient_certificateAndKey(t *testing.T) {
 				Config: testKeycloakSamlClient_signingCertificateNoKey(realmName, clientId),
 				Check: resource.ComposeTestCheckFunc(
 					testAccCheckKeycloakSamlClientExistsWithCorrectProtocol("keycloak_saml_client.saml_client"),
-					testAccCheckKeycloakSamlClientHasCertificate("keycloak_saml_client.saml_client"),
+					testAccCheckKeycloakSamlClientHasSigningCertificate("keycloak_saml_client.saml_client"),
 					resource.TestCheckResourceAttr("keycloak_saml_client.saml_client", "signing_private_key", ""),
 				),
 			},
@@ -253,6 +259,33 @@ func TestAccKeycloakSamlClient_certificateAndKey(t *testing.T) {
 	})
 }
 
+func TestAccKeycloakSamlClient_encryptionCertificate(t *testing.T) {
+	realmName := "terraform-" + acctest.RandString(10)
+	clientId := "terraform-" + acctest.RandString(10)
+
+	resource.Test(t, resource.TestCase{
+		Providers:    testAccProviders,
+		PreCheck:     func() { testAccPreCheck(t) },
+		CheckDestroy: testAccCheckKeycloakSamlClientDestroy(),
+		Steps: []resource.TestStep{
+			{
+				Config: testKeycloakSamlClient_encryptionCertificate(realmName, clientId),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckKeycloakSamlClientExistsWithCorrectProtocol("keycloak_saml_client.saml_client"),
+					testAccCheckKeycloakSamlClientHasEncryptionCertificate("keycloak_saml_client.saml_client"),
+				),
+			},
+			{
+				Config: testKeycloakSamlClient_NoEncryptionCertificate(realmName, clientId),
+				Check: resource.ComposeTestCheckFunc(
+					testAccCheckKeycloakSamlClientExistsWithCorrectProtocol("keycloak_saml_client.saml_client"),
+					resource.TestCheckResourceAttr("keycloak_saml_client.saml_client", "encryption_certificate", ""),
+				),
+			},
+		},
+	})
+}
+
 func testAccCheckKeycloakSamlClientExistsWithCorrectProtocol(resourceName string) resource.TestCheckFunc {
 	return func(s *terraform.State) error {
 		client, err := getSamlClientFromState(s, resourceName)
@@ -268,7 +301,30 @@ func testAccCheckKeycloakSamlClientExistsWithCorrectProtocol(resourceName string
 	}
 }
 
-func testAccCheckKeycloakSamlClientHasCertificate(resourceName string) resource.TestCheckFunc {
+func testAccCheckKeycloakSamlClientHasEncryptionCertificate(resourceName string) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		client, err := getSamlClientFromState(s, resourceName)
+		if err != nil {
+			return err
+		}
+
+		if *client.Attributes.EncryptionCertificate == "" {
+			return fmt.Errorf("expected saml client to have a encryption certificate")
+		}
+
+		if strings.Contains(*client.Attributes.EncryptionCertificate, "-----BEGIN CERTIFICATE-----") || strings.Contains(*client.Attributes.EncryptionCertificate, "-----END CERTIFICATE-----") {
+			return fmt.Errorf("expected saml client encryption certificate to not contain headers")
+		}
+
+		if strings.ContainsAny(*client.Attributes.EncryptionCertificate, "\n\r ") {
+			return fmt.Errorf("expected saml client encryption certificate to not contain whitespace")
+		}
+
+		return nil
+	}
+}
+
+func testAccCheckKeycloakSamlClientHasSigningCertificate(resourceName string) resource.TestCheckFunc {
 	return func(s *terraform.State) error {
 		client, err := getSamlClientFromState(s, resourceName)
 		if err != nil {
@@ -391,6 +447,11 @@ func testAccCheckKeycloakSamlClientHasDefaultBooleanAttributes(resourceName stri
 			return err
 		}
 
+		encryptAssertions, err := parseBoolAndTreatEmptyStringAsFalse(rs.Primary.Attributes["encrypt_assertions"])
+		if err != nil {
+			return err
+		}
+
 		clientSignatureRequired, err := parseBoolAndTreatEmptyStringAsFalse(rs.Primary.Attributes["client_signature_required"])
 		if err != nil {
 			return err
@@ -406,7 +467,7 @@ func testAccCheckKeycloakSamlClientHasDefaultBooleanAttributes(resourceName stri
 			return err
 		}
 
-		if !includeAuthnStatement && !signDocuments && !signAssertions && !clientSignatureRequired && !forcePostBinding && !forceNameIdFormat {
+		if !includeAuthnStatement && !signDocuments && !signAssertions && !encryptAssertions && !clientSignatureRequired && !forcePostBinding && !forceNameIdFormat {
 			return fmt.Errorf("expected saml client with id %s to have some defaults set by Keycloak", rs.Primary.ID)
 		}
 
@@ -492,6 +553,7 @@ resource "keycloak_saml_client" "saml_client" {
 	include_authn_statement    = %s
 	sign_documents             = %s
 	sign_assertions            = %s
+	encrypt_assertions         = %s
 	client_signature_required  = %s
 	force_post_binding         = %s
 	force_name_id_format       = %s
@@ -503,6 +565,7 @@ resource "keycloak_saml_client" "saml_client" {
 	base_url                   = "%s"
 	master_saml_processing_url = "%s"
 
+	encryption_certificate     = "%s"
 	signing_certificate        = "%s"
 	signing_private_key        = "%s"
 
@@ -522,6 +585,7 @@ resource "keycloak_saml_client" "saml_client" {
 		*client.Attributes.IncludeAuthnStatement,
 		*client.Attributes.SignDocuments,
 		*client.Attributes.SignAssertions,
+		*client.Attributes.EncryptAssertions,
 		*client.Attributes.ClientSignatureRequired,
 		*client.Attributes.ForcePostBinding,
 		*client.Attributes.ForceNameIdFormat,
@@ -530,6 +594,7 @@ resource "keycloak_saml_client" "saml_client" {
 		client.RootUrl,
 		arrayOfStringsForTerraformResource(client.ValidRedirectUris),
 		client.BaseUrl, client.MasterSamlProcessingUrl,
+		*client.Attributes.EncryptionCertificate,
 		*client.Attributes.SigningCertificate,
 		*client.Attributes.SigningPrivateKey,
 		client.Attributes.IDPInitiatedSSOURLName,
@@ -554,6 +619,7 @@ resource "keycloak_saml_client" "saml_client" {
 
 	sign_documents          = false
 	sign_assertions         = true
+	encrypt_assertions      = false
 	include_authn_statement = true
 
 	signing_certificate     = "${file("misc/saml-cert.pem")}"
@@ -575,9 +641,46 @@ resource "keycloak_saml_client" "saml_client" {
 
 	sign_documents          = false
 	sign_assertions         = true
+	encrypt_assertions      = false
 	include_authn_statement = true
 
 	signing_certificate     = "${file("misc/saml-cert.pem")}"
 }
 	`, realm, clientId)
 }
+
+func testKeycloakSamlClient_encryptionCertificate(realm, clientId string) string {
+	return fmt.Sprintf(`
+resource "keycloak_realm" "realm" {
+	realm = "%s"
+}
+
+resource "keycloak_saml_client" "saml_client" {
+	client_id               = "%s"
+	realm_id                = "${keycloak_realm.realm.id}"
+	name                    = "test-saml-client"
+
+	encrypt_assertions      = true
+	include_authn_statement = true
+
+	encryption_certificate     = "${file("misc/saml-cert.pem")}"
+}
+	`, realm, clientId)
+}
+
+func testKeycloakSamlClient_NoEncryptionCertificate(realm, clientId string) string {
+	return fmt.Sprintf(`
+resource "keycloak_realm" "realm" {
+	realm = "%s"
+}
+
+resource "keycloak_saml_client" "saml_client" {
+	client_id               = "%s"
+	realm_id                = "${keycloak_realm.realm.id}"
+	name                    = "test-saml-client"
+
+	encrypt_assertions      = true
+	include_authn_statement = true
+}
+	`, realm, clientId)
+}