Compare commits

4 Commits

Author SHA1 Message Date
Senad Uka
282b0a0ee8 Upstream sync 2018-05-03 07:54:09 +02:00
GotPPay
c43ae352a3 fix bug with auth and query 2018-05-01 00:24:50 +02:00
Senad Uka
bc6bfdec46 Organizations update 2018-04-30 13:25:10 +02:00
Senad Uka
654e8a5817 added authorization policy & framework 2018-04-26 10:13:46 +02:00
18 changed files with 14 additions and 312 deletions

View File

@@ -79,23 +79,18 @@ p, *, *, *, *, *, *, /v1/nemt/organization/type, GET
p, AD, *, *, *, *, *, /v1/nemt/organization/*, GET
p, AD, *, *, *, *, *, /v1/nemt/organization/*, POST
p, AD, *, *, *, *, *, /v1/nemt/organization/*, PUT
p, AD, *, *, *, *, *, /v1/nemt/organization/*, DELETE
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, GET
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, POST
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, PUT
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, DELETE
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, GET
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, POST
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, PUT
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, DELETE
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, GET
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, POST
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, PUT
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, DELETE
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, GET
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, POST
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, PUT
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, DELETE
p, SPT, *, programsupport, *, *, *, /v1/nemt/organization/*, GET
p, SP, *, provider, *, *, *, /v1/nemt/organization, GET
p, SP, *, plan, *, *, *, /v1/nemt/organization, GET
@@ -113,3 +108,4 @@ p, BCBSIAD, *, bcbsi, *, *, *, /v1/nemt/eligibility, POST
p, BDCAD, *, techsupport, *, *, *, /v1/nemt/eligibility, POST
p, PLANAD, *, plan, *, *, *, /v1/nemt/eligibility, POST
p, AD, *, *, *, *, *, /v1/nemt/eligibility, POST
1 p AD * * * * * * *
79 p AD * * * * * /v1/nemt/organization/* GET
80 p AD * * * * * /v1/nemt/organization/* POST
81 p AD * * * * * /v1/nemt/organization/* PUT
p AD * * * * * /v1/nemt/organization/* DELETE
82 p SCHDAD * * * [equal*] * /v1/nemt/organization/* GET
83 p SCHDAD * * * [equal*] * /v1/nemt/organization/* POST
84 p SCHDAD * * * [equal*] * /v1/nemt/organization/* PUT
p SCHDAD * * * [equal*] * /v1/nemt/organization/* DELETE
85 p PLANAD * * * [equal*] * /v1/nemt/organization/* GET
86 p PLANAD * * * [equal*] * /v1/nemt/organization/* POST
87 p PLANAD * * * [equal*] * /v1/nemt/organization/* PUT
p PLANAD * * * [equal*] * /v1/nemt/organization/* DELETE
88 p BDCAD * * * * * /v1/nemt/organization/* GET
89 p BDCAD * * * * * /v1/nemt/organization/* POST
90 p BDCAD * * * * * /v1/nemt/organization/* PUT
p BDCAD * * * * * /v1/nemt/organization/* DELETE
91 p BCBSIAD * * * * * /v1/nemt/organization/* GET
92 p BCBSIAD * * * * * /v1/nemt/organization/* POST
93 p BCBSIAD * * * * * /v1/nemt/organization/* PUT
p BCBSIAD * * * * * /v1/nemt/organization/* DELETE
94 p SPT * programsupport * * * /v1/nemt/organization/* GET
95 p SP * provider * * * /v1/nemt/organization GET
96 p SP * plan * * * /v1/nemt/organization GET
108 p BDCAD * techsupport * * * /v1/nemt/eligibility POST
109 p PLANAD * plan * * * /v1/nemt/eligibility POST
110 p AD * * * * * /v1/nemt/eligibility POST
111

View File

@@ -37,6 +37,7 @@ db = 0
pass = "3rdaP3KL2x%V"
prefix = "nemt-portal-api-dev"
default-expiration = "5m"
master-name = "devmaster01"
[log]
log-to-file = false

View File

@@ -37,6 +37,7 @@ db = 0
pass = "3rdaP3KL2x%V"
prefix = "portal-api-prod"
default-expiration = "5m"
master-name = "master01"
[log]
log-to-file = false

View File

@@ -37,6 +37,7 @@ db = 0
pass = "3rdaP3KL2x%V"
prefix = "portal-api-test"
default-expiration = "5m"
master-name = "devmaster01"
[log]
log-to-file = false

View File

@@ -80,7 +80,9 @@ func (c *notificationRepo) getQuery() string {
INNER JOIN tab_login e
ON c.user_id = e.user_id
INNER JOIN tab_login f
ON d.user_id = f.user_id`
ON d.user_id = f.user_id
INNER JOIN tab_ride g
ON g.ride_id = a.ride_id `
}
func (c *notificationRepo) GetLastNotificationFromPhoneNumber(notificationType string, phoneNumber string, status string) (entity.Notification, error) {

View File

@@ -31,10 +31,11 @@ type RedisCache struct {
func Instance(cfg *config.Config) contract.CacheManager {
once.Do(func() {
client := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: "master01",
MasterName: cfg.Cache.Master,
SentinelAddrs: []string{fmt.Sprintf("%s:%v", cfg.Cache.Server, cfg.Cache.Port)},
Password: cfg.Cache.Pass,
DB: cfg.Cache.DB,
MaxRetries: 10,
})
instance = &RedisCache{cfg, client}

View File

@@ -119,6 +119,7 @@ type CacheConfig struct {
Pass string
Prefix string
DefaultExpiration time.Duration
Master string
}
// CacheConfig represents the configuration values about the documentation config.
@@ -194,6 +195,7 @@ func Read() (*Config, error) {
Pass: viper.GetString("cache.pass"),
Prefix: viper.GetString("cache.prefix"),
DefaultExpiration: viper.GetDuration("cache.default-expiration"),
Master: viper.GetString("cache.master-name"),
},
Lyft: LyftConfig{
Client: viper.GetString("lyft.key"),

View File

@@ -1,15 +0,0 @@
package authorization
import (
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
)
func CanCreateAddress(user viewmodel.User, organization viewmodel.Organization) bool {
//rules are the same for address creation and for organization creation
return CanCreateOrganization(user, organization)
}
func CanUpdateAddress(user viewmodel.User, organization viewmodel.Organization) bool {
return CanCreateAddress(user, organization)
}

View File

@@ -1 +0,0 @@
package authorization

View File

@@ -1,15 +0,0 @@
package authorization
import (
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
)
func CanCreateContact(user viewmodel.User, organization viewmodel.Organization) bool {
//rules are the same for contact creation and for organization creation
return CanCreateOrganization(user, organization)
}
func CanUpdateContact(user viewmodel.User, organization viewmodel.Organization) bool {
return CanCreateAddress(user, organization)
}

View File

@@ -1,68 +0,0 @@
package authorization
import (
"fmt"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
)
func isAChildOrganization(potentialParent viewmodel.Organization, potentialChild viewmodel.Organization) bool {
for _, org := range potentialParent.ChildOrgs {
if potentialChild.UUID == org.UUID {
return true
}
}
return false
}
func isSameOrganization(organizationA viewmodel.Organization, organizationB viewmodel.Organization) bool {
return organizationA.UUID == organizationB.UUID
}
func grabOrgFromUser(user viewmodel.User) (viewmodel.Organization, error) {
if len(user.Organizations) < 1 {
return viewmodel.Organization{}, fmt.Errorf("User has no organizations %v", user)
}
return user.Organizations[0], nil
}
func CanCreateOrganization(user viewmodel.User, organization viewmodel.Organization ) bool {
userRole, err := grabProfileFromUser(user)
if err != nil {
return false
}
/*
Admin BCBSI
Admin Technical Support
Super Admin Technical Support
Manage all Organizations*/
if userRole.Key == bcbsiAdmin || userRole.Key == brighterDevAdmin || userRole.Key == superAdmin{
return true
}
userOrg, err := grabOrgFromUser(user)
if err != nil{
return false
}
/*
Admin Provider
Admin Plan
Manage the authenticated Authorized User's Organization and child Organizations */
if userRole.Key == providerAdmin || userRole.Key == planAdmin{
if isSameOrganization(userOrg, organization) || isAChildOrganization(userOrg, organization) {
return true
}
return false
}
return false
}
func CanUpdateOrganization(user viewmodel.User, organization viewmodel.Organization) bool{
return CanCreateOrganization(user, organization)
}

