Files
1Panel/core/init/auth/mfa_session.go
be672d604f feat:Support logging in with oidc and saml2 (#13441)
* feat(auth): implement OIDC authentication endpoints and error handling

* feat(auth): add OIDC provider discovery endpoint and related functionality

* feat(auth): add SAML2 authentication support and related functionality

* feat(auth): add LDAP authentication support and related functionality

* fix(auth): improve login keydown handler for better event handling
2026-08-03 13:43:01 +08:00

125 lines
3.2 KiB
Go

package auth
import (
"crypto/rand"
"encoding/base64"
"time"
"github.com/1Panel-dev/1Panel/core/utils/ttlstore"
)
const (
MFASessionTTL = 5 * time.Minute
MFASessionStoreMaxEntries = 1024
MFASessionMaxFailures = 5
)
var mfaSessions = newMFASessionStore()
func GetMFASessionStore() *mfaSessionStore {
return mfaSessions
}
type mfaSession struct {
Name string
Entrance string
IP string
AuthSource string
AuthSourceID uint
AuthSourceConfigVersion uint64
ExternalIssuer string
ExternalNameID string
ExternalNameIDFormat string
ExternalSessionIndex string
ExternalSessionExpiresAt time.Time
ExternalSessionRequired bool
Failures int
ExpiresAt time.Time
}
type mfaSessionStore struct {
store *ttlstore.Store[mfaSession]
}
func newMFASessionStore() *mfaSessionStore {
return &mfaSessionStore{
store: ttlstore.New[mfaSession](MFASessionTTL, MFASessionStoreMaxEntries, generateMFASessionID),
}
}
func (s *mfaSessionStore) Set(name, entrance, ip string) string {
return s.store.Set(mfaSession{
Name: name,
Entrance: entrance,
IP: ip,
})
}
func (s *mfaSessionStore) SetWithAuthSource(
name, entrance, ip, authSource string,
authSourceID uint,
authSourceConfigVersion uint64,
) string {
return s.store.Set(mfaSession{
Name: name,
Entrance: entrance,
IP: ip,
AuthSource: authSource,
AuthSourceID: authSourceID,
AuthSourceConfigVersion: authSourceConfigVersion,
})
}
func (s *mfaSessionStore) SetWithAuthSourceSession(
name, entrance, ip, authSource string,
authSourceID uint,
authSourceConfigVersion uint64,
externalIssuer, externalNameID, externalNameIDFormat, externalSessionIndex string,
externalSessionExpiresAt time.Time,
externalSessionRequired bool,
) string {
return s.store.Set(mfaSession{
Name: name, Entrance: entrance, IP: ip,
AuthSource: authSource, AuthSourceID: authSourceID,
AuthSourceConfigVersion: authSourceConfigVersion,
ExternalIssuer: externalIssuer, ExternalNameID: externalNameID,
ExternalNameIDFormat: externalNameIDFormat,
ExternalSessionIndex: externalSessionIndex,
ExternalSessionExpiresAt: externalSessionExpiresAt,
ExternalSessionRequired: externalSessionRequired,
})
}
func (s *mfaSessionStore) Get(sessionID string) (mfaSession, bool) {
return s.store.Get(sessionID)
}
func (s *mfaSessionStore) Delete(sessionID string) {
s.store.Delete(sessionID)
}
func (s *mfaSessionStore) RecordFailure(sessionID string) int {
failures := 0
ok := s.store.Update(sessionID, func(item *mfaSession) bool {
item.Failures++
failures = item.Failures
return item.Failures < MFASessionMaxFailures
})
if !ok {
return 0
}
return failures
}
func generateMFASessionID() string {
raw := make([]byte, 32)
if _, err := rand.Read(raw); err != nil {
return generateFallbackMFASessionID()
}
return base64.RawURLEncoding.EncodeToString(raw)
}
func generateFallbackMFASessionID() string {
return base64.RawURLEncoding.EncodeToString([]byte(time.Now().Format(time.RFC3339Nano)))
}