Skip to content

Commit a2654e3

Browse files
feat: Users - Managed & OIDC (#55)
1 parent 7ea22cc commit a2654e3

File tree

11 files changed

+724
-13
lines changed

11 files changed

+724
-13
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ build:
33
.PHONY: build
44

55
test:
6-
go test -v -cover
6+
go test -v -cover -timeout=15m
77
.PHONY: test
88

99
clean:

client.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ type Client struct {
4141
BOM BOMService
4242
Component ComponentService
4343
Config ConfigService
44-
Finding FindingService
4544
Event EventService
45+
Finding FindingService
46+
Health HealthService
4647
LDAP LDAPService
4748
License LicenseService
4849
Metrics MetricsService
@@ -93,8 +94,9 @@ func NewClient(baseURL string, options ...ClientOption) (*Client, error) {
9394
client.BOM = BOMService{client: &client}
9495
client.Component = ComponentService{client: &client}
9596
client.Config = ConfigService{client: &client}
96-
client.Finding = FindingService{client: &client}
9797
client.Event = EventService{client: &client}
98+
client.Finding = FindingService{client: &client}
99+
client.Health = HealthService{client: &client}
98100
client.LDAP = LDAPService{client: &client}
99101
client.License = LicenseService{client: &client}
100102
client.Metrics = MetricsService{client: &client}
@@ -193,7 +195,7 @@ func withPathParams(params map[string]string) requestOption {
193195
}
194196

195197
for k, v := range params {
196-
req.URL.Path = strings.Replace(req.URL.Path, fmt.Sprintf("{%s}", k), v, -1)
198+
req.URL.Path = strings.ReplaceAll(req.URL.Path, fmt.Sprintf("{%s}", k), v)
197199
}
198200
return nil
199201
}

component_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ func TestComponentLifecycle(t *testing.T) {
6969
// Delete
7070
{
7171
err := client.Component.Delete(context.Background(), component.UUID)
72+
// Occassionally receives 500 response from API - https://github.com/DependencyTrack/client-go/actions/runs/20657420675/job/59312871798?pr=55
73+
// Due to the intermittent nature, the cause is not yet identified.
7274
require.NoError(t, err)
7375
}
7476

health.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package dtrack
2+
3+
import (
4+
"context"
5+
"net/http"
6+
)
7+
8+
type HealthCheck struct {
9+
Name string `json:"name"`
10+
Status string `json:"status"`
11+
Data interface{} `json:"data,omitempty"`
12+
}
13+
14+
type Health struct {
15+
Status string `json:"status"`
16+
Checks []HealthCheck `json:"checks"`
17+
}
18+
19+
type HealthService struct {
20+
client *Client
21+
}
22+
23+
func (hs HealthService) Get(ctx context.Context) (h Health, err error) {
24+
req, err := hs.client.newRequest(ctx, http.MethodGet, "health", withoutAuth())
25+
if err != nil {
26+
return
27+
}
28+
29+
_, err = hs.client.doRequest(req, &h)
30+
return
31+
}

health_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package dtrack
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestHealth(t *testing.T) {
11+
client := setUpContainer(t, testContainerOptions{})
12+
13+
health, err := client.Health.Get(context.TODO())
14+
require.NoError(t, err)
15+
require.NotNil(t, health)
16+
17+
require.Equal(t, "UP", health.Status)
18+
require.Equal(t, 1, len(health.Checks))
19+
require.Equal(t, "database", health.Checks[0].Name)
20+
require.Equal(t, "UP", health.Checks[0].Status)
21+
require.NotNil(t, health.Checks[0].Data)
22+
require.Equal(t, "UP", health.Checks[0].Data.(map[string]any)["nontx_connection_pool"])
23+
require.Equal(t, "UP", health.Checks[0].Data.(map[string]any)["tx_connection_pool"])
24+
}

oidc.go

Lines changed: 137 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"net/http"
7+
"net/url"
78
"strconv"
89

910
"github.com/google/uuid"
@@ -28,7 +29,25 @@ type OIDCMapping struct {
2829
UUID uuid.UUID `json:"uuid"`
2930
}
3031

32+
type OIDCUser struct {
33+
Username string `json:"username"`
34+
SubjectIdentifier string `json:"subjectIdentifier"`
35+
Email string `json:"email"`
36+
Teams []Team `json:"teams"`
37+
Permissions []Permission `json:"permissions"`
38+
}
39+
40+
type OIDCTokens struct {
41+
ID string `json:"idToken"`
42+
Access string `json:"accessToken,omitempty"`
43+
}
44+
3145
func (s OIDCService) Available(ctx context.Context) (available bool, err error) {
46+
err = s.client.assertServerVersionAtLeast("4.0.0")
47+
if err != nil {
48+
return
49+
}
50+
3251
req, err := s.client.newRequest(ctx, http.MethodGet, "api/v1/oidc/available", withAcceptContentType("text/plain"))
3352
if err != nil {
3453
return
@@ -44,22 +63,28 @@ func (s OIDCService) Available(ctx context.Context) (available bool, err error)
4463
return
4564
}
4665

47-
func (s OIDCService) GetAllGroups(ctx context.Context, po PageOptions) (p Page[OIDCGroup], err error) {
48-
req, err := s.client.newRequest(ctx, http.MethodGet, "api/v1/oidc/group", withPageOptions(po))
66+
func (s OIDCService) GetAllGroups(ctx context.Context) (groups []OIDCGroup, err error) {
67+
err = s.client.assertServerVersionAtLeast("4.0.0")
4968
if err != nil {
5069
return
5170
}
5271

53-
res, err := s.client.doRequest(req, &p.Items)
72+
req, err := s.client.newRequest(ctx, http.MethodGet, "api/v1/oidc/group")
5473
if err != nil {
5574
return
5675
}
5776

58-
p.TotalCount = res.TotalCount
77+
_, err = s.client.doRequest(req, &groups)
5978
return
79+
6080
}
6181

6282
func (s OIDCService) CreateGroup(ctx context.Context, name string) (g OIDCGroup, err error) {
83+
err = s.client.assertServerVersionAtLeast("4.0.0")
84+
if err != nil {
85+
return
86+
}
87+
6388
req, err := s.client.newRequest(ctx, http.MethodPut, "api/v1/oidc/group", withBody(OIDCGroup{Name: name}))
6489
if err != nil {
6590
return
@@ -69,6 +94,11 @@ func (s OIDCService) CreateGroup(ctx context.Context, name string) (g OIDCGroup,
6994
return
7095
}
7196
func (s OIDCService) UpdateGroup(ctx context.Context, group OIDCGroup) (g OIDCGroup, err error) {
97+
err = s.client.assertServerVersionAtLeast("4.0.0")
98+
if err != nil {
99+
return
100+
}
101+
72102
req, err := s.client.newRequest(ctx, http.MethodPost, "api/v1/oidc/group", withBody(group))
73103
if err != nil {
74104
return
@@ -79,6 +109,11 @@ func (s OIDCService) UpdateGroup(ctx context.Context, group OIDCGroup) (g OIDCGr
79109
}
80110

81111
func (s OIDCService) DeleteGroup(ctx context.Context, groupUUID uuid.UUID) (err error) {
112+
err = s.client.assertServerVersionAtLeast("4.0.0")
113+
if err != nil {
114+
return
115+
}
116+
82117
req, err := s.client.newRequest(ctx, http.MethodDelete, fmt.Sprintf("api/v1/oidc/group/%s", groupUUID.String()))
83118
if err != nil {
84119
return
@@ -88,22 +123,27 @@ func (s OIDCService) DeleteGroup(ctx context.Context, groupUUID uuid.UUID) (err
88123
return
89124
}
90125

91-
func (s OIDCService) GetAllTeamsOf(ctx context.Context, group OIDCGroup, po PageOptions) (p Page[Team], err error) {
92-
req, err := s.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("api/v1/oidc/group/%s/team", group.UUID.String()), withPageOptions(po))
126+
func (s OIDCService) GetAllTeamsOf(ctx context.Context, group OIDCGroup) (teams []Team, err error) {
127+
err = s.client.assertServerVersionAtLeast("4.0.0")
93128
if err != nil {
94129
return
95130
}
96131

97-
res, err := s.client.doRequest(req, &p.Items)
132+
req, err := s.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("api/v1/oidc/group/%s/team", group.UUID.String()))
98133
if err != nil {
99134
return
100135
}
101136

102-
p.TotalCount = res.TotalCount
137+
_, err = s.client.doRequest(req, &teams)
103138
return
104139
}
105140

106141
func (s OIDCService) AddTeamMapping(ctx context.Context, mapping OIDCMappingRequest) (m OIDCMapping, err error) {
142+
err = s.client.assertServerVersionAtLeast("4.0.0")
143+
if err != nil {
144+
return
145+
}
146+
107147
req, err := s.client.newRequest(ctx, http.MethodPut, "api/v1/oidc/mapping", withBody(mapping))
108148
if err != nil {
109149
return
@@ -114,6 +154,11 @@ func (s OIDCService) AddTeamMapping(ctx context.Context, mapping OIDCMappingRequ
114154
}
115155

116156
func (s OIDCService) RemoveTeamMapping(ctx context.Context, mappingID uuid.UUID) (err error) {
157+
err = s.client.assertServerVersionAtLeast("4.0.0")
158+
if err != nil {
159+
return
160+
}
161+
117162
req, err := s.client.newRequest(ctx, http.MethodDelete, fmt.Sprintf("api/v1/oidc/mapping/%s", mappingID.String()))
118163
if err != nil {
119164
return
@@ -122,3 +167,87 @@ func (s OIDCService) RemoveTeamMapping(ctx context.Context, mappingID uuid.UUID)
122167
_, err = s.client.doRequest(req, nil)
123168
return
124169
}
170+
171+
func (s OIDCService) RemoveTeamMapping2(ctx context.Context, groupID, teamID uuid.UUID) (err error) {
172+
err = s.client.assertServerVersionAtLeast("4.0.0")
173+
if err != nil {
174+
return
175+
}
176+
177+
req, err := s.client.newRequest(ctx, http.MethodDelete, fmt.Sprintf("api/v1/oidc/group/%s/team/%s/mapping", groupID.String(), teamID.String()))
178+
if err != nil {
179+
return
180+
}
181+
182+
_, err = s.client.doRequest(req, nil)
183+
return
184+
}
185+
186+
func (s OIDCService) GetAllUsers(ctx context.Context) (p Page[OIDCUser], err error) {
187+
err = s.client.assertServerVersionAtLeast("4.0.0")
188+
if err != nil {
189+
return
190+
}
191+
192+
req, err := s.client.newRequest(ctx, http.MethodGet, "api/v1/user/oidc")
193+
if err != nil {
194+
return
195+
}
196+
197+
res, err := s.client.doRequest(req, &p.Items)
198+
if err != nil {
199+
return
200+
}
201+
202+
p.TotalCount = res.TotalCount
203+
return
204+
}
205+
206+
func (s OIDCService) CreateUser(ctx context.Context, userReq OIDCUser) (userRes OIDCUser, err error) {
207+
err = s.client.assertServerVersionAtLeast("4.0.0")
208+
if err != nil {
209+
return
210+
}
211+
212+
req, err := s.client.newRequest(ctx, http.MethodPut, "api/v1/user/oidc", withBody(userReq))
213+
if err != nil {
214+
return
215+
}
216+
217+
_, err = s.client.doRequest(req, &userRes)
218+
return
219+
}
220+
221+
func (s OIDCService) DeleteUser(ctx context.Context, user OIDCUser) (err error) {
222+
err = s.client.assertServerVersionAtLeast("4.0.0")
223+
if err != nil {
224+
return
225+
}
226+
227+
req, err := s.client.newRequest(ctx, http.MethodDelete, "api/v1/user/oidc", withBody(user))
228+
if err != nil {
229+
return
230+
}
231+
232+
_, err = s.client.doRequest(req, nil)
233+
return
234+
}
235+
236+
func (s OIDCService) Login(ctx context.Context, tokens OIDCTokens) (token string, err error) {
237+
err = s.client.assertServerVersionAtLeast("4.0.0")
238+
if err != nil {
239+
return
240+
}
241+
242+
body := url.Values{}
243+
body.Set("idToken", tokens.ID)
244+
body.Set("accessToken", tokens.Access)
245+
246+
req, err := s.client.newRequest(ctx, http.MethodPost, "api/v1/user/oidc/login", withBody(body))
247+
if err != nil {
248+
return
249+
}
250+
251+
_, err = s.client.doRequest(req, &token)
252+
return
253+
}

0 commit comments

Comments
 (0)