Skip to content

Commit

Permalink
new resource: resource_keycloak_openid_client_service_account_realm_r…
Browse files Browse the repository at this point in the history
…ole (#202)
  • Loading branch information
waldemarschmalz authored and mrparkers committed Jan 27, 2020
1 parent 6c8bf69 commit 57d19b8
Show file tree
Hide file tree
Showing 4 changed files with 362 additions and 0 deletions.
59 changes: 59 additions & 0 deletions keycloak/openid_client_service_account_realm_role.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package keycloak

import (
"fmt"
)

type OpenidClientServiceAccountRealmRole struct {
Id string `json:"id"`
RealmId string `json:"-"`
ServiceAccountUserId string `json:"-"`
Name string `json:"name,omitempty"`
Description string `json:"description"`
}

func (keycloakClient *KeycloakClient) NewOpenidClientServiceAccountRealmRole(serviceAccountRole *OpenidClientServiceAccountRealmRole) error {
serviceAccountRoles := []OpenidClientServiceAccountRealmRole{*serviceAccountRole}

_, _, err := keycloakClient.post(fmt.Sprintf("/realms/%s/users/%s/role-mappings/realm", serviceAccountRole.RealmId, serviceAccountRole.ServiceAccountUserId), serviceAccountRoles)

if err != nil {
return err
}
return nil
}

func (keycloakClient *KeycloakClient) DeleteOpenidClientServiceAccountRealmRole(realm, serviceAccountUserId, roleId string) error {
serviceAccountRole, err := keycloakClient.GetOpenidClientServiceAccountRealmRole(realm, serviceAccountUserId, roleId)
if err != nil {
return err
}
serviceAccountRoles := []OpenidClientServiceAccountRealmRole{*serviceAccountRole}
err = keycloakClient.delete(fmt.Sprintf("/realms/%s/users/%s/role-mappings/realm", realm, serviceAccountUserId), &serviceAccountRoles)
if err != nil {
return err
}
return nil
}

func (keycloakClient *KeycloakClient) GetOpenidClientServiceAccountRealmRole(realm, serviceAccountUserId, roleId string) (*OpenidClientServiceAccountRealmRole, error) {
serviceAccountRoles := []OpenidClientServiceAccountRealmRole{
{
Id: roleId,
RealmId: realm,
ServiceAccountUserId: serviceAccountUserId,
},
}
err := keycloakClient.get(fmt.Sprintf("/realms/%s/users/%s/role-mappings/realm", realm, serviceAccountUserId), &serviceAccountRoles, nil)
if err != nil {
return nil, err
}
for _, serviceAccountRole := range serviceAccountRoles {
if serviceAccountRole.Id == roleId {
serviceAccountRole.RealmId = realm
serviceAccountRole.ServiceAccountUserId = serviceAccountUserId
return &serviceAccountRole, nil
}
}
return &OpenidClientServiceAccountRealmRole{}, nil
}
1 change: 1 addition & 0 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func KeycloakProvider() *schema.Provider {
"keycloak_openid_client_authorization_scope": resourceKeycloakOpenidClientAuthorizationScope(),
"keycloak_openid_client_authorization_permission": resourceKeycloakOpenidClientAuthorizationPermission(),
"keycloak_openid_client_service_account_role": resourceKeycloakOpenidClientServiceAccountRole(),
"keycloak_openid_client_service_account_realm_role": resourceKeycloakOpenidClientServiceAccountRealmRole(),
"keycloak_role": resourceKeycloakRole(),
},
Schema: map[string]*schema.Schema{
Expand Down
125 changes: 125 additions & 0 deletions provider/resource_keycloak_openid_client_service_account_realm_role.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package provider

import (
"fmt"
"github.com/hashicorp/terraform/helper/schema"
"github.com/mrparkers/terraform-provider-keycloak/keycloak"
"strings"
)

func resourceKeycloakOpenidClientServiceAccountRealmRole() *schema.Resource {
return &schema.Resource{
Create: resourceKeycloakOpenidClientServiceAccountRealmRoleCreate,
Read: resourceKeycloakOpenidClientServiceAccountRealmRoleRead,
Delete: resourceKeycloakOpenidClientServiceAccountRealmRoleDelete,
Importer: &schema.ResourceImporter{
State: resourceKeycloakOpenidClientServiceAccountRealmRoleImport,
},
Schema: map[string]*schema.Schema{
"service_account_user_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"realm_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"role": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
}
}

func getOpenidClientServiceAccountRealmRoleFromData(data *schema.ResourceData, keycloakClient *keycloak.KeycloakClient) (*keycloak.OpenidClientServiceAccountRealmRole, error) {
roleName := data.Get("role").(string)
realmId := data.Get("realm_id").(string)
serviceAccountRoleId := data.Get("service_account_user_id").(string)

role, err := keycloakClient.GetRoleByName(realmId, "", roleName)
if err != nil {
if keycloak.ErrorIs404(err) {
role = &keycloak.Role{Id: ""}
} else {
return nil, err
}
}

return &keycloak.OpenidClientServiceAccountRealmRole{
Id: role.Id,
Name: roleName,
RealmId: realmId,
ServiceAccountUserId: serviceAccountRoleId,
}, nil
}

func setOpenidClientServiceAccountRealmRoleData(data *schema.ResourceData, serviceAccountRole *keycloak.OpenidClientServiceAccountRealmRole) {
data.SetId(fmt.Sprintf("%s/%s", serviceAccountRole.ServiceAccountUserId, serviceAccountRole.Id))
data.Set("realm_id", serviceAccountRole.RealmId)
data.Set("service_account_user_id", serviceAccountRole.ServiceAccountUserId)
data.Set("role", serviceAccountRole.Name)
}

func resourceKeycloakOpenidClientServiceAccountRealmRoleCreate(data *schema.ResourceData, meta interface{}) error {
keycloakClient := meta.(*keycloak.KeycloakClient)
serviceAccountRole, err := getOpenidClientServiceAccountRealmRoleFromData(data, keycloakClient)
if err != nil {
return err
}

err = keycloakClient.NewOpenidClientServiceAccountRealmRole(serviceAccountRole)
if err != nil {
return err
}
setOpenidClientServiceAccountRealmRoleData(data, serviceAccountRole)
return resourceKeycloakOpenidClientServiceAccountRealmRoleRead(data, meta)
}

func resourceKeycloakOpenidClientServiceAccountRealmRoleRead(data *schema.ResourceData, meta interface{}) error {
keycloakClient := meta.(*keycloak.KeycloakClient)

serviceAccountRole, err := getOpenidClientServiceAccountRealmRoleFromData(data, keycloakClient)
if err != nil {
return err
}

serviceAccountRole, err = keycloakClient.GetOpenidClientServiceAccountRealmRole(serviceAccountRole.RealmId, serviceAccountRole.ServiceAccountUserId, serviceAccountRole.Id)
if err != nil {
return handleNotFoundError(err, data)
}

setOpenidClientServiceAccountRealmRoleData(data, serviceAccountRole)

return nil
}

func resourceKeycloakOpenidClientServiceAccountRealmRoleDelete(data *schema.ResourceData, meta interface{}) error {
keycloakClient := meta.(*keycloak.KeycloakClient)

serviceAccountRole, err := getOpenidClientServiceAccountRealmRoleFromData(data, keycloakClient)
if err != nil {
return err
}

err = keycloakClient.DeleteOpenidClientServiceAccountRealmRole(serviceAccountRole.RealmId, serviceAccountRole.ServiceAccountUserId, serviceAccountRole.Id)
if err != nil {
return handleNotFoundError(err, data)
}
return nil
}

func resourceKeycloakOpenidClientServiceAccountRealmRoleImport(d *schema.ResourceData, _ interface{}) ([]*schema.ResourceData, error) {
parts := strings.Split(d.Id(), "/")
if len(parts) != 2 {
return nil, fmt.Errorf("Invalid import. Supported import formats: {{realmId}}/{{serviceAccountUserId}}/{{roleId}}")
}
d.Set("realm_id", parts[0])
d.Set("service_account_user_id", parts[1])
d.SetId(fmt.Sprintf("%s/%s", parts[1], parts[2]))

return []*schema.ResourceData{d}, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package provider

import (
"fmt"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/mrparkers/terraform-provider-keycloak/keycloak"
"strings"
"testing"
)

func TestAccKeycloakOpenidClientServiceAccountRealmRole_basic(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: testAccCheckKeycloakOpenidClientServiceAccountRealmRoleDestroy(),
Steps: []resource.TestStep{
{
Config: testKeycloakOpenidClientServiceAccountRealmRole_basic(realmName, clientId),
Check: testAccCheckKeycloakOpenidClientServiceAccountRealmRoleExists("keycloak_openid_client_service_account_realm_role.test"),
},
},
})
}

func TestAccKeycloakOpenidClientServiceAccountRealmRole_createAfterManualDestroy(t *testing.T) {
var serviceAccountRole = &keycloak.OpenidClientServiceAccountRealmRole{}

realmName := "terraform-" + acctest.RandString(10)
clientId := "terraform-" + acctest.RandString(10)

resource.Test(t, resource.TestCase{
Providers: testAccProviders,
PreCheck: func() { testAccPreCheck(t) },
CheckDestroy: testAccCheckKeycloakOpenidClientServiceAccountRealmRoleDestroy(),
Steps: []resource.TestStep{
{
Config: testKeycloakOpenidClientServiceAccountRealmRole_basic(realmName, clientId),
Check: testAccCheckKeycloakOpenidClientServiceAccountRealmRoleFetch("keycloak_openid_client_service_account_realm_role.test", serviceAccountRole),
},
{
PreConfig: func() {
keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)

err := keycloakClient.DeleteOpenidClientServiceAccountRealmRole(serviceAccountRole.RealmId, serviceAccountRole.ServiceAccountUserId, serviceAccountRole.Id)
if err != nil {
t.Fatal(err)
}
},
Config: testKeycloakOpenidClientServiceAccountRealmRole_basic(realmName, clientId),
Check: testAccCheckKeycloakOpenidClientServiceAccountRealmRoleExists("keycloak_openid_client_service_account_realm_role.test"),
},
},
})
}

func TestAccKeycloakOpenidClientServiceAccountRealmRole_basicUpdateRealm(t *testing.T) {
firstRealm := "terraform-" + acctest.RandString(10)
secondRealm := "terraform-" + acctest.RandString(10)
clientId := "terraform-" + acctest.RandString(10)

resource.Test(t, resource.TestCase{
Providers: testAccProviders,
PreCheck: func() { testAccPreCheck(t) },
CheckDestroy: testAccCheckKeycloakOpenidClientServiceAccountRealmRoleDestroy(),
Steps: []resource.TestStep{
{
Config: testKeycloakOpenidClientServiceAccountRealmRole_basic(firstRealm, clientId),
Check: resource.ComposeTestCheckFunc(
testAccCheckKeycloakOpenidClientServiceAccountRealmRoleExists("keycloak_openid_client_service_account_realm_role.test"),
resource.TestCheckResourceAttr("keycloak_openid_client_service_account_realm_role.test", "realm_id", firstRealm),
),
},
{
Config: testKeycloakOpenidClientServiceAccountRealmRole_basic(secondRealm, clientId),
Check: resource.ComposeTestCheckFunc(
testAccCheckKeycloakOpenidClientServiceAccountRealmRoleExists("keycloak_openid_client_service_account_realm_role.test"),
resource.TestCheckResourceAttr("keycloak_openid_client_service_account_realm_role.test", "realm_id", secondRealm),
),
},
},
})
}

func testAccCheckKeycloakOpenidClientServiceAccountRealmRoleExists(resourceName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
_, err := getKeycloakOpenidClientServiceAccountRealmRoleFromState(s, resourceName)
if err != nil {
return err
}

return nil
}
}

