/
client.go
256 lines (196 loc) · 10.8 KB
/
client.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
package authorize
import (
"context"
"net"
"os"
"time"
"github.com/aws/aws-sdk-go/aws/session"
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
"github.com/SKF/go-enlight-sdk/interceptors/reconnect"
"github.com/SKF/go-utility/v2/log"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"github.com/SKF/proto/common"
authorize_grpcapi "github.com/SKF/proto/authorize"
)
type client struct {
conn *grpc.ClientConn
api authorize_grpcapi.AuthorizeClient
requestTimeout time.Duration
}
type AuthorizeClient interface { // nolint: golint
Dial(host, port string, opts ...grpc.DialOption) error
DialWithContext(ctx context.Context, host, port string, opts ...grpc.DialOption) error
DialUsingCredentials(sess *session.Session, host, port, secretKey string, opts ...grpc.DialOption) error
DialUsingCredentialsWithContext(ctx context.Context, sess *session.Session, host, port, secretKey string, opts ...grpc.DialOption) error
Close() error
SetRequestTimeout(d time.Duration)
DeepPing() error
DeepPingWithContext(ctx context.Context) error
IsAuthorized(userID, action string, resource *common.Origin) (bool, error)
IsAuthorizedWithContext(ctx context.Context, userID, action string, resource *common.Origin) (bool, error)
IsAuthorizedBulk(userID, action string, resource []common.Origin) ([]string, []bool, error)
IsAuthorizedBulkWithContext(ctx context.Context, userID, action string, resource []common.Origin) ([]string, []bool, error)
IsAuthorizedByEndpoint(api, method, endpoint, userID string) (bool, error)
IsAuthorizedByEndpointWithContext(ctx context.Context, api, method, endpoint, userID string) (bool, error)
AddResource(resource common.Origin) error
AddResourceWithContext(ctx context.Context, resource common.Origin) error
GetResource(id, originType string) (common.Origin, error)
GetResourceWithContext(ctx context.Context, id, originType string) (common.Origin, error)
AddResources(resources []common.Origin) error
AddResourcesWithContext(ctx context.Context, resources []common.Origin) error
RemoveResource(resource common.Origin) error
RemoveResourceWithContext(ctx context.Context, resource common.Origin) error
RemoveResources(resources []common.Origin) error
RemoveResourcesWithContext(ctx context.Context, resources []common.Origin) error
GetResourcesWithActionsAccess(actions []string, resourceType string, resource *common.Origin) ([]common.Origin, error)
GetResourcesWithActionsAccessWithContext(ctx context.Context, actions []string, resourceType string, resource *common.Origin) ([]common.Origin, error)
GetResourcesByUserAction(userID, actionName, resourceType string) ([]common.Origin, error)
GetResourcesByUserActionWithContext(ctx context.Context, userID, actionName, resourceType string) ([]common.Origin, error)
GetResourcesByType(resourceType string) (resources []common.Origin, err error)
GetResourcesByTypeWithContext(ctx context.Context, resourceType string) (resources []common.Origin, err error)
GetResourcesByOriginAndType(resource common.Origin, resourceType string, depth int32) (resources []common.Origin, err error)
GetResourcesByOriginAndTypeWithContext(ctx context.Context, resource common.Origin, resourceType string, depth int32) (resources []common.Origin, err error)
GetResourceParents(resource common.Origin, parentOriginType string) (resources []common.Origin, err error)
GetResourceParentsWithContext(ctx context.Context, resource common.Origin, parentOriginType string) (resources []common.Origin, err error)
GetResourceChildren(resource common.Origin, childOriginType string) (resources []common.Origin, err error)
GetResourceChildrenWithContext(ctx context.Context, resource common.Origin, childOriginType string) (resources []common.Origin, err error)
GetUserIDsWithAccessToResource(resource common.Origin) (resources []string, err error)
GetUserIDsWithAccessToResourceWithContext(ctx context.Context, resource common.Origin) (resources []string, err error)
AddResourceRelation(resource common.Origin, parent common.Origin) error
AddResourceRelationWithContext(ctx context.Context, resource common.Origin, parent common.Origin) error
AddResourceRelations(resources authorize_grpcapi.AddResourceRelationsInput) error
AddResourceRelationsWithContext(ctx context.Context, resources authorize_grpcapi.AddResourceRelationsInput) error
RemoveResourceRelation(resource common.Origin, parent common.Origin) error
RemoveResourceRelationWithContext(ctx context.Context, resource common.Origin, parent common.Origin) error
RemoveResourceRelations(resources authorize_grpcapi.RemoveResourceRelationsInput) error
RemoveResourceRelationsWithContext(ctx context.Context, resources authorize_grpcapi.RemoveResourceRelationsInput) error
ApplyUserAction(userID, action string, resource *common.Origin) error
ApplyUserActionWithContext(ctx context.Context, userID, action string, resource *common.Origin) error
RemoveUserAction(userID, action string, resource *common.Origin) error
RemoveUserActionWithContext(ctx context.Context, userID, action string, resource *common.Origin) error
GetActionsByUserRole(userRole string) ([]authorize_grpcapi.Action, error)
GetActionsByUserRoleWithContext(ctx context.Context, userRole string) ([]authorize_grpcapi.Action, error)
GetResourcesAndActionsByUser(userID string) ([]authorize_grpcapi.ActionResource, error)
GetResourcesAndActionsByUserWithContext(ctx context.Context, userID string) ([]authorize_grpcapi.ActionResource, error)
AddAction(action authorize_grpcapi.Action) error
AddActionWithContext(ctx context.Context, action authorize_grpcapi.Action) error
RemoveAction(name string) error
RemoveActionWithContext(ctx context.Context, name string) error
GetAction(name string) (authorize_grpcapi.Action, error)
GetActionWithContext(ctx context.Context, name string) (authorize_grpcapi.Action, error)
GetAllActions() ([]authorize_grpcapi.Action, error)
GetAllActionsWithContext(ctx context.Context) ([]authorize_grpcapi.Action, error)
GetUserActions(userID string) ([]authorize_grpcapi.Action, error)
GetUserActionsWithContext(ctx context.Context, userID string) ([]authorize_grpcapi.Action, error)
AddUserRole(role authorize_grpcapi.UserRole) error
AddUserRoleWithContext(ctx context.Context, role authorize_grpcapi.UserRole) error
GetUserRole(roleName string) (authorize_grpcapi.UserRole, error)
GetUserRoleWithContext(ctx context.Context, roleName string) (authorize_grpcapi.UserRole, error)
RemoveUserRole(roleName string) error
RemoveUserRoleWithContext(ctx context.Context, roleName string) error
}
func CreateClient() AuthorizeClient {
return &client{
requestTimeout: 60 * time.Second,
}
}
// Dial creates a client connection to the given host with background context and no timeout
func (c *client) Dial(host, port string, opts ...grpc.DialOption) error {
ctx, cancel := context.WithTimeout(context.Background(), c.requestTimeout)
defer cancel()
return c.DialWithContext(ctx, host, port, opts...)
}
// DialWithContext creates a client connection to the given host with context (for timeout and transaction id)
func (c *client) DialWithContext(ctx context.Context, host, port string, opts ...grpc.DialOption) (err error) {
conn, err := grpc.DialContext(ctx, host+":"+port, opts...)
if err != nil {
return
}
c.conn = conn
c.api = authorize_grpcapi.NewAuthorizeClient(conn)
err = c.logClientState(ctx, "opening connection")
return
}
// DialUsingCredentials creates a client connection to the given host with background context and no timeout
func (c *client) DialUsingCredentials(sess *session.Session, host, port, secretKey string, opts ...grpc.DialOption) error {
ctx, cancel := context.WithTimeout(context.Background(), c.requestTimeout)
defer cancel()
return c.DialUsingCredentialsWithContext(ctx, sess, host, port, secretKey, opts...)
}
// DialUsingCredentialsWithContext creates a client connection to the given host with context (for timeout and transaction id)
func (c *client) DialUsingCredentialsWithContext(ctx context.Context, sess *session.Session, host, port, secretKey string, opts ...grpc.DialOption) error {
var newClientConn reconnect.NewConnectionFunc
newClientConn = func(invokerCtx context.Context, invokerConn *grpc.ClientConn, invokerOptions ...grpc.CallOption) (context.Context, *grpc.ClientConn, []grpc.CallOption, error) {
credOpt, err := getCredentialOption(invokerCtx, sess, host, secretKey)
if err != nil {
log.WithTracing(invokerCtx).WithError(err).Error("Failed to get credential options")
return invokerCtx, invokerConn, invokerOptions, err
}
dialOptsReconnectRetry := reconnectRetryInterceptor(newClientConn)
dialOpts := append(opts, credOpt, dialOptsReconnectRetry, grpc.WithBlock())
newConn, err := grpc.DialContext(invokerCtx, net.JoinHostPort(host, port), dialOpts...)
if err != nil {
log.WithTracing(invokerCtx).WithError(err).Error("Failed to dial context")
return invokerCtx, invokerConn, invokerOptions, err
}
_ = invokerConn.Close()
c.conn = newConn
c.api = authorize_grpcapi.NewAuthorizeClient(c.conn)
return invokerCtx, c.conn, invokerOptions, err
}
opt, err := getCredentialOption(ctx, sess, host, secretKey)
if err != nil {
return err
}
dialOptsReconnectRetry := reconnectRetryInterceptor(newClientConn)
newOpts := append(opts, opt, dialOptsReconnectRetry)
conn, err := grpc.DialContext(ctx, host+":"+port, newOpts...)
if err != nil {
return err
}
c.conn = conn
c.api = authorize_grpcapi.NewAuthorizeClient(c.conn)
err = c.logClientState(ctx, "opening connection")
return err
}
func reconnectRetryInterceptor(newClientConn reconnect.NewConnectionFunc) grpc.DialOption {
retryIC := grpc_retry.UnaryClientInterceptor(
grpc_retry.WithBackoff(grpc_retry.BackoffLinear(100*time.Millisecond)),
grpc_retry.WithCodes(codes.Unavailable, codes.ResourceExhausted, codes.Aborted),
)
reconnectIC := reconnect.UnaryInterceptor(
reconnect.WithNewConnection(newClientConn),
)
dialOptsReconnectRetry := grpc.WithChainUnaryInterceptor(reconnectIC, retryIC) // first one is outer, being called last
return dialOptsReconnectRetry
}
func (c *client) Close() (err error) {
ctx, cancel := context.WithTimeout(context.Background(), c.requestTimeout)
defer cancel()
err = c.logClientState(ctx, "closing connection")
if c.conn != nil {
return c.conn.Close()
}
return nil
}
func (c *client) DeepPing() error {
ctx, cancel := context.WithTimeout(context.Background(), c.requestTimeout)
defer cancel()
return c.DeepPingWithContext(ctx)
}
func (c *client) DeepPingWithContext(ctx context.Context) error {
_, err := c.api.DeepPing(ctx, &common.Void{})
return err
}
func (c *client) logClientState(ctx context.Context, state string) error {
hostname, err := os.Hostname()
if err != nil {
hostname = ""
}
_, err = c.api.LogClientState(ctx, &authorize_grpcapi.LogClientStateInput{
State: state,
Hostname: hostname,
})
return err
}