How to use WithVisibility method of types Package

Best Ginkgo code snippet using types.WithVisibility

Run Ginkgo automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

organization_registry.go

Source: organization_registry.go Github

copy
1// Copyright © 2020 The Things Network Foundation, The Things Industries B.V.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package identityserver
16
17import (
18	"context"
19
20	"github.com/gogo/protobuf/types"
21	"github.com/jinzhu/gorm"
22	"go.thethings.network/lorawan-stack/v3/pkg/auth/rights"
23	"go.thethings.network/lorawan-stack/v3/pkg/errors"
24	"go.thethings.network/lorawan-stack/v3/pkg/events"
25	"go.thethings.network/lorawan-stack/v3/pkg/identityserver/blacklist"
26	"go.thethings.network/lorawan-stack/v3/pkg/identityserver/store"
27	"go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
28)
29
30var (
31	evtCreateOrganization = events.Define(
32		"organization.create", "create organization",
33		events.WithVisibility(ttnpb.RIGHT_ORGANIZATION_INFO),
34		events.WithAuthFromContext(),
35		events.WithClientInfoFromContext(),
36	)
37	evtUpdateOrganization = events.Define(
38		"organization.update", "update organization",
39		events.WithVisibility(ttnpb.RIGHT_ORGANIZATION_INFO),
40		events.WithUpdatedFieldsDataType(),
41		events.WithAuthFromContext(),
42		events.WithClientInfoFromContext(),
43	)
44	evtDeleteOrganization = events.Define(
45		"organization.delete", "delete organization",
46		events.WithVisibility(ttnpb.RIGHT_ORGANIZATION_INFO),
47		events.WithAuthFromContext(),
48		events.WithClientInfoFromContext(),
49	)
50	evtPurgeOrganization = events.Define(
51		"organization.purge", "purge organization",
52		events.WithVisibility(ttnpb.RIGHT_ORGANIZATION_INFO),
53		events.WithAuthFromContext(),
54		events.WithClientInfoFromContext(),
55	)
56)
57
58var (
59	errNestedOrganizations       = errors.DefineInvalidArgument("nested_organizations", "organizations can not be nested")
60	errAdminsCreateOrganizations = errors.DefinePermissionDenied("admins_create_organizations", "organizations may only be created by admins")
61	errAdminsPurgeOrganizations  = errors.DefinePermissionDenied("admins_purge_organizations", "organizations may only be purged by admins")
62)
63
64func (is *IdentityServer) createOrganization(ctx context.Context, req *ttnpb.CreateOrganizationRequest) (org *ttnpb.Organization, err error) {
65	if err = blacklist.Check(ctx, req.OrganizationID); err != nil {
66		return nil, err
67	}
68	if usrIDs := req.Collaborator.GetUserIDs(); usrIDs != nil {
69		if !is.IsAdmin(ctx) && !is.configFromContext(ctx).UserRights.CreateOrganizations {
70			return nil, errAdminsCreateOrganizations
71		}
72		if err = rights.RequireUser(ctx, *usrIDs, ttnpb.RIGHT_USER_ORGANIZATIONS_CREATE); err != nil {
73			return nil, err
74		}
75	} else if orgIDs := req.Collaborator.GetOrganizationIDs(); orgIDs != nil {
76		return nil, errNestedOrganizations.New()
77	}
78	if err := validateContactInfo(req.Organization.ContactInfo); err != nil {
79		return nil, err
80	}
81	err = is.withDatabase(ctx, func(db *gorm.DB) (err error) {
82		org, err = store.GetOrganizationStore(db).CreateOrganization(ctx, &req.Organization)
83		if err != nil {
84			return err
85		}
86		if err = is.getMembershipStore(ctx, db).SetMember(
87			ctx,
88			&req.Collaborator,
89			org.OrganizationIdentifiers,
90			ttnpb.RightsFrom(ttnpb.RIGHT_ALL),
91		); err != nil {
92			return err
93		}
94		if len(req.ContactInfo) > 0 {
95			cleanContactInfo(req.ContactInfo)
96			org.ContactInfo, err = store.GetContactInfoStore(db).SetContactInfo(ctx, org.OrganizationIdentifiers, req.ContactInfo)
97			if err != nil {
98				return err
99			}
100		}
101		return nil
102	})
103	if err != nil {
104		return nil, err
105	}
106	events.Publish(evtCreateOrganization.NewWithIdentifiersAndData(ctx, req.OrganizationIdentifiers, nil))
107	return org, nil
108}
109
110func (is *IdentityServer) getOrganization(ctx context.Context, req *ttnpb.GetOrganizationRequest) (org *ttnpb.Organization, err error) {
111	if err = is.RequireAuthenticated(ctx); err != nil {
112		return nil, err
113	}
114	req.FieldMask.Paths = cleanFieldMaskPaths(ttnpb.OrganizationFieldPathsNested, req.FieldMask.Paths, getPaths, nil)
115	if err = rights.RequireOrganization(ctx, req.OrganizationIdentifiers, ttnpb.RIGHT_ORGANIZATION_INFO); err != nil {
116		if ttnpb.HasOnlyAllowedFields(req.FieldMask.Paths, ttnpb.PublicOrganizationFields...) {
117			defer func() { org = org.PublicSafe() }()
118		} else {
119			return nil, err
120		}
121	}
122	err = is.withDatabase(ctx, func(db *gorm.DB) (err error) {
123		org, err = store.GetOrganizationStore(db).GetOrganization(ctx, &req.OrganizationIdentifiers, &req.FieldMask)
124		if err != nil {
125			return err
126		}
127		if ttnpb.HasAnyField(req.FieldMask.Paths, "contact_info") {
128			org.ContactInfo, err = store.GetContactInfoStore(db).GetContactInfo(ctx, org.OrganizationIdentifiers)
129			if err != nil {
130				return err
131			}
132		}
133		return err
134	})
135	if err != nil {
136		return nil, err
137	}
138	return org, nil
139}
140
141func (is *IdentityServer) listOrganizations(ctx context.Context, req *ttnpb.ListOrganizationsRequest) (orgs *ttnpb.Organizations, err error) {
142	req.FieldMask.Paths = cleanFieldMaskPaths(ttnpb.OrganizationFieldPathsNested, req.FieldMask.Paths, getPaths, nil)
143	var includeIndirect bool
144	if req.Collaborator == nil {
145		authInfo, err := is.authInfo(ctx)
146		if err != nil {
147			return nil, err
148		}
149		collaborator := authInfo.GetOrganizationOrUserIdentifiers()
150		if collaborator == nil {
151			return &ttnpb.Organizations{}, nil
152		}
153		req.Collaborator = collaborator
154		includeIndirect = true
155	}
156	if usrIDs := req.Collaborator.GetUserIDs(); usrIDs != nil {
157		if err = rights.RequireUser(ctx, *usrIDs, ttnpb.RIGHT_USER_ORGANIZATIONS_LIST); err != nil {
158			return nil, err
159		}
160	} else if orgIDs := req.Collaborator.GetOrganizationIDs(); orgIDs != nil {
161		return nil, errNestedOrganizations.New()
162	}
163	ctx = store.WithOrder(ctx, req.Order)
164	var total uint64
165	paginateCtx := store.WithPagination(ctx, req.Limit, req.Page, &total)
166	defer func() {
167		if err == nil {
168			setTotalHeader(ctx, total)
169		}
170	}()
171	orgs = &ttnpb.Organizations{}
172	err = is.withDatabase(ctx, func(db *gorm.DB) (err error) {
173		ids, err := is.getMembershipStore(ctx, db).FindMemberships(paginateCtx, req.Collaborator, "organization", includeIndirect)
174		if err != nil {
175			return err
176		}
177		if len(ids) == 0 {
178			return nil
179		}
180		orgIDs := make([]*ttnpb.OrganizationIdentifiers, 0, len(ids))
181		for _, id := range ids {
182			if orgID := id.EntityIdentifiers().GetOrganizationIDs(); orgID != nil {
183				orgIDs = append(orgIDs, orgID)
184			}
185		}
186		orgs.Organizations, err = store.GetOrganizationStore(db).FindOrganizations(ctx, orgIDs, &req.FieldMask)
187		if err != nil {
188			return err
189		}
190		return nil
191	})
192	if err != nil {
193		return nil, err
194	}
195
196	for i, org := range orgs.Organizations {
197		if rights.RequireOrganization(ctx, org.OrganizationIdentifiers, ttnpb.RIGHT_ORGANIZATION_INFO) != nil {
198			orgs.Organizations[i] = org.PublicSafe()
199		}
200	}
201
202	return orgs, nil
203}
204
205func (is *IdentityServer) updateOrganization(ctx context.Context, req *ttnpb.UpdateOrganizationRequest) (org *ttnpb.Organization, err error) {
206	if err = rights.RequireOrganization(ctx, req.OrganizationIdentifiers, ttnpb.RIGHT_ORGANIZATION_SETTINGS_BASIC); err != nil {
207		return nil, err
208	}
209	req.FieldMask.Paths = cleanFieldMaskPaths(ttnpb.OrganizationFieldPathsNested, req.FieldMask.Paths, nil, getPaths)
210	if len(req.FieldMask.Paths) == 0 {
211		req.FieldMask.Paths = updatePaths
212	}
213	if ttnpb.HasAnyField(req.FieldMask.Paths, "contact_info") {
214		if err := validateContactInfo(req.Organization.ContactInfo); err != nil {
215			return nil, err
216		}
217	}
218	err = is.withDatabase(ctx, func(db *gorm.DB) (err error) {
219		org, err = store.GetOrganizationStore(db).UpdateOrganization(ctx, &req.Organization, &req.FieldMask)
220		if err != nil {
221			return err
222		}
223		if ttnpb.HasAnyField(req.FieldMask.Paths, "contact_info") {
224			cleanContactInfo(req.ContactInfo)
225			org.ContactInfo, err = store.GetContactInfoStore(db).SetContactInfo(ctx, org.OrganizationIdentifiers, req.ContactInfo)
226			if err != nil {
227				return err
228			}
229		}
230		return nil
231	})
232	if err != nil {
233		return nil, err
234	}
235	events.Publish(evtUpdateOrganization.NewWithIdentifiersAndData(ctx, req.OrganizationIdentifiers, req.FieldMask.Paths))
236	return org, nil
237}
238
239func (is *IdentityServer) deleteOrganization(ctx context.Context, ids *ttnpb.OrganizationIdentifiers) (*types.Empty, error) {
240	if err := rights.RequireOrganization(ctx, *ids, ttnpb.RIGHT_ORGANIZATION_DELETE); err != nil {
241		return nil, err
242	}
243	err := is.withDatabase(ctx, func(db *gorm.DB) error {
244		return store.GetOrganizationStore(db).DeleteOrganization(ctx, ids)
245	})
246	if err != nil {
247		return nil, err
248	}
249	events.Publish(evtDeleteOrganization.NewWithIdentifiersAndData(ctx, ids, nil))
250	return ttnpb.Empty, nil
251}
252
253func (is *IdentityServer) purgeOrganization(ctx context.Context, ids *ttnpb.OrganizationIdentifiers) (*types.Empty, error) {
254	if !is.IsAdmin(ctx) {
255		return nil, errAdminsPurgeOrganizations
256	}
257	err := is.withDatabase(ctx, func(db *gorm.DB) error {
258		err := store.GetContactInfoStore(db).DeleteEntityContactInfo(ctx, ids)
259		if err != nil {
260			return err
261		}
262		// Delete related API keys before purging the organization.
263		err = store.GetAPIKeyStore(db).DeleteEntityAPIKeys(ctx, ids)
264		if err != nil {
265			return err
266		}
267		err = store.GetMembershipStore(db).DeleteAccountMembers(ctx, ids.GetOrganizationOrUserIdentifiers())
268		if err != nil {
269			return err
270		}
271		return store.GetOrganizationStore(db).PurgeOrganization(ctx, ids)
272	})
273	if err != nil {
274		return nil, err
275	}
276	events.Publish(evtPurgeOrganization.NewWithIdentifiersAndData(ctx, ids, nil))
277	return ttnpb.Empty, nil
278}
279
280type organizationRegistry struct {
281	*IdentityServer
282}
283
284func (or *organizationRegistry) Create(ctx context.Context, req *ttnpb.CreateOrganizationRequest) (*ttnpb.Organization, error) {
285	return or.createOrganization(ctx, req)
286}
287
288func (or *organizationRegistry) Get(ctx context.Context, req *ttnpb.GetOrganizationRequest) (*ttnpb.Organization, error) {
289	return or.getOrganization(ctx, req)
290}
291
292func (or *organizationRegistry) List(ctx context.Context, req *ttnpb.ListOrganizationsRequest) (*ttnpb.Organizations, error) {
293	return or.listOrganizations(ctx, req)
294}
295
296func (or *organizationRegistry) Update(ctx context.Context, req *ttnpb.UpdateOrganizationRequest) (*ttnpb.Organization, error) {
297	return or.updateOrganization(ctx, req)
298}
299
300func (or *organizationRegistry) Delete(ctx context.Context, req *ttnpb.OrganizationIdentifiers) (*types.Empty, error) {
301	return or.deleteOrganization(ctx, req)
302}
303
304func (or *organizationRegistry) Purge(ctx context.Context, req *ttnpb.OrganizationIdentifiers) (*types.Empty, error) {
305	return or.purgeOrganization(ctx, req)
306}
307
Full Screen

