You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
3.5 KiB
147 lines
3.5 KiB
package client
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"github.com/pkg/errors"
|
|
"time"
|
|
"net/http"
|
|
"gopkg.in/h2non/gentleman.v2"
|
|
"gopkg.in/h2non/gentleman.v2/plugin"
|
|
"gopkg.in/h2non/gentleman.v2/plugins/timeout"
|
|
//"gopkg.in/h2non/gentleman.v2/plugins/multipart"
|
|
)
|
|
|
|
|
|
type Client interface {
|
|
GetRealms() ([]RealmRepresentation, error)
|
|
GetUsers(realm string) ([]UserRepresentation, error)
|
|
}
|
|
|
|
type HttpConfig struct {
|
|
Addr string
|
|
Username string
|
|
Password string
|
|
Timeout time.Duration
|
|
}
|
|
|
|
type client struct {
|
|
username string
|
|
password string
|
|
accessToken string
|
|
httpClient *gentleman.Client
|
|
}
|
|
|
|
|
|
func NewHttpClient(config HttpConfig) (Client, error) {
|
|
var u *url.URL
|
|
{
|
|
var err error
|
|
u, err = url.Parse(config.Addr)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Parse failed")
|
|
}
|
|
}
|
|
|
|
if u.Scheme != "http" {
|
|
var m string = fmt.Sprintf("Unsupported protocol %s. Your address must start with http://", u.Scheme)
|
|
return nil, errors.New(m)
|
|
}
|
|
|
|
var httpClient *gentleman.Client = gentleman.New()
|
|
{
|
|
httpClient = httpClient.URL(u.String())
|
|
httpClient = httpClient.Use(timeout.Request(config.Timeout))
|
|
}
|
|
|
|
return &client{
|
|
username: config.Username,
|
|
password: config.Password,
|
|
httpClient: httpClient,
|
|
}, nil
|
|
}
|
|
|
|
func (c *client) getToken() error {
|
|
var req *gentleman.Request
|
|
{
|
|
var authPath string = "/auth/realms/master/protocol/openid-connect/token"
|
|
//var formData multipart.FormData = multipart.FormData{
|
|
// Data: map[string]multipart.Values{
|
|
// "username": multipart.Values{c.username},
|
|
// "password": multipart.Values{c.password},
|
|
// "grant_type": multipart.Values{"password"},
|
|
// "client_id": multipart.Values{"admin-cli"},
|
|
// },
|
|
//}
|
|
req = c.httpClient.Post()
|
|
req = req.SetHeader("Content-Type", "application/x-www-form-urlencoded")
|
|
req = req.Path(authPath)
|
|
req = req.Type("urlencoded")
|
|
req = req.BodyString(fmt.Sprintf("username=%s&password=%s&grant_type=password&client_id=admin-cli",c.username,c.password))
|
|
}
|
|
|
|
var resp *gentleman.Response
|
|
{
|
|
var err error
|
|
resp, err = req.Do()
|
|
if err != nil {
|
|
return errors.Wrap(err, "Failed to get the token response")
|
|
}
|
|
}
|
|
defer resp.Close()
|
|
|
|
var unmarshalledBody map[string]interface{}
|
|
{
|
|
var err error
|
|
err = resp.JSON(&unmarshalledBody)
|
|
if err != nil {
|
|
return errors.Wrap(err, "Failed to unmarshal response json")
|
|
}
|
|
}
|
|
|
|
var accessToken interface{}
|
|
{
|
|
var ok bool
|
|
accessToken, ok = unmarshalledBody["access_token"]
|
|
if !ok {
|
|
return errors.New("No access token in reponse body")
|
|
}
|
|
}
|
|
|
|
c.accessToken = accessToken.(string)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *client) do(path string, plugins ...plugin.Plugin) (*gentleman.Response, error) {
|
|
var req *gentleman.Request = c.httpClient.Get()
|
|
{
|
|
req = req.Path(path)
|
|
req = req.SetHeader("Authorization", fmt.Sprintf("Bearer %s", c.accessToken))
|
|
for _, p := range plugins {
|
|
req = req.Use(p)
|
|
}
|
|
}
|
|
var resp *gentleman.Response
|
|
{
|
|
var err error
|
|
resp, err = req.Do()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Failed to get the response")
|
|
}
|
|
switch resp.StatusCode {
|
|
case http.StatusUnauthorized:
|
|
var err = c.getToken()
|
|
//This induces a potential infinite loop, where a new token gets requested and the
|
|
//process gets delayed so much it expires before the recursion.
|
|
//It is decided that should this happen, the machine would be considered to be in terrible shape
|
|
//and the loop wouldn't be the biggest problem.
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Failed to get token")
|
|
}
|
|
return c.do(path)
|
|
default:
|
|
return resp, nil
|
|
}
|
|
}
|
|
}
|