Skip to content

Commit

Permalink
New data source: azuread_directory_object (#847)
Browse files Browse the repository at this point in the history
* Initial DataSource file created

* Update location

* Switch Case added for some types

* Basic docs, removed linter problem and added client

* Run tflint

* Forgetting that it has to define the provider in the datasource registration

* Adding the Registration function

* Assign data to state correctly

* Update docs/data-sources/principal_type.md

Additional Interpolation removed

Co-authored-by: Tom Bamford <[email protected]>

* Update internal/services/directoryobjects/principal_type_data_source.go

Imports tidied up

Co-authored-by: Tom Bamford <[email protected]>

* Update docs/data-sources/principal_type.md

Wording as per suggestion

Co-authored-by: Tom Bamford <[email protected]>

* Updated as per other comments

* Removed redundant type for this data_source

* Import fmt and tests

* Fixing Tests + Documents

* Accidentally wrote the docs twice??

* Test config fixes, use provider context

* Rename data source, add missing nil checking

* TC config for directoryobjects package

* Docs to reflect renamed data source

* Docs wording for azuread_directory_object data source

* Update application_password.md

* Changelog for #844

* Fix for Issue #843 - end_date_relative for application_password (#844)

* Simple fix for end_date_relative bug

* Testing locally + logic

* There is no reason these two functions should be this different

* v2.27.0

* Add warning that OIDC auth only works in GitHub Actions

* Update docs/guides/service_principal_oidc.md

* Update to Go 1.19

* Remove tfproviderlint

* Docs: azuread_group.dynamic_membership.rule is required, not optional. Fixes #857

Co-authored-by: Tom Bamford <[email protected]>
Co-authored-by: Sam Gladstone <[email protected]>
  • Loading branch information
3 people authored Aug 25, 2022
1 parent 4360e46 commit 1381ad4
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 0 deletions.
1 change: 1 addition & 0 deletions .teamcity/components/project.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var services = mapOf(
"applications" to "Applications",
"approleassignments" to "App Role Assignments",
"conditionalaccess" to "Conditional Access",
"directoryobjects" to "Directory Objects",
"directoryroles" to "Directory Roles",
"domains" to "Domains",
"groups" to "Groups",
Expand Down
41 changes: 41 additions & 0 deletions docs/data-sources/directory_object.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
subcategory: "Base"
---

# Data Source: azuread_directory_object

Retrieves the OData type for a generic directory object having the provided object ID.

## API Permissions

The following API permissions are required in order to use this data source.

When authenticated with a service principal, this data source requires either `User.Read.All`, `Group.Read.All` or `Directory.Read.All`, depending on the type of object being queried.

When authenticated with a user principal, this data source does not require any additional roles.

## Example Usage

*Look up and output type of object by ID*
```terraform
data "azuread_directory_object" "example" {
object_id = "00000000-0000-0000-0000-000000000000"
}
output "object_type" {
value = data.azuread_directory_object.example.type
}
```

## Argument Reference

The following arguments are supported:

* `object_id` - (Optional) Specifies the Object ID of the directory object to look up.

## Attributes Reference

The following attributes are exported:

*`object_id` - The object ID of the directory object.
*`type` - The shortened OData type of the directory object. Possible values include: `Group`, `User` or `ServicePrincipal`.
2 changes: 2 additions & 0 deletions internal/provider/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/hashicorp/terraform-provider-azuread/internal/services/applications"
"github.com/hashicorp/terraform-provider-azuread/internal/services/approleassignments"
"github.com/hashicorp/terraform-provider-azuread/internal/services/conditionalaccess"
"github.com/hashicorp/terraform-provider-azuread/internal/services/directoryobjects"
"github.com/hashicorp/terraform-provider-azuread/internal/services/directoryroles"
"github.com/hashicorp/terraform-provider-azuread/internal/services/domains"
"github.com/hashicorp/terraform-provider-azuread/internal/services/groups"
Expand All @@ -20,6 +21,7 @@ func SupportedServices() []ServiceRegistration {
applications.Registration{},
approleassignments.Registration{},
conditionalaccess.Registration{},
directoryobjects.Registration{},
directoryroles.Registration{},
domains.Registration{},
groups.Registration{},
Expand Down
20 changes: 20 additions & 0 deletions internal/services/directoryobjects/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package client

import (
"github.com/manicminer/hamilton/msgraph"

"github.com/hashicorp/terraform-provider-azuread/internal/common"
)

type Client struct {
DirectoryObjectsClient *msgraph.DirectoryObjectsClient
}

func NewClient(o *common.ClientOptions) *Client {
directoryObjectsClient := msgraph.NewDirectoryObjectsClient(o.TenantID)
o.ConfigureClient(&directoryObjectsClient.BaseClient)

return &Client{
DirectoryObjectsClient: directoryObjectsClient,
}
}
78 changes: 78 additions & 0 deletions internal/services/directoryobjects/directory_object_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package directoryobjects

import (
"context"
"fmt"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/manicminer/hamilton/msgraph"
"github.com/manicminer/hamilton/odata"

"github.com/hashicorp/terraform-provider-azuread/internal/clients"
"github.com/hashicorp/terraform-provider-azuread/internal/tf"
"github.com/hashicorp/terraform-provider-azuread/internal/validate"
)

func directoryObjectDataSource() *schema.Resource {
return &schema.Resource{
ReadContext: directoryObjectDataSourceRead,

Timeouts: &schema.ResourceTimeout{
Read: schema.DefaultTimeout(5 * time.Minute),
},

Schema: map[string]*schema.Schema{
"object_id": {
Description: "The object ID of the principal",
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: validate.NoEmptyStrings,
},
"type": {
Description: "The OData type of the principal",
Type: schema.TypeString,
Computed: true,
},
},
}
}

func directoryObjectDataSourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*clients.Client).Users.DirectoryObjectsClient
client.BaseClient.DisableRetries = true

var directoryObject *msgraph.DirectoryObject

objectId := d.Get("object_id").(string)

directoryObject, _, err := client.Get(ctx, objectId, odata.Query{})
if err != nil {
return tf.ErrorDiagPathF(nil, "object_id", "Directory Object with ID %q was not found", objectId)
}
if directoryObject == nil {
return tf.ErrorDiagF(fmt.Errorf("nil object returned for directory object with ID: %q", objectId), "Bad API Response")
}
if directoryObject.ID == nil {
return tf.ErrorDiagF(fmt.Errorf("nil object ID returned for directory object with ID: %q", objectId), "Bad API Response")
}
if directoryObject.ODataType == nil {
return tf.ErrorDiagF(fmt.Errorf("nil OData Type returned for directory object with ID: %q", objectId), "Bad API Response")
}

d.SetId(*directoryObject.ID)

switch *directoryObject.ODataType {
case odata.TypeUser:
tf.Set(d, "type", "User")
case odata.TypeGroup:
tf.Set(d, "type", "Group")
case odata.TypeServicePrincipal:
tf.Set(d, "type", "ServicePrincipal")
default:
return diag.Errorf("unknown object type %q returned for directory object with ID: %q", *directoryObject.ODataType, objectId)
}

return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package directoryobjects_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"

"github.com/hashicorp/terraform-provider-azuread/internal/acceptance"
"github.com/hashicorp/terraform-provider-azuread/internal/acceptance/check"
)

type PrincipalTypeDataSource struct{}

func TestAccPrincipalTypeDataSource_groupByObjectId(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azuread_principal_type", "test")

data.DataSourceTest(t, []resource.TestStep{
{
Config: PrincipalTypeDataSource{}.objectTypeFromGroup(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("type").HasValue("Group"),
),
},
})
}

func TestAccPrincipalTypeDataSource_userByObjectId(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azuread_principal_type", "test")

data.DataSourceTest(t, []resource.TestStep{
{
Config: PrincipalTypeDataSource{}.objectTypeFromUser(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("type").HasValue("User"),
),
},
})
}

func TestAccPrincipalTypeDataSource_servicePrincipalByObjectId(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azuread_principal_type", "test")

data.DataSourceTest(t, []resource.TestStep{
{
Config: PrincipalTypeDataSource{}.objectTypeFromServicePrincipal(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("type").HasValue("ServicePrincipal"),
),
},
})
}

func (PrincipalTypeDataSource) basicGroup(data acceptance.TestData) string {
return fmt.Sprintf(`
resource "azuread_group" "test" {
display_name = "acctestGroup-%d"
security_enabled = true
}
`, data.RandomInteger)
}

func (PrincipalTypeDataSource) basicUser(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azuread" {}
data "azuread_domains" "test" {
only_initial = true
}
resource "azuread_user" "test" {
user_principal_name = "acctestUser'%[1]d@${data.azuread_domains.test.domains.0.domain_name}"
display_name = "acctestUser-%[1]d"
password = "%[2]s"
}
`, data.RandomInteger, data.RandomPassword)
}

func (PrincipalTypeDataSource) basicServicePrincipal(data acceptance.TestData) string {
return fmt.Sprintf(`
resource "azuread_application" "test" {
display_name = "acctest-%[1]d"
}
resource "azuread_service_principal" "test" {
application_id = azuread_application.test.application_id
}
`, data.RandomInteger)
}

func (PrincipalTypeDataSource) objectTypeFromGroup(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
data "azuread_principal_type" "test" {
object_id = azuread_group.test.object_id
}
`, PrincipalTypeDataSource{}.basicGroup(data))
}

