Commit 3fffcb954a1cc48a4bfe8823c655015cfd70c93b

Authored by Marko Tikvić
1 parent 1b7dfab733
Exists in master and in 1 other branch v2

removed old http API

... ... @@ -12,10 +12,6 @@ import (
12 12 "github.com/dgrijalva/jwt-go"
13 13 )
14 14  
15   -const OneDay = time.Hour * 24
16   -const OneWeek = OneDay * 7
17   -const saltSize = 32
18   -
19 15 var appName = "webutility"
20 16 var secret = "webutility"
21 17  
... ... @@ -91,7 +87,7 @@ func CreateHash(str, presalt string) (hash, salt string, err error) {
91 87 // It returns an error if it fails.
92 88 func CreateAuthToken(username string, role Role) (TokenClaims, error) {
93 89 t0 := (time.Now()).Unix()
94   - t1 := (time.Now().Add(OneWeek)).Unix()
  90 + t1 := (time.Now().Add(time.Hour * 24 * 7)).Unix()
95 91 claims := TokenClaims{
96 92 TokenType: "Bearer",
97 93 Username: username,
... ... @@ -113,8 +109,8 @@ func CreateAuthToken(username string, role Role) (TokenClaims, error) {
113 109 return claims, nil
114 110 }
115 111  
116   -// RefreshAuthToken returns new JWT token with sprolongs JWT token's expiration date for one week.
117   -// It returns new JWT token or an error if it fails.
  112 +// RefreshAuthToken returns new JWT token with same claims contained in tok but with prolonged expiration date.
  113 +// It returns an error if it fails.
118 114 func RefreshAuthToken(tok string) (TokenClaims, error) {
119 115 token, err := jwt.ParseWithClaims(tok, &TokenClaims{}, secretFunc)
120 116 if err != nil {
... ... @@ -139,44 +135,13 @@ func RefreshAuthToken(tok string) (TokenClaims, error) {
139 135 return CreateAuthToken(claims.Username, Role{claims.Role, claims.RoleID})
140 136 }
141 137  
142   -// RbacCheck returns true if user that made HTTP request is authorized to
143   -// access the resource it is targeting.
144   -// It exctracts user's role from the JWT token located in Authorization header of
145   -// http.Request and then compares it with the list of supplied roles and returns
146   -// true if there's a match, if "*" is provided or if the authRoles is nil.
147   -// Otherwise it returns false.
148   -func RbacCheck(req *http.Request, authRoles []string) bool {
149   - if authRoles == nil {
150   - return true
151   - }
152   -
153   - // validate token and check expiration date
154   - claims, err := GetTokenClaims(req)
155   - if err != nil {
156   - return false
157   - }
158   - // check if token has expired
159   - if claims.ExpiresAt < (time.Now()).Unix() {
160   - return false
161   - }
162   -
163   - // check if role extracted from token matches
164   - // any of the provided (allowed) ones
165   - for _, r := range authRoles {
166   - if claims.Role == r || r == "*" {
167   - return true
168   - }
169   - }
170   -
171   - return false
172   -}
173   -
174   -// AuthCheck returns token claims and boolean value based on user's rights to access resource specified in req.
175   -// It exctracts user's role from the JWT token located in Authorization header of
176   -// HTTP request and then compares it with the list of supplied (authorized);
177   -// it returns true if there's a match, if "*" is provided or if the authRoles is nil.
178   -func AuthCheck(req *http.Request, authRoles []string) (*TokenClaims, bool) {
179   - if authRoles == nil {
  138 +// AuthCheck returns JWT claims and boolean result of a check if req contains any role from roles.
  139 +// It checks if role extracted from reqest's Authorization header (JWT claims) matches any of
  140 +// provided comma-separated roles in roles. If roles is empty string check is skipped,
  141 +// otherwise role is extracted from token claims and compared against roles.
  142 +// If roles is "*" the check is automatically validated.
  143 +func AuthCheck(req *http.Request, roles string) (*TokenClaims, bool) {
  144 + if roles == "" {
180 145 return nil, true
181 146 }
182 147  
... ... @@ -190,10 +155,14 @@ func AuthCheck(req *http.Request, authRoles []string) (*TokenClaims, bool) {
190 155 return claims, false
191 156 }
192 157  
193   - // check if role extracted from token matches
194   - // any of the provided (allowed) ones
195   - for _, r := range authRoles {
196   - if claims.Role == r || r == "*" {
  158 + if roles == "*" {
  159 + return claims, true
  160 + }
  161 +
  162 + parts := strings.Split(roles, ",")
  163 + for i, _ := range parts {
  164 + r := strings.Trim(parts[i], " ")
  165 + if claims.Role == r {
197 166 return claims, true
198 167 }
199 168 }
... ... @@ -201,7 +170,7 @@ func AuthCheck(req *http.Request, authRoles []string) (*TokenClaims, bool) {
201 170 return claims, false
202 171 }
203 172  
204   -// GetTokenClaims extracts JWT claims from Authorization header of the request.
  173 +// GetTokenClaims extracts JWT claims from Authorization header of req.
205 174 // Returns token claims or an error.
206 175 func GetTokenClaims(req *http.Request) (*TokenClaims, error) {
207 176 // check for and strip 'Bearer' prefix
... ... @@ -227,7 +196,9 @@ func GetTokenClaims(req *http.Request) (*TokenClaims, error) {
227 196 return claims, nil
228 197 }
229 198  
230   -// randomSalt returns a string of random characters of 'saltSize' length.
  199 +// randomSalt returns a string of 32 random characters.
  200 +const saltSize = 32
  201 +
231 202 func randomSalt() (s string, err error) {
232 203 rawsalt := make([]byte, saltSize)
233 204  
... ...
... ... @@ -6,11 +6,6 @@ import (
6 6 "net/http"
7 7 )
8 8  
9   -type webError struct {
10   - Request string `json:"request"`
11   - Error string `json:"error"`
12   -}
13   -
14 9 // NotFoundHandlerFunc writes HTTP error 404 to w.
15 10 func NotFoundHandlerFunc(w http.ResponseWriter, req *http.Request) {
16 11 SetDefaultHeaders(w)
... ... @@ -54,9 +49,14 @@ func Created(w http.ResponseWriter, payload interface{}) {
54 49 Success(w, payload, http.StatusCreated)
55 50 }
56 51  
  52 +type weberror struct {
  53 + Request string `json:"request"`
  54 + Error string `json:"error"`
  55 +}
  56 +
57 57 // 4xx; 5xx
58 58 func Error(w http.ResponseWriter, r *http.Request, code int, err string) {
59   - werr := webError{Error: err, Request: r.Method + " " + r.RequestURI}
  59 + werr := weberror{Error: err, Request: r.Method + " " + r.RequestURI}
60 60 w.WriteHeader(code)
61 61 json.NewEncoder(w).Encode(werr)
62 62 }
... ... @@ -90,76 +90,3 @@ func Conflict(w http.ResponseWriter, r *http.Request, err string) {
90 90 func InternalServerError(w http.ResponseWriter, r *http.Request, err string) {
91 91 Error(w, r, http.StatusInternalServerError, err)
92 92 }
93   -
94   -///
95   -/// Old API
96   -///
97   -
98   -const (
99   - templateHttpErr500_EN = "An internal server error has occurred."
100   - templateHttpErr500_RS = "Došlo je do greške na serveru."
101   - templateHttpErr400_EN = "Bad request."
102   - templateHttpErr400_RS = "Neispravan zahtev."
103   - templateHttpErr404_EN = "Resource not found."
104   - templateHttpErr404_RS = "Resurs nije pronadjen."
105   - templateHttpErr401_EN = "Unauthorized request."
106   - templateHttpErr401_RS = "Neautorizovan zahtev."
107   -)
108   -
109   -type httpError struct {
110   - Error []HttpErrorDesc `json:"error"`
111   - Request string `json:"request"`
112   -}
113   -
114   -type HttpErrorDesc struct {
115   - Lang string `json:"lang"`
116   - Desc string `json:"description"`
117   -}
118   -
119   -// DeliverPayload encodes payload as JSON to w.
120   -func DeliverPayload(w http.ResponseWriter, payload Payload) {
121   - // Don't write status OK in the headers here. Leave it up for the caller.
122   - // E.g. Status 201.
123   - json.NewEncoder(w).Encode(payload)
124   - payload.Data = nil
125   -}
126   -
127   -// ErrorResponse writes HTTP error to w.
128   -func ErrorResponse(w http.ResponseWriter, r *http.Request, code int, desc []HttpErrorDesc) {
129   - err := httpError{desc, r.Method + " " + r.RequestURI}
130   - w.WriteHeader(code)
131   - json.NewEncoder(w).Encode(err)
132   -}
133   -
134   -// NotFoundResponse writes HTTP error 404 to w.
135   -func NotFoundResponse(w http.ResponseWriter, req *http.Request) {
136   - ErrorResponse(w, req, http.StatusNotFound, []HttpErrorDesc{
137   - {"en", templateHttpErr404_EN},
138   - {"rs", templateHttpErr404_RS},
139   - })
140   -}
141   -
142   -// BadRequestResponse writes HTTP error 400 to w.
143   -func BadRequestResponse(w http.ResponseWriter, req *http.Request) {
144   - ErrorResponse(w, req, http.StatusBadRequest, []HttpErrorDesc{
145   - {"en", templateHttpErr400_EN},
146   - {"rs", templateHttpErr400_RS},
147   - })
148   -}
149   -
150   -// InternalSeverErrorResponse writes HTTP error 500 to w.
151   -func InternalServerErrorResponse(w http.ResponseWriter, req *http.Request) {
152   - ErrorResponse(w, req, http.StatusInternalServerError, []HttpErrorDesc{
153   - {"en", templateHttpErr500_EN},
154   - {"rs", templateHttpErr500_RS},
155   - })
156   -}
157   -
158   -// UnauthorizedError writes HTTP error 401 to w.
159   -func UnauthorizedResponse(w http.ResponseWriter, req *http.Request) {
160   - w.Header().Set("WWW-Authenticate", "Bearer")
161   - ErrorResponse(w, req, http.StatusUnauthorized, []HttpErrorDesc{
162   - {"en", templateHttpErr401_EN},
163   - {"rs", templateHttpErr401_RS},
164   - })
165   -}
... ...
... ... @@ -14,8 +14,9 @@ import (
14 14 )
15 15  
16 16 var (
17   - mu = &sync.Mutex{}
18   - metadata = make(map[string]Payload)
  17 + mu = &sync.Mutex{}
  18 + metadata = make(map[string]Payload)
  19 +
19 20 updateQue = make(map[string][]byte)
20 21  
21 22 metadataDB *sql.DB
... ...
... ... @@ -4,9 +4,11 @@ import (
4 4 "encoding/json"
5 5 "errors"
6 6 "io/ioutil"
  7 + "sync"
7 8 )
8 9  
9 10 type Dictionary struct {
  11 + my sync.Mutex
10 12 locales map[string]map[string]string
11 13 supported []string
12 14 defaultLocale string
... ... @@ -34,6 +36,9 @@ func (d *Dictionary) AddLocale(loc, filePath string) error {
34 36 for k, v := range data.(map[string]interface{}) {
35 37 l[k] = v.(string)
36 38 }
  39 +
  40 + mu.Lock()
  41 + defer mu.Unlock()
37 42 d.locales[loc] = l
38 43 d.supported = append(d.supported, loc)
39 44  
... ...
... ... @@ -7,9 +7,7 @@ import (
7 7 "git.to-net.rs/marko.tikvic/gologger"
8 8 )
9 9  
10   -var reqLogger *gologger.Logger
11   -
12   -func WithSetHeaders(h http.HandlerFunc) http.HandlerFunc {
  10 +func SetHeaders(h http.HandlerFunc) http.HandlerFunc {
13 11 return func(w http.ResponseWriter, req *http.Request) {
14 12 SetDefaultHeaders(w)
15 13 if req.Method == http.MethodOptions {
... ... @@ -19,7 +17,7 @@ func WithSetHeaders(h http.HandlerFunc) http.HandlerFunc {
19 17 }
20 18 }
21 19  
22   -func WithParseForm(h http.HandlerFunc) http.HandlerFunc {
  20 +func ParseForm(h http.HandlerFunc) http.HandlerFunc {
23 21 return func(w http.ResponseWriter, req *http.Request) {
24 22 err := req.ParseForm()
25 23 if err != nil {
... ... @@ -30,13 +28,15 @@ func WithParseForm(h http.HandlerFunc) http.HandlerFunc {
30 28 }
31 29 }
32 30  
  31 +var reqLogger *gologger.Logger
  32 +
33 33 func EnableLogging(log string) error {
34 34 var err error
35 35 reqLogger, err = gologger.New(log, gologger.MaxLogSize5MB)
36 36 return err
37 37 }
38 38  
39   -func WithLog(h http.HandlerFunc) http.HandlerFunc {
  39 +func Log(h http.HandlerFunc) http.HandlerFunc {
40 40 return func(w http.ResponseWriter, req *http.Request) {
41 41 reqLogger.LogRequest(req, "")
42 42 t1 := time.Now()
... ... @@ -46,9 +46,9 @@ func WithLog(h http.HandlerFunc) http.HandlerFunc {
46 46 }
47 47 }
48 48  
49   -func WithAuth(authorizedRoles []string, h http.HandlerFunc) http.HandlerFunc {
  49 +func Auth(roles string, h http.HandlerFunc) http.HandlerFunc {
50 50 return func(w http.ResponseWriter, req *http.Request) {
51   - if _, ok := AuthCheck(req, authorizedRoles); !ok {
  51 + if _, ok := AuthCheck(req, roles); !ok {
52 52 Unauthorized(w, req, "")
53 53 return
54 54 }
... ...