netmaker/pro/idp/google/google.go
2025-07-31 21:58:45 +05:30

160 lines
3.5 KiB
Go

package google
import (
"context"
"encoding/base64"
"encoding/json"
"errors"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/pro/idp"
admindir "google.golang.org/api/admin/directory/v1"
"google.golang.org/api/googleapi"
"google.golang.org/api/impersonate"
"google.golang.org/api/option"
)
type Client struct {
service *admindir.Service
}
func NewGoogleWorkspaceClient(adminEmail, creds string) (*Client, error) {
credsJson, err := base64.StdEncoding.DecodeString(creds)
if err != nil {
return nil, err
}
credsJsonMap := make(map[string]interface{})
err = json.Unmarshal(credsJson, &credsJsonMap)
if err != nil {
return nil, err
}
var targetPrincipal string
_, ok := credsJsonMap["client_email"]
if !ok {
return nil, errors.New("invalid service account credentials: missing client_email field")
} else {
targetPrincipal = credsJsonMap["client_email"].(string)
}
source, err := impersonate.CredentialsTokenSource(
context.TODO(),
impersonate.CredentialsConfig{
TargetPrincipal: targetPrincipal,
Scopes: []string{
admindir.AdminDirectoryUserReadonlyScope,
admindir.AdminDirectoryGroupReadonlyScope,
admindir.AdminDirectoryGroupMemberReadonlyScope,
},
Subject: adminEmail,
},
option.WithCredentialsJSON(credsJson),
)
if err != nil {
return nil, err
}
service, err := admindir.NewService(
context.TODO(),
option.WithTokenSource(source),
)
if err != nil {
return nil, err
}
return &Client{
service: service,
}, nil
}
func NewGoogleWorkspaceClientFromSettings() (*Client, error) {
settings := logic.GetServerSettings()
return NewGoogleWorkspaceClient(settings.GoogleAdminEmail, settings.GoogleSACredsJson)
}
func (g *Client) Verify() error {
_, err := g.service.Users.List().
Customer("my_customer").
MaxResults(1).
Do()
if err != nil {
var gerr *googleapi.Error
if errors.As(err, &gerr) {
return errors.New(gerr.Message)
}
return err
}
_, err = g.service.Groups.List().
Customer("my_customer").
MaxResults(1).
Do()
if err != nil {
var gerr *googleapi.Error
if errors.As(err, &gerr) {
return errors.New(gerr.Message)
}
return err
}
return nil
}
func (g *Client) GetUsers() ([]idp.User, error) {
var retval []idp.User
err := g.service.Users.List().
Customer("my_customer").
Fields("users(id,primaryEmail,name,suspended,archived)", "nextPageToken").
Pages(context.TODO(), func(users *admindir.Users) error {
for _, user := range users.Users {
retval = append(retval, idp.User{
ID: user.Id,
Username: user.PrimaryEmail,
DisplayName: user.Name.FullName,
AccountDisabled: user.Suspended,
AccountArchived: user.Archived,
})
}
return nil
})
return retval, err
}
func (g *Client) GetGroups() ([]idp.Group, error) {
var retval []idp.Group
err := g.service.Groups.List().
Customer("my_customer").
Fields("groups(id,name)", "nextPageToken").
Pages(context.TODO(), func(groups *admindir.Groups) error {
for _, group := range groups.Groups {
var retvalMembers []string
err := g.service.Members.List(group.Id).
Fields("members(id)", "nextPageToken").
Pages(context.TODO(), func(members *admindir.Members) error {
for _, member := range members.Members {
retvalMembers = append(retvalMembers, member.Id)
}
return nil
})
if err != nil {
return err
}
retval = append(retval, idp.Group{
ID: group.Id,
Name: group.Name,
Members: retvalMembers,
})
}
return nil
})
return retval, err
}