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

Add IP and Country Named Locations #24

Merged
merged 22 commits into from
Apr 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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
44 changes: 36 additions & 8 deletions msgraph/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,14 @@ type AppRole struct {
Value *string `json:"value,omitempty"`
}

type BaseNamedLocation struct {
ODataType *string `json:"@odata.type,omitempty"`
ID *string `json:"id,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
CreatedDateTime *time.Time `json:"createdDateTime,omitempty"`
ModifiedDateTime *time.Time `json:"modifiedDateTime,omitempty"`
}

type CloudAppSecurityControl struct {
IsEnabled *bool `json:"isEnabled,omitempty"`
CloudAppSecurityType *string `json:"cloudAppSecurityType,omitempty"`
Expand Down Expand Up @@ -306,6 +314,21 @@ type ConditionalAccessSessionControls struct {
SignInFrequency *SignInFrequencySessionControl `json:"signInFrequency,omitempty"`
}

// CountryNamedLocation describes an Country Named Location object.
type CountryNamedLocation struct {
*BaseNamedLocation
CountriesAndRegions *[]string `json:"countriesAndRegions,omitempty"`
IncludeUnknownCountriesAndRegions *bool `json:"includeUnknownCountriesAndRegions,omitempty"`
}

// DirectoryRoleTemplate describes a Directory Role Template.
type DirectoryRoleTemplate struct {
ID *string `json:"id,omitempty"`
DeletedDateTime *time.Time `json:"deletedDateTime,omitempty"`
Description *string `json:"description,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
}