application_access.go

Source: application_access.go Github

copy
1// Copyright © 2019 The Things Network Foundation, The Things Industries B.V.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package identityserver
16
17import (
18	"context"
19
20	"github.com/gogo/protobuf/types"
21	"github.com/jinzhu/gorm"
22	"go.thethings.network/lorawan-stack/v3/pkg/auth/rights"
23	"go.thethings.network/lorawan-stack/v3/pkg/email"
24	"go.thethings.network/lorawan-stack/v3/pkg/errors"
25	"go.thethings.network/lorawan-stack/v3/pkg/events"
26	"go.thethings.network/lorawan-stack/v3/pkg/identityserver/emails"
27	"go.thethings.network/lorawan-stack/v3/pkg/identityserver/store"
28	"go.thethings.network/lorawan-stack/v3/pkg/log"
29	"go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
30)
31
32var (
33	evtCreateApplicationAPIKey = events.Define(
34		"application.api-key.create", "create application API key",
35		events.WithVisibility(ttnpb.RIGHT_APPLICATION_SETTINGS_API_KEYS),
36		events.WithAuthFromContext(),
37		events.WithClientInfoFromContext(),
38	)
39	evtUpdateApplicationAPIKey = events.Define(
40		"application.api-key.update", "update application API key",
41		events.WithVisibility(ttnpb.RIGHT_APPLICATION_SETTINGS_API_KEYS),
42		events.WithAuthFromContext(),
43		events.WithClientInfoFromContext(),
44	)
45	evtDeleteApplicationAPIKey = events.Define(
46		"application.api-key.delete", "delete application API key",
47		events.WithVisibility(ttnpb.RIGHT_APPLICATION_SETTINGS_API_KEYS),
48		events.WithAuthFromContext(),
49		events.WithClientInfoFromContext(),
50	)
51	evtUpdateApplicationCollaborator = events.Define(
52		"application.collaborator.update", "update application collaborator",
53		events.WithVisibility(
54			ttnpb.RIGHT_APPLICATION_SETTINGS_COLLABORATORS,
55			ttnpb.RIGHT_USER_APPLICATIONS_LIST,
56		),
57		events.WithAuthFromContext(),
58		events.WithClientInfoFromContext(),
59	)
60	evtDeleteApplicationCollaborator = events.Define(
61		"application.collaborator.delete", "delete application collaborator",
62		events.WithVisibility(
63			ttnpb.RIGHT_APPLICATION_SETTINGS_COLLABORATORS,
64			ttnpb.RIGHT_USER_APPLICATIONS_LIST,
65		),
66		events.WithAuthFromContext(),
67		events.WithClientInfoFromContext(),
68	)
69)
70
71func (is *IdentityServer) listApplicationRights(ctx context.Context, ids *ttnpb.ApplicationIdentifiers) (*ttnpb.Rights, error) {
72	appRights, err := rights.ListApplication(ctx, *ids)
73	if err != nil {
74		return nil, err
75	}
76	return appRights.Intersect(ttnpb.AllApplicationRights), nil
77}
78
79func (is *IdentityServer) createApplicationAPIKey(ctx context.Context, req *ttnpb.CreateApplicationAPIKeyRequest) (key *ttnpb.APIKey, err error) {
80	// Require that caller has rights to manage API keys.
81	if err = rights.RequireApplication(ctx, req.ApplicationIdentifiers, ttnpb.RIGHT_APPLICATION_SETTINGS_API_KEYS); err != nil {
82		return nil, err
83	}
84	// Require that caller has at least the rights of the API key.
85	if err = rights.RequireApplication(ctx, req.ApplicationIdentifiers, req.Rights...); err != nil {
86		return nil, err
87	}
88	key, token, err := GenerateAPIKey(ctx, req.Name, req.Rights...)
89	if err != nil {
90		return nil, err
91	}
92	err = is.withDatabase(ctx, func(db *gorm.DB) error {
93		return store.GetAPIKeyStore(db).CreateAPIKey(ctx, req.ApplicationIdentifiers, key)
94	})
95	if err != nil {
96		return nil, err
97	}
98	key.Key = token
99	events.Publish(evtCreateApplicationAPIKey.NewWithIdentifiersAndData(ctx, req.ApplicationIdentifiers, nil))
100	err = is.SendContactsEmail(ctx, req.EntityIdentifiers(), func(data emails.Data) email.MessageData {
101		data.SetEntity(req.EntityIdentifiers())
102		return &emails.APIKeyCreated{Data: data, Identifier: key.PrettyName(), Rights: key.Rights}
103	})
104	if err != nil {
105		log.FromContext(ctx).WithError(err).Error("Could not send API key creation notification email")
106	}
107	return key, nil
108}
109
110func (is *IdentityServer) listApplicationAPIKeys(ctx context.Context, req *ttnpb.ListApplicationAPIKeysRequest) (keys *ttnpb.APIKeys, err error) {
111	if err = rights.RequireApplication(ctx, req.ApplicationIdentifiers, ttnpb.RIGHT_APPLICATION_SETTINGS_API_KEYS); err != nil {
112		return nil, err
113	}
114	var total uint64
115	ctx = store.WithPagination(ctx, req.Limit, req.Page, &total)
116	defer func() {
117		if err == nil {
118			setTotalHeader(ctx, total)
119		}
120	}()
121	keys = &ttnpb.APIKeys{}
122	err = is.withDatabase(ctx, func(db *gorm.DB) (err error) {
123		keys.APIKeys, err = store.GetAPIKeyStore(db).FindAPIKeys(ctx, req.ApplicationIdentifiers)
124		return err
125	})
126	if err != nil {
127		return nil, err
128	}
129	for _, key := range keys.APIKeys {
130		key.Key = ""
131	}
132	return keys, nil
133}
134
135func (is *IdentityServer) getApplicationAPIKey(ctx context.Context, req *ttnpb.GetApplicationAPIKeyRequest) (key *ttnpb.APIKey, err error) {
136	if err = rights.RequireApplication(ctx, req.ApplicationIdentifiers, ttnpb.RIGHT_APPLICATION_SETTINGS_API_KEYS); err != nil {
137		return nil, err
138	}
139
140	err = is.withDatabase(ctx, func(db *gorm.DB) (err error) {
141		_, key, err = store.GetAPIKeyStore(db).GetAPIKey(ctx, req.KeyID)
142		if err != nil {
143			return err
144		}
145
146		return nil
147	})
148	if err != nil {
149		return nil, err
150	}
151	key.Key = ""
152	return key, nil
153}
154
155func (is *IdentityServer) updateApplicationAPIKey(ctx context.Context, req *ttnpb.UpdateApplicationAPIKeyRequest) (key *ttnpb.APIKey, err error) {
156	// Require that caller has rights to manage API keys.
157	if err := rights.RequireApplication(ctx, req.ApplicationIdentifiers, ttnpb.RIGHT_APPLICATION_SETTINGS_API_KEYS); err != nil {
158		return nil, err
159	}
160
161	err = is.withDatabase(ctx, func(db *gorm.DB) (err error) {
162		if len(req.APIKey.Rights) > 0 {
163			_, key, err := store.GetAPIKeyStore(db).GetAPIKey(ctx, req.APIKey.ID)
164			if err != nil {
165				return err
166			}
167
168			newRights := ttnpb.RightsFrom(req.APIKey.Rights...)
169			existingRights := ttnpb.RightsFrom(key.Rights...)
170
171			// Require the caller to have all added rights.
172			if err := rights.RequireApplication(ctx, req.ApplicationIdentifiers, newRights.Sub(existingRights).GetRights()...); err != nil {
173				return err
174			}
175			// Require the caller to have all removed rights.
176			if err := rights.RequireApplication(ctx, req.ApplicationIdentifiers, existingRights.Sub(newRights).GetRights()...); err != nil {
177				return err
178			}
179		}
180
181		key, err = store.GetAPIKeyStore(db).UpdateAPIKey(ctx, req.ApplicationIdentifiers, &req.APIKey)
182		return err
183	})
184	if err != nil {
185		return nil, err
186	}
187	if key == nil { // API key was deleted.
188		events.Publish(evtDeleteApplicationAPIKey.NewWithIdentifiersAndData(ctx, req.ApplicationIdentifiers, nil))
189		return &ttnpb.APIKey{}, nil
190	}
191	key.Key = ""
192	events.Publish(evtUpdateApplicationAPIKey.NewWithIdentifiersAndData(ctx, req.ApplicationIdentifiers, nil))
193	err = is.SendContactsEmail(ctx, req.EntityIdentifiers(), func(data emails.Data) email.MessageData {
194		data.SetEntity(req.EntityIdentifiers())
195		return &emails.APIKeyChanged{Data: data, Identifier: key.PrettyName(), Rights: key.Rights}
196	})
197	if err != nil {
198		log.FromContext(ctx).WithError(err).Error("Could not send API key update notification email")
199	}
200
201	return key, nil
202}
203
204func (is *IdentityServer) getApplicationCollaborator(ctx context.Context, req *ttnpb.GetApplicationCollaboratorRequest) (*ttnpb.GetCollaboratorResponse, error) {
205	if err := rights.RequireApplication(ctx, req.ApplicationIdentifiers, ttnpb.RIGHT_APPLICATION_SETTINGS_COLLABORATORS); err != nil {
206		return nil, err
207	}
208	res := &ttnpb.GetCollaboratorResponse{
209		OrganizationOrUserIdentifiers: req.OrganizationOrUserIdentifiers,
210	}
211	err := is.withDatabase(ctx, func(db *gorm.DB) error {
212		rights, err := is.getMembershipStore(ctx, db).GetMember(
213			ctx,
214			&req.OrganizationOrUserIdentifiers,
215			req.ApplicationIdentifiers,
216		)
217		if err != nil {
218			return err
219		}
220		res.Rights = rights.GetRights()
221		return nil
222	})
223	if err != nil {
224		return nil, err
225	}
226	return res, nil
227}
228
229func (is *IdentityServer) setApplicationCollaborator(ctx context.Context, req *ttnpb.SetApplicationCollaboratorRequest) (*types.Empty, error) {
230	// Require that caller has rights to manage collaborators.
231	if err := rights.RequireApplication(ctx, req.ApplicationIdentifiers, ttnpb.RIGHT_APPLICATION_SETTINGS_COLLABORATORS); err != nil {
232		return nil, err
233	}
234
235	err := is.withDatabase(ctx, func(db *gorm.DB) error {
236		store := is.getMembershipStore(ctx, db)
237
238		if len(req.Collaborator.Rights) > 0 {
239			newRights := ttnpb.RightsFrom(req.Collaborator.Rights...)
240			existingRights, err := store.GetMember(
241				ctx,
242				&req.Collaborator.OrganizationOrUserIdentifiers,
243				req.ApplicationIdentifiers,
244			)
245
246			if err != nil && !errors.IsNotFound(err) {
247				return err
248			}
249			// Require the caller to have all added rights.
250			if err := rights.RequireApplication(ctx, req.ApplicationIdentifiers, newRights.Sub(existingRights).GetRights()...); err != nil {
251				return err
252			}
253			// Require the caller to have all removed rights.
254			if err := rights.RequireApplication(ctx, req.ApplicationIdentifiers, existingRights.Sub(newRights).GetRights()...); err != nil {
255				return err
256			}
257		}
258
259		return store.SetMember(
260			ctx,
261			&req.Collaborator.OrganizationOrUserIdentifiers,
262			req.ApplicationIdentifiers,
263			ttnpb.RightsFrom(req.Collaborator.Rights...),
264		)
265	})
266	if err != nil {
267		return nil, err
268	}
269	if len(req.Collaborator.Rights) > 0 {
270		events.Publish(evtUpdateApplicationCollaborator.NewWithIdentifiersAndData(ctx, ttnpb.CombineIdentifiers(req.ApplicationIdentifiers, req.Collaborator), nil))
271		err = is.SendContactsEmail(ctx, req.EntityIdentifiers(), func(data emails.Data) email.MessageData {
272			data.SetEntity(req.EntityIdentifiers())
273			return &emails.CollaboratorChanged{Data: data, Collaborator: req.Collaborator}
274		})
275		if err != nil {
276			log.FromContext(ctx).WithError(err).Error("Could not send collaborator updated notification email")
277		}
278	} else {
279		events.Publish(evtDeleteApplicationCollaborator.NewWithIdentifiersAndData(ctx, ttnpb.CombineIdentifiers(req.ApplicationIdentifiers, req.Collaborator), nil))
280	}
281	return ttnpb.Empty, nil
282}
283
284func (is *IdentityServer) listApplicationCollaborators(ctx context.Context, req *ttnpb.ListApplicationCollaboratorsRequest) (collaborators *ttnpb.Collaborators, err error) {
285	if err = rights.RequireApplication(ctx, req.ApplicationIdentifiers, ttnpb.RIGHT_APPLICATION_SETTINGS_COLLABORATORS); err != nil {
286		return nil, err
287	}
288	var total uint64
289	ctx = store.WithPagination(ctx, req.Limit, req.Page, &total)
290	defer func() {
291		if err == nil {
292			setTotalHeader(ctx, total)
293		}
294	}()
295	err = is.withDatabase(ctx, func(db *gorm.DB) error {
296		memberRights, err := is.getMembershipStore(ctx, db).FindMembers(ctx, req.ApplicationIdentifiers)
297		if err != nil {
298			return err
299		}
300		collaborators = &ttnpb.Collaborators{}
301		for member, rights := range memberRights {
302			collaborators.Collaborators = append(collaborators.Collaborators, &ttnpb.Collaborator{
303				OrganizationOrUserIdentifiers: *member,
304				Rights:                        rights.GetRights(),
305			})
306		}
307		return nil
308	})
309	if err != nil {
310		return nil, err
311	}
312	return collaborators, nil
313}
314
315type applicationAccess struct {
316	*IdentityServer
317}
318
319func (aa *applicationAccess) ListRights(ctx context.Context, req *ttnpb.ApplicationIdentifiers) (*ttnpb.Rights, error) {
320	return aa.listApplicationRights(ctx, req)
321}
322
323func (aa *applicationAccess) CreateAPIKey(ctx context.Context, req *ttnpb.CreateApplicationAPIKeyRequest) (*ttnpb.APIKey, error) {
324	return aa.createApplicationAPIKey(ctx, req)
325}
326
327func (aa *applicationAccess) ListAPIKeys(ctx context.Context, req *ttnpb.ListApplicationAPIKeysRequest) (*ttnpb.APIKeys, error) {
328	return aa.listApplicationAPIKeys(ctx, req)
329}
330
331func (aa *applicationAccess) GetAPIKey(ctx context.Context, req *ttnpb.GetApplicationAPIKeyRequest) (*ttnpb.APIKey, error) {
332	return aa.getApplicationAPIKey(ctx, req)
333}
334
335func (aa *applicationAccess) UpdateAPIKey(ctx context.Context, req *ttnpb.UpdateApplicationAPIKeyRequest) (*ttnpb.APIKey, error) {
336	return aa.updateApplicationAPIKey(ctx, req)
337}
338
339func (aa *applicationAccess) GetCollaborator(ctx context.Context, req *ttnpb.GetApplicationCollaboratorRequest) (*ttnpb.GetCollaboratorResponse, error) {
340	return aa.getApplicationCollaborator(ctx, req)
341}
342
343func (aa *applicationAccess) SetCollaborator(ctx context.Context, req *ttnpb.SetApplicationCollaboratorRequest) (*types.Empty, error) {
344	return aa.setApplicationCollaborator(ctx, req)
345}
346
347func (aa *applicationAccess) ListCollaborators(ctx context.Context, req *ttnpb.ListApplicationCollaboratorsRequest) (*ttnpb.Collaborators, error) {
348	return aa.listApplicationCollaborators(ctx, req)
349}
350
Full Screen