View File

@@ -1,62 +0,0 @@
package authorization
import (
"fmt"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
)
const (
superAdmin = "AD"
scheduler = "SP"
support = "SPT"
member = "US"
brighterDevAdmin = "BDCAD"
bcbsiAdmin = "BCBSIAD"
planAdmin = "PLANAD"
providerAdmin = "SCHDAD"
)
func grabProfileFromUser(user viewmodel.User) (viewmodel.Profile, error) {
if len(user.Profiles) < 1 {
return viewmodel.Profile{}, fmt.Errorf("User has no profiles %v", user)
}
return user.Profiles[0], nil
}
func morePrivileged(who viewmodel.Profile, towardsWhom viewmodel.Profile) bool {
order := []string{superAdmin, brighterDevAdmin, bcbsiAdmin, planAdmin, providerAdmin, support, scheduler, member}
for _, value := range order {
if value == who.Key {
return true
}
if value == towardsWhom.Key {
return false
}
}
// should hapen only in case profile key is empty
// and that's something fishy so let's deny!
return false
}
func equallyOrMorePrivileged(who viewmodel.Profile, towardsWhom viewmodel.Profile) bool {
if who.Key == towardsWhom.Key {
return true
}
return morePrivileged(who, towardsWhom)
}
func lessPrivilegedThanAdmin(who viewmodel.Profile) bool {
switch who.Key {
case member:
return true
case scheduler:
return true
case support:
return true
}
return false
}

