mirror of
https://github.com/nais/wonderwall.git
synced 2026-05-07 00:46:56 +00:00
110 lines
3.0 KiB
Go
110 lines
3.0 KiB
Go
package session
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/nais/wonderwall/internal/crypto"
|
|
"github.com/nais/wonderwall/pkg/cookie"
|
|
"github.com/nais/wonderwall/pkg/openid"
|
|
)
|
|
|
|
var (
|
|
ErrInactive = errors.New("is inactive")
|
|
ErrInvalid = errors.New("session is invalid")
|
|
ErrInvalidExternal = errors.New("session has invalid state at identity provider")
|
|
ErrNotFound = errors.New("not found")
|
|
)
|
|
|
|
// Reader knows how to read a session.
|
|
type Reader interface {
|
|
// Get returns the session for a given http.Request, or an error if the session is invalid or not found.
|
|
Get(r *http.Request) (*Session, error)
|
|
}
|
|
|
|
// Writer knows how to create, update and delete a session.
|
|
type Writer interface {
|
|
// Create creates and stores a session in the Store.
|
|
Create(r *http.Request, tokens *openid.Tokens, sessionLifetime time.Duration) (*Session, error)
|
|
// Delete deletes a session for a given Session.
|
|
Delete(ctx context.Context, session *Session) error
|
|
// DeleteForExternalID deletes a session for a given external session ID (e.g. front-channel logout).
|
|
DeleteForExternalID(ctx context.Context, id string) error
|
|
// Refresh refreshes the user's tokens and returns the updated session. If the session should not be
|
|
// refreshed, it will return the existing session without modifications.
|
|
Refresh(r *http.Request, sess *Session) (*Session, error)
|
|
}
|
|
|
|
// Manager is both a Reader and a Writer.
|
|
type Manager interface {
|
|
Reader
|
|
Writer
|
|
|
|
// GetOrRefresh returns the session for a given http.Request. If the tokens within the session are expired and the
|
|
// session is still valid, it will automatically attempt to refresh and update the session.
|
|
GetOrRefresh(r *http.Request) (*Session, error)
|
|
}
|
|
|
|
type Session struct {
|
|
data *Data
|
|
ticket *Ticket
|
|
}
|
|
|
|
func (in *Session) AccessToken() (string, error) {
|
|
if in.data != nil && in.data.HasActiveAccessToken() {
|
|
return in.data.AccessToken, nil
|
|
}
|
|
|
|
return "", fmt.Errorf("%w: access token is expired", ErrInvalid)
|
|
}
|
|
|
|
func (in *Session) Acr() string {
|
|
if in.data != nil {
|
|
return in.data.Acr
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (in *Session) ExternalSessionID() string {
|
|
if in.data != nil {
|
|
return in.data.ExternalSessionID
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func (in *Session) IDToken() string {
|
|
return in.data.IDToken
|
|
}
|
|
|
|
func (in *Session) MetadataVerbose() MetadataVerbose {
|
|
return in.data.Metadata.Verbose()
|
|
}
|
|
|
|
func (in *Session) SetCookie(w http.ResponseWriter, opts cookie.Options, crypter crypto.Crypter) error {
|
|
return in.ticket.SetCookie(w, opts, crypter)
|
|
}
|
|
|
|
func (in *Session) canRefresh() bool {
|
|
return in.data != nil && in.data.HasRefreshToken() && !in.data.Metadata.IsRefreshOnCooldown()
|
|
}
|
|
|
|
func (in *Session) encrypt() (*EncryptedData, error) {
|
|
return in.data.Encrypt(in.ticket.Crypter())
|
|
}
|
|
|
|
func (in *Session) key() string {
|
|
return in.ticket.Key()
|
|
}
|
|
|
|
func (in *Session) shouldRefresh() bool {
|
|
return in.data != nil && in.data.Metadata.ShouldRefresh()
|
|
}
|
|
|
|
func NewSession(data *Data, ticket *Ticket) *Session {
|
|
return &Session{data: data, ticket: ticket}
|
|
}
|