diff --git a/README.md b/README.md index 8bd487c28..cb8dd7ffd 100644 --- a/README.md +++ b/README.md @@ -54,11 +54,11 @@ - [Cleaning Unreferenced Git LFS Files from Artifactory](#cleaning-unreferenced-git-lfs-files-from-artifactory) - [Executing AQLs](#executing-aqls) - [Reading Files in Artifactory](#reading-files-in-artifactory) - - [Creating an Access Token](#creating-an-access-token) - - [Fetching Access Tokens](#fetching-access-tokens) - - [Fetching Access Tokens of a User](#fetching-access-tokens-of-a-user) - - [Refreshing an Access Token](#refreshing-an-access-token) - - [Revoking an Access Token](#revoking-an-access-token) + - [Creating an Artifactory Access Token](#creating-an-artifactory-access-token) + - [Fetching Artifactory Access Tokens](#fetching-artifactory-access-tokens) + - [Fetching Artifactory Access Tokens of a User](#fetching-artifactory-access-tokens-of-a-user) + - [Refreshing an Artifactory Access Token](#refreshing-an-artifactory-access-token) + - [Revoking an Artifactory Access Token](#revoking-an-artifactory-access-token) - [Create API Key](#create-api-key) - [Regenerate API Key](#regenerate-api-key) - [Get API Key](#get-api-key) @@ -111,13 +111,15 @@ - [Getting a Project](#getting-a-project) - [Getting all Projects](#getting-all-projects) - [Assigning Repository to Project](#assigning-repository-to-project) - - [Unassigning Repository from Project](#unassigning-repository-from-project) + - [Un-assigning Repository from Project](#un-assigning-repository-from-project) - [Get all groups assigned to a project](#get-all-groups-assigned-to-a-project) - [Get a specific group assigned to a project](#get-a-specific-group-assigned-to-a-project) - [Add or update a group assigned to a project](#add-or-update-a-group-assigned-to-a-project) - [Remove a group from a project](#remove-a-group-from-a-project) - [Send Web Login Authentication Request](#send-web-login-authentication-request) - [Get Web Login Authentication Token](#get-web-login-authentication-token) + - [Creating an Access Token](#creating-an-access-token) + - [Refreshing an Access Token](#refreshing-an-access-token) - [Distribution APIs](#distribution-apis) - [Creating Distribution Service Manager](#creating-distribution-service-manager) - [Creating Distribution Details](#creating-distribution-details) @@ -725,7 +727,7 @@ rtManager.Aql(aql string) rtManager.ReadRemoteFile(FilePath string) ``` -#### Creating an Access Token +#### Creating an Artifactory Access Token ```go params := services.NewCreateTokenParams() @@ -739,19 +741,19 @@ params.Audience = "jfrt@ jfrt@" results, err := rtManager.CreateToken(params) ``` -#### Fetching Access Tokens +#### Fetching Artifactory Access Tokens ```go results, err := rtManager.GetTokens() ``` -#### Fetching Access Tokens of a User +#### Fetching Artifactory Access Tokens of a User ```g results, err := rtManager.GetUserTokens(username) ``` -#### Refreshing an Access Token +#### Refreshing an Artifactory Access Token ```go params := services.NewRefreshTokenParams() @@ -762,7 +764,7 @@ params.Token.ExpiresIn = 3600 results, err := rtManager.RefreshToken(params) ``` -#### Revoking an Access Token +#### Revoking an Artifactory Access Token ```go params := services.NewRevokeTokenParams() @@ -1467,7 +1469,7 @@ err = accessManager.GetAllProjects() err = accessManager.AssignRepoToProject("repoName", "tstprj", true) ``` -#### Unassigning Repository from Project +#### Un-assigning Repository from Project ```go err = accessManager.AssignRepoToProject("repoName") @@ -1515,6 +1517,32 @@ uuid := "09b34617-b48a-455d-8b05-25a6989fb76a" err = accessManager.GetLoginAuthenticationToken(uuid) ``` +#### Creating an Access Token + +```go +params := CreateTokenParams{} +params.Scope = "applied-permissions/user" +params.Username = "my-user" +params.ExpiresIn = 12345 // nil = system default, 0 = no expiry. +params.Refreshable = true +params.Audience = "jfrt@" +reference := true +params.IncludeReferenceToken = &reference +params.ProjectKey = "my-project" +params.Description = "my-token" + +results, err := accessManager.CreateToken(params) +``` + +#### Refreshing an Access Token + +```go +params := accessServices.CreateTokenParams{} +params.RefreshToken = "" + +results, err := accessManager.RefreshToken(params) +``` + ## Distribution APIs ### Creating Distribution Service Manager diff --git a/access/services/accesstoken.go b/access/services/accesstoken.go index 622ee8d22..8659701a6 100644 --- a/access/services/accesstoken.go +++ b/access/services/accesstoken.go @@ -22,7 +22,10 @@ type TokenService struct { type CreateTokenParams struct { auth.CommonTokenParams - IncludeReferenceToken *bool `json:"include_reference_token,omitempty"` + IncludeReferenceToken *bool `json:"include_reference_token,omitempty"` + Username string `json:"username,omitempty"` + ProjectKey string `json:"project_key,omitempty"` + Description string `json:"description,omitempty"` } func NewCreateTokenParams(params CreateTokenParams) CreateTokenParams { @@ -37,22 +40,19 @@ func (ps *TokenService) CreateAccessToken(params CreateTokenParams) (auth.Create return ps.createAccessToken(params) } -func (ps *TokenService) RefreshAccessToken(token CreateTokenParams) (auth.CreateTokenResponseData, error) { - param, err := createRefreshTokenRequestParams(token) +func (ps *TokenService) RefreshAccessToken(params CreateTokenParams) (auth.CreateTokenResponseData, error) { + refreshParams, err := prepareForRefresh(params) if err != nil { return auth.CreateTokenResponseData{}, err } - return ps.createAccessToken(*param) + return ps.createAccessToken(*refreshParams) } // createAccessToken is used to create & refresh access tokens. -func (ps *TokenService) createAccessToken(params CreateTokenParams) (auth.CreateTokenResponseData, error) { - // Set the request headers - tokenInfo := auth.CreateTokenResponseData{} +func (ps *TokenService) createAccessToken(params CreateTokenParams) (tokenInfo auth.CreateTokenResponseData, err error) { httpDetails := ps.ServiceDetails.CreateHttpClientDetails() utils.SetContentType("application/json", &httpDetails.Headers) - err := ps.addAccessTokenAuthorizationHeader(params, &httpDetails) - if err != nil { + if err = ps.handleUnauthenticated(params, &httpDetails); err != nil { return tokenInfo, err } requestContent, err := json.Marshal(params) @@ -71,23 +71,26 @@ func (ps *TokenService) createAccessToken(params CreateTokenParams) (auth.Create return tokenInfo, errorutils.CheckError(err) } -func (ps *TokenService) addAccessTokenAuthorizationHeader(params CreateTokenParams, httpDetails *httputils.HttpClientDetails) error { - access := ps.ServiceDetails.GetAccessToken() - if access == "" { - access = params.AccessToken +func (ps *TokenService) handleUnauthenticated(params CreateTokenParams, httpDetails *httputils.HttpClientDetails) error { + // Creating access tokens using username and password is available since Artifactory 7.63.2, + // by enabling "Enable Token Generation via API" in the UI. + if httpDetails.AccessToken != "" || (httpDetails.User != "" && httpDetails.Password != "") { + return nil } - if access == "" { - return errorutils.CheckErrorf("failed: adding accessToken authorization, but No accessToken was provided. ") + // Use token from params if provided. + if params.AccessToken != "" { + httpDetails.AccessToken = params.AccessToken + return nil } - utils.AddHeader("Authorization", fmt.Sprintf("Bearer %s", access), &httpDetails.Headers) - return nil + return errorutils.CheckErrorf("cannot create access token without credentials") } -func createRefreshTokenRequestParams(p CreateTokenParams) (*CreateTokenParams, error) { +func prepareForRefresh(p CreateTokenParams) (*CreateTokenParams, error) { // Validate provided parameters if p.RefreshToken == "" { - return nil, errorutils.CheckErrorf("error: trying to refresh token, but 'refresh_token' field wasn't provided. ") + return nil, errorutils.CheckErrorf("trying to refresh token, but 'refresh_token' field wasn't provided") } + params := NewCreateTokenParams(p) // Set refresh required parameters params.GrantType = "refresh_token" diff --git a/auth/authutils.go b/auth/authutils.go index b18ff7915..885d10708 100644 --- a/auth/authutils.go +++ b/auth/authutils.go @@ -14,12 +14,13 @@ import ( type CreateTokenResponseData struct { CommonTokenParams ReferenceToken string `json:"reference_token,omitempty"` + TokenId string `json:"token_id,omitempty"` } type CommonTokenParams struct { Scope string `json:"scope,omitempty"` AccessToken string `json:"access_token,omitempty"` - ExpiresIn int `json:"expires_in,omitempty"` + ExpiresIn *uint `json:"expires_in,omitempty"` TokenType string `json:"token_type,omitempty"` Refreshable *bool `json:"refreshable,omitempty"` RefreshToken string `json:"refresh_token,omitempty"` diff --git a/tests/accesstokens_test.go b/tests/accesstokens_test.go index 1aeb4194b..8a535bfd1 100644 --- a/tests/accesstokens_test.go +++ b/tests/accesstokens_test.go @@ -24,7 +24,7 @@ func testCreateRefreshableToken(t *testing.T) { assert.NotEqual(t, "", token.AccessToken, "Access token is empty") assert.NotEqual(t, tokenParams.AccessToken, token.AccessToken, "New access token is identical to original one") assert.NotEqual(t, "", token.RefreshToken, "Refresh token is empty") - assert.Equal(t, testExpiredInSeconds, token.ExpiresIn) + assert.EqualValues(t, testExpiredInSeconds, *token.ExpiresIn) assert.Empty(t, token.ReferenceToken) } @@ -36,7 +36,7 @@ func testAccessTokenWithReference(t *testing.T) { assert.NotEqual(t, "", token.AccessToken, "Access token is empty") assert.NotEqual(t, tokenParams.AccessToken, token.AccessToken, "New access token is identical to original one") assert.NotEqual(t, "", token.RefreshToken, "Refresh token is empty") - assert.Equal(t, testExpiredInSeconds, token.ExpiresIn) + assert.EqualValues(t, testExpiredInSeconds, *token.ExpiresIn) assert.NotEmpty(t, token.ReferenceToken) } @@ -52,13 +52,13 @@ func testRefreshTokenTest(t *testing.T) { // Validate assert.NotEqual(t, token.AccessToken, newToken.AccessToken, "New access token is identical to original one") assert.NotEqual(t, token.RefreshToken, newToken.RefreshToken, "New refresh token is identical to original one") - assert.Equal(t, token.ExpiresIn, newToken.ExpiresIn, "New access token's expiration is different from original one") + assert.EqualValues(t, token.ExpiresIn, newToken.ExpiresIn, "New access token's expiration is different from original one") assert.Empty(t, token.ReferenceToken) } -func createRefreshableAccessTokenParams(expiredIn int) services.CreateTokenParams { +func createRefreshableAccessTokenParams(expiredIn uint) services.CreateTokenParams { tokenParams := services.CreateTokenParams{} - tokenParams.ExpiresIn = expiredIn + tokenParams.ExpiresIn = &expiredIn tokenParams.Refreshable = utils.Pointer(true) tokenParams.Audience = "*@*" return tokenParams