ValidateSession validates a cookie session without rotating it. Transport-agnostic port of graphqlProvider.ValidateSession. Resolution order for the session cookie: explicit params.Cookie first, then the request cookies (via cookie.GetSession with a gin shim). Both are checked because the GraphQL p
(ctx context.Context, meta RequestMetadata, params *model.ValidateSessionRequest)
| 18 | // are checked because the GraphQL path historically fell back to the |
| 19 | // cookie when params was empty. |
| 20 | func (p *provider) ValidateSession(ctx context.Context, meta RequestMetadata, params *model.ValidateSessionRequest) (*model.ValidateSessionResponse, *ResponseSideEffects, error) { |
| 21 | log := p.Log.With().Str("func", "ValidateSession").Logger() |
| 22 | |
| 23 | // TokenProvider.ValidateBrowserSession + cookie.GetSession both take |
| 24 | // *gin.Context but only read Request fields. Shim it. |
| 25 | gc := &gin.Context{Request: meta.Request} |
| 26 | |
| 27 | sessionToken := "" |
| 28 | if params != nil && params.Cookie != "" { |
| 29 | sessionToken = params.Cookie |
| 30 | } else { |
| 31 | var err error |
| 32 | sessionToken, err = cookie.GetSession(gc) |
| 33 | if err != nil { |
| 34 | log.Debug().Err(err).Msg("Failed to get session token") |
| 35 | return nil, nil, Unauthenticated("unauthorized") |
| 36 | } |
| 37 | } |
| 38 | if sessionToken == "" { |
| 39 | log.Debug().Msg("Empty session token") |
| 40 | return nil, nil, Unauthenticated("unauthorized") |
| 41 | } |
| 42 | |
| 43 | claims, err := p.TokenProvider.ValidateBrowserSession(gc, sessionToken) |
| 44 | if err != nil { |
| 45 | log.Debug().Err(err).Msg("Failed to validate session") |
| 46 | return nil, nil, Unauthenticated("unauthorized") |
| 47 | } |
| 48 | userID := claims.Subject |
| 49 | log.Debug().Str("userID", userID).Msg("Validated session") |
| 50 | user, err := p.StorageProvider.GetUserByID(ctx, userID) |
| 51 | if err != nil { |
| 52 | log.Debug().Err(err).Msg("failed GetUserByID") |
| 53 | return nil, nil, err |
| 54 | } |
| 55 | |
| 56 | claimRoles := append([]string{}, claims.Roles...) |
| 57 | if params != nil && len(params.Roles) > 0 { |
| 58 | for _, v := range params.Roles { |
| 59 | if !utils.StringSliceContains(claimRoles, v) { |
| 60 | log.Debug().Str("role", v).Msg("Role not found in claims") |
| 61 | return nil, nil, Unauthenticated("unauthorized") |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | // Fine-grained authorization gate (AND semantics, fail-closed). |
| 66 | if params != nil && len(params.RequiredRelations) > 0 { |
| 67 | if err := p.enforceRequiredRelations(ctx, log, userID, params.RequiredRelations); err != nil { |
| 68 | log.Debug().Err(err).Msg("Required relations not satisfied") |
| 69 | return nil, nil, err |
| 70 | } |
| 71 | } |
| 72 | return &model.ValidateSessionResponse{ |
| 73 | IsValid: true, |
| 74 | User: user.AsAPIUser(), |
| 75 | }, nil, nil |
| 76 | } |
nothing calls this directly
no test coverage detected