Fixed JSON parsing

rc-1.25 v1.25.2
kjubybot 3 years ago
parent 3164793f69
commit 28db919ffa

@ -25,7 +25,6 @@ Visit https://github.com/rudecs/terraform-provider-decort for full source code p
package decort package decort
import ( import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"fmt" "fmt"
@ -34,6 +33,7 @@ import (
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
// "time" // "time"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -42,30 +42,29 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/schema"
// "github.com/hashicorp/terraform-plugin-sdk/terraform" // "github.com/hashicorp/terraform-plugin-sdk/terraform"
) )
// enumerated constants that define authentication modes // enumerated constants that define authentication modes
const ( const (
MODE_UNDEF = iota // this is the invalid mode - it should never be seen MODE_UNDEF = iota // this is the invalid mode - it should never be seen
MODE_LEGACY = iota MODE_LEGACY = iota
MODE_OAUTH2 = iota MODE_OAUTH2 = iota
MODE_JWT = iota MODE_JWT = iota
) )
type ControllerCfg struct { type ControllerCfg struct {
controller_url string // always required controller_url string // always required
auth_mode_code int // always required auth_mode_code int // always required
auth_mode_txt string // always required, it is a text representation of auth mode auth_mode_txt string // always required, it is a text representation of auth mode
legacy_user string // required for legacy mode legacy_user string // required for legacy mode
legacy_password string // required for legacy mode legacy_password string // required for legacy mode
legacy_sid string // obtained from DECORT controller on successful login in legacy mode legacy_sid string // obtained from DECORT controller on successful login in legacy mode
jwt string // obtained from Outh2 provider on successful login in oauth2 mode, required in jwt mode jwt string // obtained from Outh2 provider on successful login in oauth2 mode, required in jwt mode
app_id string // required for oauth2 mode app_id string // required for oauth2 mode
app_secret string // required for oauth2 mode app_secret string // required for oauth2 mode
oauth2_url string // always required oauth2_url string // always required
decort_username string // assigned to either legacy_user (legacy mode) or Oauth2 user (oauth2 mode) upon successful verification decort_username string // assigned to either legacy_user (legacy mode) or Oauth2 user (oauth2 mode) upon successful verification
cc_client *http.Client // assigned when all initial checks successfully passed cc_client *http.Client // assigned when all initial checks successfully passed
} }
func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) { func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
@ -90,7 +89,7 @@ func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
app_id: d.Get("app_id").(string), app_id: d.Get("app_id").(string),
app_secret: d.Get("app_secret").(string), app_secret: d.Get("app_secret").(string),
oauth2_url: d.Get("oauth2_url").(string), oauth2_url: d.Get("oauth2_url").(string),
decort_username: "", decort_username: "",
} }
var allow_unverified_ssl bool var allow_unverified_ssl bool
@ -137,10 +136,10 @@ func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
if allow_unverified_ssl { if allow_unverified_ssl {
log.Warn("ControllerConfigure: allow_unverified_ssl is set - will not check certificates!") log.Warn("ControllerConfigure: allow_unverified_ssl is set - will not check certificates!")
transCfg := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true},} transCfg := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
ret_config.cc_client = &http.Client{ ret_config.cc_client = &http.Client{
Transport: transCfg, Transport: transCfg,
Timeout: Timeout180s, Timeout: Timeout180s,
} }
} else { } else {
ret_config.cc_client = &http.Client{ ret_config.cc_client = &http.Client{
@ -181,7 +180,7 @@ func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
tbuf.WriteString(claims["username"].(string)) tbuf.WriteString(claims["username"].(string))
tbuf.WriteString("@") tbuf.WriteString("@")
tbuf.WriteString(claims["iss"].(string)) tbuf.WriteString(claims["iss"].(string))
ret_config.decort_username = tbuf.String() ret_config.decort_username = tbuf.String()
} else { } else {
return nil, fmt.Errorf("Failed to extract user and iss fields from JWT token in oauth2 mode.") return nil, fmt.Errorf("Failed to extract user and iss fields from JWT token in oauth2 mode.")
} }
@ -195,7 +194,7 @@ func ControllerConfigure(d *schema.ResourceData) (*ControllerCfg, error) {
return ret_config, nil return ret_config, nil
} }
func (config *ControllerCfg) getDecortUsername() (string) { func (config *ControllerCfg) getDecortUsername() string {
return config.decort_username return config.decort_username
} }
@ -216,7 +215,7 @@ func (config *ControllerCfg) getOAuth2JWT() (string, error) {
params.Add("validity", "3600") params.Add("validity", "3600")
params_str := params.Encode() params_str := params.Encode()
req, err := http.NewRequest("POST", config.oauth2_url + "/v1/oauth/access_token", strings.NewReader(params_str)) req, err := http.NewRequest("POST", config.oauth2_url+"/v1/oauth/access_token", strings.NewReader(params_str))
if err != nil { if err != nil {
return "", err return "", err
} }
@ -232,14 +231,14 @@ func (config *ControllerCfg) getOAuth2JWT() (string, error) {
// fmt.Println("response Headers:", resp.Header) // fmt.Println("response Headers:", resp.Header)
// fmt.Println("response Headers:", req.URL) // fmt.Println("response Headers:", req.URL)
return "", fmt.Errorf("getOauth2JWT: unexpected status code %d when obtaining JWT from %q for APP_ID %q, request Body %q", return "", fmt.Errorf("getOauth2JWT: unexpected status code %d when obtaining JWT from %q for APP_ID %q, request Body %q",
resp.StatusCode, req.URL, config.app_id, params_str) resp.StatusCode, req.URL, config.app_id, params_str)
} }
defer resp.Body.Close() defer resp.Body.Close()
responseData, err := ioutil.ReadAll(resp.Body) responseData, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return "", err return "", err
} }
// validation successful - store JWT in the corresponding field of the ControllerCfg structure // validation successful - store JWT in the corresponding field of the ControllerCfg structure
config.jwt = strings.TrimSpace(string(responseData)) config.jwt = strings.TrimSpace(string(responseData))
@ -249,10 +248,10 @@ func (config *ControllerCfg) getOAuth2JWT() (string, error) {
func (config *ControllerCfg) validateJWT(jwt string) (bool, error) { func (config *ControllerCfg) validateJWT(jwt string) (bool, error) {
/* /*
Validate JWT against DECORT controller. JWT can be supplied as argument to this method. If empty string supplied as Validate JWT against DECORT controller. JWT can be supplied as argument to this method. If empty string supplied as
argument, JWT will be taken from config attribute. argument, JWT will be taken from config attribute.
DECORT controller URL will always be taken from the config attribute assigned at instantiation. DECORT controller URL will always be taken from the config attribute assigned at instantiation.
Validation is accomplished by attempting API call that lists accounts for the invoking user. Validation is accomplished by attempting API call that lists accounts for the invoking user.
*/ */
if jwt == "" { if jwt == "" {
if config.jwt == "" { if config.jwt == "" {
@ -265,7 +264,7 @@ func (config *ControllerCfg) validateJWT(jwt string) (bool, error) {
return false, fmt.Errorf("validateJWT method called, but no OAuth2 URL provided.") return false, fmt.Errorf("validateJWT method called, but no OAuth2 URL provided.")
} }
req, err := http.NewRequest("POST", config.controller_url + "/restmachine/cloudapi/accounts/list", nil) req, err := http.NewRequest("POST", config.controller_url+"/restmachine/cloudapi/accounts/list", nil)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -280,7 +279,7 @@ func (config *ControllerCfg) validateJWT(jwt string) (bool, error) {
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return false, fmt.Errorf("validateJWT: unexpected status code %d when validating JWT against %q.", return false, fmt.Errorf("validateJWT: unexpected status code %d when validating JWT against %q.",
resp.StatusCode, req.URL) resp.StatusCode, req.URL)
} }
defer resp.Body.Close() defer resp.Body.Close()
@ -289,10 +288,10 @@ func (config *ControllerCfg) validateJWT(jwt string) (bool, error) {
func (config *ControllerCfg) validateLegacyUser() (bool, error) { func (config *ControllerCfg) validateLegacyUser() (bool, error) {
/* /*
Validate legacy user by obtaining a session key, which will be used for authenticating subsequent API calls Validate legacy user by obtaining a session key, which will be used for authenticating subsequent API calls
to DECORT controller. to DECORT controller.
If successful, the session key is stored in config.legacy_sid and true is returned. If unsuccessful for any If successful, the session key is stored in config.legacy_sid and true is returned. If unsuccessful for any
reason, the method will return false and error. reason, the method will return false and error.
*/ */
if config.auth_mode_code == MODE_UNDEF { if config.auth_mode_code == MODE_UNDEF {
return false, fmt.Errorf("validateLegacyUser method called for undefined authorization mode.") return false, fmt.Errorf("validateLegacyUser method called for undefined authorization mode.")
@ -306,7 +305,7 @@ func (config *ControllerCfg) validateLegacyUser() (bool, error) {
params.Add("password", config.legacy_password) params.Add("password", config.legacy_password)
params_str := params.Encode() params_str := params.Encode()
req, err := http.NewRequest("POST", config.controller_url + "/restmachine/cloudapi/users/authenticate", strings.NewReader(params_str)) req, err := http.NewRequest("POST", config.controller_url+"/restmachine/cloudapi/users/authenticate", strings.NewReader(params_str))
if err != nil { if err != nil {
return false, err return false, err
} }
@ -320,14 +319,14 @@ func (config *ControllerCfg) validateLegacyUser() (bool, error) {
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return false, fmt.Errorf("validateLegacyUser: unexpected status code %d when validating legacy user %q against %q.", return false, fmt.Errorf("validateLegacyUser: unexpected status code %d when validating legacy user %q against %q.",
resp.StatusCode, config.legacy_user, config.controller_url) resp.StatusCode, config.legacy_user, config.controller_url)
} }
defer resp.Body.Close() defer resp.Body.Close()
responseData, err := ioutil.ReadAll(resp.Body) responseData, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
// validation successful - keep session ID for future use // validation successful - keep session ID for future use
config.legacy_sid = string(responseData) config.legacy_sid = string(responseData)
@ -367,12 +366,13 @@ func (config *ControllerCfg) decortAPICall(method string, api_name string, url_v
} }
params_str := url_values.Encode() params_str := url_values.Encode()
req, err := http.NewRequest(method, config.controller_url + api_name, strings.NewReader(params_str)) req, err := http.NewRequest(method, config.controller_url+api_name, strings.NewReader(params_str))
if err != nil { if err != nil {
return "", err return "", err
} }
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Content-Length", strconv.Itoa(len(params_str))) req.Header.Set("Content-Length", strconv.Itoa(len(params_str)))
req.Header.Set("Accept", "application/json")
if config.auth_mode_code == MODE_OAUTH2 || config.auth_mode_code == MODE_JWT { if config.auth_mode_code == MODE_OAUTH2 || config.auth_mode_code == MODE_JWT {
req.Header.Set("Authorization", fmt.Sprintf("bearer %s", config.jwt)) req.Header.Set("Authorization", fmt.Sprintf("bearer %s", config.jwt))
@ -384,25 +384,23 @@ func (config *ControllerCfg) decortAPICall(method string, api_name string, url_v
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode == http.StatusOK { if resp.StatusCode == http.StatusOK {
tmp_body, err := ioutil.ReadAll(resp.Body) body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return "", err return "", err
} }
json_resp := Jo2JSON(string(tmp_body)) log.Debugf("decortAPICall: %s %s\n %s", method, api_name, body)
log.Debugf("decortAPICall: %s %s\n %s", method, api_name, json_resp) return string(body), nil
return json_resp, nil
} else { } else {
return "", fmt.Errorf("decortAPICall: unexpected status code %d when calling API %q with request Body %q", return "", fmt.Errorf("decortAPICall: unexpected status code %d when calling API %q with request Body %q",
resp.StatusCode, req.URL, params_str) resp.StatusCode, req.URL, params_str)
} }
/* /*
if resp.StatusCode == StatusServiceUnavailable { if resp.StatusCode == StatusServiceUnavailable {
return nil, fmt.Errorf("decortAPICall method called for incompatible authorization mode %q.", config.auth_mode_txt) return nil, fmt.Errorf("decortAPICall method called for incompatible authorization mode %q.", config.auth_mode_txt)
} }
*/ */
return "", err return "", err
} }

Loading…
Cancel
Save