snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
This commit is contained in:
191
session/manager.go
Normal file
191
session/manager.go
Normal file
@@ -0,0 +1,191 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package session
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/ory/kratos/identity"
|
||||
|
||||
"github.com/ory/kratos/selfservice/flow"
|
||||
"github.com/ory/kratos/text"
|
||||
"github.com/ory/kratos/ui/node"
|
||||
"github.com/ory/kratos/x/swagger"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
|
||||
"github.com/ory/herodot"
|
||||
)
|
||||
|
||||
// ErrNoActiveSessionFound is returned when no active cookie session could be found in the request.
|
||||
type ErrNoActiveSessionFound struct {
|
||||
*herodot.DefaultError `json:"error"`
|
||||
|
||||
// True when the request had no credentials in it.
|
||||
CredentialsMissing bool
|
||||
}
|
||||
|
||||
// NewErrNoActiveSessionFound creates a new ErrNoActiveSessionFound
|
||||
func NewErrNoActiveSessionFound() *ErrNoActiveSessionFound {
|
||||
return &ErrNoActiveSessionFound{
|
||||
DefaultError: herodot.ErrUnauthorized().WithID(text.ErrIDNoActiveSession).WithError("request does not have a valid authentication session").WithReason("No active session was found in this request."),
|
||||
}
|
||||
}
|
||||
|
||||
// NewErrNoCredentialsForSession creates a new NewErrNoCredentialsForSession
|
||||
func NewErrNoCredentialsForSession() *ErrNoActiveSessionFound {
|
||||
e := NewErrNoActiveSessionFound()
|
||||
e.CredentialsMissing = true
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *ErrNoActiveSessionFound) EnhanceJSONError() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
// Is returned when an active session was found but the requested AAL is not satisfied.
|
||||
//
|
||||
// swagger:model errorAuthenticatorAssuranceLevelNotSatisfied
|
||||
//
|
||||
//nolint:deadcode,unused
|
||||
//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions
|
||||
type errorAuthenticatorAssuranceLevelNotSatisfied struct {
|
||||
Error swagger.GenericError `json:"error"`
|
||||
|
||||
// Points to where to redirect the user to next.
|
||||
RedirectTo string `json:"redirect_browser_to"`
|
||||
}
|
||||
|
||||
// ErrAALNotSatisfied is returned when an active session was found but the requested AAL is not satisfied.
|
||||
type ErrAALNotSatisfied struct {
|
||||
*herodot.DefaultError `json:"error"`
|
||||
RedirectTo string `json:"redirect_browser_to"`
|
||||
}
|
||||
|
||||
func (e *ErrAALNotSatisfied) EnhanceJSONError() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *ErrAALNotSatisfied) PassReturnToAndLoginChallengeParameters(requestURL string) error {
|
||||
req, err := url.Parse(requestURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
u, err := url.Parse(e.RedirectTo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q := u.Query()
|
||||
|
||||
hlc := req.Query().Get("login_challenge")
|
||||
if len(hlc) != 0 {
|
||||
q.Set("login_challenge", hlc)
|
||||
}
|
||||
|
||||
returnTo := req.Query().Get("return_to")
|
||||
if len(returnTo) != 0 {
|
||||
q.Set("return_to", returnTo)
|
||||
}
|
||||
|
||||
u.RawQuery = q.Encode()
|
||||
e.RedirectTo = u.String()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewErrAALNotSatisfied creates a new ErrAALNotSatisfied.
|
||||
func NewErrAALNotSatisfied(redirectTo string) *ErrAALNotSatisfied {
|
||||
return &ErrAALNotSatisfied{
|
||||
RedirectTo: redirectTo,
|
||||
DefaultError: &herodot.DefaultError{
|
||||
IDField: text.ErrIDHigherAALRequired,
|
||||
StatusField: http.StatusText(http.StatusForbidden),
|
||||
ErrorField: "Session does not fulfill the requested Authenticator Assurance Level",
|
||||
ReasonField: "An active session was found but it does not fulfill the requested Authenticator Assurance Level. Please verify yourself with a second factor to resolve this issue.",
|
||||
CodeField: http.StatusForbidden,
|
||||
DetailsField: map[string]interface{}{
|
||||
"redirect_browser_to": redirectTo,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Manager handles identity sessions.
|
||||
type Manager interface {
|
||||
// UpsertAndIssueCookie stores a session in the database and issues a cookie by calling IssueCookie.
|
||||
//
|
||||
// Also regenerates CSRF tokens due to assumed principal change.
|
||||
UpsertAndIssueCookie(context.Context, http.ResponseWriter, *http.Request, *Session) error
|
||||
|
||||
// IssueCookie issues a cookie for the given session.
|
||||
//
|
||||
// Also regenerates CSRF tokens due to assumed principal change.
|
||||
IssueCookie(context.Context, http.ResponseWriter, *http.Request, *Session) error
|
||||
|
||||
// RefreshCookie checks if the request uses an outdated cookie and refreshes the cookie if needed.
|
||||
RefreshCookie(context.Context, http.ResponseWriter, *http.Request, *Session) error
|
||||
|
||||
// FetchFromRequest creates an HTTP session using cookies.
|
||||
//
|
||||
// sessionExpand controls which session associations (devices, identity) are loaded, and
|
||||
// identityExpand controls which identity relations are loaded when sessionExpand includes
|
||||
// ExpandSessionIdentity. Pass ExpandEverything/identity.ExpandEverything unless you are
|
||||
// certain the caller never reads an association: expanding the identity's credentials in
|
||||
// particular is by far the most expensive part of fetching a session, so hot paths that
|
||||
// never read Identity.Credentials (such as /sessions/whoami) can pass
|
||||
// identity.ExpandEverythingButCredentials, and callers that only need session columns
|
||||
// (ID, IdentityID, AAL, ...) can pass ExpandNothing/identity.ExpandNothing. AAL
|
||||
// enforcement stays intact: DoesSessionSatisfy loads the identity and hydrates the
|
||||
// credentials lazily when it has to.
|
||||
FetchFromRequest(ctx context.Context, r *http.Request, sessionExpand Expandables, identityExpand identity.Expandables) (*Session, error)
|
||||
|
||||
// FetchFromRequestContext returns the session from the context or if that is unset, falls back to FetchFromRequest.
|
||||
FetchFromRequestContext(context.Context, *http.Request) (*Session, error)
|
||||
|
||||
// SessionActiveForRequest reports whether the request carries an active session, without loading the identity.
|
||||
SessionActiveForRequest(context.Context, *http.Request) error
|
||||
|
||||
// PurgeFromRequest removes an HTTP session.
|
||||
PurgeFromRequest(context.Context, http.ResponseWriter, *http.Request) error
|
||||
|
||||
// DoesSessionSatisfy answers if a session is satisfying the AAL of a user.
|
||||
//
|
||||
// The matcher value can be one of:
|
||||
//
|
||||
// - `highest_available`: If set requires the user to upgrade their session to the highest available AAL for that user.
|
||||
// - `aal1`: Requires the user to have authenticated with at least one authentication factor.
|
||||
//
|
||||
// This method is implemented in such a way, that if a second factor is found for the user, it is always assumed
|
||||
// that the user is able to authenticate with it. This means that if a user has a second factor, the user is always
|
||||
// asked to authenticate with it if `highest_available` is set and the session's AAL is `aal1`.
|
||||
DoesSessionSatisfy(ctx context.Context, sess *Session, matcher string, opts ...ManagerOptions) error
|
||||
|
||||
// SessionAddAuthenticationMethods adds one or more authentication method to the session
|
||||
// and refreshes the session's authenticated_at timestamp, because completing an
|
||||
// authentication method counts as an authentication event.
|
||||
SessionAddAuthenticationMethods(ctx context.Context, sid uuid.UUID, methods ...AuthenticationMethod) error
|
||||
|
||||
// MaybeRedirectAPICodeFlow for API+Code flows redirects the user to the return_to URL and adds the code query parameter.
|
||||
// `handled` is true if the request a redirect was written, false otherwise.
|
||||
MaybeRedirectAPICodeFlow(w http.ResponseWriter, r *http.Request, f flow.Flow, sessionID uuid.UUID, uiNode node.UiNodeGroup) (handled bool, err error)
|
||||
|
||||
// ActivateSession activates a session.
|
||||
//
|
||||
// This method is used to activate a session after a user authenticated with a first or second factor. It sets
|
||||
// all computed values (e.g. authenticator assurance level) and updates the session object but does not store
|
||||
// the session in the database or on the client device.
|
||||
ActivateSession(r *http.Request, session *Session, i *identity.Identity, authenticatedAt time.Time) error
|
||||
|
||||
// IsPrivileged checks if a session can be considered privileged.
|
||||
// https://ory.com/docs/kratos/session-management/session-lifespan#privileged-sessions
|
||||
IsPrivileged(ctx context.Context, session *Session) bool
|
||||
}
|
||||
|
||||
type ManagementProvider interface {
|
||||
SessionManager() Manager
|
||||
}
|
||||
Reference in New Issue
Block a user