Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 28 additions & 18 deletions service/internal/auth/authn.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ var (
}
)

const refreshInterval = 15 * time.Minute
const (
refreshInterval = 15 * time.Minute
ActionRead = "read"
ActionWrite = "write"
ActionDelete = "delete"
ActionUnsafe = "unsafe"
ActionOther = "other"
)

// Authentication holds a jwks cache and information about the openid configuration
type Authentication struct {
Expand Down Expand Up @@ -230,13 +237,13 @@ func (a Authentication) MuxHandler(handler http.Handler) http.Handler {
var action string
switch r.Method {
case http.MethodGet:
action = "read"
action = ActionRead
case http.MethodPost, http.MethodPut, http.MethodPatch:
action = "write"
action = ActionWrite
case http.MethodDelete:
action = "delete"
action = ActionDelete
default:
action = "unsafe"
action = ActionUnsafe
}
if allow, err := a.enforcer.Enforce(accessTok, r.URL.Path, action); err != nil {
if err.Error() == "permission denied" {
Expand Down Expand Up @@ -280,19 +287,7 @@ func (a Authentication) UnaryServerInterceptor(ctx context.Context, req any, inf
// parse the rpc method
p := strings.Split(info.FullMethod, "/")
resource := p[1] + "/" + p[2]
var action string
switch {
case strings.HasPrefix(p[2], "List") || strings.HasPrefix(p[2], "Get"):
action = "read"
case strings.HasPrefix(p[2], "Create") || strings.HasPrefix(p[2], "Update"):
action = "write"
case strings.HasPrefix(p[2], "Delete"):
action = "delete"
case strings.HasPrefix(p[2], "Unsafe"):
action = "unsafe"
default:
action = "other"
}
action := getAction(p[2])

token, newCtx, err := a.checkToken(
ctx,
Expand Down Expand Up @@ -322,6 +317,21 @@ func (a Authentication) UnaryServerInterceptor(ctx context.Context, req any, inf
return handler(newCtx, req)
}

// getAction returns the action based on the rpc name
func getAction(method string) string {
switch {
case strings.HasPrefix(method, "List") || strings.HasPrefix(method, "Get"):
return ActionRead
case strings.HasPrefix(method, "Create") || strings.HasPrefix(method, "Update") || strings.HasPrefix(method, "Assign"):
return ActionWrite
case strings.HasPrefix(method, "Delete") || strings.HasPrefix(method, "Remove") || strings.HasPrefix(method, "Deactivate"):
return ActionDelete
case strings.HasPrefix(method, "Unsafe"):
return ActionUnsafe
}
return ActionOther
}

// checkToken is a helper function to verify the token.
func (a Authentication) checkToken(ctx context.Context, authHeader []string, dpopInfo receiverInfo, dpopHeader []string) (jwt.Token, context.Context, error) {
var tokenRaw string
Expand Down
24 changes: 24 additions & 0 deletions service/internal/auth/authn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -658,3 +658,27 @@ func (s *AuthSuite) Test_PublicPath_Matches() {
s.Require().False(slices.ContainsFunc(s.auth.publicRoutes, s.auth.isPublicRoute("/private")))
s.Require().False(slices.ContainsFunc(s.auth.publicRoutes, s.auth.isPublicRoute("/public2/test/fail")))
}

func (s *AuthSuite) Test_GetAction() {
cases := []struct {
method string
expected string
}{
{"GetSomething", ActionRead},
{"CreateSomething", ActionWrite},
{"UpdateSomething", ActionWrite},
{"AssignSomething", ActionWrite},
{"DeleteSomething", ActionDelete},
{"RemoveSomething", ActionDelete},
{"DeactivateSomething", ActionDelete},
{"ListSomething", ActionRead},
{"UnsafeDelete", ActionUnsafe},
{"UnsafeUpdate", ActionUnsafe},
{"UnsafeActivate", ActionUnsafe},
{"UnsafeReactivate", ActionUnsafe},
{"DoSomething", ActionOther},
}
for _, c := range cases {
s.Equal(c.expected, getAction(c.method))
}
}