// Domain describes a Domain object.
type Domain struct {
ID *string `json:"id,omitempty"`
Expand Down Expand Up @@ -451,6 +474,17 @@ type InvitedUserMessageInfo struct {
MessageLanguage *string `json:"messageLanguage,omitempty"`
}

// IPNamedLocation describes an IP Named Location object.
type IPNamedLocation struct {
*BaseNamedLocation
IPRanges *[]IPNamedLocationIPRange `json:"ipRanges,omitempty"`
IsTrusted *bool `json:"isTrusted,omitempty"`
}

type IPNamedLocationIPRange struct {
CIDRAddress *string `json:"cidrAddress,omitempty"`
}

type KerberosSignOnSettings struct {
ServicePrincipalName *string `json:"kerberosServicePrincipalName,omitempty"`
SignOnMappingAttributeType *string `jsonL:"kerberosSignOnMappingAttributeType,omitempty"`
Expand All @@ -475,6 +509,8 @@ type Me struct {
UserPrincipalName *string `json:"userPrincipalName"`
}

type NamedLocation interface{}

type OnPremisesPublishing struct {
AlternateUrl *string `json:"alternateUrl,omitempty"`
ApplicationServerTimeout *string `json:"applicationServerTimeout,omitempty"`
Expand Down Expand Up @@ -712,11 +748,3 @@ type VerifiedPublisher struct {
DisplayName *string `json:"displayName,omitempty"`
VerifiedPublisherId *string `json:"verifiedPublisherId,omitempty"`
}

// DirectoryRoleTemplate describes a Directory Role Template.
type DirectoryRoleTemplate struct {
ID *string `json:"id,omitempty"`
DeletedDateTime *time.Time `json:"deletedDateTime,omitempty"`
Description *string `json:"description,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
}
250 changes: 250 additions & 0 deletions msgraph/namedlocations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
package msgraph

import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"

"github.com/manicminer/hamilton/internal/utils"
"github.com/manicminer/hamilton/odata"
)

// NamedLocationsClient performs operations on Named Locations.
type NamedLocationsClient struct {
BaseClient Client
}

// NewNamedLocationsClient returns a new NamedLocationsClient.
func NewNamedLocationsClient(tenantId string) *NamedLocationsClient {
return &NamedLocationsClient{
BaseClient: NewClient(Version10, tenantId),
}
}

// List returns a list of Named Locations, optionally filtered using OData.
func (c *NamedLocationsClient) List(ctx context.Context, filter string) (*[]NamedLocation, int, error) {
params := url.Values{}
if filter != "" {
params.Add("$filter", filter)
}

resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: "/identity/conditionalAccess/namedLocations",
Params: params,
HasTenantId: true,
},
})

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

defer resp.Body.Close()
respBody, _ := ioutil.ReadAll(resp.Body)

var data struct {
NamedLocations *[]json.RawMessage `json:"value"`
}

if err := json.Unmarshal(respBody, &data); err != nil {
return nil, status, err
}

if data.NamedLocations == nil {
return nil, status, err
}
// The Graph API returns a mixture of types, this loop matches up the result to the appropriate model
var ret []NamedLocation
for _, namedLocation := range *data.NamedLocations {
var o odata.OData
if err := json.Unmarshal(namedLocation, &o); err != nil {
return nil, status, err
}

if o.Type == nil {
continue
}
switch *o.Type {
case "#microsoft.graph.countryNamedLocation":
var loc CountryNamedLocation
if err := json.Unmarshal(namedLocation, &loc); err != nil {
return nil, status, err
}
ret = append(ret, loc)
case "#microsoft.graph.ipNamedLocation":
var loc IPNamedLocation
if err := json.Unmarshal(namedLocation, &loc); err != nil {
return nil, status, err
}
ret = append(ret, loc)
}
}

return &ret, status, nil

}

// Delete removes a Named Location.
func (c *NamedLocationsClient) Delete(ctx context.Context, id string) (int, error) {
_, status, _, err := c.BaseClient.Delete(ctx, DeleteHttpRequestInput{
ValidStatusCodes: []int{http.StatusNoContent},
Uri: Uri{
Entity: fmt.Sprintf("/identity/conditionalAccess/namedLocations/%s", id),
HasTenantId: true,
},
})
if err != nil {
return status, err
}
return status, nil
}

// CreateIP creates a new IP Named Location.
func (c *NamedLocationsClient) CreateIP(ctx context.Context, ipNamedLocation IPNamedLocation) (*IPNamedLocation, int, error) {
var status int

ipNamedLocation.ODataType = utils.StringPtr("#microsoft.graph.ipNamedLocation")
body, err := json.Marshal(ipNamedLocation)
if err != nil {
return nil, status, err
}
resp, status, _, err := c.BaseClient.Post(ctx, PostHttpRequestInput{
Body: body,
ValidStatusCodes: []int{http.StatusCreated},
Uri: Uri{
Entity: "/identity/conditionalAccess/namedLocations",
HasTenantId: true,
},
})
if err != nil {
return nil, status, err
}
defer resp.Body.Close()
respBody, _ := ioutil.ReadAll(resp.Body)
var newIPNamedLocation IPNamedLocation
if err := json.Unmarshal(respBody, &newIPNamedLocation); err != nil {
return nil, status, err
}
return &newIPNamedLocation, status, nil
}

// CreateCountry creates a new Country Named Location.
func (c *NamedLocationsClient) CreateCountry(ctx context.Context, countryNamedLocation CountryNamedLocation) (*CountryNamedLocation, int, error) {
var status int

countryNamedLocation.ODataType = utils.StringPtr("#microsoft.graph.countryNamedLocation")

body, err := json.Marshal(countryNamedLocation)
if err != nil {
return nil, status, err
}
resp, status, _, err := c.BaseClient.Post(ctx, PostHttpRequestInput{
Body: body,
ValidStatusCodes: []int{http.StatusCreated},
Uri: Uri{
Entity: "/identity/conditionalAccess/namedLocations",
HasTenantId: true,
},
})
if err != nil {
return nil, status, err
}
defer resp.Body.Close()
respBody, _ := ioutil.ReadAll(resp.Body)
var newCountryNamedLocation CountryNamedLocation
if err := json.Unmarshal(respBody, &newCountryNamedLocation); err != nil {
return nil, status, err
}
return &newCountryNamedLocation, status, nil
}

// GetIP retrieves an IP Named Location.
func (c *NamedLocationsClient) GetIP(ctx context.Context, id string) (*IPNamedLocation, int, error) {
resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: fmt.Sprintf("/identity/conditionalAccess/namedLocations/%s", id),
HasTenantId: true,
},
})
if err != nil {
return nil, status, err
}
defer resp.Body.Close()
respBody, _ := ioutil.ReadAll(resp.Body)
var ipNamedLocation IPNamedLocation
if err := json.Unmarshal(respBody, &ipNamedLocation); err != nil {
return nil, status, err
}
return &ipNamedLocation, status, nil
}

// GetCountry retrieves an Country Named Location.
func (c *NamedLocationsClient) GetCountry(ctx context.Context, id string) (*CountryNamedLocation, int, error) {
resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: fmt.Sprintf("/identity/conditionalAccess/namedLocations/%s", id),
HasTenantId: true,
},
})
if err != nil {
return nil, status, err
}
defer resp.Body.Close()
respBody, _ := ioutil.ReadAll(resp.Body)
var countryNamedLocation CountryNamedLocation
if err := json.Unmarshal(respBody, &countryNamedLocation); err != nil {
return nil, status, err
}
return &countryNamedLocation, status, nil
}

// UpdateIP amends an existing IP Named Location.
func (c *NamedLocationsClient) UpdateIP(ctx context.Context, ipNamedLocation IPNamedLocation) (int, error) {
var status int

body, err := json.Marshal(ipNamedLocation)
if err != nil {
return status, err
}
_, status, _, err = c.BaseClient.Patch(ctx, PatchHttpRequestInput{
Body: body,
ValidStatusCodes: []int{http.StatusNoContent},
Uri: Uri{
Entity: fmt.Sprintf("/identity/conditionalAccess/namedLocations/%s", *ipNamedLocation.ID),
HasTenantId: true,
},
})
if err != nil {
return status, err
}
return status, nil
}

// UpdateCountry amends an existing Country Named Location.
func (c *NamedLocationsClient) UpdateCountry(ctx context.Context, countryNamedLocation CountryNamedLocation) (int, error) {
var status int

body, err := json.Marshal(countryNamedLocation)
if err != nil {
return status, err
}
_, status, _, err = c.BaseClient.Patch(ctx, PatchHttpRequestInput{
Body: body,
ValidStatusCodes: []int{http.StatusNoContent},
Uri: Uri{
Entity: fmt.Sprintf("/identity/conditionalAccess/namedLocations/%s", *countryNamedLocation.ID),
HasTenantId: true,
},
})
if err != nil {
return status, err
}
return status, nil
}
Loading