func testAccCheckKeycloakOpenidClientServiceAccountRealmRoleFetch(resourceName string, serviceAccountRole *keycloak.OpenidClientServiceAccountRealmRole) resource.TestCheckFunc {
return func(s *terraform.State) error {
fetchedServiceAccountRole, err := getKeycloakOpenidClientServiceAccountRealmRoleFromState(s, resourceName)
if err != nil {
return err
}

serviceAccountRole.ServiceAccountUserId = fetchedServiceAccountRole.ServiceAccountUserId
serviceAccountRole.RealmId = fetchedServiceAccountRole.RealmId
serviceAccountRole.Id = fetchedServiceAccountRole.Id

return nil
}
}

func testAccCheckKeycloakOpenidClientServiceAccountRealmRoleDestroy() resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "keycloak_openid_client_service_account_realm_role" {
continue
}

realmId := rs.Primary.Attributes["realm_id"]
serviceAccountUserId := rs.Primary.Attributes["service_account_user_id"]
id := strings.Split(rs.Primary.ID, "/")[1]

keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)

serviceAccountRole, _ := keycloakClient.GetOpenidClientServiceAccountRealmRole(realmId, serviceAccountUserId, id)
if serviceAccountRole != nil {
return fmt.Errorf("service account role exists")
}
}