View File

@@ -1,86 +0,0 @@
package authorization
import "bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
/*
CanCreateUser returns true if currentUser is allowed to create updatingUser according to
authorization rules
*/
func CanCreateUser(currentUser viewmodel.User, updatingUser viewmodel.User) bool {
if len(currentUser.Profiles) < 1 {
return false
}
if len(updatingUser.Profiles) < 1 {
return false
}
currentUserOrganization, err := grabOrgFromUser(currentUser)
if err != nil {
return false
}
updatingUserOrganization, err := grabOrgFromUser(updatingUser)
if err != nil {
return false
}
currentUserRole, err := grabProfileFromUser(currentUser)
if err != nil {
return false
}
updatingUserRole, err := grabProfileFromUser(updatingUser)
if err != nil {
return false
}
/*
Admin Provider
Manage all Authorized Users of the provider Organization or child organization
The (Provider) Admin can manage Authorized Users of their Parent/ Top-level Org , but not Admins
*/
currentUserHigherOrEqualOrg := isSameOrganization(currentUserOrganization, updatingUserOrganization) || isAChildOrganization(currentUserOrganization, updatingUserOrganization)
currentUserLowerOrg := isAChildOrganization(updatingUserOrganization, currentUserOrganization)
if currentUserRole.Key == providerAdmin && currentUserHigherOrEqualOrg && equallyOrMorePrivileged(currentUserRole, updatingUserRole) {
return true
}
if currentUserRole.Key == providerAdmin && currentUserLowerOrg && lessPrivilegedThanAdmin(updatingUserRole) {
return true
}
/* Admin BCBSI
Manage all Authorized Users except Admins
return false
*/
if currentUserRole.Key == bcbsiAdmin && lessPrivilegedThanAdmin(updatingUserRole) {
return true
}
/* Admin Technical Support Manage all Authorized Users except Admins */
if currentUserRole.Key == brighterDevAdmin && lessPrivilegedThanAdmin(updatingUserRole) {
return true
}
/* Admin Plan Manage all Authorized Users of a single participating Plan except Admins */
if currentUserRole.Key == planAdmin && lessPrivilegedThanAdmin(updatingUserRole) && isSameOrganization(currentUserOrganization, updatingUserOrganization) {
return true
}
/* Super Admin Technical Support
Manage all Members, INCLUDING Admins */
if currentUserRole.Key == superAdmin {
return true
}
return false
}

View File

