added authorization policy & framework
This commit is contained in:
11
authorization_model.conf
Normal file
11
authorization_model.conf
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[request_definition]
|
||||||
|
r = role, objectsRole, orgRelation, objectsRelation, obj, act
|
||||||
|
|
||||||
|
[policy_definition]
|
||||||
|
p = role, objectsRole, orgRelation, objectsRelation, obj, act
|
||||||
|
|
||||||
|
[policy_effect]
|
||||||
|
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
|
||||||
|
|
||||||
|
[matchers]
|
||||||
|
m = keyMatch(r.role, p.role) && keyMatch(r.objectsRole, p.objectsRole) && keyMatch(r.objectsRelation, p.objectsRelation) && keyMatch(r.orgRelation, p.orgRelation) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*")
|
||||||
27
authorization_policy.csv
Normal file
27
authorization_policy.csv
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
p, *, *, *, *, /v1/authenticate/portal, POST
|
||||||
|
p, *, *, *, *, /health/, GET
|
||||||
|
p, *, *, *, [self], /v1/users/*/, GET
|
||||||
|
p, *, *, *, [self], /v1/users/portal/*, DELETE
|
||||||
|
p, *, *, *, [self], /v1/users/portal/*, POST
|
||||||
|
p, *, *, *, [self], /v1/users/portal/*, GET
|
||||||
|
p, *AD, *, *, *, /v1/users/, GET
|
||||||
|
p, BDCAD, BCBSIAD, *, [other], /v1/users/*/, GET
|
||||||
|
p, BDCAD, BCBSIAD, *, [other], /v1/users/portal/*, DELETE
|
||||||
|
p, BDCAD, BCBSIAD, *, [other], /v1/users/portal/*, POST
|
||||||
|
p, BDCAD, BCBSIAD, *, [other], /v1/users/portal/*, GET
|
||||||
|
p, BDCAD, PLANAD, *, [other], /v1/users/*/, GET
|
||||||
|
p, BDCAD, PLANAD, *, [other], /v1/users/portal/*, DELETE
|
||||||
|
p, BDCAD, PLANAD, *, [other], /v1/users/portal/*, POST
|
||||||
|
p, BDCAD, PLANAD, *, [other], /v1/users/portal/*, GET
|
||||||
|
p, BCBSIAD, SP, *, [other], /v1/users/*/, GET
|
||||||
|
p, BCBSIAD, SP, *, [other], /v1/users/portal/*, DELETE
|
||||||
|
p, BCBSIAD, SP, *, [other], /v1/users/portal/*, POST
|
||||||
|
p, BCBSIAD, SP, *, [other], /v1/users/portal/*, GET
|
||||||
|
p, BCBSIAD, US, *, [other], /v1/users/*/, GET
|
||||||
|
p, BCBSIAD, US, *, [other], /v1/users/portal/*, DELETE
|
||||||
|
p, BCBSIAD, US, *, [other], /v1/users/portal/*, POST
|
||||||
|
p, BCBSIAD, US, *, [other], /v1/users/portal/*, GET
|
||||||
|
p, PLANAD, US, [equal], [other], /v1/users/*/, GET
|
||||||
|
p, PLANAD, US, [equal], [other], /v1/users/portal/*, DELETE
|
||||||
|
p, PLANAD, US, [equal], [other], /v1/users/portal/*, POST
|
||||||
|
p, PLANAD, US, [equal], [other], /v1/users/portal/*, GET
|
||||||
|
@@ -42,3 +42,5 @@ import:
|
|||||||
- package: github.com/ttacon/builder
|
- package: github.com/ttacon/builder
|
||||||
- package: github.com/casbin/casbin
|
- package: github.com/casbin/casbin
|
||||||
version: ~1.5.0
|
version: ~1.5.0
|
||||||
|
- package: github.com/Knetic/govaluate
|
||||||
|
version: 9aa49832a739dcd78a5542ff189fb82c3e423116
|
||||||
|
|||||||
@@ -52,16 +52,16 @@ func (s *Server) Run() error {
|
|||||||
|
|
||||||
s.srv.Debug = s.cfg.App.Debug
|
s.srv.Debug = s.cfg.App.Debug
|
||||||
|
|
||||||
err := serverconfig.SetMiddlewares(s.srv, s.cfg, s.log, s.svc)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
entityMapper := entitymapping.New()
|
entityMapper := entitymapping.New()
|
||||||
notificationService := notificationservice.New(s.svc, entityMapper, s.cfg, s.cache)
|
notificationService := notificationservice.New(s.svc, entityMapper, s.cfg, s.cache)
|
||||||
appService := applicationservice.New(s.svc, entityMapper, notificationService, s.cfg)
|
appService := applicationservice.New(s.svc, entityMapper, notificationService, s.cfg)
|
||||||
tncService := tncservice.New(s.svc, entityMapper, s.cfg, notificationService)
|
tncService := tncservice.New(s.svc, entityMapper, s.cfg, notificationService)
|
||||||
|
|
||||||
|
err := serverconfig.SetMiddlewares(s.srv, s.cfg, s.log, s.svc, appService)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
router.Register(s.srv, s.cfg, appService, tncService, notificationService)
|
router.Register(s.srv, s.cfg, appService, tncService, notificationService)
|
||||||
|
|
||||||
err = s.srv.Start(fmt.Sprintf(":%d", s.cfg.HTTP.Port))
|
err = s.srv.Start(fmt.Sprintf(":%d", s.cfg.HTTP.Port))
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package serverconfig
|
package serverconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
|
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
|
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/infra/auth"
|
"bitbucket.org/nemt/nemt-portal-api/infra/auth"
|
||||||
@@ -44,6 +46,8 @@ func MiddlewareWithConfig(cfg *config.Config, svc *applicationservice.Service, l
|
|||||||
|
|
||||||
config := &DefaultConfig
|
config := &DefaultConfig
|
||||||
|
|
||||||
|
config.Enforcer = casbin.NewEnforcer("authorization_model.conf", "authorization_policy.csv")
|
||||||
|
|
||||||
config.Svc = svc
|
config.Svc = svc
|
||||||
config.Logger = log
|
config.Logger = log
|
||||||
config.Application = cfg
|
config.Application = cfg
|
||||||
@@ -68,26 +72,100 @@ func setAuthorizationMiddleware(e *echo.Echo, log *logger.Logger, cfg *config.Co
|
|||||||
func (a *Config) CheckPermission(c echo.Context) bool {
|
func (a *Config) CheckPermission(c echo.Context) bool {
|
||||||
user, err := auth.GetUserDetail(c, a.Application)
|
user, err := auth.GetUserDetail(c, a.Application)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.Logger.Warningf("Cannot get user details. %v ", err)
|
a.Logger.Warningf("Cannot get user details. %v\n", err)
|
||||||
|
user = viewmodel.User{}
|
||||||
}
|
}
|
||||||
method := c.Request().Method
|
method := c.Request().Method
|
||||||
path := c.Request().URL.Path
|
path := c.Request().URL.Path
|
||||||
//objectOrganization := a.organizationGoverningObject(c, user)
|
objectOrganization := a.organizationGoverningObject(c, user)
|
||||||
|
objectRole := a.roleGoverningObject(c, user)
|
||||||
|
|
||||||
return a.Enforcer.Enforce(user, path, method)
|
currentUsersOrganization := viewmodel.Organization{}
|
||||||
|
if len(user.Organizations) > 0 {
|
||||||
|
currentUsersOrganization = user.Organizations[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentUsersRole := viewmodel.Profile{}
|
||||||
|
if len(user.Profiles) > 0 {
|
||||||
|
currentUsersRole = user.Profiles[0]
|
||||||
|
}
|
||||||
|
orgRelation := organizationsRelation(currentUsersOrganization, objectOrganization)
|
||||||
|
objRelation := a.objectRelation(c, user)
|
||||||
|
|
||||||
|
// parameters to Enforce must match the request section of the authorization model
|
||||||
|
return a.Enforcer.Enforce(currentUsersRole.Key, objectRole.Key, orgRelation, objRelation, path, method)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// organizationGoverningObject returns the organization that is the owner of the object that is being accessed
|
||||||
|
// in case object exists and returns users role if it is a new object
|
||||||
func (a *Config) organizationGoverningObject(c echo.Context, userDetails viewmodel.User) (result viewmodel.Organization) {
|
func (a *Config) organizationGoverningObject(c echo.Context, userDetails viewmodel.User) (result viewmodel.Organization) {
|
||||||
|
|
||||||
existingUser := strings.Contains(c.Request().URL.Path, "/users") && len(c.ParamValues()) > 0
|
fmt.Println("***************")
|
||||||
newUser := strings.Contains(c.Request().URL.Path, "/users") && len(c.ParamValues()) <= 0
|
fmt.Println(c.ParamValues())
|
||||||
|
fmt.Println("***************")
|
||||||
|
existingUser := strings.Contains(c.Request().URL.Path, "/users") && len(c.ParamValues()) > 1
|
||||||
|
newUser := strings.Contains(c.Request().URL.Path, "/users") && len(c.ParamValues()) <= 1
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case existingUser:
|
case existingUser:
|
||||||
user, _ := a.Svc.Users.GetByUUID(c.ParamValues()[0], "")
|
user, _ := a.Svc.Users.GetByUUID(c.ParamValues()[1], "")
|
||||||
result = user.Organizations[0]
|
result = user.Organizations[0]
|
||||||
case newUser:
|
case newUser && len(userDetails.Organizations) > 0:
|
||||||
result = userDetails.Organizations[0]
|
result = userDetails.Organizations[0]
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// organizationGoverningObject returns the role that is the owner of the object that is being accessed
|
||||||
|
// in case object exists and returns users role if it is a new object
|
||||||
|
func (a *Config) roleGoverningObject(c echo.Context, userDetails viewmodel.User) (result viewmodel.Profile) {
|
||||||
|
|
||||||
|
existingUser := strings.Contains(c.Request().URL.Path, "/users") && len(c.ParamValues()) > 1
|
||||||
|
newUser := strings.Contains(c.Request().URL.Path, "/users") && len(c.ParamValues()) <= 1
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case existingUser:
|
||||||
|
user, _ := a.Svc.Users.GetByUUID(c.ParamValues()[1], "")
|
||||||
|
result = user.Profiles[0]
|
||||||
|
case newUser && len(userDetails.Organizations) > 0:
|
||||||
|
result = userDetails.Profiles[0]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func organizationsRelation(requestOrganization, currentUsersOrganization viewmodel.Organization) string {
|
||||||
|
if requestOrganization.UUID == currentUsersOrganization.UUID {
|
||||||
|
return "[equal]"
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, childOrg := range currentUsersOrganization.ChildOrgs {
|
||||||
|
if childOrg.UUID == requestOrganization.UUID {
|
||||||
|
return "[equal-or-child]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, childOrg := range requestOrganization.ChildOrgs {
|
||||||
|
if childOrg.UUID == currentUsersOrganization.UUID {
|
||||||
|
return "[parent]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "[unrelated]"
|
||||||
|
}
|
||||||
|
|
||||||
|
// organizationGoverningObject returns the role that is the owner of the object that is being accessed
|
||||||
|
// in case object exists and returns users role if it is a new object
|
||||||
|
func (a *Config) objectRelation(c echo.Context, userDetails viewmodel.User) string {
|
||||||
|
|
||||||
|
existingUser := strings.Contains(c.Request().URL.Path, "/users") && len(c.ParamValues()) > 1
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case existingUser:
|
||||||
|
user, _ := a.Svc.Users.GetByUUID(c.ParamValues()[1], "")
|
||||||
|
if user.ID == userDetails.ID {
|
||||||
|
return "[self]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "[other]"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package serverconfig
|
package serverconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/domain/service"
|
"bitbucket.org/nemt/nemt-portal-api/domain/service"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
|
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
|
||||||
@@ -9,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// SetMiddlewares attaches middlewares to server
|
// SetMiddlewares attaches middlewares to server
|
||||||
func SetMiddlewares(server *echo.Echo, cfg *config.Config, log *logger.Logger, svc *service.Service) error {
|
func SetMiddlewares(server *echo.Echo, cfg *config.Config, log *logger.Logger, svc *service.Service, appsvc *applicationservice.Service) error {
|
||||||
setRecoverMiddleware(server)
|
setRecoverMiddleware(server)
|
||||||
setGZIPMiddleware(server)
|
setGZIPMiddleware(server)
|
||||||
setRequestIDMiddleware(server)
|
setRequestIDMiddleware(server)
|
||||||
@@ -17,7 +18,7 @@ func SetMiddlewares(server *echo.Echo, cfg *config.Config, log *logger.Logger, s
|
|||||||
setCORSMiddleware(server, cfg)
|
setCORSMiddleware(server, cfg)
|
||||||
setBodyLimitMiddleware(server)
|
setBodyLimitMiddleware(server)
|
||||||
setRateLimitMiddleware(server)
|
setRateLimitMiddleware(server)
|
||||||
//setAuthorizationMiddleware(server, log, svc)
|
setAuthorizationMiddleware(server, log, cfg, appsvc)
|
||||||
|
|
||||||
err := setJWTMiddleware(server, cfg)
|
err := setJWTMiddleware(server, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user