Skip to content

Commit

Permalink
Add Support for Identity Registration and Usage Reports (#85)
Browse files Browse the repository at this point in the history
* Add support for Registration and Usage Reports
* Add more tests
* Prevent panic
* go mod tidy
* More panic fixing

Co-authored-by: Mark Dordoy <[email protected]>
  • Loading branch information
MarkDordoy and MarkDordoy authored Aug 9, 2021
1 parent cb52b72 commit 8e4b9d6
Show file tree
Hide file tree
Showing 7 changed files with 461 additions and 2 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.16
require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0
github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/go-version v1.3.0
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4=
github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
Expand Down
62 changes: 62 additions & 0 deletions msgraph/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,30 @@ type CountryNamedLocation struct {
IncludeUnknownCountriesAndRegions *bool `json:"includeUnknownCountriesAndRegions,omitempty"`
}

type CredentialUserRegistrationCount struct {
ID *string `json:"id,omitempty"`
TotalUserCount *int64 `json:"totalUserCount,omitempty"`
UserRegistrationCounts *[]UserRegistrationCount `json:"userRegistrationCounts,omitempty"`
}

type CredentialUsageSummary struct {
AuthMethod *UsageAuthMethod `json:"usageAuthMethod,omitempty"`
FailureActivityCount *int64 `json:"failureActivityCount,omitempty"`
Feature *FeatureType `json:"feature,omitempty"`
ID *string `json:"id,omitempty"`
SuccessfulActivityCount *int64 `json:"successfulActivityCount,omitempty"`
}
type CredentialUserRegistrationDetails struct {
AuthMethods *[]RegistrationAuthMethod `json:"authMethods,omitempty"`
ID *string `json:"id,omitempty"`
IsCapable *bool `json:"isCapable,omitempty"`
IsEnabled *bool `json:"isEnabled,omitempty"`
IsMfaRegistered *bool `json:"isMfaRegistered,omitempty"`
IsRegistered *bool `json:"isRegistered,omitempty"`
UserDisplayName *string `json:"userDisplayName,omitempty"`
UserPrincipalName *string `json:"UserPrincipalName,omitempty"`
}

type DeviceDetail struct {
Browser *string `json:"browser,omitempty"`
DeviceId *string `json:"deviceId,omitempty"`
Expand Down Expand Up @@ -1128,6 +1152,44 @@ type UserPasswordProfile struct {
Password *string `json:"password,omitempty"`
}

type UserRegistrationCount struct {
RegistrationStatus *RegistrationStatus `json:"registrationStatus,omitempty"`
RegistrationCount *int64 `json:"registrationCount,omitempty"`
}

type UserRegistrationFeatureCount struct {
Feature *AuthenticationMethodFeature `json:"feature,omitempty"`
UserCount *int64 `json:"userCount"`
}
type UserRegistrationFeatureSummary struct {
TotalUserCount *int64 `json:"totalUserCount,omitempty"`
UserRegistrationFeatureCounts *[]UserRegistrationFeatureCount `json:"userRegistrationFeatureCounts"`
UserRoles IncludedUserRoles `json:"userRoles,omitempty"`
UserTypes IncludedUserTypes `json:"userTypes,omitempty"`
}

type UserRegistrationMethodCount struct {
AuthenticationMethod *string `json:"authenticationMethod,omitempty"`
UserCount *int64 `json:"userCount,omitempty"`
}

type UserRegistrationMethodSummary struct {
TotalUserCount *int64 `json:"totalUserCount"`
UserRegistrationMethodsCount *[]UserRegistrationMethodCount `json:"userRegistrationMethodCounts,omitempty"`
UerRoles IncludedUserRoles `json:"userRoles,omitempty"`
UserTypes IncludedUserTypes `json:"userTypes,omitempty"`
}

type UserCredentialUsageDetails struct {
AuthMethod *UsageAuthMethod `json:"authMethod,omitempty"`
EventDateTime *time.Time `json:"eventDateTime,omitempty"`
FailureReason *string `json:"failureReason,omitempty"`
Feature *FeatureType `json:"feature,omitempty"`
ID *string `json:"id,omitempty"`
IsSuccess *bool `json:"isSuccess,omitempty"`
UserDisplayName *string `json:"userDisplayName,omitempty"`
UserPrincipalName *string `json:"userPrincipalName,omitempty"`
}
type VerifiedPublisher struct {
AddedDateTime *time.Time `json:"addedDateTime,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
Expand Down
185 changes: 185 additions & 0 deletions msgraph/reports.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package msgraph

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

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

// ReportsClient Client performs operations on reports.
type ReportsClient struct {
BaseClient Client
}

// NewReportsClient returns a new ReportsClient.
func NewReportsClient(tenantId string) *ReportsClient {
return &ReportsClient{
BaseClient: NewClient(VersionBeta, tenantId),
}
}

func (c *ReportsClient) GetCredentialUserRegistrationCount(ctx context.Context, query odata.Query) (*[]CredentialUserRegistrationCount, int, error) {
resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
DisablePaging: query.Top > 0,
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: "/reports/getCredentialUserRegistrationCount",
Params: query.Values(),
HasTenantId: true,
},
})
if err != nil {
return nil, status, fmt.Errorf("ReportsClient.BaseClient.Get(): %v", err)
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, status, fmt.Errorf("ioutil.ReadAll(): %v", err)
}
var data struct {
CredentialUserRegistrationCount []CredentialUserRegistrationCount `json:"value"`
}
if err := json.Unmarshal(respBody, &data); err != nil {
return nil, status, fmt.Errorf("json.Unmarshal(): %v", err)
}
return &data.CredentialUserRegistrationCount, status, nil
}

func (c *ReportsClient) GetCredentialUserRegistrationDetails(ctx context.Context, query odata.Query) (*[]CredentialUserRegistrationDetails, int, error) {
resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
DisablePaging: query.Top > 0,
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: "/reports/credentialUserRegistrationDetails",
Params: query.Values(),
HasTenantId: true,
},
})
if err != nil {
return nil, status, fmt.Errorf("ReportsClient.BaseClient.Get(): %v", err)
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, status, fmt.Errorf("ioutil.ReadAll(): %v", err)
}
var data struct {
CredentialUserRegistrationDetails []CredentialUserRegistrationDetails `json:"value"`
}
if err := json.Unmarshal(respBody, &data); err != nil {
return nil, status, fmt.Errorf("json.Unmarshal(): %v", err)
}
return &data.CredentialUserRegistrationDetails, status, nil
}

func (c *ReportsClient) GetUserCredentialUsageDetails(ctx context.Context, query odata.Query) (*[]UserCredentialUsageDetails, int, error) {
resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
DisablePaging: query.Top > 0,
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: "/reports/userCredentialUsageDetails",
Params: query.Values(),
HasTenantId: true,
},
})
if err != nil {
return nil, status, fmt.Errorf("ReportsClient.BaseClient.Get(): %v", err)
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, status, fmt.Errorf("ioutil.ReadAll(): %v", err)
}
var data struct {
UserCredentialUsageDetails []UserCredentialUsageDetails `json:"value"`
}
if err := json.Unmarshal(respBody, &data); err != nil {
return nil, status, fmt.Errorf("json.Unmarshal(): %v", err)
}
return &data.UserCredentialUsageDetails, status, nil
}

func (c *ReportsClient) GetCredentialUsageSummary(ctx context.Context, period CredentialUsageSummaryPeriod, query odata.Query) (*[]CredentialUsageSummary, int, error) {
resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
DisablePaging: query.Top > 0,
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: fmt.Sprintf("/reports/getCredentialUsageSummary(period='%s')", period),
Params: query.Values(),
HasTenantId: true,
},
})
if err != nil {
return nil, status, fmt.Errorf("ReportsClient.BaseClient.Get(): %v", err)
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, status, fmt.Errorf("ioutil.ReadAll(): %v", err)
}
var data struct {
CredentialUsageSummary []CredentialUsageSummary `json:"value"`
}
if err := json.Unmarshal(respBody, &data); err != nil {
return nil, status, fmt.Errorf("json.Unmarshal(): %v", err)
}
return &data.CredentialUsageSummary, status, nil
}

func (c *ReportsClient) GetAuthenticationMethodsUsersRegisteredByFeature(ctx context.Context, query odata.Query) (*UserRegistrationFeatureSummary, int, error) {
resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
DisablePaging: query.Top > 0,
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: "/reports/authenticationMethods/usersRegisteredByFeature",
Params: query.Values(),
HasTenantId: true,
},
})
if err != nil {
return nil, status, fmt.Errorf("ReportsClient.BaseClient.Get(): %v", err)
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, status, fmt.Errorf("ioutil.ReadAll(): %v", err)
}

var userRegistrationFeatureSummary UserRegistrationFeatureSummary

if err := json.Unmarshal(respBody, &userRegistrationFeatureSummary); err != nil {
return nil, status, fmt.Errorf("json.Unmarshal(): %v", err)
}
return &userRegistrationFeatureSummary, status, nil
}

func (c *ReportsClient) GetAuthenticationMethodsUsersRegisteredByMethod(ctx context.Context, query odata.Query) (*UserRegistrationMethodSummary, int, error) {
resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{
DisablePaging: query.Top > 0,
ValidStatusCodes: []int{http.StatusOK},
Uri: Uri{
Entity: "/reports/authenticationMethods/usersRegisteredByMethod",
Params: query.Values(),
HasTenantId: true,
},
})
if err != nil {
return nil, status, fmt.Errorf("ReportsClient.BaseClient.Get(): %v", err)
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, status, fmt.Errorf("ioutil.ReadAll(): %v", err)
}

var userRegistrationMethodSummary UserRegistrationMethodSummary

if err := json.Unmarshal(respBody, &userRegistrationMethodSummary); err != nil {
return nil, status, fmt.Errorf("json.Unmarshal(): %v", err)
}
return &userRegistrationMethodSummary, status, nil
}
Loading

0 comments on commit 8e4b9d6

Please sign in to comment.