Documentation
¶
Index ¶
- Constants
- func AssertPermission(ctx corectx.Context, requiredPerm Perm) *ft.ClientErrors
- func BuildExpression(actionCode string, resourceCode string, scope ResourceScope, scopeId *model.Id) string
- func CandidateExpressions(required Perm, evalCtx EvalContext) []string
- func IsKnownScope(scope ResourceScope) bool
- func OmnipotentExpression() string
- type EvalContext
- type ExtGetUserEntitlementsQuery
- type ExtGetUserEntitlementsResult
- type ExtGetUserEntitlementsResultData
- type GetUserEntitlementsQuery
- type GetUserEntitlementsResult
- type GetUserEntitlementsResultData
- type ParsedExpression
- type Perm
- type PermissionContext
- type RequestGuardService
- type ResourceScope
- type StaticRequestGuardServiceImpl
- func (this *StaticRequestGuardServiceImpl) CalcRequestFingerprint(_ corectx.Context, request *http.Request) (fingerprint string, err error)
- func (this *StaticRequestGuardServiceImpl) GetCorsMiddleware(_ corectx.Context) (echo.MiddlewareFunc, error)
- func (this *StaticRequestGuardServiceImpl) GetUserEntitlements(ctx corectx.Context, query GetUserEntitlementsQuery) (*GetUserEntitlementsResult, error)
- func (this *StaticRequestGuardServiceImpl) VerifyJwt(ctx corectx.Context, request *http.Request) (*VerifyRequestResult, error)
- func (this *StaticRequestGuardServiceImpl) VerifyJwtDpop(ctx corectx.Context, request *http.Request) (*VerifyRequestResult, error)
- func (this *StaticRequestGuardServiceImpl) VerifySessionBlacklist(ctx corectx.Context, request *http.Request) (*VerifyRequestResult, error)
- type StaticRequestGuardServiceParams
- type VerifyRequestResult
Constants ¶
const ( ResourceScopeTenant = ResourceScope("tenant") ResourceScopeOrg = ResourceScope("org") ResourceScopeOrgUnit = ResourceScope("orgunit") ResourceScopePrivate = ResourceScope("private") )
const Wildcard = "*"
Wildcard is the token that matches any action or any resource in an entitlement expression.
Variables ¶
This section is empty.
Functions ¶
func AssertPermission ¶
func AssertPermission(ctx corectx.Context, requiredPerm Perm) *ft.ClientErrors
AssertPermission answers whether the caller may perform requiredPerm.
It holds no rules of its own: it asks CandidateExpressions which stored expressions would answer, and checks whether the caller holds any of them. The SQL matcher and the permission probe ask the same function, which is what keeps the three of them from drifting into disagreeing about the same question.
func BuildExpression ¶
func BuildExpression(actionCode string, resourceCode string, scope ResourceScope, scopeId *model.Id) string
An entitlement expression has the shape `{action}:{resource}:{scope}[/{scopeId}]` where action and resource may be the wildcard `*`, and the scope segment carries an optional id for the org / orgunit scopes.
BuildExpression is the ONLY producer of expressions in the codebase: the entitlement model persists what it returns, the guard matches against what it returns, and the SQL matcher builds its IN-list from it. Any second implementation is a defect - the two sides silently drift apart (see plan D1/D4).
func CandidateExpressions ¶
func CandidateExpressions(required Perm, evalCtx EvalContext) []string
CandidateExpressions returns every stored expression that would satisfy the required permission for this caller. Holding ANY of them means "allowed".
This is the single definition of the evaluation semantics. The in-memory guard tests set membership against it; the SQL matcher turns it into an IN-list; the permission probe range-scans the cache with it. Because all three consume the same slice they cannot disagree - which is the whole point, since a permission system whose "can I?" and "may I?" answers differ is a security defect, not an inconsistency.
Scope widening runs tenant > org > orgunit: a wider grant satisfies a narrower requirement. There is deliberately NO inheritance between org units - a grant on a parent unit does not reach its children, which is the documented entitlement semantics and what makes a unit grant auditable.
func IsKnownScope ¶
func IsKnownScope(scope ResourceScope) bool
IsKnownScope reports whether the scope is one this system evaluates.
func OmnipotentExpression ¶
func OmnipotentExpression() string
OmnipotentExpression grants everything, everywhere. It is the only expression whose scope segment is a wildcard.
Types ¶
type EvalContext ¶
type EvalContext struct {
// Orgs the caller belongs to.
UserOrgIds []model.Id
// The org unit the caller belongs to, if any.
OrgUnitId *model.Id
// The org that OrgUnitId belongs to. Needed for the orgunit -> org fallback.
OrgUnitOrgId *model.Id
}
EvalContext is what the evaluator knows about the *caller*, as opposed to Perm which describes the *record* being reached for. Both sides are needed: a bare `org` grant only answers when the caller is a member of the record's org.
func EvalContextFrom ¶
func EvalContextFrom(userPerm corectx.ContextPermissions) EvalContext
EvalContextFrom lifts the caller's org and unit membership out of the request context, so callers of CandidateExpressions do not each reach into it.
type ExtGetUserEntitlementsQuery ¶
type ExtGetUserEntitlementsQuery struct {
UserId *model.Id `json:"user_id"`
UserEmail *string `json:"user_email"`
}
func (ExtGetUserEntitlementsQuery) CqrsRequestType ¶
func (ExtGetUserEntitlementsQuery) CqrsRequestType() cqrs.RequestType
type ExtGetUserEntitlementsResult ¶
type ExtGetUserEntitlementsResult = dyn.OpResult[ExtGetUserEntitlementsResultData]
type ExtGetUserEntitlementsResultData ¶
type ExtGetUserEntitlementsResultData struct {
IsOwner bool `json:"is_owner"`
Entitlements []string `json:"entitlements"`
OrgUnitId *model.Id `json:"org_unit_id"`
OrgUnitOrgId *model.Id `json:"org_unit_org_id"`
UserId model.Id `json:"user_id"`
UserOrgIds []model.Id `json:"user_org_ids"`
User dmodel.DynamicFields `json:"user"`
}
type GetUserEntitlementsQuery ¶
type GetUserEntitlementsQuery = ExtGetUserEntitlementsQuery
type GetUserEntitlementsResult ¶
type GetUserEntitlementsResult = dyn.OpResult[GetUserEntitlementsResultData]
type GetUserEntitlementsResultData ¶
type GetUserEntitlementsResultData = ExtGetUserEntitlementsResultData
type ParsedExpression ¶
type ParsedExpression struct {
ActionCode string
ResourceCode string
Scope ResourceScope
ScopeId *model.Id
}
ParsedExpression is the decomposition of an entitlement expression.
func ParseExpression ¶
func ParseExpression(expr string) (*ParsedExpression, error)
ParseExpression decomposes an entitlement expression. It is strict on purpose: callers hand it untrusted input (the permission probe accepts an expression in a request body), so every malformed shape must come back as a plain error the transport turns into a 400, never a panic.
func (ParsedExpression) HasWildcard ¶
func (this ParsedExpression) HasWildcard() bool
HasWildcard reports whether the expression grants across all actions or all resources. A *question* asked of the permission probe must never have one: a real requirement is always concrete, and a wildcard question would turn the probe into a grant-enumeration tool.
func (ParsedExpression) String ¶
func (this ParsedExpression) String() string
String rebuilds the canonical expression, so that parsing then rebuilding is the identity for every valid input.
type Perm ¶
type Perm struct {
ResourceCode string
ActionCode string
Scope ResourceScope
// This is Org Unit ID to which the resource belongs (if any).
// If this is not nil, then OrgId must be this Org Unit's Org ID.
OrgUnitId *model.Id
// This is the Org ID to which the resource belongs (if any)
// Or, this can be the Org Unit's Org ID (if the resource belongs to an org unit)
OrgId *model.Id
// IsRecordOwnedByCaller answers the private scope: the caller may act on their
// own record. Callers whose scope is private must set it; leaving it false
// simply means "not the caller's record", which denies.
IsRecordOwnedByCaller bool
}
func PermFor ¶
func PermFor(actionCode string, resourceCode string, scope ResourceScope) Perm
PermFor starts a Perm for the given action on the given resource. Use the InOrg / InOrgUnit / OwnedByCaller builders to attach the record's context - an org- or unit-scoped check without it can only ever match an exact or tenant grant, which is how org-scoped checks silently degraded before.
func (Perm) InOrgUnit ¶
InOrgUnit names the org unit the record belongs to. Pass the unit's org as well via InOrg so that the org-level fallback can apply.
func (Perm) OwnedByCaller ¶
OwnedByCaller marks the record as the caller's own, which is what a private scope grant is about.
type PermissionContext ¶
type RequestGuardService ¶
type RequestGuardService interface {
// Calculate a fingerprint for the request that can be used to identify the request.
// This can be used for caching or to prevent replay attacks.
CalcRequestFingerprint(ctx corectx.Context, request *http.Request) (fingerprint string, err error)
GetCorsMiddleware(ctx corectx.Context) (echo.MiddlewareFunc, error)
GetUserEntitlements(ctx corectx.Context, query GetUserEntitlementsQuery) (*GetUserEntitlementsResult, error)
VerifyJwt(ctx corectx.Context, request *http.Request) (result *VerifyRequestResult, err error)
}
func NewStaticRequestGuardServiceImpl ¶
func NewStaticRequestGuardServiceImpl(params StaticRequestGuardServiceParams) RequestGuardService
type ResourceScope ¶
type ResourceScope string
type StaticRequestGuardServiceImpl ¶
type StaticRequestGuardServiceImpl struct {
// contains filtered or unexported fields
}
func (*StaticRequestGuardServiceImpl) CalcRequestFingerprint ¶
func (*StaticRequestGuardServiceImpl) GetCorsMiddleware ¶
func (this *StaticRequestGuardServiceImpl) GetCorsMiddleware(_ corectx.Context) (echo.MiddlewareFunc, error)
func (*StaticRequestGuardServiceImpl) GetUserEntitlements ¶
func (this *StaticRequestGuardServiceImpl) GetUserEntitlements( ctx corectx.Context, query GetUserEntitlementsQuery, ) (*GetUserEntitlementsResult, error)
func (*StaticRequestGuardServiceImpl) VerifyJwt ¶
func (this *StaticRequestGuardServiceImpl) VerifyJwt(ctx corectx.Context, request *http.Request) (*VerifyRequestResult, error)
func (*StaticRequestGuardServiceImpl) VerifyJwtDpop ¶
func (this *StaticRequestGuardServiceImpl) VerifyJwtDpop(ctx corectx.Context, request *http.Request) (*VerifyRequestResult, error)
Verify JWT DPoP (OAuth2 Demonstraing Proof of Possession)
func (*StaticRequestGuardServiceImpl) VerifySessionBlacklist ¶
func (this *StaticRequestGuardServiceImpl) VerifySessionBlacklist(ctx corectx.Context, request *http.Request) (*VerifyRequestResult, error)
type StaticRequestGuardServiceParams ¶
type StaticRequestGuardServiceParams struct {
dig.In
ConfigSvc config.ConfigService
CqrsBus cqrs.CqrsBus
TokenSvc coretoken.AuthTokenService
}
type VerifyRequestResult ¶
type VerifyRequestResult struct {
IsOk bool
JwtClaims jwt.Claims
ClientError *ft.ClientErrorItem
}