-
Notifications
You must be signed in to change notification settings - Fork 7
/
client.go
342 lines (283 loc) · 10.4 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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
package storage
import (
"github.com/ory/fosite"
)
// Client provides the structure of an OAuth2.0 Client.
type Client struct {
//// Client Meta
// ID is the id for this client.
ID string `bson:"id" json:"id" xml:"id"`
// createTime is when the resource was created in seconds from the epoch.
CreateTime int64 `bson:"createTime" json:"createTime" xml:"createTime"`
// updateTime is the last time the resource was modified in seconds from
// the epoch.
UpdateTime int64 `bson:"updateTime" json:"updateTime" xml:"updateTime"`
// AllowedAudiences contains a list of Audiences that the client has been
// given rights to access.
AllowedAudiences []string `bson:"allowedAudiences" json:"allowedAudiences,omitempty" xml:"allowedAudiences,omitempty"`
// AllowedRegions contains a list of regions that the client has been
// given permission to access. This enables filtering for clients based on
// geographic region.
AllowedRegions []string `bson:"allowedRegions" json:"allowedRegions,omitempty" xml:"allowedRegions,omitempty"`
// AllowedTenantAccess contains a list of Tenants that the client has been
// given rights to access.
AllowedTenantAccess []string `bson:"allowedTenantAccess" json:"allowedTenantAccess,omitempty" xml:"allowedTenantAccess,omitempty"`
// GrantTypes contains a list of grant types the client is allowed to use.
//
// Pattern: client_credentials|authorize_code|implicit|refresh_token
GrantTypes []string `bson:"grantTypes" json:"grantTypes" xml:"grantTypes"`
// ResponseTypes contains a list of the OAuth 2.0 response type strings
// that the client can use at the authorization endpoint.
//
// Pattern: id_token|code|token
ResponseTypes []string `bson:"responseTypes" json:"responseTypes" xml:"responseTypes"`
// Scopes contains a list of values the client is entitled to use when
// requesting an access token (as described in Section 3.3 of OAuth 2.0
// [RFC6749]).
//
// Pattern: ([a-zA-Z0-9\.]+\s)+
Scopes []string `bson:"scopes" json:"scopes" xml:"scopes"`
// Public is a boolean that identifies this client as public, meaning that
// it does not have a secret. It will disable the client_credentials grant
// type for this client if set.
Public bool `bson:"public" json:"public" xml:"public"`
// Disabled stops the client from being able to authenticate to the system.
Disabled bool `bson:"disabled" json:"disabled" xml:"disabled"`
//// Client Content
// Name contains a human-readable string name of the client to be presented
// to the end-user during authorization.
Name string `bson:"name" json:"name" xml:"name"`
// Secret is the client's secret. The secret will be included in the create
// request as cleartext, and then never again. The secret is stored using
// BCrypt so it is impossible to recover it.
// Tell your users that they need to remember the client secret as it will
// not be made available again.
Secret string `bson:"secret,omitempty" json:"secret,omitempty" xml:"secret,omitempty"`
// RedirectURIs contains a list of allowed redirect urls for the client, for
// example: http://mydomain/oauth/callback.
RedirectURIs []string `bson:"redirectUris" json:"redirectUris" xml:"redirectUris"`
// Owner identifies the owner of the OAuth 2.0 Client.
Owner string `bson:"owner" json:"owner" xml:"owner"`
// PolicyURI allows the application developer to provide a URI string that
// points to a human-readable privacy policy document that describes how the
// deployment organization collects, uses, retains, and discloses personal
// data.
PolicyURI string `bson:"policyUri" json:"policyUri" xml:"policyUri"`
// TermsOfServiceURI allows the application developer to provide a URI
// string that points to a human-readable terms of service document that
// describes and outlines the contractual relationship between the end-user
// and the client application that the end-user accepts when authorizing
// their use of the client.
TermsOfServiceURI string `bson:"termsOfServiceUri" json:"termsOfServiceUri" xml:"termsOfServiceUri"`
// ClientURI allows the application developer to provide a URI string that
// points to a human-readable web page that provides information about the
// client application.
// If present, the server SHOULD display this URL to the end-user in a
// click-able fashion.
ClientURI string `bson:"clientUri" json:"clientUri" xml:"clientUri"`
// LogoURI is an URL string that references a logo for the client.
LogoURI string `bson:"logoUri" json:"logoUri" xml:"logoUri"`
// Contacts contains a list ways to contact the developers responsible for
// this OAuth 2.0 client, typically email addresses.
Contacts []string `bson:"contacts" json:"contacts" xml:"contacts"`
// Published provides a switch to hide specific clients if not quite ready
// for the prime time, or if wanting to keep them hidden.
Published bool `bson:"published" json:"published" xml:"published"`
}
// GetID returns the client's Client ID.
func (c *Client) GetID() string {
return c.ID
}
// GetRedirectURIs returns the OAuth2.0 authorized Client redirect URIs.
func (c *Client) GetRedirectURIs() []string {
return c.RedirectURIs
}
// GetHashedSecret returns the Client's Hashed Secret for authenticating with
// the Identity Provider.
func (c *Client) GetHashedSecret() []byte {
return []byte(c.Secret)
}
// GetScopes returns an array of strings, wrapped as `fosite.Arguments` to
// provide functions that allow verifying the
// Client's scopes against incoming requests.
func (c *Client) GetScopes() fosite.Arguments {
return c.Scopes
}
// GetGrantTypes returns an array of strings, wrapped as `fosite.Arguments` to
// provide functions that allow verifying
// the Client's Grant Types against incoming requests.
func (c *Client) GetGrantTypes() fosite.Arguments {
// https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
//
// JSON array containing a list of the OAuth 2.0 Grant Types that the Client
// is declaring that it will restrict itself to using.
// If omitted, the default is that the Client will use only the
// authorization_code Grant Type.
if len(c.GrantTypes) == 0 {
return fosite.Arguments{"authorization_code"}
}
return c.GrantTypes
}
// GetResponseTypes returns an array of strings, wrapped as `fosite.Arguments`
// to provide functions that allow verifying
// the Client's Response Types against incoming requests.
func (c *Client) GetResponseTypes() fosite.Arguments {
// https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
//
// <JSON array containing a list of the OAuth 2.0 response_type values that
// the Client is declaring that it will restrict itself to using. If
// omitted, the default is that the Client will use only the code Response
// Type.
if len(c.ResponseTypes) == 0 {
return fosite.Arguments{"code"}
}
return c.ResponseTypes
}
// GetOwner returns a string which contains the OAuth Client owner's name.
// Generally speaking, this will be a developer or an organisation.
func (c *Client) GetOwner() string {
return c.Owner
}
// IsPublic returns a boolean as to whether the Client itself is either private
// or public. If public, only trusted OAuth grant types should be used as
// client secrets shouldn't be exposed to a public client.
func (c *Client) IsPublic() bool {
return c.Public
}
// GetAudience returns the allowed audience(s) for this client.
func (c *Client) GetAudience() fosite.Arguments {
return c.AllowedAudiences
}
// IsDisabled returns a boolean as to whether the Client itself has had it's
// access disabled.
func (c *Client) IsDisabled() bool {
return c.Disabled
}
// EnableScopeAccess enables client scope access.
func (c *Client) EnableScopeAccess(scopes ...string) {
for i := range scopes {
found := false
for j := range c.Scopes {
if scopes[i] == c.Scopes[j] {
found = true
break
}
}
if !found {
c.Scopes = append(c.Scopes, scopes[i])
}
}
}
// DisableScopeAccess disables client scope access.
func (c *Client) DisableScopeAccess(scopes ...string) {
for i := range scopes {
for j := range c.Scopes {
if scopes[i] == c.Scopes[j] {
copy(c.Scopes[j:], c.Scopes[j+1:])
c.Scopes[len(c.Scopes)-1] = ""
c.Scopes = c.Scopes[:len(c.Scopes)-1]
break
}
}
}
}
// EnableTenantAccess adds a single or multiple tenantIDs to the given client.
func (c *Client) EnableTenantAccess(tenantIDs ...string) {
for i := range tenantIDs {
found := false
for j := range c.AllowedTenantAccess {
if tenantIDs[i] == c.AllowedTenantAccess[j] {
found = true
break
}
}
if !found {
c.AllowedTenantAccess = append(c.AllowedTenantAccess, tenantIDs[i])
}
}
}
// DisableTenantAccess removes a single or multiple tenantIDs from the given
// client.
func (c *Client) DisableTenantAccess(tenantIDs ...string) {
for i := range tenantIDs {
for j := range c.AllowedTenantAccess {
if tenantIDs[i] == c.AllowedTenantAccess[j] {
copy(c.AllowedTenantAccess[j:], c.AllowedTenantAccess[j+1:])
c.AllowedTenantAccess[len(c.AllowedTenantAccess)-1] = ""
c.AllowedTenantAccess = c.AllowedTenantAccess[:len(c.AllowedTenantAccess)-1]
break
}
}
}
}
// Equal enables checking for client equality.
func (c Client) Equal(x Client) bool {
if c.ID != x.ID {
return false
}
if c.CreateTime != x.CreateTime {
return false
}
if c.UpdateTime != x.UpdateTime {
return false
}
if !stringArrayEquals(c.AllowedAudiences, x.AllowedAudiences) {
return false
}
if !stringArrayEquals(c.AllowedRegions, x.AllowedRegions) {
return false
}
if !stringArrayEquals(c.AllowedTenantAccess, x.AllowedTenantAccess) {
return false
}
if !stringArrayEquals(c.GrantTypes, x.GrantTypes) {
return false
}
if !stringArrayEquals(c.ResponseTypes, x.ResponseTypes) {
return false
}
if !stringArrayEquals(c.Scopes, x.Scopes) {
return false
}
if c.Public != x.Public {
return false
}
if c.Disabled != x.Disabled {
return false
}
if c.Name != x.Name {
return false
}
if c.Secret != x.Secret {
return false
}
if !stringArrayEquals(c.RedirectURIs, x.RedirectURIs) {
return false
}
if c.Owner != x.Owner {
return false
}
if c.PolicyURI != x.PolicyURI {
return false
}
if c.TermsOfServiceURI != x.TermsOfServiceURI {
return false
}
if c.ClientURI != x.ClientURI {
return false
}
if c.LogoURI != x.LogoURI {
return false
}
if !stringArrayEquals(c.Contacts, x.Contacts) {
return false
}
if c.Published != x.Published {
return false
}
return true
}
// IsEmpty returns whether or not the client resource is an empty record.
func (c Client) IsEmpty() bool {
return c.Equal(Client{})
}