Skip to content

Commit

Permalink
added new functions
Browse files Browse the repository at this point in the history
improved the code documentation
  • Loading branch information
ixtendio committed Jan 10, 2023
1 parent a1c2656 commit 90be3bd
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 34 deletions.
12 changes: 9 additions & 3 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,16 @@ func (g Group) HasPermission(permission Permission) bool {

// A User implements SecurityPrincipal and represents an authenticated person
type User struct {
Id string
Name string
// the user internal id
Id string
// the name of user
Name string
// the id/name of the platform were the user was authenticated (for example Google, Linkedin, Internal, etc)
IdentityPlatform string
Groups []Group
// the security groups where this user belongs
Groups []Group
// a field where any additional data to this user can be attached
Attachment any
}

func (u User) Identity() string {
Expand Down
50 changes: 32 additions & 18 deletions middleware/authz.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,56 @@ import (
"github.com/ixtendio/gofre/response"
)

type PermissionsSupplierFunc func(ctx context.Context, mc path.MatchingContext) ([]auth.Permission, error)

// AuthorizeAll checks if the authenticated auth.SecurityPrincipal has all the requested permissions
// An errors.ErrUnauthorizedRequest error is returned if not all permissions are allowed to be executed
// by the current auth.SecurityPrincipal
func AuthorizeAll(permissions ...auth.Permission) Middleware {
return func(handler handler.Handler) handler.Handler {
return func(ctx context.Context, mc path.MatchingContext) (resp response.HttpResponse, err error) {
securityPrincipal := auth.GetSecurityPrincipalFromContext(ctx)
if securityPrincipal == nil {
return nil, errors.ErrUnauthorizedRequest
}
for _, permission := range permissions {
if !securityPrincipal.HasPermission(permission) {
return nil, errors.ErrUnauthorizedRequest
}
}
return handler(ctx, mc)
}
}
return Authorize(func(ctx context.Context, mc path.MatchingContext) ([]auth.Permission, error) {
return permissions, nil
}, true)
}

// AuthorizeAny checks if the authenticated auth.SecurityPrincipal has at least one from the requested permissions
// An errors.ErrUnauthorizedRequest error is returned if not at least one permission is allowed to be executed
// by the current auth.SecurityPrincipal
func AuthorizeAny(permissions ...auth.Permission) Middleware {
return Authorize(func(ctx context.Context, mc path.MatchingContext) ([]auth.Permission, error) {
return permissions, nil
}, false)
}

// Authorize checks if the authenticated auth.SecurityPrincipal has all permission if the parameter matchAllPermissions is true
// or at least one permission, otherwise
// An errors.ErrUnauthorizedRequest error is returned if not at least one permission is allowed to be executed
// by the current auth.SecurityPrincipal
func Authorize(supplier PermissionsSupplierFunc, matchAllPermissions bool) Middleware {
return func(handler handler.Handler) handler.Handler {
return func(ctx context.Context, mc path.MatchingContext) (resp response.HttpResponse, err error) {
permissions, err := supplier(ctx, mc)
if err != nil {
return nil, err
}
securityPrincipal := auth.GetSecurityPrincipalFromContext(ctx)
if securityPrincipal == nil {
return nil, errors.ErrUnauthorizedRequest
}
for _, permission := range permissions {
if securityPrincipal.HasPermission(permission) {
return handler(ctx, mc)
if matchAllPermissions {
for _, permission := range permissions {
if !securityPrincipal.HasPermission(permission) {
return nil, errors.ErrUnauthorizedRequest
}
}
return handler(ctx, mc)
} else {
for _, permission := range permissions {
if securityPrincipal.HasPermission(permission) {
return handler(ctx, mc)
}
}
return nil, errors.ErrUnauthorizedRequest
}
return nil, errors.ErrUnauthorizedRequest
}
}
}
31 changes: 18 additions & 13 deletions middleware/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,22 @@ import (

type ResponseSupplier func(statusCode int, err error) response.HttpResponse

// ErrJsonResponse translate an error to a JSON error response
// Error2HttpStatusCode translates an error to an HTTP status code
var Error2HttpStatusCode = func(err error) int {
if _, ok := err.(errors.ErrBadRequest); ok {
return http.StatusBadRequest
} else if _, ok := err.(errors.ErrObjectNotFound); ok {
return http.StatusNotFound
} else if err == errors.ErrUnauthorizedRequest {
return http.StatusUnauthorized
} else if err == errors.ErrWrongCredentials ||
err == errors.ErrAccessDenied {
return http.StatusForbidden
}
return http.StatusInternalServerError
}

// ErrJsonResponse translates an error to a JSON response
func ErrJsonResponse() Middleware {
return ErrResponse(func(statusCode int, err error) response.HttpResponse {
return response.JsonHttpResponse(statusCode, map[string]string{
Expand All @@ -21,23 +36,13 @@ func ErrJsonResponse() Middleware {
})
}

// ErrResponse translate an error to an response.HttpResponse
// ErrResponse translates an error to an response.HttpResponse
func ErrResponse(responseSupplier ResponseSupplier) Middleware {
return func(handler handler.Handler) handler.Handler {
return func(ctx context.Context, mc path.MatchingContext) (response.HttpResponse, error) {
resp, err := handler(ctx, mc)
if err != nil {
statusCode := http.StatusInternalServerError
if _, ok := err.(errors.ErrBadRequest); ok {
statusCode = http.StatusBadRequest
} else if _, ok := err.(errors.ErrObjectNotFound); ok {
statusCode = http.StatusNotFound
} else if err == errors.ErrUnauthorizedRequest {
statusCode = http.StatusUnauthorized
} else if err == errors.ErrWrongCredentials ||
err == errors.ErrAccessDenied {
statusCode = http.StatusForbidden
}
statusCode := Error2HttpStatusCode(err)
return responseSupplier(statusCode, err), nil
}
return resp, err
Expand Down

0 comments on commit 90be3bd

Please sign in to comment.