-
Notifications
You must be signed in to change notification settings - Fork 142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for Security v2 API #754
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
package v2 | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/jfrog/jfrog-client-go/auth" | ||
"github.com/jfrog/jfrog-client-go/http/jfroghttpclient" | ||
"github.com/jfrog/jfrog-client-go/utils/errorutils" | ||
"github.com/jfrog/jfrog-client-go/utils/io/httputils" | ||
"net/http" | ||
) | ||
|
||
const groupsApi = "api/v2/groups" | ||
|
||
type GroupParams struct { | ||
GroupDetails | ||
} | ||
|
||
type GroupDetails struct { | ||
Name string `json:"name,omitempty"` | ||
Description string `json:"description,omitempty"` | ||
AutoJoin *bool `json:"auto_join,omitempty"` | ||
AdminPrivileges *bool `json:"admin_privileges,omitempty"` | ||
Realm string `json:"realm,omitempty"` | ||
RealmAttributes string `json:"realm_attributes,omitempty"` | ||
ExternalId string `json:"external_id,omitempty"` | ||
Members []string `json:"members,omitempty"` | ||
} | ||
|
||
type GroupListItem struct { | ||
GroupName string `json:"group_name"` | ||
Uri string `json:"uri"` | ||
} | ||
type GroupList struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing new-line before type definition. There a few other places in the code added by this PR which have new-lines between functions / structs missing. |
||
Cursor string `json:"cursor,omitempty"` | ||
Groups []GroupListItem `json:"groups"` | ||
} | ||
|
||
func NewGroupParams() GroupParams { | ||
return GroupParams{} | ||
} | ||
|
||
type GroupService struct { | ||
client *jfroghttpclient.JfrogHttpClient | ||
ServiceDetails auth.ServiceDetails | ||
} | ||
|
||
func NewGroupService(client *jfroghttpclient.JfrogHttpClient) *GroupService { | ||
return &GroupService{client: client} | ||
} | ||
|
||
func (gs *GroupService) getBaseUrl() string { | ||
return fmt.Sprintf("%s%s", gs.ServiceDetails.GetUrl(), groupsApi) | ||
} | ||
func (gs *GroupService) GetAll() ([]GroupListItem, error) { | ||
httpDetails := gs.ServiceDetails.CreateHttpClientDetails() | ||
url := gs.getBaseUrl() | ||
resp, body, _, err := gs.client.SendGet(url, true, &httpDetails) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if err = errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK); err != nil { | ||
return nil, err | ||
} | ||
var groupList GroupList | ||
err = json.Unmarshal(body, &groupList) | ||
return groupList.Groups, errorutils.CheckError(err) | ||
} | ||
|
||
func (gs *GroupService) Get(name string) (u *GroupDetails, err error) { | ||
httpDetails := gs.ServiceDetails.CreateHttpClientDetails() | ||
url := fmt.Sprintf("%s/%s", gs.getBaseUrl(), name) | ||
resp, body, _, err := gs.client.SendGet(url, true, &httpDetails) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if resp.StatusCode == http.StatusNotFound { | ||
return nil, nil | ||
} | ||
if err = errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK); err != nil { | ||
return nil, err | ||
} | ||
var group GroupDetails | ||
err = json.Unmarshal(body, &group) | ||
return &group, errorutils.CheckError(err) | ||
} | ||
|
||
func (gs *GroupService) Create(params GroupParams) error { | ||
group, err := gs.Get(params.Name) | ||
if err != nil { | ||
return err | ||
} | ||
if group != nil { | ||
return errorutils.CheckErrorf("group '%s' already exists", group.Name) | ||
} | ||
content, httpDetails, err := gs.createOrUpdateRequest(params) | ||
if err != nil { | ||
return err | ||
} | ||
resp, body, err := gs.client.SendPost(gs.getBaseUrl(), content, &httpDetails) | ||
if err != nil { | ||
return err | ||
} | ||
return errorutils.CheckResponseStatusWithBody(resp, body, http.StatusCreated) | ||
} | ||
|
||
func (gs *GroupService) Update(params GroupParams) error { | ||
content, httpDetails, err := gs.createOrUpdateRequest(params) | ||
if err != nil { | ||
return err | ||
} | ||
url := fmt.Sprintf("%s/%s", gs.getBaseUrl(), params.Name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use |
||
resp, body, err := gs.client.SendPatch(url, content, &httpDetails) | ||
if err != nil { | ||
return err | ||
} | ||
return errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK) | ||
} | ||
|
||
func (gs *GroupService) createOrUpdateRequest(group GroupParams) (requestContent []byte, httpDetails httputils.HttpClientDetails, err error) { | ||
httpDetails = gs.ServiceDetails.CreateHttpClientDetails() | ||
requestContent, err = json.Marshal(group) | ||
if errorutils.CheckError(err) != nil { | ||
return | ||
} | ||
httpDetails.Headers = map[string]string{ | ||
"Content-Type": "application/json", | ||
"Accept": "application/json", | ||
} | ||
return | ||
} | ||
|
||
func (gs *GroupService) Delete(name string) error { | ||
httpDetails := gs.ServiceDetails.CreateHttpClientDetails() | ||
url := fmt.Sprintf("%s/%s", gs.getBaseUrl(), name) | ||
resp, body, err := gs.client.SendDelete(url, nil, &httpDetails) | ||
if err != nil { | ||
return err | ||
} | ||
if resp == nil { | ||
return errorutils.CheckErrorf("no response provided (including status code)") | ||
} | ||
return errorutils.CheckResponseStatusWithBody(resp, body, http.StatusNoContent) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
package v2 | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/jfrog/jfrog-client-go/auth" | ||
"github.com/jfrog/jfrog-client-go/http/jfroghttpclient" | ||
"github.com/jfrog/jfrog-client-go/utils/errorutils" | ||
"github.com/jfrog/jfrog-client-go/utils/io/httputils" | ||
) | ||
|
||
const usersApi = "api/v2/users" | ||
|
||
type UserParams struct { | ||
CommonUserParams | ||
} | ||
|
||
type UserResponse struct { | ||
CommonUserParams | ||
Status string `json:"status,omitempty"` | ||
} | ||
|
||
func NewUserParams() UserParams { | ||
return UserParams{} | ||
} | ||
|
||
type CommonUserParams struct { | ||
Username string `json:"username,omitempty"` | ||
Email string `json:"email,omitempty"` | ||
Password string `json:"password,omitempty"` | ||
Admin *bool `json:"admin,omitempty"` | ||
ProfileUpdatable *bool `json:"profile_updatable,omitempty"` | ||
DisableUIAccess *bool `json:"disable_ui_access,omitempty"` | ||
InternalPasswordDisabled *bool `json:"internal_password_disabled,omitempty"` | ||
Realm string `json:"realm,omitempty"` | ||
Groups *[]string `json:"groups,omitempty"` | ||
} | ||
|
||
type UserService struct { | ||
client *jfroghttpclient.JfrogHttpClient | ||
ServiceDetails auth.ServiceDetails | ||
} | ||
|
||
func NewUserService(client *jfroghttpclient.JfrogHttpClient) *UserService { | ||
return &UserService{client: client} | ||
} | ||
|
||
func (us *UserService) getBaseUrl() string { | ||
return fmt.Sprintf("%s%s", us.ServiceDetails.GetUrl(), usersApi) | ||
} | ||
|
||
func (us *UserService) GetAll() ([]UserResponse, error) { | ||
httpDetails := us.ServiceDetails.CreateHttpClientDetails() | ||
url := us.getBaseUrl() | ||
resp, body, _, err := us.client.SendGet(url, true, &httpDetails) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if err = errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK); err != nil { | ||
return nil, err | ||
} | ||
var users []UserResponse | ||
err = json.Unmarshal(body, &users) | ||
return users, errorutils.CheckError(err) | ||
} | ||
|
||
func (us *UserService) Get(username string) (u *UserResponse, err error) { | ||
httpDetails := us.ServiceDetails.CreateHttpClientDetails() | ||
url := fmt.Sprintf("%s/%s", us.getBaseUrl(), username) | ||
resp, body, _, err := us.client.SendGet(url, true, &httpDetails) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if resp.StatusCode == http.StatusNotFound { | ||
return nil, nil | ||
} | ||
if err = errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK); err != nil { | ||
return nil, err | ||
} | ||
var user UserResponse | ||
err = json.Unmarshal(body, &user) | ||
return &user, errorutils.CheckError(err) | ||
} | ||
|
||
func (us *UserService) Create(params UserParams) error { | ||
user, err := us.Get(params.Username) | ||
if err != nil { | ||
return err | ||
} | ||
if user != nil { | ||
return errorutils.CheckErrorf("user '%s' already exists", user.Username) | ||
} | ||
content, httpDetails, err := us.createOrUpdateRequest(params) | ||
if err != nil { | ||
return err | ||
} | ||
resp, body, err := us.client.SendPost(us.getBaseUrl(), content, &httpDetails) | ||
if err != nil { | ||
return err | ||
} | ||
return errorutils.CheckResponseStatusWithBody(resp, body, http.StatusCreated) | ||
} | ||
|
||
func (us *UserService) Update(params UserParams) error { | ||
content, httpDetails, err := us.createOrUpdateRequest(params) | ||
if err != nil { | ||
return err | ||
} | ||
url := fmt.Sprintf("%s/%s", us.getBaseUrl(), params.Username) | ||
resp, body, err := us.client.SendPatch(url, content, &httpDetails) | ||
if err != nil { | ||
return err | ||
} | ||
return errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK) | ||
} | ||
|
||
func (us *UserService) createOrUpdateRequest(user UserParams) (requestContent []byte, httpDetails httputils.HttpClientDetails, err error) { | ||
httpDetails = us.ServiceDetails.CreateHttpClientDetails() | ||
requestContent, err = json.Marshal(user) | ||
if errorutils.CheckError(err) != nil { | ||
return | ||
} | ||
httpDetails.Headers = map[string]string{ | ||
"Content-Type": "application/json", | ||
"Accept": "application/json", | ||
} | ||
return | ||
} | ||
|
||
func (us *UserService) Delete(username string) error { | ||
httpDetails := us.ServiceDetails.CreateHttpClientDetails() | ||
url := fmt.Sprintf("%s/%s", us.getBaseUrl(), username) | ||
resp, body, err := us.client.SendDelete(url, nil, &httpDetails) | ||
if err != nil { | ||
return err | ||
} | ||
if resp == nil { | ||
return errorutils.CheckErrorf("no response provided (including status code)") | ||
} | ||
return errorutils.CheckResponseStatusWithBody(resp, body, http.StatusNoContent) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package tests | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
services "github.com/jfrog/jfrog-client-go/access/services/v2" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestAccessGroups(t *testing.T) { | ||
initAccessTest(t) | ||
t.Run("create", testCreateAccessGroup) | ||
t.Run("update", testUpdateAccessGroup) | ||
t.Run("delete", testDeleteAccessGroup) | ||
} | ||
|
||
func getTestAccessGroupParams() services.GroupParams { | ||
group := services.GroupDetails{ | ||
Name: fmt.Sprintf("test-%s", getRunId()), | ||
Description: "hello", | ||
AutoJoin: &falseValue, | ||
AdminPrivileges: &trueValue, | ||
Realm: "internal", | ||
RealmAttributes: "", | ||
ExternalId: "", | ||
} | ||
return services.GroupParams{GroupDetails: group} | ||
} | ||
|
||
func testCreateAccessGroup(t *testing.T) { | ||
groupParams := getTestAccessGroupParams() | ||
err := testAccessGroupService.Create(groupParams) | ||
defer deleteAccessGroupAndAssert(t, groupParams.GroupDetails.Name) | ||
assert.NoError(t, err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This error assertion should be placed right after the line that returns the error (before the defer). |
||
|
||
createdGroup, err := testAccessGroupService.Get(groupParams.Name) | ||
assert.NoError(t, err) | ||
assert.NotNil(t, createdGroup) | ||
assert.Equal(t, groupParams.GroupDetails, *createdGroup) | ||
|
||
allGroups, err := testAccessGroupService.GetAll() | ||
assert.NoError(t, err) | ||
assert.NotNil(t, allGroups) | ||
|
||
var groupNames []string | ||
for _, v := range allGroups { | ||
groupNames = append(groupNames, v.GroupName) | ||
} | ||
assert.Contains(t, groupNames, groupParams.GroupDetails.Name) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant new-line. |
||
} | ||
|
||
func testUpdateAccessGroup(t *testing.T) { | ||
groupParams := getTestAccessGroupParams() | ||
err := testAccessGroupService.Create(groupParams) | ||
defer deleteAccessGroupAndAssert(t, groupParams.Name) | ||
assert.NoError(t, err) | ||
groupParams.Description = "Changed description" | ||
groupParams.AutoJoin = &trueValue | ||
groupParams.AdminPrivileges = &falseValue | ||
err = testAccessGroupService.Update(groupParams) | ||
assert.NoError(t, err) | ||
group, err := testAccessGroupService.Get(groupParams.Name) | ||
assert.NoError(t, err) | ||
assert.Equal(t, groupParams.GroupDetails, *group) | ||
} | ||
|
||
func testDeleteAccessGroup(t *testing.T) { | ||
groupParams := getTestAccessGroupParams() | ||
assert.NoError(t, testAccessGroupService.Create(groupParams)) | ||
|
||
deleteAccessGroupAndAssert(t, groupParams.Name) | ||
|
||
group, err := testAccessGroupService.Get(groupParams.Name) | ||
assert.NoError(t, err) | ||
assert.Nil(t, group) | ||
|
||
allGroups, err := testAccessGroupService.GetAll() | ||
assert.NoError(t, err) | ||
assert.NotNil(t, allGroups) | ||
|
||
var allGroupNames []string | ||
for _, v := range allGroups { | ||
allGroupNames = append(allGroupNames, v.GroupName) | ||
} | ||
assert.NotContains(t, allGroupNames, groupParams.Name) | ||
} | ||
|
||
func deleteAccessGroupAndAssert(t *testing.T, groupName string) { | ||
assert.NoError(t, testAccessGroupService.Delete(groupName)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's rempve the
v2
package. and have this file as well asusers.go
directly umderaccess/services
.