/
service.go
141 lines (115 loc) · 4.02 KB
/
service.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package googledirectory
import (
"context"
"errors"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/option"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
admin "google.golang.org/api/admin/directory/v1"
)
func AdminService(ctx context.Context, d *plugin.QueryData) (*admin.Service, error) {
// have we already created and cached the service?
serviceCacheKey := "googledirectory.admin"
if cachedData, ok := d.ConnectionManager.Cache.Get(serviceCacheKey); ok {
return cachedData.(*admin.Service), nil
}
// so it was not in cache - create service
opts, err := getSessionConfig(ctx, d)
if err != nil {
return nil, err
}
// Create service
svc, err := admin.NewService(ctx, opts...)
if err != nil {
return nil, err
}
// cache the service
d.ConnectionManager.Cache.Set(serviceCacheKey, svc)
return svc, nil
}
func getSessionConfig(ctx context.Context, d *plugin.QueryData) ([]option.ClientOption, error) {
opts := []option.ClientOption{}
// Get credential file path, and user to impersonate from config (if mentioned)
var credentialContent, tokenPath string
googledirectoryConfig := GetConfig(d.Connection)
// 'credential_file' in connection config is DEPRECATED, and will be removed in future release
// use `credentials` instead
if googledirectoryConfig.Credentials != nil {
credentialContent = *googledirectoryConfig.Credentials
} else if googledirectoryConfig.CredentialFile != nil {
credentialContent = *googledirectoryConfig.CredentialFile
}
if googledirectoryConfig.TokenPath != nil {
tokenPath = *googledirectoryConfig.TokenPath
}
// If credential path provided, use domain-wide delegation
if credentialContent != "" {
ts, err := getTokenSource(ctx, d)
if err != nil {
return nil, err
}
opts = append(opts, option.WithTokenSource(ts))
return opts, nil
}
// If token path provided, authenticate using OAuth 2.0
if tokenPath != "" {
path, err := expandPath(tokenPath)
if err != nil {
return nil, err
}
opts = append(opts, option.WithCredentialsFile(path))
return opts, nil
}
return nil, nil
}
// Returns a JWT TokenSource using the configuration and the HTTP client from the provided context
func getTokenSource(ctx context.Context, d *plugin.QueryData) (oauth2.TokenSource, error) {
// NOTE: based on https://developers.google.com/admin-sdk/directory/v1/guides/delegation#go
// have we already created and cached the token?
cacheKey := "googledirectory.token_source"
if ts, ok := d.ConnectionManager.Cache.Get(cacheKey); ok {
return ts.(oauth2.TokenSource), nil
}
// Get credential file path, and user to impersonate from config (if mentioned)
var impersonateUser string
googledirectoryConfig := GetConfig(d.Connection)
// Read credential from JSON string, or from the given path
// NOTE: 'credential_file' in connection config is DEPRECATED, and will be removed in future release
// use `credentials` instead
var creds string
if googledirectoryConfig.Credentials != nil {
creds = *googledirectoryConfig.Credentials
} else if googledirectoryConfig.CredentialFile != nil {
creds = *googledirectoryConfig.CredentialFile
}
// Read credential
credentialContent, err := pathOrContents(creds)
if err != nil {
return nil, err
}
if googledirectoryConfig.ImpersonatedUserEmail != nil {
impersonateUser = *googledirectoryConfig.ImpersonatedUserEmail
}
// Return error, since impersonation required to authenticate using domain-wide delegation
if impersonateUser == "" {
return nil, errors.New("impersonated_user_email must be configured")
}
// Authorize the request
config, err := google.JWTConfigFromJSON(
[]byte(credentialContent),
admin.AdminDirectoryDomainReadonlyScope,
admin.AdminDirectoryGroupReadonlyScope,
admin.AdminDirectoryOrgunitReadonlyScope,
admin.AdminDirectoryRolemanagementReadonlyScope,
admin.AdminDirectoryUserReadonlyScope,
)
if err != nil {
return nil, err
}
config.Subject = impersonateUser
ts := config.TokenSource(ctx)
// cache the token source
d.ConnectionManager.Cache.Set(cacheKey, ts)
return ts, nil
}