Commit 3fffcb954a1cc48a4bfe8823c655015cfd70c93b
1 parent
1b7dfab733
Exists in
master
and in
1 other branch
removed old http API
Showing
5 changed files
with
43 additions
and
139 deletions
Show diff stats
auth.go
... | ... | @@ -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 | ... | ... |
http.go
... | ... | @@ -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 | -} | ... | ... |
json.go
localization.go
... | ... | @@ -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 | ... | ... |
middleware.go
... | ... | @@ -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 | } | ... | ... |