Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-10-30 16:30:47 +01:00
parent e77256c131
commit 57f43f822a
5 changed files with 74 additions and 143 deletions

View File

@@ -13,28 +13,23 @@ type AuthMethod int
const (
AuthMethodPassword AuthMethod = iota
AuthMethodSAML
AuthMethodAny // Used when either password or SAML would work
AuthMethodAny
)
// OrgAuthRequirement encapsulates the authentication requirements for accessing an organization
type OrgAuthRequirement struct {
OrganizationID gid.GID
EmailDomain string
SAMLConfig *coredata.SAMLConfiguration // nil if no SAML config applies to this org+domain
SAMLConfig *coredata.SAMLConfiguration
}
// AccessResult represents the result of an organization access check
type AccessResult struct {
OrganizationID gid.GID
Allowed bool
MissingAuth AuthMethod // Which auth method is missing (if not allowed)
SAMLConfig *coredata.SAMLConfiguration // The SAML config involved (if any)
MissingAuth AuthMethod
SAMLConfig *coredata.SAMLConfiguration
}
// Check performs the access control decision based on session state
// This is pure business logic with no side effects - easily testable
func (r OrgAuthRequirement) Check(session coredata.SessionData) AccessResult {
// No SAML config or disabled → requires password authentication
if r.SAMLConfig == nil || !r.SAMLConfig.Enabled || !r.SAMLConfig.DomainVerified {
return AccessResult{
OrganizationID: r.OrganizationID,
@@ -44,11 +39,9 @@ func (r OrgAuthRequirement) Check(session coredata.SessionData) AccessResult {
}
}
// Check if user has SAML authentication for this specific organization
orgKey := r.OrganizationID.String()
_, hasSAML := session.SAMLAuthenticatedOrgs[orgKey]
// SAML enforcement: REQUIRED → must have SAML auth for this org
if r.SAMLConfig.EnforcementPolicy == coredata.SAMLEnforcementPolicyRequired {
return AccessResult{
OrganizationID: r.OrganizationID,
@@ -58,11 +51,10 @@ func (r OrgAuthRequirement) Check(session coredata.SessionData) AccessResult {
}
}
// SAML enforcement: OPTIONAL → needs either password (global) OR SAML (for this org)
hasAnyAuth := session.PasswordAuthenticated || hasSAML
missingAuth := AuthMethodAny
if hasAnyAuth {
missingAuth = AuthMethodPassword // Not actually missing, but need a value
missingAuth = AuthMethodPassword
}
return AccessResult{
@@ -73,8 +65,6 @@ func (r OrgAuthRequirement) Check(session coredata.SessionData) AccessResult {
}
}
// ToError converts an AccessResult to an error if access is denied
// This handles the presentation layer concern of generating appropriate errors and redirect URLs
func (r AccessResult) ToError(baseURL string) error {
if r.Allowed {
return nil

View File

@@ -76,27 +76,30 @@ func (c *Cleaner) Run(ctx context.Context) error {
func (c *Cleaner) cleanup(ctx context.Context) error {
var assertionsDeleted, requestsDeleted, relayStatesDeleted int64
err := c.pg.WithConn(ctx, func(conn pg.Conn) error {
count, err := CleanupExpiredAssertions(ctx, conn)
if err != nil {
return err
}
assertionsDeleted = count
err := c.pg.WithConn(
ctx,
func(conn pg.Conn) error {
count, err := CleanupExpiredAssertions(ctx, conn)
if err != nil {
return err
}
assertionsDeleted = count
count, err = CleanupExpiredRequests(ctx, conn)
if err != nil {
return err
}
requestsDeleted = count
count, err = CleanupExpiredRequests(ctx, conn)
if err != nil {
return err
}
requestsDeleted = count
count, err = CleanupExpiredRelayStates(ctx, conn)
if err != nil {
return err
}
relayStatesDeleted = count
count, err = CleanupExpiredRelayStates(ctx, conn)
if err != nil {
return err
}
relayStatesDeleted = count
return nil
})
return nil
},
)
if err != nil {
return err

View File

@@ -153,52 +153,3 @@ WHERE %s
return err
}
// LoadFilesByIDs loads multiple files by their IDs in a single query
// Returns a map of file ID to File for efficient lookup
func LoadFilesByIDs(
ctx context.Context,
conn pg.Conn,
fileIDs []gid.GID,
) (map[gid.GID]*File, error) {
if len(fileIDs) == 0 {
return make(map[gid.GID]*File), nil
}
q := `
SELECT
id,
bucket_name,
mime_type,
file_name,
file_key,
file_size,
created_at,
updated_at,
deleted_at
FROM
files
WHERE
id = ANY(@file_ids)
AND deleted_at IS NULL
`
args := pgx.StrictNamedArgs{"file_ids": fileIDs}
rows, err := conn.Query(ctx, q, args)
if err != nil {
return nil, fmt.Errorf("cannot query files: %w", err)
}
files, err := pgx.CollectRows(rows, pgx.RowToStructByName[File])
if err != nil {
return nil, fmt.Errorf("cannot collect files: %w", err)
}
result := make(map[gid.GID]*File, len(files))
for i := range files {
result[files[i].ID] = &files[i]
}
return result, nil
}

View File

@@ -1080,7 +1080,7 @@ func (r *membershipResolver) AuthMethod(ctx context.Context, obj *types.Membersh
authMethod, err := auth.GetUserAuthMethod(ctx, obj.UserID, obj.OrganizationID, session)
if err != nil {
return "", fmt.Errorf("cannot get user auth method: %w", err)
panic(fmt.Errorf("cannot get user auth method: %w", err))
}
return authMethod, nil
}