Loading go-apps/meep-platform-ctrl/server/platform-ctrl.go +10 −0 Original line number Diff line number Diff line Loading @@ -167,6 +167,9 @@ func Init() (err error) { // Run Starts the Platform Controller func Run() (err error) { // Start Session Watchdog pfmCtrl.sessionMgr.StartSessionWatchdog(sessionTimeoutCb) return nil } Loading Loading @@ -217,6 +220,13 @@ func setPermissions() { } } func sessionTimeoutCb(session *sm.Session) { log.Info("Session timed out. ID[", session.ID, "] Username[", session.Username, "]") // Destroy session sandbox deleteSandbox(session.Sandbox) } // Create a new scenario in the scenario store // POST /scenario/{name} func pcCreateScenario(w http.ResponseWriter, r *http.Request) { Loading go-packages/meep-sessions/session-mgr.go +67 −3 Original line number Diff line number Diff line Loading @@ -19,17 +19,25 @@ package sessions import ( "net/http" "strings" "time" log "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger" "github.com/gorilla/mux" ) type SessionTimeoutHandler func(*Session) type SessionMgr struct { service string ss *SessionStore ps *PermissionStore wdTicker *time.Ticker wdHandler SessionTimeoutHandler wdStarted bool } const wathdogInterval = 60 // 1 minute // NewSessionStore - Create and initialize a Session Store instance func NewSessionMgr(service string, ssAddr string, psAddr string) (sm *SessionMgr, err error) { Loading @@ -37,6 +45,9 @@ func NewSessionMgr(service string, ssAddr string, psAddr string) (sm *SessionMgr log.Info("Creating new Session Manager") sm = new(SessionMgr) sm.service = service sm.wdTicker = nil sm.wdHandler = nil sm.wdStarted = false // Create new Session Store instance sm.ss, err = NewSessionStore(ssAddr) Loading Loading @@ -114,3 +125,56 @@ func (sm *SessionMgr) Authorizer(inner http.Handler) http.Handler { } }) } // StartSessionWatchdog - func (sm *SessionMgr) StartSessionWatchdog(handler SessionTimeoutHandler) { // Update Watchdog callback function sm.wdHandler = handler // Start Session Watchdog ticker to monitor timed out sessions if !sm.wdStarted { sm.wdStarted = true sm.wdTicker = time.NewTicker(wathdogInterval * time.Second) go func() { for range sm.wdTicker.C { if sm.wdStarted { ss := sm.GetSessionStore() // Get all sessions sessionList, err := ss.GetAll() if err != nil { log.Warn("Failed to retrieve session list") continue } // Remove timed out sessions currentTime := time.Now() for _, session := range sessionList { if currentTime.After(session.Timestamp.Add(SessionDuration * time.Second)) { // Invoke watchdog timeout handler if sm.wdHandler != nil { sm.wdHandler(session) } // Remove session _ = ss.DelById(session.ID) } } } } }() log.Info("Started Session Watchdog") } } // StopSessionWatchdog - func (sm *SessionMgr) StopSessionWatchdog() { if sm.wdStarted { sm.wdStarted = false sm.wdTicker.Stop() sm.wdTicker = nil sm.wdHandler = nil log.Info("Stopped Session Watchdog") } } go-packages/meep-sessions/session-store.go +58 −20 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import ( "net/http" "os" "strings" "time" dkm "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-data-key-mgr" log "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger" Loading @@ -34,11 +35,14 @@ const sessionCookie = "authCookie" const sessionsKey = "sessions:" const sessionsRedisTable = 0 const SessionDuration = 1200 // 20 minutes const ( ValSessionID = "sid" ValUsername = "user" ValSandbox = "sbox" ValRole = "role" ValTimestamp = "timestamp" ) const ( Loading @@ -52,6 +56,7 @@ type Session struct { Username string Sandbox string Role string Timestamp time.Time } type SessionStore struct { Loading Loading @@ -88,7 +93,7 @@ func NewSessionStore(addr string) (ss *SessionStore, err error) { ss.cs = sessions.NewCookieStore([]byte(sessionKey)) ss.cs.Options = &sessions.Options{ Path: "/", MaxAge: 60 * 20, // 20 minutes MaxAge: SessionDuration, // 20 minutes HttpOnly: true, } log.Info("Created Cookie Store") Loading Loading @@ -128,9 +133,34 @@ func (ss *SessionStore) Get(r *http.Request) (s *Session, err error) { s.Username = session[ValUsername] s.Sandbox = session[ValSandbox] s.Role = session[ValRole] s.Timestamp, _ = time.Parse(time.RFC3339, session[ValTimestamp]) return s, nil } // GetAll - Retrieve session by name func (ss *SessionStore) GetAll() (sessionList []*Session, err error) { // Get all sessions, if any err = ss.rc.ForEachEntry(ss.baseKey+"*", getSessionEntryHandler, &sessionList) if err != nil { return nil, err } return sessionList, nil } func getSessionEntryHandler(key string, fields map[string]string, userData interface{}) error { sessionList := userData.(*([]*Session)) // Retrieve session information & add to session list s := new(Session) s.ID = fields[ValSessionID] s.Username = fields[ValUsername] s.Sandbox = fields[ValSandbox] s.Role = fields[ValRole] s.Timestamp, _ = time.Parse(time.RFC3339, fields[ValTimestamp]) *sessionList = append(*sessionList, s) return nil } // GetByName - Retrieve session by name func (ss *SessionStore) GetByName(username string) (s *Session, err error) { // Get existing session, if any Loading @@ -149,18 +179,19 @@ func (ss *SessionStore) GetByName(username string) (s *Session, err error) { } func getUserEntryHandler(key string, fields map[string]string, userData interface{}) error { session := userData.(*Session) s := userData.(*Session) // Check if session already found if session.ID != "" { if s.ID != "" { return nil } // look for matching username if fields[ValUsername] == session.Username { session.ID = fields[ValSessionID] session.Sandbox = fields[ValSandbox] session.Role = fields[ValRole] if fields[ValUsername] == s.Username { s.ID = fields[ValSessionID] s.Sandbox = fields[ValSandbox] s.Role = fields[ValRole] s.Timestamp, _ = time.Parse(time.RFC3339, fields[ValTimestamp]) } return nil } Loading Loading @@ -189,6 +220,7 @@ func (ss *SessionStore) Set(s *Session, w http.ResponseWriter, r *http.Request) fields[ValUsername] = s.Username fields[ValSandbox] = s.Sandbox fields[ValRole] = s.Role fields[ValTimestamp] = time.Now().Format(time.RFC3339) err = ss.rc.SetEntry(ss.baseKey+sessionId, fields) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) Loading @@ -205,7 +237,7 @@ func (ss *SessionStore) Set(s *Session, w http.ResponseWriter, r *http.Request) return nil } // Del - Remove session by ID // Del - Remove session by cookie func (ss *SessionStore) Del(w http.ResponseWriter, r *http.Request) error { // Get session cookie sessionCookie, err := ss.cs.Get(r, sessionCookie) Loading Loading @@ -236,24 +268,30 @@ func (ss *SessionStore) Del(w http.ResponseWriter, r *http.Request) error { return nil } // Del - Remove session by ID func (ss *SessionStore) DelById(sessionId string) error { // Remove session from DB err := ss.rc.DelEntry(ss.baseKey + sessionId) if err != nil { log.Error("Failed to delete entry for ", sessionId, " with err: ", err.Error()) return err } return nil } // Refresh - Remove session by ID func (ss *SessionStore) Refresh(w http.ResponseWriter, r *http.Request) error { // Get existing session, if any session, err := ss.Get(r) s, err := ss.Get(r) if err != nil { http.Error(w, err.Error(), http.StatusUnauthorized) return err } // Update session timestamp log.Info(session.ID) // Refresh session cookie sessionCookie, _ := ss.cs.Get(r, sessionCookie) err = sessionCookie.Save(r, w) // Set session to refresh timestamp and cookie err = ss.Set(s, w, r) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return err } return nil Loading Loading
go-apps/meep-platform-ctrl/server/platform-ctrl.go +10 −0 Original line number Diff line number Diff line Loading @@ -167,6 +167,9 @@ func Init() (err error) { // Run Starts the Platform Controller func Run() (err error) { // Start Session Watchdog pfmCtrl.sessionMgr.StartSessionWatchdog(sessionTimeoutCb) return nil } Loading Loading @@ -217,6 +220,13 @@ func setPermissions() { } } func sessionTimeoutCb(session *sm.Session) { log.Info("Session timed out. ID[", session.ID, "] Username[", session.Username, "]") // Destroy session sandbox deleteSandbox(session.Sandbox) } // Create a new scenario in the scenario store // POST /scenario/{name} func pcCreateScenario(w http.ResponseWriter, r *http.Request) { Loading
go-packages/meep-sessions/session-mgr.go +67 −3 Original line number Diff line number Diff line Loading @@ -19,17 +19,25 @@ package sessions import ( "net/http" "strings" "time" log "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger" "github.com/gorilla/mux" ) type SessionTimeoutHandler func(*Session) type SessionMgr struct { service string ss *SessionStore ps *PermissionStore wdTicker *time.Ticker wdHandler SessionTimeoutHandler wdStarted bool } const wathdogInterval = 60 // 1 minute // NewSessionStore - Create and initialize a Session Store instance func NewSessionMgr(service string, ssAddr string, psAddr string) (sm *SessionMgr, err error) { Loading @@ -37,6 +45,9 @@ func NewSessionMgr(service string, ssAddr string, psAddr string) (sm *SessionMgr log.Info("Creating new Session Manager") sm = new(SessionMgr) sm.service = service sm.wdTicker = nil sm.wdHandler = nil sm.wdStarted = false // Create new Session Store instance sm.ss, err = NewSessionStore(ssAddr) Loading Loading @@ -114,3 +125,56 @@ func (sm *SessionMgr) Authorizer(inner http.Handler) http.Handler { } }) } // StartSessionWatchdog - func (sm *SessionMgr) StartSessionWatchdog(handler SessionTimeoutHandler) { // Update Watchdog callback function sm.wdHandler = handler // Start Session Watchdog ticker to monitor timed out sessions if !sm.wdStarted { sm.wdStarted = true sm.wdTicker = time.NewTicker(wathdogInterval * time.Second) go func() { for range sm.wdTicker.C { if sm.wdStarted { ss := sm.GetSessionStore() // Get all sessions sessionList, err := ss.GetAll() if err != nil { log.Warn("Failed to retrieve session list") continue } // Remove timed out sessions currentTime := time.Now() for _, session := range sessionList { if currentTime.After(session.Timestamp.Add(SessionDuration * time.Second)) { // Invoke watchdog timeout handler if sm.wdHandler != nil { sm.wdHandler(session) } // Remove session _ = ss.DelById(session.ID) } } } } }() log.Info("Started Session Watchdog") } } // StopSessionWatchdog - func (sm *SessionMgr) StopSessionWatchdog() { if sm.wdStarted { sm.wdStarted = false sm.wdTicker.Stop() sm.wdTicker = nil sm.wdHandler = nil log.Info("Stopped Session Watchdog") } }
go-packages/meep-sessions/session-store.go +58 −20 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import ( "net/http" "os" "strings" "time" dkm "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-data-key-mgr" log "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger" Loading @@ -34,11 +35,14 @@ const sessionCookie = "authCookie" const sessionsKey = "sessions:" const sessionsRedisTable = 0 const SessionDuration = 1200 // 20 minutes const ( ValSessionID = "sid" ValUsername = "user" ValSandbox = "sbox" ValRole = "role" ValTimestamp = "timestamp" ) const ( Loading @@ -52,6 +56,7 @@ type Session struct { Username string Sandbox string Role string Timestamp time.Time } type SessionStore struct { Loading Loading @@ -88,7 +93,7 @@ func NewSessionStore(addr string) (ss *SessionStore, err error) { ss.cs = sessions.NewCookieStore([]byte(sessionKey)) ss.cs.Options = &sessions.Options{ Path: "/", MaxAge: 60 * 20, // 20 minutes MaxAge: SessionDuration, // 20 minutes HttpOnly: true, } log.Info("Created Cookie Store") Loading Loading @@ -128,9 +133,34 @@ func (ss *SessionStore) Get(r *http.Request) (s *Session, err error) { s.Username = session[ValUsername] s.Sandbox = session[ValSandbox] s.Role = session[ValRole] s.Timestamp, _ = time.Parse(time.RFC3339, session[ValTimestamp]) return s, nil } // GetAll - Retrieve session by name func (ss *SessionStore) GetAll() (sessionList []*Session, err error) { // Get all sessions, if any err = ss.rc.ForEachEntry(ss.baseKey+"*", getSessionEntryHandler, &sessionList) if err != nil { return nil, err } return sessionList, nil } func getSessionEntryHandler(key string, fields map[string]string, userData interface{}) error { sessionList := userData.(*([]*Session)) // Retrieve session information & add to session list s := new(Session) s.ID = fields[ValSessionID] s.Username = fields[ValUsername] s.Sandbox = fields[ValSandbox] s.Role = fields[ValRole] s.Timestamp, _ = time.Parse(time.RFC3339, fields[ValTimestamp]) *sessionList = append(*sessionList, s) return nil } // GetByName - Retrieve session by name func (ss *SessionStore) GetByName(username string) (s *Session, err error) { // Get existing session, if any Loading @@ -149,18 +179,19 @@ func (ss *SessionStore) GetByName(username string) (s *Session, err error) { } func getUserEntryHandler(key string, fields map[string]string, userData interface{}) error { session := userData.(*Session) s := userData.(*Session) // Check if session already found if session.ID != "" { if s.ID != "" { return nil } // look for matching username if fields[ValUsername] == session.Username { session.ID = fields[ValSessionID] session.Sandbox = fields[ValSandbox] session.Role = fields[ValRole] if fields[ValUsername] == s.Username { s.ID = fields[ValSessionID] s.Sandbox = fields[ValSandbox] s.Role = fields[ValRole] s.Timestamp, _ = time.Parse(time.RFC3339, fields[ValTimestamp]) } return nil } Loading Loading @@ -189,6 +220,7 @@ func (ss *SessionStore) Set(s *Session, w http.ResponseWriter, r *http.Request) fields[ValUsername] = s.Username fields[ValSandbox] = s.Sandbox fields[ValRole] = s.Role fields[ValTimestamp] = time.Now().Format(time.RFC3339) err = ss.rc.SetEntry(ss.baseKey+sessionId, fields) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) Loading @@ -205,7 +237,7 @@ func (ss *SessionStore) Set(s *Session, w http.ResponseWriter, r *http.Request) return nil } // Del - Remove session by ID // Del - Remove session by cookie func (ss *SessionStore) Del(w http.ResponseWriter, r *http.Request) error { // Get session cookie sessionCookie, err := ss.cs.Get(r, sessionCookie) Loading Loading @@ -236,24 +268,30 @@ func (ss *SessionStore) Del(w http.ResponseWriter, r *http.Request) error { return nil } // Del - Remove session by ID func (ss *SessionStore) DelById(sessionId string) error { // Remove session from DB err := ss.rc.DelEntry(ss.baseKey + sessionId) if err != nil { log.Error("Failed to delete entry for ", sessionId, " with err: ", err.Error()) return err } return nil } // Refresh - Remove session by ID func (ss *SessionStore) Refresh(w http.ResponseWriter, r *http.Request) error { // Get existing session, if any session, err := ss.Get(r) s, err := ss.Get(r) if err != nil { http.Error(w, err.Error(), http.StatusUnauthorized) return err } // Update session timestamp log.Info(session.ID) // Refresh session cookie sessionCookie, _ := ss.cs.Get(r, sessionCookie) err = sessionCookie.Save(r, w) // Set session to refresh timestamp and cookie err = ss.Set(s, w, r) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return err } return nil Loading