@@ -10,7 +10,6 @@ import (
"bitbucket.org/nemt/nemt-portal-api/infra/cache"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
"bitbucket.org/nemt/nemt-portal-api/server/authorization"
"github.com/labstack/echo"
)
@@ -65,11 +64,6 @@ func (c *controller) handleAddOrganization(ctx echo.Context) error {
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if !authorization.CanCreateOrganization(authUser, org) {
return routeutils.ResponseAPIAuthorizationError(ctx)
}
org.Author.ID = authUser.ID
org.LastEditor.ID = authUser.ID
@@ -133,15 +127,6 @@ func (c *controller) handleParent(ctx echo.Context) error {
return routeutils.HandleAPIError(ctx, err)
}
organization, err := c.svc.Organization.GetByUUID(orgUUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if !authorization.CanUpdateOrganization(authUser, organization){
return routeutils.ResponseAPIAuthorizationError(ctx)
}
resp, err := c.svc.Organization.SetParentOrganization(orgUUID, parent.UUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
@@ -167,15 +152,6 @@ func (c *controller) handleChild(ctx echo.Context) error {
return routeutils.HandleAPIError(ctx, err)
}
organization, err := c.svc.Organization.GetByUUID(orgUUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if !authorization.CanUpdateOrganization(authUser, organization){
return routeutils.ResponseAPIAuthorizationError(ctx)
}
_, err = c.svc.Organization.SetParentOrganization(child.UUID, orgUUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
@@ -270,18 +246,6 @@ func (c *controller) handleAddAddress(ctx echo.Context) error {
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
organization, err := c.svc.Organization.GetByUUID(orgUUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if !authorization.CanCreateAddress(authUser, organization) {
return routeutils.ResponseAPIAuthorizationError(ctx)
}
return routeutils.ResponseAPIAuthorizationError(ctx)
address.CreatedUser.ID = authUser.ID
address.UpdatedUser.ID = authUser.ID
@@ -314,7 +278,6 @@ func (c *controller) handleRemoveContact(ctx echo.Context) error {
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
contact.UpdatedUser.ID = authUser.ID
err = c.svc.Organization.InactivateOrganizationContact(orgUUID, contact, authUser)
@@ -346,16 +309,6 @@ func (c *controller) handleAddContact(ctx echo.Context) error {
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
organization, err := c.svc.Organization.GetByUUID(orgUUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if !authorization.CanCreateContact(authUser, organization) {
return routeutils.ResponseAPIAuthorizationError(ctx)
}
contact.CreatedUser.ID = authUser.ID
contact.UpdatedUser.ID = authUser.ID

View File

@@ -49,11 +49,6 @@ func ResponseAPIAuthError(c echo.Context, message string, redirect bool) error {
return ResponseAPIError(c, http.StatusUnauthorized, message, redirect)
}
// ResponseAPIAuthorizationError returns a standard API auth error to the response
func ResponseAPIAuthorizationError(c echo.Context) error {
return ResponseAPIError(c, http.StatusForbidden, "Forbidden by controller", false)
}
// ResponseAPIServiceError returns a standard API service unavailable error to the response
func ResponseAPIServiceError(c echo.Context, message string) error {
return ResponseAPIError(c, http.StatusServiceUnavailable, message, false)

View File

@@ -13,7 +13,6 @@ import (
"bitbucket.org/nemt/nemt-portal-api/infra/auth"
"bitbucket.org/nemt/nemt-portal-api/infra/cache"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/server/authorization"
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
"github.com/labstack/echo"
)
@@ -390,10 +389,6 @@ func (c *controller) handlePortal(ctx echo.Context) error {
return routeutils.HandleAPIError(ctx, err)
}
if !authorization.CanCreateUser(authUser, user) {
return routeutils.ResponseAPIAuthorizationError(ctx)
}
if len(user.Profiles) == 0 {
return routeutils.ResponseAPIAuthError(ctx, "profile is required", false)
}

View File

@@ -193,6 +193,8 @@ func (a *Config) objectRelation(object interface{}, currentUser viewmodel.User)
case viewmodel.User:
if obj.ID == currentUser.ID {
return "[self]"
} else {
return "[other]"
}
}
return "[other]"

View File

@@ -18,7 +18,7 @@ func SetMiddlewares(server *echo.Echo, cfg *config.Config, log *logger.Logger, s
setCORSMiddleware(server, cfg)
setBodyLimitMiddleware(server)
setRateLimitMiddleware(server)
setAuthorizationMiddleware(server, log, cfg, appsvc)
//setAuthorizationMiddleware(server, log, cfg, appsvc)
err := setJWTMiddleware(server, cfg)
if err != nil {