Skip to content

Commit

Permalink
Merge pull request #92 from sanderdescamps/feat/userpass-auth
Browse files Browse the repository at this point in the history
feat: add userpass support
  • Loading branch information
fdevans authored Oct 6, 2023
2 parents aed8fac + 45340e7 commit 5d0b3c5
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 4 deletions.
32 changes: 30 additions & 2 deletions rundeck/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,22 @@ func Provider() terraform.ResourceProvider {
},
"auth_token": {
Type: schema.TypeString,
Required: true,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("RUNDECK_AUTH_TOKEN", nil),
Description: "Auth token to use with the Rundeck API.",
},
"auth_username": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("RUNDECK_AUTH_USERNAME", nil),
Description: "Username used to request a tiken for the Rundeck API.",
},
"auth_password": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("RUNDECK_AUTH_PASSWORD", nil),
Description: "Password used to request a tiken for the Rundeck API.",
},
},

ResourcesMap: map[string]*schema.Resource{
Expand All @@ -58,7 +70,23 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
return nil, error
}

token := d.Get("auth_token").(string)
_, okToken := d.GetOk("auth_token")
_, okUsername := d.GetOk("auth_username")
_, okPassword := d.GetOk("auth_password")

var token string

if okToken {
token = d.Get("auth_token").(string)
} else if okUsername && okPassword {
t, err := getToken(d)
token = t
if err != nil {
return nil, err
}
} else {
return nil, fmt.Errorf("auth_token need to be set of auth_username and auth_password")
}

client := rundeck.NewRundeckWithBaseURI(apiURL.String())
client.Authorizer = &auth.TokenAuthorizer{Token: token}
Expand Down
12 changes: 10 additions & 2 deletions rundeck/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,15 @@ func testAccPreCheck(t *testing.T) {
if v := os.Getenv("RUNDECK_URL"); v == "" {
t.Fatal("RUNDECK_URL must be set for acceptance tests")
}
if v := os.Getenv("RUNDECK_AUTH_TOKEN"); v == "" {
t.Fatal("RUNDECK_AUTH_TOKEN must be set for acceptance tests")

token := os.Getenv("RUNDECK_AUTH_TOKEN")
username := os.Getenv("RUNDECK_AUTH_USERNAME")
password := os.Getenv("RUNDECK_AUTH_PASSWORD")
if !(token != "" || (username != "" && password != "")) {
t.Logf("RUNDECK_AUTH_TOKEN=%s", token)
t.Logf("RUNDECK_AUTH_USERNAME=%s", username)
t.Logf("RUNDECK_AUTH_PASSWORD=%s", password)
t.Fatal("RUNDECK_AUTH_TOKEN must be set for acceptance tests or RUNDECK_AUTH_USERNAME and RUNDECK_AUTH_PASSWORD")
}

}
113 changes: 113 additions & 0 deletions rundeck/token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package rundeck

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
"strconv"
"time"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

type TokenResp struct {
User string `json:"user"`
Token string `json:"token"`
ID string `json:"id"`
Creator string `json:"creator"`
Name string `json:"name"`
Expiration time.Time `json:"expiration"`
Roles []string `json:"roles"`
Expired bool `json:"expired"`
}

func getToken(d *schema.ResourceData) (string, error) {
urlP, _ := d.Get("url").(string)
apiVersion, _ := d.Get("api_version").(string)
username, _ := d.Get("auth_username").(string)
password, _ := d.Get("auth_password").(string)

return _getToken(urlP, apiVersion, username, password)

}

func _getToken(urlP string, apiVersion string, username string, password string) (string, error) {

secCheckUrlString := fmt.Sprintf("%s/j_security_check", urlP)
secCheckUrl, err := url.Parse(secCheckUrlString)

if err != nil {
return "", err
}

jar, err := cookiejar.New(nil)
if err != nil {
return "", err
}

client := &http.Client{
Jar: jar,
}

data := url.Values{
"j_username": {username},
"j_password": {password},
}
_, err = client.PostForm(secCheckUrl.String(), data)
if err != nil {
return "", err
}

tokenUrlString := fmt.Sprintf("%s/api/%s/tokens", urlP, "43")
tokenUrl, err := url.Parse(tokenUrlString)

if err != nil {
return "", err
}

tokenBody := map[string]interface{}{}
tokenBody["user"] = username
tokenBody["roles"] = []string{"*"}
tokenBody["duration"] = "0"
tokenBody["name"] = "terraform-token"
tokenBodyJson, err := json.Marshal(tokenBody)
if err != nil {
return "", err
}

req, err := http.NewRequest("POST", tokenUrl.String(), bytes.NewBuffer(tokenBodyJson))
if err != nil {
return "", err
}
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/json")

resp, err := client.Do(req)
if resp.StatusCode < 200 || resp.StatusCode > 299 {
body, _ := ioutil.ReadAll(resp.Body)
return "", fmt.Errorf("statuscode %d\n%s", resp.StatusCode, string(body))
} else if err != nil {
return "", err
}

tokenResp := &TokenResp{}
err = json.NewDecoder(resp.Body).Decode(tokenResp)
if err != nil {
return "", err
}

if version, _ := strconv.Atoi(apiVersion); version >= 19 {
return tokenResp.Token, nil
} else if tokenResp.Token != "" {
return tokenResp.Token, nil
} else if tokenResp.ID != "" {
return tokenResp.ID, nil
}

return tokenResp.Token, nil

}
27 changes: 27 additions & 0 deletions rundeck/token_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package rundeck

import (
"os"
"testing"
)

func TestAccToken(t *testing.T) {
testAccPreCheck(t)

username := os.Getenv("RUNDECK_AUTH_USERNAME")
password := os.Getenv("RUNDECK_AUTH_PASSWORD")
apiVersion := os.Getenv("RUNDECK_API_VERSION")
if apiVersion == "" {
apiVersion = "14"
}
url := os.Getenv("RUNDECK_URL")

if username != "" && password != "" {
_, err := _getToken(url, apiVersion, username, password)
if err != nil {
t.Fatalf("failed to get a token: %s", err)
}
} else {
t.Logf("Can not run TestAccToken test as there is no username and password defined")
}
}

0 comments on commit 5d0b3c5

Please sign in to comment.