-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from ihippik/dev
Dev
- Loading branch information
Showing
7 changed files
with
171 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package relyingparty | ||
|
||
type err struct { | ||
Code string `json:"code"` | ||
ErrMsg string `json:"errMessage"` | ||
} | ||
|
||
const ( | ||
invalidTokenClaims = "INVALID_TOKEN_CLAIMS" | ||
tokenExpired = "TOKEN_EXPIRED" | ||
invalidToken = "INVALID_TOKEN" | ||
roleNotMatch = "ROLE_NOT_MATCH" | ||
) | ||
|
||
// custom errors. | ||
var ( | ||
tokenExpiredErr = &err{ | ||
Code: tokenExpired, | ||
ErrMsg: "token expired", | ||
} | ||
|
||
invalidUserIDErr = &err{ | ||
Code: invalidTokenClaims, | ||
ErrMsg: "invalid user id err", | ||
} | ||
|
||
invalidUserRoleErr = &err{ | ||
Code: invalidTokenClaims, | ||
ErrMsg: "user role not exists", | ||
} | ||
|
||
accessDenied = &err{ | ||
Code: roleNotMatch, | ||
ErrMsg: "access for the role denied", | ||
} | ||
) | ||
|
||
// newErr create new err with specific code & msg. | ||
func newErr(code string, msg string) *err { | ||
return &err{ | ||
Code: code, | ||
ErrMsg: msg, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,112 @@ | ||
package relyingparty | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"strings" | ||
|
||
"github.com/devopsfaith/krakend/config" | ||
"github.com/devopsfaith/krakend/proxy" | ||
krakendgin "github.com/devopsfaith/krakend/router/gin" | ||
"github.com/dgrijalva/jwt-go" | ||
"github.com/gin-gonic/gin" | ||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
// EndpointMw is a function that decorates the received handlerFunc with | ||
// gateway's own logic. | ||
type EndpointMw func(gin.HandlerFunc) gin.HandlerFunc | ||
|
||
const ( | ||
namespace = "gitlab.com/r-stat/krakend-mw/relyingparty" | ||
namespace = "github.com/ihippik/krakend-mw/relyingparty" | ||
HeaderAuthorization = "Authorization" | ||
HeaderUserID = "User-Id" | ||
TokenType = "Bearer" | ||
) | ||
|
||
type EndpointMw func(gin.HandlerFunc) gin.HandlerFunc | ||
|
||
// NewHandlerFactory builds a oauth2 wrapper over the received handler factory. | ||
func NewHandlerFactory(next krakendgin.HandlerFactory, sf *RelyingParty) krakendgin.HandlerFactory { | ||
// Run for each endpoints. | ||
func NewHandlerFactory(next krakendgin.HandlerFactory, rp *RelyingParty) krakendgin.HandlerFactory { | ||
return func(remote *config.EndpointConfig, p proxy.Proxy) gin.HandlerFunc { | ||
handlerFunc := next(remote, p) | ||
|
||
_, ok := remote.ExtraConfig[namespace] | ||
eCfg, ok := remote.ExtraConfig[namespace] | ||
if !ok { | ||
return handlerFunc | ||
} | ||
|
||
return newEndpointSelfHostMw(sf)(handlerFunc) | ||
rp.endpointCfg = getEpConfig(eCfg) | ||
return newEndpointRelyingPartyMw(rp)(handlerFunc) | ||
} | ||
} | ||
|
||
// newEndpointSelfHostMw is the handler middlware that represents endpoints of | ||
// newEndpointRelyingPartyMw is the handler middlware that represents endpoints of | ||
// gateway itself. | ||
func newEndpointSelfHostMw(sf *RelyingParty) EndpointMw { | ||
func newEndpointRelyingPartyMw(rp *RelyingParty) EndpointMw { | ||
return func(next gin.HandlerFunc) gin.HandlerFunc { | ||
return func(c *gin.Context) { | ||
// Return config in response. | ||
c.AbortWithStatusJSON(http.StatusOK, sf.cfg) | ||
logrus.Info("SF: config provided.") | ||
userToken := c.GetHeader(HeaderAuthorization) | ||
if len(userToken) == 0 { | ||
logrus.Warnln("empty user token") | ||
c.AbortWithStatusJSON(http.StatusUnauthorized, newErr(invalidToken, "token not exists")) | ||
return | ||
} | ||
items := strings.Split(userToken, " ") | ||
if len(items) != 2 || items[0] != TokenType { | ||
logrus.Warnln("invalid token") | ||
c.AbortWithStatusJSON(http.StatusUnauthorized, newErr(invalidToken, "token is malformed")) | ||
return | ||
} | ||
|
||
token, err := jwt.Parse(items[1], func(token *jwt.Token) (interface{}, error) { | ||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { | ||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) | ||
} | ||
return []byte(rp.cfg.TokenSecret), nil | ||
}) | ||
if err != nil { | ||
logrus.WithError(err).Warnln("parse token err") | ||
c.AbortWithStatusJSON(http.StatusUnauthorized, tokenExpiredErr) | ||
return | ||
} | ||
|
||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { | ||
userID, ok := claims["user_id"].(string) | ||
if !ok { | ||
logrus.Warnln("user id in claims not exist") | ||
c.AbortWithStatusJSON(http.StatusUnauthorized, invalidUserIDErr) | ||
return | ||
} | ||
userRole, ok := claims["user_role"].(string) | ||
if !ok { | ||
logrus.Warnln("user role in claims not exist") | ||
c.AbortWithStatusJSON(http.StatusUnauthorized, invalidUserRoleErr) | ||
return | ||
} | ||
if !matchRoles(userRole, rp.endpointCfg.Roles) { | ||
logrus.WithField("role", userRole).Warnln("access denied") | ||
c.AbortWithStatusJSON(http.StatusForbidden, accessDenied) | ||
return | ||
} | ||
c.Request.Header.Set(HeaderUserID, userID) | ||
} else { | ||
logrus.WithError(err).Warnln("claims err") | ||
c.AbortWithStatusJSON( | ||
http.StatusUnauthorized, | ||
newErr( | ||
invalidTokenClaims, | ||
err.Error(), | ||
), | ||
) | ||
return | ||
} | ||
next(c) | ||
} | ||
} | ||
} | ||
|
||
// matchRoles looking for matching roles | ||
func matchRoles(userRole string, acceptRoles []string) bool { | ||
for _, r := range acceptRoles { | ||
if r == userRole { | ||
return true | ||
} | ||
} | ||
return false | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters