mattermost-community-enterp.../push_proxy/push_proxy.go
Claude fad2fe9d3c Initial commit: Mattermost Community Enterprise
Open source implementation of Mattermost Enterprise features:

Authentication & SSO:
- LDAP authentication and sync
- LDAP diagnostics
- SAML 2.0 SSO
- OAuth providers (Google, Office365, OpenID Connect)

Infrastructure:
- Redis-based cluster implementation
- Prometheus metrics
- IP filtering
- Push proxy authentication

Search:
- Bleve search engine (lightweight Elasticsearch alternative)

Compliance & Security:
- Compliance reporting
- Data retention policies
- Message export (Actiance, GlobalRelay, CSV)
- Access control (PAP/PDP)

User Management:
- Account migration (LDAP/SAML)
- ID-loaded push notifications
- Outgoing OAuth connections

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:49:14 +09:00

208 lines
5.4 KiB
Go

// Copyright (c) 2024 Mattermost Community Enterprise
// Push Proxy Authentication Token Implementation
package push_proxy
import (
"crypto/rand"
"encoding/hex"
"net/http"
"sync"
"time"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/shared/mlog"
"github.com/mattermost/mattermost/server/public/shared/request"
ejobs "github.com/mattermost/mattermost/server/v8/einterfaces/jobs"
)
// PushProxyConfig holds configuration for the push proxy interface
type PushProxyConfig struct {
Config func() *model.Config
Logger mlog.LoggerIFace
}
// PushProxyImpl implements the PushProxyInterface
type PushProxyImpl struct {
config func() *model.Config
logger mlog.LoggerIFace
authToken string
mutex sync.RWMutex
// For the worker
stopChan chan struct{}
jobChan chan model.Job
}
// NewPushProxyInterface creates a new push proxy interface
func NewPushProxyInterface(cfg *PushProxyConfig) *PushProxyImpl {
return &PushProxyImpl{
config: cfg.Config,
logger: cfg.Logger,
stopChan: make(chan struct{}),
jobChan: make(chan model.Job, 1),
}
}
// GetAuthToken returns the current auth token
func (pp *PushProxyImpl) GetAuthToken() string {
pp.mutex.RLock()
defer pp.mutex.RUnlock()
return pp.authToken
}
// GenerateAuthToken generates and stores a new authentication token
func (pp *PushProxyImpl) GenerateAuthToken() *model.AppError {
pp.mutex.Lock()
defer pp.mutex.Unlock()
// Generate a cryptographically secure random token
tokenBytes := make([]byte, 32)
if _, err := rand.Read(tokenBytes); err != nil {
return model.NewAppError("GenerateAuthToken", "push_proxy.token_generation_failed", nil, err.Error(), http.StatusInternalServerError)
}
pp.authToken = hex.EncodeToString(tokenBytes)
pp.logger.Info("Generated new push proxy authentication token")
return nil
}
// DeleteAuthToken deletes the stored authentication token
func (pp *PushProxyImpl) DeleteAuthToken() *model.AppError {
pp.mutex.Lock()
defer pp.mutex.Unlock()
pp.authToken = ""
pp.logger.Info("Deleted push proxy authentication token")
return nil
}
// MakeWorker creates a worker for the auth token generation job
func (pp *PushProxyImpl) MakeWorker() model.Worker {
return &PushProxyWorker{
pushProxy: pp,
stopChan: pp.stopChan,
jobChan: pp.jobChan,
}
}
// MakeScheduler creates a scheduler for the auth token generation job
func (pp *PushProxyImpl) MakeScheduler() ejobs.Scheduler {
return &PushProxyScheduler{
pushProxy: pp,
}
}
// PushProxyWorker implements model.Worker for push proxy token management
type PushProxyWorker struct {
pushProxy *PushProxyImpl
stopChan chan struct{}
jobChan chan model.Job
}
// Run starts the worker
func (w *PushProxyWorker) Run() {
w.pushProxy.logger.Debug("Push proxy worker started")
for {
select {
case <-w.stopChan:
w.pushProxy.logger.Debug("Push proxy worker stopped")
return
case job := <-w.jobChan:
w.pushProxy.logger.Info("Processing push proxy job",
mlog.String("job_id", job.Id),
)
// Generate a new auth token
if err := w.pushProxy.GenerateAuthToken(); err != nil {
w.pushProxy.logger.Error("Failed to generate push proxy auth token",
mlog.String("job_id", job.Id),
mlog.Err(err),
)
}
}
}
}
// Stop stops the worker
func (w *PushProxyWorker) Stop() {
w.pushProxy.logger.Debug("Stopping push proxy worker")
close(w.stopChan)
}
// JobChannel returns the job channel
func (w *PushProxyWorker) JobChannel() chan<- model.Job {
return w.jobChan
}
// IsEnabled checks if the worker is enabled
func (w *PushProxyWorker) IsEnabled(cfg *model.Config) bool {
// Push proxy is enabled if push notification server is configured
if cfg.EmailSettings.PushNotificationServer == nil {
return false
}
return *cfg.EmailSettings.PushNotificationServer != ""
}
// PushProxyScheduler implements ejobs.Scheduler for push proxy token management
type PushProxyScheduler struct {
pushProxy *PushProxyImpl
}
// Enabled checks if the scheduler is enabled
func (s *PushProxyScheduler) Enabled(cfg *model.Config) bool {
// Push proxy scheduler is enabled if push notification server is configured
if cfg.EmailSettings.PushNotificationServer == nil {
return false
}
return *cfg.EmailSettings.PushNotificationServer != ""
}
// NextScheduleTime returns the next time the job should be scheduled
func (s *PushProxyScheduler) NextScheduleTime(cfg *model.Config, now time.Time, pendingJobs bool, lastSuccessfulJob *model.Job) *time.Time {
// If there's a pending job, don't schedule another one
if pendingJobs {
return nil
}
// Schedule token refresh every 24 hours
if lastSuccessfulJob == nil {
// No previous job, schedule immediately
nextTime := now.Add(time.Minute)
return &nextTime
}
// Calculate next schedule based on last successful job
lastJobTime := time.Unix(lastSuccessfulJob.LastActivityAt/1000, 0)
nextTime := lastJobTime.Add(24 * time.Hour)
if nextTime.Before(now) {
nextTime = now.Add(time.Minute)
}
return &nextTime
}
// ScheduleJob schedules a push proxy job
func (s *PushProxyScheduler) ScheduleJob(rctx request.CTX, cfg *model.Config, pendingJobs bool, lastSuccessfulJob *model.Job) (*model.Job, *model.AppError) {
// Create a new job
job := &model.Job{
Id: model.NewId(),
Type: "push_proxy_auth_token",
Status: model.JobStatusPending,
CreateAt: model.GetMillis(),
}
s.pushProxy.logger.Info("Scheduled push proxy auth token job",
mlog.String("job_id", job.Id),
)
return job, nil
}