-
Notifications
You must be signed in to change notification settings - Fork 0
/
identity.go
208 lines (183 loc) · 5.54 KB
/
identity.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
// Copyright 2019 - MinIO, Inc. All rights reserved.
// Use of this source code is governed by the AGPLv3
// license that can be found in the LICENSE file.
package kes
import (
"encoding/json"
"errors"
"io"
"time"
)
// IdentityUnknown is the identity returned
// by an IdentityFunc if it cannot map a
// particular X.509 certificate to an actual
// identity.
const IdentityUnknown Identity = ""
// An Identity should uniquely identify a client and
// is computed from the X.509 certificate presented
// by the client during the TLS handshake using an
// IdentityFunc.
type Identity string
// IsUnknown returns true if and only if the
// identity is IdentityUnknown.
func (id Identity) IsUnknown() bool { return id == IdentityUnknown }
// String returns the string representation of
// the identity.
func (id Identity) String() string { return string(id) }
// IdentityInfo describes a KES identity.
type IdentityInfo struct {
Identity Identity
IsAdmin bool // Indicates whether the identity has admin privileges
Policy string // Name of the associated policy
CreatedAt time.Time // Point in time when the identity was created
CreatedBy Identity // Identity that created the identity
}
// IdentityIterator iterates over a stream of IdentityInfo objects.
// Close the IdentityIterator to release associated resources.
type IdentityIterator struct {
decoder *json.Decoder
closer io.Closer
current IdentityInfo
err error
closed bool
}
// Value returns the current IdentityInfo. It remains valid
// until Next is called again.
func (i *IdentityIterator) Value() IdentityInfo { return i.current }
// Identity returns the current identity. It is a short-hand
// for Value().Identity.
func (i *IdentityIterator) Identity() Identity { return i.current.Identity }
// Policy returns the policy assigned to the current identity.
// It is a short-hand for Value().Policy.
func (i *IdentityIterator) Policy() string { return i.current.Policy }
// CreatedAt returns the created-at timestamp of the current
// identity. It is a short-hand for Value().CreatedAt.
func (i *IdentityIterator) CreatedAt() time.Time { return i.current.CreatedAt }
// CreatedBy returns the identiy that created the current identity.
// It is a short-hand for Value().CreatedBy.
func (i *IdentityIterator) CreatedBy() Identity { return i.current.CreatedBy }
// Next returns true if there is another IdentityInfo.
// It returns false if there are no more IdentityInfo
// objects or when the IdentityIterator encounters an
// error.
func (i *IdentityIterator) Next() bool {
type Response struct {
Identity Identity `json:"identity"`
IsAdmin bool `json:"admin"`
Policy string `json:"policy"`
CreatedAt time.Time `json:"created_at"`
CreatedBy Identity `json:"created_by"`
Err string `json:"error"`
}
if i.closed || i.err != nil {
return false
}
var resp Response
if err := i.decoder.Decode(&resp); err != nil {
if errors.Is(err, io.EOF) {
i.err = i.Close()
} else {
i.err = err
}
return false
}
if resp.Err != "" {
i.err = errors.New(resp.Err)
return false
}
i.current = IdentityInfo{
Identity: resp.Identity,
Policy: resp.Policy,
CreatedAt: resp.CreatedAt,
CreatedBy: resp.CreatedBy,
}
return true
}
// WriteTo encodes and writes all remaining IdentityInfos
// from its current iterator position to w. It returns
// the number of bytes written to w and the first error
// encounterred, if any.
func (i *IdentityIterator) WriteTo(w io.Writer) (int64, error) {
type Response struct {
Identity Identity `json:"identity"`
Admin bool `json:"admin"`
Policy string `json:"policy,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
CreatedBy Identity `json:"created_by,omitempty"`
Err string `json:"error,omitempty"`
}
if i.err != nil {
return 0, i.err
}
if i.closed {
return 0, errors.New("kes: WriteTo called after Close")
}
cw := countWriter{W: w}
encoder := json.NewEncoder(&cw)
for {
var resp Response
if err := i.decoder.Decode(&resp); err != nil {
if errors.Is(err, io.EOF) {
i.err = i.Close()
} else {
i.err = err
}
return cw.N, i.err
}
if resp.Err != "" {
i.err = errors.New(resp.Err)
return cw.N, i.err
}
if err := encoder.Encode(resp); err != nil {
i.err = err
return cw.N, err
}
}
}
// Values returns up to the next n IdentityInfo values. Subsequent
// calls will yield further IdentityInfos if there are any.
//
// If n > 0, Values returns at most n IdentityInfo structs. In this case,
// if Values returns an empty slice, it will return an error explaining
// why. At the end of the listing, the error is io.EOF.
//
// If n <= 0, Values returns all remaining IdentityInfo records. In this
// case, Values always closes the IdentityIterator. When it succeeds, it
// returns a nil error, not io.EOF.
func (i *IdentityIterator) Values(n int) ([]IdentityInfo, error) {
values := []IdentityInfo{}
if n > 0 && i.closed {
return values, io.EOF // Return early, don't alloc a slice
}
if n > 0 {
values = make([]IdentityInfo, 0, n)
}
var count int
for i.Next() {
values = append(values, i.Value())
count++
if n > 0 && count >= n {
return values, nil
}
}
if err := i.Close(); err != nil {
return values, err
}
if n > 0 && len(values) == 0 { // As by doc contract
return values, io.EOF
}
return values, nil
}
// Close closes the IdentityIterator and releases
// any associated resources
func (i *IdentityIterator) Close() error {
if !i.closed {
err := i.closer.Close()
if i.err == nil {
i.err = err
}
i.closed = true
return err
}
return i.err
}