return nil
}
}

func getKeycloakOpenidClientServiceAccountRealmRoleFromState(s *terraform.State, resourceName string) (*keycloak.OpenidClientServiceAccountRealmRole, error) {
keycloakClient := testAccProvider.Meta().(*keycloak.KeycloakClient)

rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return nil, fmt.Errorf("resource not found: %s", resourceName)
}

realmId := rs.Primary.Attributes["realm_id"]
serviceAccountUserId := rs.Primary.Attributes["service_account_user_id"]
id := strings.Split(rs.Primary.ID, "/")[1]

serviceAccountRole, err := keycloakClient.GetOpenidClientServiceAccountRealmRole(realmId, serviceAccountUserId, id)
if err != nil {
return nil, fmt.Errorf("error getting service account role mapping: %s", err)
}

return serviceAccountRole, nil
}

func testKeycloakOpenidClientServiceAccountRealmRole_basic(realm, clientId string) string {
return fmt.Sprintf(`
resource keycloak_realm test {
realm = "%s"
}
resource keycloak_openid_client test {
client_id = "%s"
realm_id = "${keycloak_realm.test.id}"
access_type = "CONFIDENTIAL"
service_accounts_enabled = true
}
resource keycloak_openid_client_service_account_realm_role test {
service_account_user_id = "${keycloak_openid_client.test.service_account_user_id}"
realm_id = "${keycloak_realm.test.id}"
role = "offline_access"
}
`, realm, clientId)
}

0 comments on commit 57d19b8

Please sign in to comment.