-
Notifications
You must be signed in to change notification settings - Fork 3
/
corbel.go
166 lines (134 loc) · 5.27 KB
/
corbel.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package corbel
import (
"fmt"
"net/http"
"time"
"github.com/Sirupsen/logrus"
)
var (
userAgent string
allowedEnvironments []string
allowedEndpoints []string
allowedJTWSigningMethods []string
)
// init defines constants that will be used later
func init() {
userAgent = fmt.Sprintf("corbel-go/%s", Version)
allowedEndpoints = []string{"iam", "oauth", "assets", "resources"}
allowedJTWSigningMethods = []string{"HS256", "RSA"}
}
// Client is the struct that manages communication with the Corbel APIs.
type Client struct {
// client is the HTTP client to communicate with the API.
httpClient *http.Client
// Endpoint is a structure that stores the uri for each resource
Endpoints map[string]string
// ClientName is the name that match the clientID
// (Optional) The required information is the clientID
ClientName string
// ClientID is the application defined client on Corbel.
ClientID string
// ClientSecret is the application secret hash that match with clientID.
ClientSecret string
// ClientScopes are those scopes the client will ask for to the platform when building the client connection
// ClientScopes is a string with the scopes delimited by spaces.
ClientScopes string
// ClientDomain is the SR domain where to make the operations using the provided credentials.
// (Optional) Every clientID only maps to one SR domain.
ClientDomain string
// ClientJWTSigningMethod defines the signing method configured for the client.
// Must match with the one configured on the platform since it will understand only that one.
// Only allowed signing methods at the moment are: HS256 and RSA
ClientJWTSigningMethod string
// TokenExpirationTime define the amount of time in seconds that a token must be valid.
// It must be lower than 3600 seconds, since is the imposed requisite from the platform.
TokenExpirationTime uint64
// UserAgent defines the UserAgent to send in the Headers for every request to the platform.
UserAgent string
// Token is the actual token to send as Authentication Bearer
CurrentToken string
// CurrentTokenExpiresAt is the unix time where the token will expire
CurrentTokenExpiresAt int64
// CurrentRefreshToken is the current refresh token received from the IAM service
CurrentRefreshToken string
// IAM endpoint struct
IAM *IAMService
Resources *ResourcesService
Assets *AssetsService
// Logger
logger *logrus.Logger
// LogLevel for the logger.
LogLevel string
}
// URLFor returns the formated url of the API using the actual url scheme
func (c *Client) URLFor(endpoint, uri string) string {
return fmt.Sprintf("%s%s", c.Endpoints[endpoint], uri)
}
// Token returns the token to use as bearer. If the token has already expired
// it refresh it.
func (c *Client) Token() string {
// if CurrentToken == "" then return it as is
if c.CurrentToken == "" {
return c.CurrentToken
}
// if we have CurrentToken check if already expired
if c.CurrentTokenExpiresAt <= time.Now().Unix()*1000 {
c.logger.Debug("refreshing token")
if c.CurrentRefreshToken != "" {
_ = c.IAM.RefreshToken()
} else {
_ = c.IAM.OauthToken()
}
}
return c.CurrentToken
}
// DefaultClient return a client with most of its values set to the default ones
func DefaultClient(endpoints map[string]string, clientID, clientName, clientSecret, clientScopes, clientDomain string) (*Client, error) {
return NewClient(nil, endpoints, clientID, clientName, clientSecret, clientScopes, clientDomain, "HS256", 3600, "info")
}
// NewClient returns a new Corbel API client.
// If a nil httpClient is provided, it will return a http.DefaultClient.
// If a empty environment is provided, it will use production as environment.
func NewClient(httpClient *http.Client, endpoints map[string]string, clientID, clientName, clientSecret, clientScopes, clientDomain, clientJWTSigningMethod string, tokenExpirationTime uint64, logLevel string) (*Client, error) {
if httpClient == nil {
httpClient = http.DefaultClient
}
if len(endpoints) == 0 {
endpoints = map[string]string{"iam": "https://iam.bqws.io", "resources": "https://resources.bqws.io"}
}
// allowedJTWSigningMethods?
if stringInSlice(allowedJTWSigningMethods, clientJWTSigningMethod) == false {
return nil, errInvalidJWTSigningMethod
}
// incorrect Token Expiration Time?
if tokenExpirationTime > 3600 || tokenExpirationTime == 0 {
return nil, errInvalidTokenExpirationTime
}
// required parameters?
if clientID == "" || clientSecret == "" {
return nil, errMissingClientParams
}
thisClient := &Client{
httpClient: httpClient,
Endpoints: endpoints,
ClientName: clientName,
ClientID: clientID,
ClientSecret: clientSecret,
ClientDomain: clientDomain,
ClientScopes: clientScopes,
ClientJWTSigningMethod: clientJWTSigningMethod,
TokenExpirationTime: tokenExpirationTime * 1000,
UserAgent: userAgent,
}
thisClient.IAM = &IAMService{client: thisClient}
thisClient.Resources = &ResourcesService{client: thisClient}
thisClient.Assets = &AssetsService{client: thisClient}
level, err := logrus.ParseLevel(logLevel)
if err != nil {
return nil, errInvalidLogLevel
}
thisClient.logger = logrus.New()
thisClient.logger.Level = level
thisClient.LogLevel = logLevel
return thisClient, nil
}