Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ module github.com/authnull0/database-agent

go 1.22.1

require github.com/spf13/viper v1.19.0
require (
github.com/google/uuid v1.4.0
github.com/spf13/viper v1.19.0
)

require (
filippo.io/edwards25519 v1.1.0 // indirect
Expand Down
19 changes: 19 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJc
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
Expand All @@ -16,10 +20,18 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZ
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60=
github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
Expand All @@ -31,6 +43,10 @@ github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
Expand All @@ -56,6 +72,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
Expand Down Expand Up @@ -88,6 +105,8 @@ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
Expand Down
145 changes: 139 additions & 6 deletions src/pkg/checkout.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"time"

"github.com/authnull0/database-agent/utils"
"github.com/google/uuid"
)

type GetAllJobQueueRequest struct {
Expand All @@ -30,6 +31,7 @@ type GetAllJobQueueResponse struct {
Data []JobQueue `json:"data"`
}
type JobQueue struct {
PolicyID uuid.UUID `gorm:"primaryKey;column:id"`
ID int `gorm:"primaryKey;column:id"`
JobName string `gorm:"column:job_name"`
Status string `gorm:"column:status"`
Expand Down Expand Up @@ -62,7 +64,51 @@ type CreateDatabaseCredentialRequestDto struct {
Password string `json:"password"`
}

type GetPolicyDetails struct {
OrgId int `json:"orgId"`
TenantId int `json:"tenantId"`
PolicyID uuid.UUID `json:"policyId"`
}
type GetPolicyDetailsResponse struct {
Code int `json:"code"`
Status string `json:"status"`
Message string `json:"message"`
Data PolicyJSON `json:"data"`
}

type PolicyJSON struct {
PolicyName string `json:"policyName" binding:"required"`
PolicyType string `json:"policyType" binding:"required"`
Endpoints Endpoints `json:"endpoints,omitempty"`
Domain Domain `json:"domain,omitempty"`
AD AD `json:"ad,omitempty"`
ADGroupInfra AdGroupPolicy `json:"infra,omitempty"`
Networks RadiusNetwork `json:"networks,omitempty"`
Dit Dit `json:"dit,omitempty"`
ServiceAccount ServiceAccount `json:"serviceaccount,omitempty"`
Database Database `json:"database,omitempty"`
Permissions Permission `json:"permissions"`
}

type Database struct {
DatabaseName string `json:"database_name"`
Tables []string `json:"tables"`
FieldMasking map[string][]string `json:"field_masking"`
User string `json:"user"`
Privilege []string `json:"privilege"`
}

type Endpoints struct{} // Placeholder for missing struct
type Domain struct{} // Placeholder for missing struct
type AD struct{} // Placeholder for missing struct
type AdGroupPolicy struct{} // Placeholder for missing struct
type RadiusNetwork struct{} // Placeholder for missing struct
type Dit struct{} // Placeholder for missing struct
type ServiceAccount struct{} // Placeholder for missing struct
type Permission struct{} // Placeholder for missing struct

func PollCheckoutJob(db *sql.DB, dbName string, Config DBConfig) error {

//API call to get all jobs from the queue
url := "https://prod.api.authnull.com/api/v1/databaseService/getJobQueue"
orgID, _ := strconv.Atoi(Config.OrgID)
Expand Down Expand Up @@ -120,12 +166,24 @@ func PollCheckoutJob(db *sql.DB, dbName string, Config DBConfig) error {
log.Printf("No jobs found in the queue")
return nil
}

//Iterate through the jobs and process them
for _, job := range response.Data {
//Call Other Function to rotate the Password for the DB User in the Database
policyDetails, err := FetchPolicyDetails(orgID, tenantID, job.PolicyID)
if err != nil {
log.Printf("Error fetching policy details for job %s: %v", job.JobName, err)
continue
}
log.Printf("Policy details retrieved - Tables: %v, FieldMasking: %v, Privileges: %v",
policyDetails.Data.Database.Tables, policyDetails.Data.Database.FieldMasking, policyDetails.Data.Database.Privilege)

fmt.Println("Policy details:", policyDetails)

fmt.Println("Job Details :", job)
success, err := GenerateCredentials(db, Config, dbName, response.DbUserName, job.Host, job.WalletUserID, job.IssuerID, job.Table_Name, job.Fields, job.Privileges)

success, err := GenerateCredentials(db, Config, dbName, response.DbUserName, job.Host,
job.WalletUserID, job.IssuerID, job.Table_Name, job.Fields, job.Privileges,
job.PolicyID, policyDetails)
if err != nil {
log.Printf("Error while generating credentials: %v", err)
continue
Expand Down Expand Up @@ -171,7 +229,77 @@ func PollCheckoutJob(db *sql.DB, dbName string, Config DBConfig) error {
return nil

}
func GenerateCredentials(db *sql.DB, Config DBConfig, dbName string, dbUserName string, host string, WalletUserID int, IssuerId int, TableName string, Fields string, Privlege string) (bool, error) {

func FetchPolicyDetails(orgID int, tenantID int, policyID uuid.UUID) (*GetPolicyDetailsResponse, error) {
url := "https://prod.api.authnull.com/api/v1/policyService/getPolicyDetails"

payload := GetPolicyDetails{
OrgId: orgID,
TenantId: tenantID,
PolicyID: policyID,
}

payloadBytes, err := json.Marshal(payload)
if err != nil {
return nil, fmt.Errorf("failed to marshal policy request: %w", err)
}

req, err := http.NewRequest("POST", url, bytes.NewBuffer(payloadBytes))
if err != nil {
return nil, fmt.Errorf("failed to create HTTP request: %w", err)
}
req.Header.Set("Content-Type", "application/json")

resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to execute HTTP request: %w", err)
}
defer resp.Body.Close()

// Check HTTP status code
if resp.StatusCode != http.StatusOK {
bodyBytes, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("API returned non-OK status: %d, body: %s", resp.StatusCode, string(bodyBytes))
}

body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}

// Parse the response
var apiResponse GetPolicyDetailsResponse
if err := json.Unmarshal(body, &apiResponse); err != nil {
return nil, fmt.Errorf("failed to parse policy response: %w", err)
}

if apiResponse.Code != 200 {
return nil, fmt.Errorf("invalid policy response: %s (code: %d)", apiResponse.Message, apiResponse.Code)
}

if apiResponse.Data.Database.Tables == nil {
return nil, errors.New("policy response contains no tables data")
}

return &apiResponse, nil
}

func GenerateCredentials(db *sql.DB, Config DBConfig, dbName string, dbUserName string, host string,
WalletUserID int, IssuerId int, TableName string, Fields string, Privlege string,
policyID uuid.UUID, policyDetails *GetPolicyDetailsResponse) (bool, error) {

// Validate policy details
if policyDetails == nil {
return false, errors.New("policy details cannot be nil")
}

if len(policyDetails.Data.Database.Tables) == 0 {
return false, errors.New("no tables found in policy details")
}

if len(policyDetails.Data.Database.Privilege) == 0 {
return false, errors.New("no privileges found in policy details")
}
//Rotate the Credentials for the DB User in the Database
//Step1 : Generate a Random Password for the DB User
password, err := GenerateRandomPassword(16)
Expand Down Expand Up @@ -249,8 +377,13 @@ func GenerateCredentials(db *sql.DB, Config DBConfig, dbName string, dbUserName
return false, err
}
log.Printf("Password for user %s updated successfully in ProxySQL", dbUserName)

orgId, _ := strconv.Atoi(Config.OrgID)
tenantId, _ := strconv.Atoi(Config.TenantID)

tables := policyDetails.Data.Database.Tables
fieldMasking := policyDetails.Data.Database.FieldMasking
privilege := policyDetails.Data.Database.Privilege
//Step3 : Call Create Database Credential API
//Create the request body
databaseCredentialRequest := CreateDatabaseCredentialRequestDto{
Expand All @@ -262,10 +395,10 @@ func GenerateCredentials(db *sql.DB, Config DBConfig, dbName string, dbUserName
CredentialType: "DATABASE",
DatabaseName: dbName,
Password: password,
Tables: []string{TableName},
FieldMasking: map[string][]string{TableName: {Fields}},
Tables: tables,
FieldMasking: fieldMasking,
DBUser: dbUserName,
Privilege: []string{Privlege},
Privilege: privilege,
}
//Call the API
err = CallCreateDatabaseCredentialAPI(databaseCredentialRequest)
Expand Down