diff --git a/auth_utility.go b/auth_utility.go index 1675b54..e0d161b 100644 --- a/auth_utility.go +++ b/auth_utility.go @@ -7,7 +7,10 @@ import ( "crypto/rand" "encoding/hex" "strings" + "net/http" + "github.com/dgrijalva/jwt-go" + "fmt" ) const OneDay = time.Hour*24 @@ -16,6 +19,11 @@ const saltSize = 32 const appName = "korisnicki-centar" const secret = "korisnicki-centar-api" +const RoleAdmin string = "ADMINISTRATOR" +const RoleManager string = "RUKOVODILAC" +const RoleReporter string = "REPORTER" +const RoleOperator string = "OPERATER" + // TokenClaims are JWT token claims. type TokenClaims struct { Username string `json:"username"` @@ -152,7 +160,43 @@ func ParseAPIToken(tokenString string) (*TokenClaims, error) { return claims, nil } +func GetTokenClaims(r *http.Request) (claims *TokenClaims, err error) { + token := r.Header.Get("Authorization") + if ok := strings.HasPrefix(token, "Bearer "); ok { + token = strings.TrimPrefix(token, "Bearer ") + } else { + return &TokenClaims{}, errors.New("Authorization header is incomplete") + } + + parsedToken, err := jwt.ParseWithClaims(token, &TokenClaims{}, secretFunc) + if err != nil { + return &TokenClaims{}, err + } + + // type assertion + claims, ok := parsedToken.Claims.(*TokenClaims) + if !ok || !parsedToken.Valid { + return &TokenClaims{}, errors.New("token is not valid") + } + return claims, err +} + // secretFunc returns byte slice of API secret keyword. func secretFunc(token *jwt.Token) (interface{}, error) { return []byte(secret), nil } + +// roleAuthorized returns true if role from userClaims matches any of the authorizedRoles +// or if authorizedRoles contains "*". +func roleAuthorized(authorizedRoles []string, userClaims *TokenClaims) bool { + if userClaims == nil { + return false + } + for _, r := range authorizedRoles { + fmt.Printf("comparing %s with %s\n", userClaims.Role, r) + if userClaims.Role == r || r == "*" { + return true + } + } + return false +} diff --git a/http_utility.go b/http_utility.go index c187b47..05dd2ee 100644 --- a/http_utility.go +++ b/http_utility.go @@ -3,6 +3,7 @@ package webutility import ( "net/http" "encoding/json" + "fmt" ) const templateHttpErr500_EN = "An internal server error has occurred." @@ -54,9 +55,9 @@ func UnauthorizedResponse(w http.ResponseWriter, req *http.Request) { } // TODO: Check for content type -// WrapHandler sets common headers, checks for token validity and performs access control. +// WrapHandler sets common headers, checks for token validity and performs access control checks. // If authentication passes it calls the handlerFunc. -func WrapHandler(handlerFunc http.HandlerFunc, auth bool) http.HandlerFunc { +func WrapHandler(handlerFunc http.HandlerFunc, authorizedRoles []string) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") @@ -73,9 +74,11 @@ func WrapHandler(handlerFunc http.HandlerFunc, auth bool) http.HandlerFunc { return } - if auth { + if authorizedRoles != nil { token := req.Header.Get("Authorization") - if _, err := ParseAPIToken(token); err != nil { + claims, err := ParseAPIToken(token); + if err != nil || !roleAuthorized(authorizedRoles, claims) { + fmt.Printf("not authorized %s %s...\n", claims.Username, claims.Role) UnauthorizedResponse(w, req) return } diff --git a/json_utility.go b/json_utility.go index eab04a9..b4b53b8 100644 --- a/json_utility.go +++ b/json_utility.go @@ -171,11 +171,16 @@ func fetchJSON(db *ora.Ses, project string) ([]byte, error) { bytes := make([]byte, 0) if rset.Next() { lob := rset.Row[0].(io.Reader) - bytes, err = ioutil.ReadAll(lob) - if err != nil { - // Ignore for now, it's some weird streaming read/write LOB error. - // TODO: Find a fix for this. - //return nil, err + if lob != nil { + bytes, err = ioutil.ReadAll(lob) + if err != nil { + // TODO: Find a fix for this. + // Some weird streaming read/write LOB error. + // Ignore for now. + //return nil, err + } + } else { + return nil, errors.New("json config is null") } }