gateway_access.go

Source: gateway_access.go Github

copy
1// Copyright © 2019 The Things Network Foundation, The Things Industries B.V.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package identityserver
16
17import (
18	"context"
19
20	"github.com/gogo/protobuf/types"
21	"github.com/jinzhu/gorm"
22	"go.thethings.network/lorawan-stack/v3/pkg/auth/rights"
23	"go.thethings.network/lorawan-stack/v3/pkg/email"
24	"go.thethings.network/lorawan-stack/v3/pkg/errors"
25	"go.thethings.network/lorawan-stack/v3/pkg/events"
26	"go.thethings.network/lorawan-stack/v3/pkg/identityserver/emails"
27	"go.thethings.network/lorawan-stack/v3/pkg/identityserver/store"
28	"go.thethings.network/lorawan-stack/v3/pkg/log"
29	"go.thethings.network/lorawan-stack/v3/pkg/ttnpb"
30)
31
32var (
33	evtCreateGatewayAPIKey = events.Define(
34		"gateway.api-key.create", "create gateway API key",
35		events.WithVisibility(ttnpb.RIGHT_GATEWAY_SETTINGS_API_KEYS),
36		events.WithAuthFromContext(),
37		events.WithClientInfoFromContext(),
38	)
39	evtUpdateGatewayAPIKey = events.Define(
40		"gateway.api-key.update", "update gateway API key",
41		events.WithVisibility(ttnpb.RIGHT_GATEWAY_SETTINGS_API_KEYS),
42		events.WithAuthFromContext(),
43		events.WithClientInfoFromContext(),
44	)
45	evtDeleteGatewayAPIKey = events.Define(
46		"gateway.api-key.delete", "delete gateway API key",
47		events.WithVisibility(ttnpb.RIGHT_GATEWAY_SETTINGS_API_KEYS),
48		events.WithAuthFromContext(),
49		events.WithClientInfoFromContext(),
50	)
51	evtUpdateGatewayCollaborator = events.Define(
52		"gateway.collaborator.update", "update gateway collaborator",
53		events.WithVisibility(
54			ttnpb.RIGHT_GATEWAY_SETTINGS_COLLABORATORS,
55			ttnpb.RIGHT_USER_GATEWAYS_LIST,
56		),
57		events.WithAuthFromContext(),
58		events.WithClientInfoFromContext(),
59	)
60	evtDeleteGatewayCollaborator = events.Define(
61		"gateway.collaborator.delete", "delete gateway collaborator",
62		events.WithVisibility(
63			ttnpb.RIGHT_GATEWAY_SETTINGS_COLLABORATORS,
64			ttnpb.RIGHT_USER_GATEWAYS_LIST,
65		),
66		events.WithAuthFromContext(),
67		events.WithClientInfoFromContext(),
68	)
69)
70
71func (is *IdentityServer) listGatewayRights(ctx context.Context, ids *ttnpb.GatewayIdentifiers) (*ttnpb.Rights, error) {
72	gtwRights, err := rights.ListGateway(ctx, *ids)
73	if err != nil {
74		return nil, err
75	}
76	return gtwRights.Intersect(ttnpb.AllGatewayRights), nil
77}
78
79func (is *IdentityServer) createGatewayAPIKey(ctx context.Context, req *ttnpb.CreateGatewayAPIKeyRequest) (key *ttnpb.APIKey, err error) {
80	// Require that caller has rights to manage API keys.
81	if err = rights.RequireGateway(ctx, req.GatewayIdentifiers, ttnpb.RIGHT_GATEWAY_SETTINGS_API_KEYS); err != nil {
82		return nil, err
83	}
84	// Require that caller has at least the rights of the API key.
85	if err = rights.RequireGateway(ctx, req.GatewayIdentifiers, req.Rights...); err != nil {
86		return nil, err
87	}
88	key, token, err := GenerateAPIKey(ctx, req.Name, req.Rights...)
89	if err != nil {
90		return nil, err
91	}
92	err = is.withDatabase(ctx, func(db *gorm.DB) error {
93		return store.GetAPIKeyStore(db).CreateAPIKey(ctx, req.GatewayIdentifiers, key)
94	})
95	if err != nil {
96		return nil, err
97	}
98	key.Key = token
99	events.Publish(evtCreateGatewayAPIKey.NewWithIdentifiersAndData(ctx, req.GatewayIdentifiers, nil))
100	err = is.SendContactsEmail(ctx, req.EntityIdentifiers(), func(data emails.Data) email.MessageData {
101		data.SetEntity(req.EntityIdentifiers())
102		return &emails.APIKeyCreated{Data: data, Identifier: key.PrettyName(), Rights: key.Rights}
103	})
104	if err != nil {
105		log.FromContext(ctx).WithError(err).Error("Could not send API key creation notification email")
106	}
107	return key, nil
108}
109
110func (is *IdentityServer) listGatewayAPIKeys(ctx context.Context, req *ttnpb.ListGatewayAPIKeysRequest) (keys *ttnpb.APIKeys, err error) {
111	if err = rights.RequireGateway(ctx, req.GatewayIdentifiers, ttnpb.RIGHT_GATEWAY_SETTINGS_API_KEYS); err != nil {
112		return nil, err
113	}
114	var total uint64
115	ctx = store.WithPagination(ctx, req.Limit, req.Page, &total)
116	defer func() {
117		if err == nil {
118			setTotalHeader(ctx, total)
119		}
120	}()
121	keys = &ttnpb.APIKeys{}
122	err = is.withDatabase(ctx, func(db *gorm.DB) (err error) {
123		keys.APIKeys, err = store.GetAPIKeyStore(db).FindAPIKeys(ctx, req.GatewayIdentifiers)
124		return err
125	})
126	if err != nil {
127		return nil, err
128	}
129	for _, key := range keys.APIKeys {
130		key.Key = ""
131	}
132	return keys, nil
133}
134
135func (is *IdentityServer) getGatewayAPIKey(ctx context.Context, req *ttnpb.GetGatewayAPIKeyRequest) (key *ttnpb.APIKey, err error) {
136	if err = rights.RequireGateway(ctx, req.GatewayIdentifiers, ttnpb.RIGHT_GATEWAY_SETTINGS_API_KEYS); err != nil {
137		return nil, err
138	}
139
140	err = is.withDatabase(ctx, func(db *gorm.DB) (err error) {
141		_, key, err = store.GetAPIKeyStore(db).GetAPIKey(ctx, req.KeyID)
142		if err != nil {
143			return err
144		}
145
146		return nil
147	})
148	if err != nil {
149		return nil, err
150	}
151	key.Key = ""
152	return key, nil
153}
154
155func (is *IdentityServer) updateGatewayAPIKey(ctx context.Context, req *ttnpb.UpdateGatewayAPIKeyRequest) (key *ttnpb.APIKey, err error) {
156	// Require that caller has rights to manage API keys.
157	if err = rights.RequireGateway(ctx, req.GatewayIdentifiers, ttnpb.RIGHT_GATEWAY_SETTINGS_API_KEYS); err != nil {
158		return nil, err
159	}
160
161	err = is.withDatabase(ctx, func(db *gorm.DB) (err error) {
162		if len(req.APIKey.Rights) > 0 {
163			_, key, err := store.GetAPIKeyStore(db).GetAPIKey(ctx, req.APIKey.ID)
164			if err != nil {
165				return err
166			}
167
168			newRights := ttnpb.RightsFrom(req.APIKey.Rights...)
169			existingRights := ttnpb.RightsFrom(key.Rights...)
170
171			// Require the caller to have all added rights.
172			if err := rights.RequireGateway(ctx, req.GatewayIdentifiers, newRights.Sub(existingRights).GetRights()...); err != nil {
173				return err
174			}
175			// Require the caller to have all removed rights.
176			if err := rights.RequireGateway(ctx, req.GatewayIdentifiers, existingRights.Sub(newRights).GetRights()...); err != nil {
177				return err
178			}
179		}
180
181		key, err = store.GetAPIKeyStore(db).UpdateAPIKey(ctx, req.GatewayIdentifiers, &req.APIKey)
182		return err
183	})
184	if err != nil {
185		return nil, err
186	}
187	if key == nil { // API key was deleted.
188		events.Publish(evtDeleteGatewayAPIKey.NewWithIdentifiersAndData(ctx, req.GatewayIdentifiers, nil))
189		return &ttnpb.APIKey{}, nil
190	}
191	key.Key = ""
192	events.Publish(evtUpdateGatewayAPIKey.NewWithIdentifiersAndData(ctx, req.GatewayIdentifiers, nil))
193	err = is.SendContactsEmail(ctx, req.EntityIdentifiers(), func(data emails.Data) email.MessageData {
194		data.SetEntity(req.EntityIdentifiers())
195		return &emails.APIKeyChanged{Data: data, Identifier: key.PrettyName(), Rights: key.Rights}
196	})
197	if err != nil {
198		log.FromContext(ctx).WithError(err).Error("Could not send API key update notification email")
199	}
200
201	return key, nil
202}
203
204func (is *IdentityServer) getGatewayCollaborator(ctx context.Context, req *ttnpb.GetGatewayCollaboratorRequest) (*ttnpb.GetCollaboratorResponse, error) {
205	if err := rights.RequireGateway(ctx, req.GatewayIdentifiers, ttnpb.RIGHT_GATEWAY_SETTINGS_COLLABORATORS); err != nil {
206		return nil, err
207	}
208	res := &ttnpb.GetCollaboratorResponse{
209		OrganizationOrUserIdentifiers: req.OrganizationOrUserIdentifiers,
210	}
211	err := is.withDatabase(ctx, func(db *gorm.DB) error {
212		rights, err := is.getMembershipStore(ctx, db).GetMember(
213			ctx,
214			&req.OrganizationOrUserIdentifiers,
215			req.GatewayIdentifiers,
216		)
217		if err != nil {
218			return err
219		}
220		res.Rights = rights.GetRights()
221		return nil
222	})
223	if err != nil {
224		return nil, err
225	}
226	return res, nil
227}
228
229func (is *IdentityServer) setGatewayCollaborator(ctx context.Context, req *ttnpb.SetGatewayCollaboratorRequest) (*types.Empty, error) {
230	// Require that caller has rights to manage collaborators.
231	if err := rights.RequireGateway(ctx, req.GatewayIdentifiers, ttnpb.RIGHT_GATEWAY_SETTINGS_COLLABORATORS); err != nil {
232		return nil, err
233	}
234	err := is.withDatabase(ctx, func(db *gorm.DB) error {
235		store := is.getMembershipStore(ctx, db)
236
237		if len(req.Collaborator.Rights) > 0 {
238			newRights := ttnpb.RightsFrom(req.Collaborator.Rights...)
239			existingRights, err := store.GetMember(
240				ctx,
241				&req.Collaborator.OrganizationOrUserIdentifiers,
242				req.GatewayIdentifiers,
243			)
244
245			if err != nil && !errors.IsNotFound(err) {
246				return err
247			}
248			// Require the caller to have all added rights.
249			if err := rights.RequireGateway(ctx, req.GatewayIdentifiers, newRights.Sub(existingRights).GetRights()...); err != nil {
250				return err
251			}
252			// Require the caller to have all removed rights.
253			if err := rights.RequireGateway(ctx, req.GatewayIdentifiers, existingRights.Sub(newRights).GetRights()...); err != nil {
254				return err
255			}
256		}
257
258		return store.SetMember(
259			ctx,
260			&req.Collaborator.OrganizationOrUserIdentifiers,
261			req.GatewayIdentifiers,
262			ttnpb.RightsFrom(req.Collaborator.Rights...),
263		)
264	})
265	if err != nil {
266		return nil, err
267	}
268	if len(req.Collaborator.Rights) > 0 {
269		events.Publish(evtUpdateGatewayCollaborator.NewWithIdentifiersAndData(ctx, ttnpb.CombineIdentifiers(req.GatewayIdentifiers, req.Collaborator), nil))
270		err = is.SendContactsEmail(ctx, req.EntityIdentifiers(), func(data emails.Data) email.MessageData {
271			data.SetEntity(req.EntityIdentifiers())
272			return &emails.CollaboratorChanged{Data: data, Collaborator: req.Collaborator}
273		})
274		if err != nil {
275			log.FromContext(ctx).WithError(err).Error("Could not send collaborator updated notification email")
276		}
277	} else {
278		events.Publish(evtDeleteGatewayCollaborator.NewWithIdentifiersAndData(ctx, ttnpb.CombineIdentifiers(req.GatewayIdentifiers, req.Collaborator), nil))
279	}
280	return ttnpb.Empty, nil
281}
282
283func (is *IdentityServer) listGatewayCollaborators(ctx context.Context, req *ttnpb.ListGatewayCollaboratorsRequest) (collaborators *ttnpb.Collaborators, err error) {
284	if err = rights.RequireGateway(ctx, req.GatewayIdentifiers, ttnpb.RIGHT_GATEWAY_SETTINGS_COLLABORATORS); err != nil {
285		return nil, err
286	}
287	var total uint64
288	ctx = store.WithPagination(ctx, req.Limit, req.Page, &total)
289	defer func() {
290		if err == nil {
291			setTotalHeader(ctx, total)
292		}
293	}()
294	err = is.withDatabase(ctx, func(db *gorm.DB) error {
295		memberRights, err := is.getMembershipStore(ctx, db).FindMembers(ctx, req.GatewayIdentifiers)
296		if err != nil {
297			return err
298		}
299		collaborators = &ttnpb.Collaborators{}
300		for member, rights := range memberRights {
301			collaborators.Collaborators = append(collaborators.Collaborators, &ttnpb.Collaborator{
302				OrganizationOrUserIdentifiers: *member,
303				Rights:                        rights.GetRights(),
304			})
305		}
306		return nil
307	})
308	if err != nil {
309		return nil, err
310	}
311	return collaborators, nil
312}
313
314type gatewayAccess struct {
315	*IdentityServer
316}
317
318func (ga *gatewayAccess) ListRights(ctx context.Context, req *ttnpb.GatewayIdentifiers) (*ttnpb.Rights, error) {
319	return ga.listGatewayRights(ctx, req)
320}
321
322func (ga *gatewayAccess) CreateAPIKey(ctx context.Context, req *ttnpb.CreateGatewayAPIKeyRequest) (*ttnpb.APIKey, error) {
323	return ga.createGatewayAPIKey(ctx, req)
324}
325
326func (ga *gatewayAccess) ListAPIKeys(ctx context.Context, req *ttnpb.ListGatewayAPIKeysRequest) (*ttnpb.APIKeys, error) {
327	return ga.listGatewayAPIKeys(ctx, req)
328}
329
330func (ga *gatewayAccess) GetAPIKey(ctx context.Context, req *ttnpb.GetGatewayAPIKeyRequest) (*ttnpb.APIKey, error) {
331	return ga.getGatewayAPIKey(ctx, req)
332}
333
334func (ga *gatewayAccess) UpdateAPIKey(ctx context.Context, req *ttnpb.UpdateGatewayAPIKeyRequest) (*ttnpb.APIKey, error) {
335	return ga.updateGatewayAPIKey(ctx, req)
336}
337
338func (ga *gatewayAccess) GetCollaborator(ctx context.Context, req *ttnpb.GetGatewayCollaboratorRequest) (*ttnpb.GetCollaboratorResponse, error) {
339	return ga.getGatewayCollaborator(ctx, req)
340}
341
342func (ga *gatewayAccess) SetCollaborator(ctx context.Context, req *ttnpb.SetGatewayCollaboratorRequest) (*types.Empty, error) {
343	return ga.setGatewayCollaborator(ctx, req)
344}
345
346func (ga *gatewayAccess) ListCollaborators(ctx context.Context, req *ttnpb.ListGatewayCollaboratorsRequest) (*ttnpb.Collaborators, error) {
347	return ga.listGatewayCollaborators(ctx, req)
348}
349
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Most used method in

Trigger WithVisibility code on LambdaTest Cloud Grid

Execute automation tests with WithVisibility on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)