github.com/cobalt77/jfrog-client-go@v0.14.5/artifactory/services/security.go (about) 1 package services 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net/http" 8 "net/url" 9 "strconv" 10 11 rthttpclient "github.com/cobalt77/jfrog-client-go/artifactory/httpclient" 12 "github.com/cobalt77/jfrog-client-go/artifactory/services/utils" 13 "github.com/cobalt77/jfrog-client-go/auth" 14 clientutils "github.com/cobalt77/jfrog-client-go/utils" 15 "github.com/cobalt77/jfrog-client-go/utils/errorutils" 16 ) 17 18 const tokenPath = "api/security/token" 19 const APIKeyPath = "api/security/apiKey" 20 21 type SecurityService struct { 22 client *rthttpclient.ArtifactoryHttpClient 23 ArtDetails auth.ServiceDetails 24 } 25 26 func NewSecurityService(client *rthttpclient.ArtifactoryHttpClient) *SecurityService { 27 return &SecurityService{client: client} 28 } 29 30 func (ss *SecurityService) getArtifactoryDetails() auth.ServiceDetails { 31 return ss.ArtDetails 32 } 33 34 // RegenerateAPIKey regenerates the API Key in Artifactory 35 func (ss *SecurityService) RegenerateAPIKey() (string, error) { 36 httpClientDetails := ss.ArtDetails.CreateHttpClientDetails() 37 38 reqURL, err := utils.BuildArtifactoryUrl(ss.ArtDetails.GetUrl(), APIKeyPath, nil) 39 if err != nil { 40 return "", err 41 } 42 43 resp, body, err := ss.client.SendPut(reqURL, nil, &httpClientDetails) 44 if err != nil { 45 return "", err 46 } 47 48 if resp.StatusCode != http.StatusOK { 49 return "", errors.New("API key reneration failed with status: " + resp.Status + "\n" + clientutils.IndentJson(body)) 50 } 51 52 var data map[string]interface{} = make(map[string]interface{}) 53 if err := json.Unmarshal(body, &data); err != nil { 54 return "", fmt.Errorf("Unable to decode json. Error: %w Upstream response: %s", err, string(body)) 55 } 56 57 apiKey := data["apiKey"].(string) 58 return apiKey, nil 59 } 60 61 func (ss *SecurityService) CreateToken(params CreateTokenParams) (CreateTokenResponseData, error) { 62 artifactoryUrl := ss.ArtDetails.GetUrl() 63 data := buildCreateTokenUrlValues(params) 64 httpClientsDetails := ss.getArtifactoryDetails().CreateHttpClientDetails() 65 resp, body, err := ss.client.SendPostForm(artifactoryUrl+tokenPath, data, &httpClientsDetails) 66 tokenInfo := CreateTokenResponseData{} 67 if err != nil { 68 return tokenInfo, err 69 } 70 if resp.StatusCode != http.StatusOK { 71 return tokenInfo, errorutils.CheckError( 72 errors.New("Artifactory response: " + resp.Status + "\n" + clientutils.IndentJson(body))) 73 } 74 if err = json.Unmarshal(body, &tokenInfo); err != nil { 75 return tokenInfo, errorutils.CheckError(err) 76 } 77 return tokenInfo, err 78 } 79 80 func (ss *SecurityService) GetTokens() (GetTokensResponseData, error) { 81 artifactoryUrl := ss.ArtDetails.GetUrl() 82 httpClientsDetails := ss.getArtifactoryDetails().CreateHttpClientDetails() 83 resp, body, _, err := ss.client.SendGet(artifactoryUrl+tokenPath, true, &httpClientsDetails) 84 tokens := GetTokensResponseData{} 85 if err != nil { 86 return tokens, err 87 } 88 if resp.StatusCode != http.StatusOK { 89 return tokens, errorutils.CheckError( 90 errors.New("Artifactory response: " + resp.Status + "\n" + clientutils.IndentJson(body))) 91 } 92 if err = json.Unmarshal(body, &tokens); err != nil { 93 return tokens, errorutils.CheckError(err) 94 } 95 return tokens, err 96 } 97 98 func (ss *SecurityService) RefreshToken(params RefreshTokenParams) (CreateTokenResponseData, error) { 99 artifactoryUrl := ss.ArtDetails.GetUrl() 100 data := buildRefreshTokenUrlValues(params) 101 httpClientsDetails := ss.getArtifactoryDetails().CreateHttpClientDetails() 102 resp, body, err := ss.client.SendPostForm(artifactoryUrl+tokenPath, data, &httpClientsDetails) 103 tokenInfo := CreateTokenResponseData{} 104 if err != nil { 105 return tokenInfo, err 106 } 107 if resp.StatusCode != http.StatusOK { 108 return tokenInfo, errorutils.CheckError( 109 errors.New("Artifactory response: " + resp.Status + "\n" + clientutils.IndentJson(body))) 110 } 111 if err = json.Unmarshal(body, &tokenInfo); err != nil { 112 return tokenInfo, errorutils.CheckError(err) 113 } 114 return tokenInfo, err 115 } 116 117 func (ss *SecurityService) RevokeToken(params RevokeTokenParams) (string, error) { 118 artifactoryUrl := ss.ArtDetails.GetUrl() 119 requestFullUrl := artifactoryUrl + tokenPath + "/revoke" 120 httpClientsDetails := ss.getArtifactoryDetails().CreateHttpClientDetails() 121 data := buildRevokeTokenUrlValues(params) 122 resp, body, err := ss.client.SendPostForm(requestFullUrl, data, &httpClientsDetails) 123 if err != nil { 124 return "", err 125 } 126 if resp.StatusCode != http.StatusOK { 127 return "", errorutils.CheckError( 128 errors.New("Artifactory response: " + resp.Status + "\n" + clientutils.IndentJson(body))) 129 } 130 return string(body), err 131 } 132 133 func buildCreateTokenUrlValues(params CreateTokenParams) url.Values { 134 // Gathers required data while avoiding default/ignored values 135 data := url.Values{} 136 if params.Refreshable { 137 data.Set("refreshable", "true") 138 } 139 if params.Scope != "" { 140 data.Set("scope", params.Scope) 141 } 142 if params.Username != "" { 143 data.Set("username", params.Username) 144 } 145 if params.Audience != "" { 146 data.Set("audience", params.Audience) 147 } 148 if params.ExpiresIn >= 0 { 149 data.Set("expires_in", strconv.Itoa(params.ExpiresIn)) 150 } 151 return data 152 } 153 154 func buildRefreshTokenUrlValues(params RefreshTokenParams) url.Values { 155 data := buildCreateTokenUrlValues(params.Token) 156 157 // <grant_type> is used to tell the rest api whether to create or refresh a token. 158 // Both operations are performed by the same endpoint. 159 data.Set("grant_type", "refresh_token") 160 161 if params.RefreshToken != "" { 162 data.Set("refresh_token", params.RefreshToken) 163 } 164 if params.AccessToken != "" { 165 data.Set("access_token", params.AccessToken) 166 } 167 return data 168 } 169 170 func buildRevokeTokenUrlValues(params RevokeTokenParams) url.Values { 171 data := url.Values{} 172 if params.Token != "" { 173 data.Set("token", params.Token) 174 } 175 if params.TokenId != "" { 176 data.Set("token_id", params.TokenId) 177 } 178 return data 179 } 180 181 type CreateTokenResponseData struct { 182 Scope string `json:"scope,omitempty"` 183 AccessToken string `json:"access_token,omitempty"` 184 ExpiresIn int `json:"expires_in,omitempty"` 185 TokenType string `json:"token_type,omitempty"` 186 RefreshToken string `json:"refresh_token,omitempty"` 187 } 188 189 type GetTokensResponseData struct { 190 Tokens []struct { 191 Issuer string `json:"issuer,omitempty"` 192 Subject string `json:"subject,omitempty"` 193 Refreshable bool `json:"refreshable,omitempty"` 194 Expiry int `json:"expiry,omitempty"` 195 TokenId string `json:"token_id,omitempty"` 196 IssuedAt int `json:"issued_at,omitempty"` 197 } 198 } 199 200 type CreateTokenParams struct { 201 Scope string 202 Username string 203 ExpiresIn int 204 Refreshable bool 205 Audience string 206 } 207 208 type RefreshTokenParams struct { 209 Token CreateTokenParams 210 RefreshToken string 211 AccessToken string 212 } 213 214 type RevokeTokenParams struct { 215 Token string 216 TokenId string 217 } 218 219 func NewCreateTokenParams() CreateTokenParams { 220 return CreateTokenParams{ExpiresIn: -1} 221 } 222 223 func NewRefreshTokenParams() RefreshTokenParams { 224 return RefreshTokenParams{Token: NewCreateTokenParams()} 225 } 226 227 func NewRevokeTokenParams() RevokeTokenParams { 228 return RevokeTokenParams{} 229 }