2017-12-11 15:11:45 +01:00
|
|
|
// Package client provides a manager service client intended for internal
|
|
|
|
// service communication.
|
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2017-12-29 11:09:08 +01:00
|
|
|
"fmt"
|
2017-12-11 15:11:45 +01:00
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/mainflux/mainflux/manager"
|
2017-12-12 11:11:01 +01:00
|
|
|
"github.com/sony/gobreaker"
|
2017-12-11 15:11:45 +01:00
|
|
|
)
|
|
|
|
|
2017-12-12 11:11:01 +01:00
|
|
|
const (
|
|
|
|
timeout = time.Second * 5
|
|
|
|
maxFailedReqs = 3
|
|
|
|
maxFailureRatio = 0.6
|
|
|
|
)
|
2017-12-11 15:11:45 +01:00
|
|
|
|
2018-01-26 20:50:31 +01:00
|
|
|
var (
|
|
|
|
// ErrServiceUnreachable indicates that the service instance is not available.
|
|
|
|
ErrServiceUnreachable = errors.New("manager service unavailable")
|
|
|
|
|
|
|
|
// ErrUnauthorizedAccess indicates missing or invalid credentials provided
|
|
|
|
// when accessing a protected resource.
|
|
|
|
ErrUnauthorizedAccess = manager.ErrUnauthorizedAccess
|
|
|
|
)
|
2017-12-11 15:11:45 +01:00
|
|
|
|
2018-01-13 18:23:47 +01:00
|
|
|
// ManagerClient provides an access to the manager service authorization
|
|
|
|
// endpoints.
|
2018-01-07 14:42:38 +01:00
|
|
|
type ManagerClient struct {
|
2017-12-11 15:11:45 +01:00
|
|
|
url string
|
2017-12-12 11:11:01 +01:00
|
|
|
cb *gobreaker.CircuitBreaker
|
2017-12-11 15:11:45 +01:00
|
|
|
}
|
|
|
|
|
2017-12-12 11:11:01 +01:00
|
|
|
// NewClient instantiates the manager service client given its base URL.
|
2018-01-07 14:42:38 +01:00
|
|
|
func NewClient(url string) ManagerClient {
|
2017-12-12 11:11:01 +01:00
|
|
|
st := gobreaker.Settings{
|
|
|
|
Name: "Manager",
|
|
|
|
ReadyToTrip: func(counts gobreaker.Counts) bool {
|
|
|
|
fr := float64(counts.TotalFailures) / float64(counts.Requests)
|
|
|
|
return counts.Requests >= maxFailedReqs && fr >= maxFailureRatio
|
|
|
|
},
|
2017-12-11 15:11:45 +01:00
|
|
|
}
|
|
|
|
|
2018-01-07 14:42:38 +01:00
|
|
|
mc := ManagerClient{
|
2017-12-12 11:11:01 +01:00
|
|
|
url: url,
|
|
|
|
cb: gobreaker.NewCircuitBreaker(st),
|
2017-12-11 15:11:45 +01:00
|
|
|
}
|
|
|
|
|
2017-12-12 11:11:01 +01:00
|
|
|
return mc
|
|
|
|
}
|
|
|
|
|
2018-01-13 18:23:47 +01:00
|
|
|
// VerifyToken tries to extract an identity from the provided token.
|
2018-01-07 14:42:38 +01:00
|
|
|
func (mc ManagerClient) VerifyToken(token string) (string, error) {
|
2017-12-29 11:09:08 +01:00
|
|
|
url := fmt.Sprintf("%s/access-grant", mc.url)
|
|
|
|
return mc.makeRequest(url, token)
|
|
|
|
}
|
|
|
|
|
2018-01-13 18:23:47 +01:00
|
|
|
// CanAccess checks whether or not the client having a provided token has
|
|
|
|
// access to the specified channel.
|
2018-01-07 14:42:38 +01:00
|
|
|
func (mc ManagerClient) CanAccess(channel, token string) (string, error) {
|
2017-12-29 11:09:08 +01:00
|
|
|
url := fmt.Sprintf("%s/channels/%s/access-grant", mc.url, channel)
|
|
|
|
return mc.makeRequest(url, token)
|
|
|
|
}
|
|
|
|
|
2018-01-07 14:42:38 +01:00
|
|
|
func (mc ManagerClient) makeRequest(url, token string) (string, error) {
|
2017-12-12 11:11:01 +01:00
|
|
|
response, err := mc.cb.Execute(func() (interface{}, error) {
|
|
|
|
hc := &http.Client{
|
|
|
|
Timeout: timeout,
|
|
|
|
}
|
|
|
|
|
2017-12-29 11:09:08 +01:00
|
|
|
mgReq, err := http.NewRequest("GET", url, nil)
|
2017-12-12 11:11:01 +01:00
|
|
|
if err != nil {
|
|
|
|
return "", ErrServiceUnreachable
|
|
|
|
}
|
2017-12-11 15:11:45 +01:00
|
|
|
|
2017-12-29 11:09:08 +01:00
|
|
|
mgReq.Header.Set("Authorization", token)
|
2017-12-12 11:11:01 +01:00
|
|
|
|
|
|
|
res, err := hc.Do(mgReq)
|
|
|
|
if err != nil {
|
|
|
|
return "", ErrServiceUnreachable
|
|
|
|
}
|
2018-01-13 18:15:41 +01:00
|
|
|
defer res.Body.Close()
|
2017-12-12 11:11:01 +01:00
|
|
|
|
|
|
|
if res.StatusCode != http.StatusOK {
|
2018-01-26 20:50:31 +01:00
|
|
|
return ErrUnauthorizedAccess, nil
|
2017-12-12 11:11:01 +01:00
|
|
|
}
|
|
|
|
|
2017-12-29 11:09:08 +01:00
|
|
|
return res.Header.Get("X-client-id"), nil
|
2017-12-12 11:11:01 +01:00
|
|
|
})
|
2017-12-11 15:11:45 +01:00
|
|
|
|
|
|
|
if err != nil {
|
2017-12-12 11:11:01 +01:00
|
|
|
return "", err
|
2017-12-11 15:11:45 +01:00
|
|
|
}
|
|
|
|
|
2018-01-13 18:23:47 +01:00
|
|
|
id, ok := response.(string)
|
|
|
|
if !ok {
|
2017-12-11 15:11:45 +01:00
|
|
|
return "", manager.ErrUnauthorizedAccess
|
|
|
|
}
|
2018-01-13 18:23:47 +01:00
|
|
|
|
|
|
|
return id, nil
|
2017-12-11 15:11:45 +01:00
|
|
|
}
|