manicminer / hamilton Goto Github PK
View Code? Open in Web Editor NEWGo SDK for Microsoft Graph
License: Apache License 2.0
Go SDK for Microsoft Graph
License: Apache License 2.0
Running into an issue attempting to interact with /identityGovernance/accessReviews/definitions
type AccessReviewClient struct {
BaseClient msgraph.Client
}
func NewAccessReviewClient(tenantId string) *AccessReviewClient {
return &AccessReviewClient{
BaseClient: msgraph.NewClient(msgraph.VersionBeta, tenantId),
}
}
func main() {
ctx := context.Background()
clientSecret := os.Getenv("CLIENT_SECRET")
authConfig := &auth.Config{
Environment: environments.USGovernmentL4,
TenantID: "<redacted>",
ClientID: "<redacted>",
ClientSecret: clientSecret,
EnableClientSecretAuth: true,
}
authorizer, err := authConfig.NewAuthorizer(ctx, auth.MsGraph)
if err != nil {
log.Fatal(err)
}
accessReviewClient := NewAccessReviewClient(authConfig.TenantID)
accessReviewClient.BaseClient.Authorizer = authorizer
accessReviewClient.BaseClient.Endpoint = environments.MsGraphUSGovL4Endpoint
resp, _, _, err := accessReviewClient.BaseClient.Get(ctx, msgraph.GetHttpRequestInput{
ValidStatusCodes: []int{http.StatusOK},
DisablePaging: false,
Uri: msgraph.Uri{
Entity: "/identityGovernance/accessReviews/definitions",
HasTenantId: true,
},
})
}
The response I get back is
"could not read response body: http: read on closed response body"
Did some digging with the help of @MarkDordoy
And found what we believe is the source of the issue
When performing this call via https://developer.microsoft.com/
Below is an example response (some details redacted)
{
"@odata.context": "https://graph.microsoft.us/beta/$metadata#identityGovernance/accessReviews/definitions",
"@odata.count": 4,
"value": [
{
"id": "<redacted>",
"displayName": "<redacted>",
"createdDateTime": "<redacted>",
"lastModifiedDateTime": "<redacted>",
"status": "InProgress",
"descriptionForAdmins": "",
"descriptionForReviewers": "",
"customDataProvider": null,
"customData": null,
"createdBy": {
"id": "<redacted>",
"displayName": "<redacted>",
"type": null,
"userPrincipalName": "<redacted>"
},
"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "<redacted>",
"queryType": "MicrosoftGraph",
"queryRoot": null
},
"instanceEnumerationScope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "<redacted>",
"queryType": "MicrosoftGraph",
"queryRoot": null
},
"reviewers": [
{
"query": "<redacted>",
"queryType": "MicrosoftGraph",
"queryRoot": null
},
{
"query": "<redacted>",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
],
"backupReviewers": [],
"fallbackReviewers": [],
"settings": {
"mailNotificationsEnabled": true,
"reminderNotificationsEnabled": true,
"justificationRequiredOnApproval": true,
"defaultDecisionEnabled": false,
"defaultDecision": "None",
"instanceDurationInDays": 30,
"autoApplyDecisionsEnabled": false,
"recommendationsEnabled": true,
"recommendationLookBackDuration": "P30D",
"recurrence": {
"pattern": null,
"range": {
"type": "numbered",
"numberOfOccurrences": 0,
"recurrenceTimeZone": null,
"startDate": "<redacted>",
"endDate": "<redacted>"
}
},
"applyActions": [
{
"@odata.type": "#microsoft.graph.removeAccessApplyAction"
}
]
},
"additionalNotificationRecipients": [],
"[email protected]": "https://graph.microsoft.us/beta/$metadata#identityGovernance/accessReviews/definitions('<redacted>')/instances",
"instances": []
}
]
}
Specifically the return value of "@odata.count": 4,
is important to note
https://github.com/manicminer/hamilton/blob/main/odata/odata.go#L89
type OData struct {
Context *string `json:"@odata.context"`
MetadataEtag *string `json:"@odata.metadataEtag"`
Type *Type `json:"@odata.type"`
Count *string `json:"@odata.count"`
NextLink *string `json:"@odata.nextLink"`
Delta *string `json:"@odata.delta"`
DeltaLink *string `json:"@odata.deltaLink"`
Id *Id `json:"@odata.id"`
Etag *string `json:"@odata.etag"`
Error *Error `json:"-"`
Value interface{} `json:"value"`
}
when we changed the Count
type from *string
to *int
the call was successful
Is it possible msgraph sometimes returns *string
for Count
and other times *int
?
Hello everyone ๐
Vincent here from the Microsoft Graph SDKs team. I'm reaching out to announce we're working on an official Go SDK, we haven't announced the community preview yet as there are still a number of things we need to work through, but I though I'd reach out to give you an opportunity to provide feedback before anybody else!
A few benefits from this new SDK:
As with every pre-previews, we have a list of known limitations we're working through.
We'd love for you to pop by the repos under our org, give it a try, and give us feedback on your experience with this new SDK.
General Issue tracker for everything related to AccessPackage implementation within Identity & Governance Management. Will leave PR in draft state any comments, suggestions or contributions welcome
https://docs.microsoft.com/en-us/graph/api/resources/entitlementmanagement-root?view=graph-rest-beta
Rest of endpoints do not have Creation/Deletion capabiltity / Directly related to IDAG IaC flows
Hi!
Do you plan to support CAE in the ConditionalAccessSessionControls model?
Thanks in advance!
KR,
-J
msgraph.SynchronizationJobProvisionOnDemand
requires RuleId
of synchronization schema as its parameter for on-demand provisioning; but, so far I could not find implementations fetching the schema. The document can be found in below:
I have read several classes including SynchronizationJobClient
, but if there is one, please let me know
Thanks in advance.
It would be really awesome if we could add support for JSON batch requests https://docs.microsoft.com/en-us/graph/json-batching.
Although I'm really not sure the best way to cleanly integrate it here especially if batching multiple different request types and then mapping the responses appropriately. I don't mind having a poke around to see if it's possible given a consensus it would be a beneficial feature to have.
We would like to use terraform to allow JIT groups to get conditional access, like effective / or active.
Hi!
Just found this project looking through the azuread terraform provider. Great work!
I've been building a reverse proxy that allows normal users and service principals to connect to any Kubernetes API and one part of this is extracting the groups they are members of.
I'm using a pure http client to get all the groups for a service principal, but after looking at this SDK it should fit quite well here instead.
Do you have any thoughts on adding this functionality to this SDK?
This is how I am doing it right now: https://github.com/XenitAB/azad-kube-proxy/blob/main/pkg/azure/service_principal.go
It seems synapse api is available in USGovernmentCloud
It would be nice to have OIDC authentication support instead of just GitHub Tokens, which appears to be a more specific unique implementation only to GitHub that differs from Kubernetes and the "Other Issuer" for OIDC support for Service Principal Authentication
I'm passing an autorest.BearerAuthorization to the wrappedAuth, err := auth.NewAutorestAuthorizerWrapper(authorizer)
method call but it returns could not obtain access token from token provider
.
It appears it's trying to find .Token
method and failing. The autorest.BearerAuthorization provider only has a OAuthToken
method.
Is this a bug or am I using it incorrectly?
Thanks.
I have around 605 service principals in my tenant.
I am calling the below function nearly concurrently for all the 605 service principals
func getAdServicePrincipalOwners(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
servicePrincipalId := *h.Item.(msgraph.ServicePrincipal).ID
session, err := GetNewSession(ctx, d)
if err != nil {
return nil, err
}
client := msgraph.NewServicePrincipalsClient(session.TenantID)
client.BaseClient.Authorizer = session.Authorizer
owners, _, err := client.ListOwners(ctx, servicePrincipalId)
if err != nil {
return nil, err
}
return owners, nil
}
At the moment the HttpClient used isn't exported, which means it's not possible to use a custom client. Just to give some background, the reason I want to be able to do this is to provide a custom client that adds tracing of HTTP requests.
I've created a fork to quickly test out replacing the client by making it exported: adamconnelly@11eb20a. That allows me to create a client like this:
client := msgraph.NewApplicationsClient(tenantID)
client.BaseClient.Authorizer = authorizer
client.BaseClient.HttpClient = tracedClient
That works great, but I wanted to check a couple of things:
NewApplicationsClient()
function, or something along those lines?Thanks!
Hi!
As always, love the job you are doing here! ๐ฅ
As per our previous dialouge, it would be quite nice if hamilton could be used without having to import Microsofts autorest library.
I see two possible ways of handling this:
Choice 1 - new module in hamilton repo
PROS:
CONS:
auth/autorest/v0.39.0
in sync with v0.39.0
Choice 2 - new repository
PROS:
CONS:
Conclusion
I would personally vote for a separate repository, hamilton-autorest
, and just place everything that is using autorest there. This repository should be "clean" and easy to use - if autorest is needed it is available in a different place.
The beta version returns more info than the v1.0 version, including the important catalogId
, see below screenshots.
hamilton/msgraph/accesspackage.go
Line 20 in 74bfde9
Attempting to query below API endpoint -
GET
/identityGovernance/accessReviews/definitions/{accessReviewScheduleDefinitionId}/instances/{accessReviewInstanceId}/decisions/
I'm running into a weird issue where some of the data is returning blank. In addition I'm getting interesting errors when attempting to debug in vscode
type AccessReviewDecisionClient struct {
BaseClient msgraph.Client
}
func NewAccessReviewDecisionClient(tenantId string) *AccessReviewDecisionClient {
return &AccessReviewDecisionClient{
BaseClient: msgraph.NewClient(msgraph.Version10, tenantId),
}
}
type ReviewedBy struct {
ID *string `json:"id,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
Type *string `json:"type,omitempty"`
UserPrincipalName *string `json:"userPrincipalName,omitempty"`
}
type AccessReviewDecision struct {
Decision *string `json:"decision,omitempty"`
ID *string `json:"id,omitempty"`
Justification *string `json:"justification,omitempty"`
LastModifiedDateTimeateTime *time.Time `json:"lastModifiedDateTime,omitempty"`
ReviewedBy *[]ReviewedBy `json:"reviewedBy,omitempty"`
Status *string `json:"target,omitempty"`
Target *string `json:"status,omitempty"`
}
// Get returns a list of AccessReviewDecisions
func (c *AccessReviewDecisionClient) Get(ctx context.Context, id string, query odata.Query) (*[]AccessReviewDecision, int, error) {
resp, status, _, err := c.BaseClient.Get(ctx, msgraph.GetHttpRequestInput{
DisablePaging: query.Top > 0,
ValidStatusCodes: []int{http.StatusOK},
Uri: msgraph.Uri{
Entity: fmt.Sprintf("/identityGovernance/accessReviews/definitions/%s/instances/%s/decisions", id, id),
Params: query.Values(),
HasTenantId: true,
},
})
if err != nil {
return nil, status, fmt.Errorf("AccessReviewDecisionClient.BaseClient.Get(): %v", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, status, fmt.Errorf("io.ReadAll(): %v", err)
}
var data struct {
AccessReviewDecisions []AccessReviewDecision `json:"value"`
}
if err := json.Unmarshal(respBody, &data); err != nil {
return nil, status, fmt.Errorf("json.Unmarshal(): %v", err)
}
return &data.AccessReviewDecisions, status, nil
}
During the debug I've narrowed it down to the response itself - https://github.com/manicminer/hamilton/blob/main/msgraph/client.go#L209
As I attempt to see what is being returned specifically for the reviewedBy
property within the o
var the value is blank
Interestingly I get below errors when attempting to expand the reviewedBy
property in vscode (which I'm not sure is related or not)
Failed to evaluate expression - could not find symbol value for undefined
Last known immediate stacktrace (goroutine id 1):
/Users/amarbut/go/pkg/mod/github.com/manicminer/[email protected]/odata/http.go:37
github.com/manicminer/hamilton/odata.FromResponse
/Users/amarbut/go/pkg/mod/github.com/manicminer/[email protected]/msgraph/client.go:208
github.com/manicminer/hamilton/msgraph.Client.performRequest
/Users/amarbut/go/pkg/mod/github.com/manicminer/[email protected]/msgraph/client.go:342
github.com/manicminer/hamilton/msgraph.Client.Get
/Users/amarbut/Github/accessreview-bot/main/accessreviewdecision.go:44
main.(*AccessReviewDecisionClient).Get
/Users/amarbut/Github/accessreview-bot/main/main.go:50
main.main
/usr/local/Cellar/go/1.17/libexec/src/runtime/proc.go:255
runtime.main
/usr/local/Cellar/go/1.17/libexec/src/runtime/asm_amd64.s:1581
runtime.goexit
If I query this same object using something like Powershell I get a proper value back
"reviewedBy": {
"id": "ef1ba2d2-7ec6-4924-bf52-7ffc0bbb4e95",
"displayName": "John Doe",
"type": null,
"userPrincipalName": "[email protected]"
},
Sorry if this is just me doing something terribly wrong
In case it helps below is an example returned value (with some randomized GUIDs and fake users)
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews/definitions('99009005-f369-4b40-a571-0b200d5953ac')/instances('99009005-f369-4b40-a571-0b200d5953ac')/decisions",
"@odata.count": 9,
"value": [
{
"id": "b50bc646-3a3d-462a-952e-e6314964aa14",
"accessReviewId": "99009005-f369-4b40-a571-0b200d5953ac",
"reviewedDateTime": "2021-03-10T01:29:22.543Z",
"decision": "Approve",
"justification": "",
"appliedDateTime": null,
"applyResult": "New",
"recommendation": "Deny",
"principalLink": "https://graph.microsoft.com/v1.0/users/a18f6504-4d68-4636-b9a9-af21a94953cf",
"resourceLink": null,
"resource": null,
"reviewedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "Test User",
"type": null,
"userPrincipalName": "[email protected]"
},
"appliedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "",
"type": null,
"userPrincipalName": ""
},
"principal": {
"@odata.type": "#microsoft.graph.userIdentity",
"id": "f7e60e6e-a04f-4716-8dfc-e4078207cadf",
"displayName": "test guest",
"type": "user",
"userPrincipalName": "[email protected]",
"lastUserSignInDateTime": ""
}
}
]
}
Currently uses /administrativeUnits
It appears this has been moved to /directory/administrativeUnits
Hi!
One thing I've been missing for a long time is to have "current user" information available easily.
Information that would be interesting:
Not sure if this is actually possible, but a normal user does have information available from /me and I think some of the information should be available from the token. I know a service principal can lookup itself as long as it knows the AppID.
Thoughts? ๐
This would be really useful to add a data source to the terraform provider to support hashicorp/terraform-provider-azuread#1032
The List
method on appRoleAssignments is missing the ability to specify OData query parameters. This should be supported according to the docs:
https://learn.microsoft.com/en-us/graph/api/group-list-approleassignments
https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list-approleassignments
https://learn.microsoft.com/en-us/graph/api/user-list-approleassignments
EnvironmentFromString hardcodes a list of supported environments. The Hashicorp Terraform Provider for AzureRM makes use of EnvironmentFromString here
Because the list is hardcoded, the terraform provider is useless for Azure environments whose URLs cannot be publicly published. Azure provides a method to discover the URLs for all the endpoints referenced in the Environment structure by using the metadata URL. A sample implementation of using this URL is located here
Please add EnvironmentFromMetadataUrl(url string) (Environment, error)
to support additional Azure environments and make hamilton more globally useful.
Thanks!
Currently, in AzureCliAuthorizer.Token()
, the arguments to az
are hard-coded as
{"account", "get-access-token", fmt.Sprintf("--resource=%s", a.conf.Endpoint)}
This is correct for ADAL and also works for MSAL as long as you need the default scope of Resource Manager. However, for a different scope like KeyVault, the arguments should instead be
{"account", "get-access-token", fmt.Sprintf("--scope=%s", a.conf.Endpoint+"/.default")}
Note the MSAL-style (OAuth v2) scope
.
I tested the above change and it unblocked a small program that changes Key Vault secrets. I don't have a full PR just yet because I wasn't sure how you wanted to treat MSAL vs ADAL here.
currently NewDirectoryObjectsClient().GetByIds()
only provides following information:
type DirectoryObject struct {
ODataId *odata.Id `json:"@odata.id,omitempty"`
ODataType *odata.Type `json:"@odata.type,omitempty"`
ID *string `json:"id,omitempty"`
}
would be good to have more information about the objects which is available in the response from MsGraph REST API, eg displayName
, appId
, alternativeNames
, ...
or make provide a possible way to supply own struct here or only provide an dynamic interface here (to dynamically fetch data)
I've notice that all requests are using a double forward slash, e.g.:
GET /v1.0//servicePrincipals
If there is no particular reason, can those be removed?
Hi @manicminer!
See this as and idea / feature request.
It would be a nice feature if scopes was configurable, to make it possible to use the auth package to get access tokens for plain AAD applications.
I'm using azidentity right now for this. Would be able to slim down my dependencies to only your lib.
There is no support for operations on Connected Organizations in entitlement management.
This SDK supports creating schema extensions, however it does not yet support for example adding an extensions data to an allowed object, for example a user.
Reading the documentation/examples it looks like we need to perform a patch call against the target object, however our update functions for users/groups etc requires a user/group object which has no concept of the schema extension (as in theory it could be anything).
I'd like to extend the SDK to support these kind of updates, however i'm looking to get some opinions on the best way to achieve this.
I can get myself around the problem by writing my own function that expects the schema extension i want to use, but i want to make this generic and add to the SDK.
Im still new to writing go so i'll welcome the most simple options :-)
This is a really great library that was pretty easy to figure out from the logical structure of the code so far, nice work!
The testing section of the readme mentions this:
some tests require an Azure AD Premium P2 license and/or an Office 365 license. You can authenticate with any supported method for the client tests, and the auth tests are split by authentication method.
In principle I hate the idea of any kind of selective behavior for test execution, but given the pricing structure of Azure services it seems unavoidable unless every potential contributor is willing to spend $$ for the requires SKUs to support executing all tests in their own local dev environment.
For some development use cases having an entire P2 AAD and O365 environment enabled to run tests seems like overkill. Do you have any ideas or suggestions how we could selectively disable parts of the test infrastructure that depend on those more expensive features?
Hi!
I am currently trying to get cosign
to work with Azure Container Registry: sigstore/cosign#1350
It is using the following project to get the token for ACR: https://github.com/chrismellard/docker-credential-acr-env
I would like to include a similar helper in hamilton that will be using hamilton instead of autorest.
Hi, I have noticed that writebackConfiguration is not currently supported, is there a special reason for that? Is there another way to achieve that?
As far as I understand, all it requires is adding this to the group creation payload:
"writebackConfiguration": {
"isEnabled": true,
"onPremisesGroupType": UniversalSecurityGroup
},
If there is no reason for this to not be there, I can make a PR for it
Hi @manicminer!
There's a quite new endpoint that would be really awesome to have support for, especially in regard to using it with the Azure AD terraform provider: https://docs.microsoft.com/en-us/graph/api/resources/federatedidentitycredentials-overview?view=graph-rest-beta
The big reason for this is to enable SSO between GitHub Actions and Azure / Azure AD: https://docs.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-cli%2Clinux#use-the-azure-login-action-with-openid-connect
We would like support for CRUD of service principals app role assignments.
https://docs.microsoft.com/en-us/graph/api/resources/approleassignment?view=graph-rest-1.0
This can then eventually be incorporated into the Terraform AzureAD provider to alleviate workarounds such as this.
I see many fields on the Group struct are pointers to slices. Is this to ensure the value can be used as a key in a map?
The Group value is something that would be fit for caching. There are a few fields whose types do not allow values of type Group to be hashable for some implementations of an LRU cache. For example, []GroupType
and []GroupResourceBehaviorOption
.
Since many slice fields are already pointers to a slice, is it possible to convert those remaining fields' types to pointer to a slice, so that Group may be used as a key in a map?
Also, the GroupsClient returns not a slice of group pointers []*Group
, but a pointer to a slice of groups *[]Group
? Is this intentional as well?
Reading the code of this line:
Line 174 in aa2110f
If I need to pass the tuple (group_id, member_id) and the return is an ID of the member, the method shouldn't be called IsMemberOf
?
I would expect to have the full member object if I do a GetMember
First, nice work, very easy to understand, congrats
I have a question after reading your code, Did you think about the use resty? it's a small lib for REST that will handle backoff retries and you will be able to inject the oauth2 client.
Your code will get (even more) cleaner and easy to maintain probably.
Hi!
I'm using this great SDK in a proxy and after running for a few days it seems like token refresh stops working. Not sure exactly when it happens but it at least takes a few days. A restart of my proxy resolves the issue.
I have created an issue in my repo with some logs (that I think are related): XenitAB/azad-kube-proxy#118
Not completely sure this is caused by Hamilton, but creating issue and will get back with how I resolve it.
Hi,
Is it possible to add support for the chat resource at all?
I'm able to get the data I need using msgraph.NewClient
and providing an msgraph.GetHttpRequestInput
with the relevant entity for now, but built in support would be awesome.
Many thanks,
D.
Hi!
It would be great if there was a soft fail for when multiple auth methods are used.
As an example, if we're not able to get a token with MSI - the next method should be tried.
I've got a similar issue with azidentity: Azure/azure-sdk-for-go#14214
My personal opinion is that auth methods should be tried in the following order:
Thanks!
Hi!
When using List and methods like it, pagination will most likely be required when there are large amount of groups/users etc.
Hi, I'm having some issues with getting the msi authorizer to work. I'm kinda new to azure so might be something I'm not getting, but I'm getting this error when calling the groups client:
GroupsClient.BaseClient.Get(): MsiAuthorizer: failed to request token from metadata endpoint: Get "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fgraph.microsoft.com%2F": context deadline exceeded
This is how I set up the client and authorizer, am I missing something in the authConfig?
func NewClient(ctx context.Context, tenantID string) (*GraphClient, error) {
environment := environments.Global
authConfig := &auth.Config{
EnableMsiAuth: true,
}
authorizer, err := authConfig.NewAuthorizer(ctx, environment.MsGraph)
if err != nil {
log.Fatal(err)
}
log.Println("Print authorizer token")
log.Println(authorizer.Token())
usersClient := msgraph.NewUsersClient(tenantID)
groupsClient := msgraph.NewGroupsClient(tenantID)
objectsClient := msgraph.NewDirectoryObjectsClient(tenantID)
servicePrincipalClient := msgraph.NewServicePrincipalsClient(tenantID)
usersClient.BaseClient.Authorizer = authorizer
groupsClient.BaseClient.Authorizer = authorizer
objectsClient.BaseClient.Authorizer = authorizer
servicePrincipalClient.BaseClient.Authorizer = authorizer
return &GraphClient{
*groupsClient,
*usersClient,
*objectsClient,
*servicePrincipalClient,
}, nil
}
It is deployed to a Kubernetes pod, and it prints a token which I'm able to decode.
The error message stems from msi.go line 47, and based on the "context deadline exceeded" I was wondering if it was some timeout issue?
Anything that might point me to a solution is much appreciated!
Thanks in advance :)
I'm still learning a bit how everything in here is wired up, sorry if this is a beginner question. I was wondering if you could briefly explain how this is used to build the odata id url refs? Where does Uri method bound to this type get called?
type DirectoryObject struct {
ODataId *odata.Id `json:"@odata.id,omitempty"`
ODataType *odata.Type `json:"@odata.type,omitempty"`
ID *string `json:"id,omitempty"`
}
func (o *DirectoryObject) Uri(endpoint environments.ApiEndpoint, apiVersion ApiVersion) string {
if o.ID == nil {
return ""
}
return fmt.Sprintf("%s/%s/directoryObjects/%s", endpoint, apiVersion, *o.ID)
}
Thanks!
In the preceding command, 5657e26c-cc92-45d9-bc47-9da6cfdb4ed9 is the app ID for Azure Database for PostgreSQL - Flexible Server.
As there is a limit of 20 link changes, AddMembers
correctly splits the API calls into batches of 20. However, this logic is not followed when Create
is called. This causes create group to fail when there is a combination of more than 20 owners + members.
Possible solution:
In Create
, create the group with only owners (up to the first 20). Then use AddOwners
to add the remaining owners and AddMembers
to add all the members. Note: The group must not be created without owners as it will leave the possibility of the authenticated client unable to modify the group if it does not have directory admin permissions.
Would it be possible (or is there already a way to do it?) to add casting as part of constructing the OData query, as per example 3 and 4 from the official docs? https://docs.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-1.0&tabs=http
Because if I now for instance want to list all users that are members of a group I have to list all members, iterate through them and calling get on the user client and then I will of course get a bunch of 404 errs which I have to handle. Whereas if I could cast ListMembers to users then I would be set with that one call. Think this would also solve this issue. #20
Thanks for the SDK btw, replaced graphrbac with the official sdk only to discover build time went up an absurd amount.
Related: hashicorp/terraform-provider-azuread#633
Hamilton's MSI authentication doesn't consider the URL formats needed to get an MSI Access Token when run inside the cloud shell.
https://docs.microsoft.com/en-us/azure/cloud-shell/msi-authorization
The URL format is http://localhost:50342/oauth2/token
In https://github.com/manicminer/hamilton/blob/main/auth/msi.go#L115 we see the format of the URL expects to contain "/metadata", which is part of the URL when MSI is used in a VM, for instance
'http://169.254.169.254/metadata/identity/oauth2/token"
SynchronizationJobClient ProvisionOnDemand() returns non-nil error although both logs and admin console declares provisioning has been successful .
jobs, _, err := syncJobClient.List(ctx, request.ServicePrincipalId)
if err != nil {
return fmt.Errorf("failed to get job from app(%v): %v", request.ServicePrincipalId, err)
}
ruleId := {RULE_ID}
objType := "User"
param := &msgraph.SynchronizationJobProvisionOnDemand{
Parameters: &[]msgraph.SynchronizationJobApplicationParameters{{
RuleId: &ruleId,
Subjects: &[]msgraph.SynchronizationJobSubject{{
ObjectId: request.User.ID(),
ObjectTypeName: &objType}},
}},
}
if _, err := syncJobClient.ProvisionOnDemand(ctx, *(*jobs)[0].ID, param, request.ServicePrincipalId); err != nil {
return fmt.Errorf("failed provisioning user(%v) to app(%v): %v", *request.User.ID(), request.ServicePrincipalId, err)
}
SynchronizationJobClient.BaseClient.Post(): unexpected status 200 with response: {"@odata.context":"https://graph.microsoft.com/beta/$metadata#microsoft.graph.stringKeyStringValuePair","key":"Microsoft.Identity.Health.CPP.Common.DataContracts.SyncFabric.StatusInfo","value":"[{\"provisioningSteps\":[{\"name\":\"EntryImport\",\"type\":\"Import\",\"status\":\"Success\",\"description\":\"Retrieved User ' ' from Azure Active Directory","timestamp":"2023-01-03T03:21:28.5276533Z","details\โ:HIDDEN},{"name":"EntryImport","type":"Matching","status":"Success","description":"Retrieved '[email protected]' from Google Cloud / Workspace","timestamp":"2023-01-03T03:21:29.3960403Z","details\โ: HIDDEN,{"name":"EntrySynchronizationScoping","type":"Scoping","status":"Success","description":"Determine if User in scope by evaluating against each scoping filter","timestamp":"2023-01-03T03:21:29.4160394Z","details":{"Active in the source system":"True","Assigned to the application":"True","User has the required role":"True","Scoping filter evaluation passed":"True","ScopeEvaluationResult":"{}"}},{"name":"EntryExportUpdate","type":"Export","status":"Success","description":"User '[email protected]' was updated in Google Cloud / Workspace","timestamp":"2023-01-03T03:21:30.6197578Z","details":{}},{"name":"EntryExportUpdate","type":"Export","status":"Success","description":"User '[email protected]' was updated in Google Cloud / Workspace","timestamp":"2023-01-03T03:21:30.6237579Z","details":{}}],"modifiedProperties":[{"displayName":"emails.[type eq \"work\"].address","oldValue":null,"newValue":"[email protected]"}],"action":"Update","changeId":"4f9f0d6a-b8e0-4069-b0e2-a24ff5d578ff","endTime":"2023-01-03T03:21:30.6267623Z","reportableIdentifier":"[email protected]","sourceIdentity":{"id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","type":"User","name":null,"details":null},"sourceSystem":{"id":null,"name":"Azure Active Directory","details":null},"startTime":"2023-01-03T03:21:28.5206543Z","statusInfo":{"status":"Success","errorCode":null,"reason":null,"additionalDetails":null,"errorCategory":null,"recommendedAction":null},"targetIdentity":{"id":"104020537153314748066","type":"User","name":null,"details":null},"targetSystem":{"id":null,"name":"Google Cloud / Workspace","details":null}}]"}
Are there any plans on your roadmap to add support for the endpoints of Azure's management APIs?
This would apply to the existing endpoint constant already in ResourceManagerPublicEndpoint ApiEndpoint = "https://management.azure.com"
We're specifically looking for the ability to list all custom subscriber roles definition list with a {scope} and potentially additional management endpoints in the future.
~ Thank you
To be able to manage application claims mappings with Terraform we need to be able to use the claimsMappingPolicy
API in hamilton
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.