func (PrincipalTypeDataSource) objectTypeFromUser(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
data "azuread_principal_type" "test" {
object_id = azuread_user.test.object_id
}
`, PrincipalTypeDataSource{}.basicUser(data))
}

func (PrincipalTypeDataSource) objectTypeFromServicePrincipal(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
data "azuread_principal_type" "test" {
object_id = azuread_service_principal.test.object_id
}
`, PrincipalTypeDataSource{}.basicServicePrincipal(data))
}
29 changes: 29 additions & 0 deletions internal/services/directoryobjects/registration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package directoryobjects

import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

type Registration struct{}

// Name is the name of this Service
func (r Registration) Name() string {
return "DirectoryObjects"
}

// WebsiteCategories returns a list of categories which can be used for the sidebar
func (r Registration) WebsiteCategories() []string {
return []string{
"Directory Objects",
}
}

// SupportedDataSources returns the supported Data Sources supported by this Service
func (r Registration) SupportedDataSources() map[string]*schema.Resource {
return map[string]*schema.Resource{
"azuread_directory_object": directoryObjectDataSource(),
}
}

// SupportedResources returns the supported Resources supported by this Service
func (r Registration) SupportedResources() map[string]*schema.Resource {
return map[string]*schema.Resource{}
}

0 comments on commit 1381ad4

Please sign in to comment.