Commit a0f3709b authored by wang yan's avatar wang yan
Browse files

add expiration data time when to create a robot account



Update API of creating robot accout, user can specify expiration time per account.
Signed-off-by: default avatarwang yan <wangyan@vmware.com>
parent 76dcedb4
......@@ -6239,6 +6239,9 @@ definitions:
description:
type: string
description: The description of robot account
expires_at:
type: integer
description: The expiration time on or after which the JWT MUST NOT be accepted for processing.
access:
type: array
description: The permission of robot account
......
......@@ -18,6 +18,7 @@ import (
"fmt"
"net/http"
"testing"
"time"
"github.com/goharbor/harbor/src/common/dao"
"github.com/goharbor/harbor/src/common/models"
......@@ -40,6 +41,9 @@ func TestRobotAPIPost(t *testing.T) {
policies := []*rbac.Policy{}
policies = append(policies, rbacPolicy)
tokenDuration := time.Duration(30) * time.Minute
expiresAt := time.Now().UTC().Add(tokenDuration).Unix()
cases := []*codeCheckingCase{
// 401
{
......@@ -68,6 +72,7 @@ func TestRobotAPIPost(t *testing.T) {
bodyJSON: &model.RobotCreate{
Name: "test",
Description: "test desc",
ExpiresAt: expiresAt,
Access: policies,
},
credential: projAdmin4Robot,
......@@ -82,6 +87,20 @@ func TestRobotAPIPost(t *testing.T) {
bodyJSON: &model.RobotCreate{
Name: "testIllgel#",
Description: "test desc",
ExpiresAt: expiresAt,
},
credential: projAdmin4Robot,
},
code: http.StatusBadRequest,
},
{
request: &testingRequest{
method: http.MethodPost,
url: robotPath,
bodyJSON: &model.RobotCreate{
Name: "test not set expiration",
Description: "test desc",
ExpiresAt: -100,
},
credential: projAdmin4Robot,
},
......@@ -94,6 +113,7 @@ func TestRobotAPIPost(t *testing.T) {
bodyJSON: &model.RobotCreate{
Name: "test",
Description: "resource not exist",
ExpiresAt: expiresAt,
Access: []*rbac.Policy{
{Resource: res.Subresource("foo"), Action: rbac.ActionCreate},
},
......@@ -109,6 +129,7 @@ func TestRobotAPIPost(t *testing.T) {
bodyJSON: &model.RobotCreate{
Name: "test",
Description: "action not exist",
ExpiresAt: expiresAt,
Access: []*rbac.Policy{
{Resource: res.Subresource(rbac.ResourceRepository), Action: "foo"},
},
......@@ -124,6 +145,7 @@ func TestRobotAPIPost(t *testing.T) {
bodyJSON: &model.RobotCreate{
Name: "test",
Description: "policy not exit",
ExpiresAt: expiresAt,
Access: []*rbac.Policy{
{Resource: res.Subresource(rbac.ResourceMember), Action: rbac.ActionPush},
},
......@@ -140,6 +162,7 @@ func TestRobotAPIPost(t *testing.T) {
bodyJSON: &model.RobotCreate{
Name: "test2",
Description: "test2 desc",
ExpiresAt: expiresAt,
},
credential: projDeveloper,
},
......@@ -154,6 +177,7 @@ func TestRobotAPIPost(t *testing.T) {
bodyJSON: &model.RobotCreate{
Name: "test",
Description: "test desc",
ExpiresAt: expiresAt,
Access: policies,
},
credential: projAdmin4Robot,
......
......@@ -58,17 +58,19 @@ func (d *DefaultAPIController) GetRobotAccount(id int64) (*model.Robot, error) {
func (d *DefaultAPIController) CreateRobotAccount(robotReq *model.RobotCreate) (*model.Robot, error) {
var deferDel error
// Token duration in minutes
tokenDuration := time.Duration(config.RobotTokenDuration()) * time.Minute
expiresAt := time.Now().UTC().Add(tokenDuration).Unix()
createdName := common.RobotPrefix + robotReq.Name
if robotReq.ExpiresAt == 0 {
tokenDuration := time.Duration(config.RobotTokenDuration()) * time.Minute
robotReq.ExpiresAt = time.Now().UTC().Add(tokenDuration).Unix()
}
// first to add a robot account, and get its id.
robot := &model.Robot{
Name: createdName,
Description: robotReq.Description,
ProjectID: robotReq.ProjectID,
ExpiresAt: expiresAt,
ExpiresAt: robotReq.ExpiresAt,
Visible: robotReq.Visible,
}
id, err := d.manager.CreateRobotAccount(robot)
......@@ -85,7 +87,7 @@ func (d *DefaultAPIController) CreateRobotAccount(robotReq *model.RobotCreate) (
Access: robotReq.Access,
StandardClaims: jwt.StandardClaims{
IssuedAt: time.Now().UTC().Unix(),
ExpiresAt: expiresAt,
ExpiresAt: robotReq.ExpiresAt,
Issuer: opt.Issuer,
},
}
......
......@@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"testing"
"time"
)
type ControllerTestSuite struct {
......@@ -47,9 +48,13 @@ func (s *ControllerTestSuite) TestRobotAccount() {
policies := []*rbac.Policy{}
policies = append(policies, rbacPolicy)
tokenDuration := time.Duration(30) * time.Minute
expiresAt := time.Now().UTC().Add(tokenDuration).Unix()
robot1 := &model.RobotCreate{
Name: "robot1",
Description: "TestCreateRobotAccount",
ExpiresAt: expiresAt,
ProjectID: int64(1),
Access: policies,
}
......@@ -74,6 +79,7 @@ func (s *ControllerTestSuite) TestRobotAccount() {
robot2 := &model.RobotCreate{
Name: "robot2",
Description: "TestCreateRobotAccount",
ExpiresAt: expiresAt,
ProjectID: int64(1),
Access: policies,
}
......
......@@ -49,6 +49,7 @@ type RobotCreate struct {
ProjectID int64 `json:"pid"`
Description string `json:"description"`
Disabled bool `json:"disabled"`
ExpiresAt int64 `json:"expires_at"`
Visible bool `json:"-"`
Access []*rbac.Policy `json:"access"`
}
......@@ -67,6 +68,9 @@ func (rq *RobotCreate) Valid(v *validation.Validation) {
if utils.IsContainIllegalChar(rq.Name, []string{",", "~", "#", "$", "%"}) {
v.SetError("name", "robot name contains illegal characters")
}
if rq.ExpiresAt < 0 {
v.SetError("expires_at", "expiration time must be a positive integer if set")
}
}
// RobotRep ...
......
......@@ -173,7 +173,7 @@ class Project(base.Base):
base._assert_status_code(expect_status_code, status_code)
return base._get_id_from_header(header)
def add_project_robot_account(self, project_id, project_name, robot_name = None, robot_desc = None, has_pull_right = True, has_push_right = True, expect_status_code = 201, **kwargs):
def add_project_robot_account(self, project_id, project_name, expires_at, robot_name = None, robot_desc = None, has_pull_right = True, has_push_right = True, expect_status_code = 201, **kwargs):
if robot_name is None:
robot_name = base._random_name("robot")
if robot_desc is None:
......@@ -190,7 +190,7 @@ class Project(base.Base):
if has_push_right is True:
robotAccountAccess = swagger_client.RobotAccountAccess(resource = resource_by_project_id, action = action_push)
access_list.append(robotAccountAccess)
robotAccountCreate = swagger_client.RobotAccountCreate(robot_name, robot_desc, access_list)
robotAccountCreate = swagger_client.RobotAccountCreate(robot_name, robot_desc, expires_at, access_list)
client = self._get_client(**kwargs)
data = []
data, status_code, header = client.projects_project_id_robots_post_with_http_info(project_id, robotAccountCreate)
......
......@@ -93,7 +93,8 @@ class TestProjects(unittest.TestCase):
TestProjects.repo_name_in_project_c, tag_c = push_image_to_project(project_ra_name_c, harbor_server, user_ra_name, user_ra_password, image_project_c, tag)
print "#4. Create a new robot account(RA) with pull and push privilige in project(PA) by user(UA);"
robot_id, robot_account = self.project.add_project_robot_account(TestProjects.project_ra_id_a, project_ra_name_a, **TestProjects.USER_RA_CLIENT)
robot_id, robot_account = self.project.add_project_robot_account(TestProjects.project_ra_id_a, project_ra_name_a,
2441000531 ,**TestProjects.USER_RA_CLIENT)
print robot_account.name
print robot_account.token
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment