Add harness api call validation support

This commit is contained in:
Hen Amar 2023-10-30 14:01:58 +02:00
parent 44985f574d
commit 379f7be90d
6 changed files with 85 additions and 0 deletions

View File

@ -268,6 +268,7 @@ func (svr *Service) login() (conn net.Conn, cm *ConnectionManager, err error) {
Timestamp: time.Now().Unix(),
RunID: svr.runID,
Metas: svr.cfg.Metadatas,
ApiKey: svr.cfg.ApiKey,
}
// Add auth

View File

@ -15,7 +15,11 @@
package auth
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
"github.com/samber/lo"
@ -62,10 +66,84 @@ func (auth *TokenAuthSetterVerifier) SetNewWorkConn(newWorkConnMsg *msg.NewWorkC
return nil
}
func extractBetweenDots(input string) string {
firstDotIndex := strings.Index(input, ".")
if firstDotIndex == -1 {
return ""
}
secondDotIndex := strings.Index(input[firstDotIndex+1:], ".")
if secondDotIndex == -1 {
return ""
}
extracted := input[firstDotIndex+1 : firstDotIndex+1+secondDotIndex]
return extracted
}
func validateApiKey(apiKey string) bool {
accoundId := extractBetweenDots(apiKey)
if accoundId == "" {
fmt.Errorf("token in login doesn't match format. Can't extract account ID")
return false
}
reqUrl := "https://app.harness.io/authz/api/acl"
var formated = fmt.Sprintf(`{
"permissions": [
{
"resourceScope": {
"accountIdentifier": "%s",
"orgIdentifier": "",
"projectIdentifier": ""
},
"resourceType": "PIPLINE",
"permission": "core_pipeline_view"
}
]
}`, accoundId)
req, err := http.NewRequest("POST", reqUrl, bytes.NewReader([]byte(formated)))
if err != nil {
fmt.Errorf(err.Error())
return false
}
req.Header.Add("Content-Type", "application/json")
req.Header.Add("x-api-key", apiKey)
res, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Errorf("Error calling api call for api key validation")
return false
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Errorf("Api key validation response error")
return false
}
searchSubstring := `"permitted":true`
bodyStr := string(body)
if !strings.Contains(bodyStr, searchSubstring) {
fmt.Errorf("The API key is not valid")
return false
}
return true
}
func (auth *TokenAuthSetterVerifier) VerifyLogin(m *msg.Login) error {
if !util.ConstantTimeEqString(util.GetAuthKey(auth.token, m.Timestamp), m.PrivilegeKey) {
return fmt.Errorf("token in login doesn't match token from configuration")
}
if !validateApiKey(m.ApiKey) {
return fmt.Errorf("Harness Api key isn't valid")
}
return nil
}

View File

@ -167,6 +167,8 @@ type ClientCommonConf struct {
// Enable golang pprof handlers in admin listener.
// Admin port must be set first.
PprofEnable bool `ini:"pprof_enable" json:"pprof_enable"`
ApiKey string `ini:"api_key" json:"api_key"`
}
// Supported sources including: string(file path), []byte, Reader interface.

View File

@ -25,6 +25,7 @@ import (
func Convert_ClientCommonConf_To_v1(conf *ClientCommonConf) *v1.ClientCommonConfig {
out := &v1.ClientCommonConfig{}
out.ApiKey = conf.ApiKey
out.User = conf.User
out.Auth.Method = v1.AuthMethod(conf.ClientConfig.AuthenticationMethod)
out.Auth.Token = conf.ClientConfig.Token

View File

@ -70,6 +70,8 @@ type ClientCommonConfig struct {
// Include other config files for proxies.
IncludeConfigFiles []string `json:"includes,omitempty"`
ApiKey string `json:"api_key,omitempty"`
}
func (c *ClientCommonConfig) Complete() {

View File

@ -74,6 +74,7 @@ type Login struct {
Timestamp int64 `json:"timestamp,omitempty"`
RunID string `json:"run_id,omitempty"`
Metas map[string]string `json:"metas,omitempty"`
ApiKey string `json:"api_key,omitempty"`
// Some global configures.
PoolCount int `json:"pool_count,omitempty"`