open-vault/vendor/github.com/centrify/cloud-golang-sdk/restapi/restapi.go
Jeff Mitchell 98b479ab58 Bump deps
2018-01-26 18:51:00 -05:00

195 lines
5 KiB
Go

package restapi
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
"strings"
)
type HttpClientFactory func() *http.Client
// BaseAPIResponse represents the most basic standard Centrify API response,
// where Result itself is left as raw json
type BaseAPIResponse struct {
Success bool `json:"success"`
Result json.RawMessage
Message string
}
type StringResponse struct {
BaseAPIResponse
Result string
}
type BoolResponse struct {
BaseAPIResponse
Result bool
}
// GenericMapResponse represents Centrify API responses where results are map[string]interface{},
// this type allows direct access to these without further decoding.
type GenericMapResponse struct {
BaseAPIResponse
Result map[string]interface{}
}
// BackendType is the type of backend that is being implemented
type RestClientMode uint32
// RestClient represents a stateful API client (cookies maintained between calls, single service etc)
type RestClient struct {
Service string
Client *http.Client
Headers map[string]string
SourceHeader string
}
// GetNewRestClient creates a new RestClient for the specified endpoint. If a factory for creating
// http.Client's is not provided, you'll get a new: &http.Client{}.
func GetNewRestClient(service string, httpFactory HttpClientFactory) (*RestClient, error) {
jar, err := cookiejar.New(nil)
if err != nil {
return nil, err
}
// Munge on the service a little bit, force it to have no trailing / and always start with https://
url, err := url.Parse(service)
if err != nil {
return nil, err
}
url.Scheme = "https"
url.Path = ""
client := &RestClient{}
client.Service = url.String()
if httpFactory != nil {
client.Client = httpFactory()
} else {
client.Client = &http.Client{}
}
client.Client.Jar = jar
client.Headers = make(map[string]string)
client.SourceHeader = "cloud-golang-sdk"
return client, nil
}
func (r *RestClient) CallRawAPI(method string, args map[string]interface{}) ([]byte, error) {
return r.postAndGetBody(method, args)
}
func (r *RestClient) CallBaseAPI(method string, args map[string]interface{}) (*BaseAPIResponse, error) {
body, err := r.postAndGetBody(method, args)
if err != nil {
return nil, err
}
return bodyToBaseAPIResponse(body)
}
func (r *RestClient) CallGenericMapAPI(method string, args map[string]interface{}) (*GenericMapResponse, error) {
body, err := r.postAndGetBody(method, args)
if err != nil {
return nil, err
}
return bodyToGenericMapResponse(body)
}
func (r *RestClient) CallStringAPI(method string, args map[string]interface{}) (*StringResponse, error) {
body, err := r.postAndGetBody(method, args)
if err != nil {
return nil, err
}
return bodyToStringResponse(body)
}
func (r *RestClient) CallBoolAPI(method string, args map[string]interface{}) (*BoolResponse, error) {
body, err := r.postAndGetBody(method, args)
if err != nil {
return nil, err
}
return bodyToBoolResponse(body)
}
func (r *RestClient) postAndGetBody(method string, args map[string]interface{}) ([]byte, error) {
service := strings.TrimSuffix(r.Service, "/")
method = strings.TrimPrefix(method, "/")
postdata := strings.NewReader(payloadFromMap(args))
postreq, err := http.NewRequest("POST", service+"/"+method, postdata)
if err != nil {
return nil, err
}
postreq.Header.Add("Content-Type", "application/json")
postreq.Header.Add("X-CENTRIFY-NATIVE-CLIENT", "Yes")
postreq.Header.Add("X-CFY-SRC", r.SourceHeader)
for k, v := range r.Headers {
postreq.Header.Add(k, v)
}
httpresp, err := r.Client.Do(postreq)
if err != nil {
return nil, err
}
defer httpresp.Body.Close()
if httpresp.StatusCode == 200 {
return ioutil.ReadAll(httpresp.Body)
}
body, _ := ioutil.ReadAll(httpresp.Body)
return nil, fmt.Errorf("POST to %s failed with code %d, body: %s", method, httpresp.StatusCode, body)
}
// This function converts a map[string]interface{} into json string
func payloadFromMap(input map[string]interface{}) string {
if input != nil {
p, _ := json.Marshal(input)
return string(p)
}
return ""
}
func bodyToBaseAPIResponse(body []byte) (*BaseAPIResponse, error) {
reply := &BaseAPIResponse{}
err := json.Unmarshal(body, &reply)
if err != nil {
return nil, fmt.Errorf("Failed to unmarshal BaseApiResponse from HTTP response: %v", err)
}
return reply, nil
}
func bodyToGenericMapResponse(body []byte) (*GenericMapResponse, error) {
reply := &GenericMapResponse{}
err := json.Unmarshal(body, &reply)
if err != nil {
return nil, fmt.Errorf("Failed to unmarshal GenericMapResponse from HTTP response: %v", err)
}
return reply, nil
}
func bodyToStringResponse(body []byte) (*StringResponse, error) {
reply := &StringResponse{}
err := json.Unmarshal(body, &reply)
if err != nil {
return nil, fmt.Errorf("Failed to unmarshal StringResponse from HTTP response: %v", err)
}
return reply, nil
}
func bodyToBoolResponse(body []byte) (*BoolResponse, error) {
reply := &BoolResponse{}
err := json.Unmarshal(body, &reply)
if err != nil {
return nil, fmt.Errorf("Failed to unmarshal BoolResponse from HTTP response: %v", err)
}
return reply, nil
}