auth
162:6f473576c6ae Browse Files
Clean up sessions and tokens after Profile is deleted. Add a terminateSessionsByProfile method to our sessionStore to mark Sessions associated with a Profile as inactive. Implement memstore and postgres implementations of the terminateSessionsByProfile method. Add a TerminateSessionsByProfile wrapper method to Context. Add a revokeTokensByProfileID method to our tokenStore to mark Tokens associated with a Profile as revoked. Implement memstore and postgres implementation of the revokeTokensByProfileID method. Add a RevokeTokensByProfileID wrapper method to Context. Call our RevokeTokensByProfileID and TerminateSessionsByProfile methods after a Profile is deleted, to clean up the Tokens and Sessions associated with it.
context.go profile.go session.go session_postgres.go token.go token_postgres.go
1.1 --- a/context.go Sat Apr 11 17:58:15 2015 -0400 1.2 +++ b/context.go Sat Apr 11 19:07:26 2015 -0400 1.3 @@ -328,6 +328,15 @@ 1.4 return c.tokens.revokeToken(token, refresh) 1.5 } 1.6 1.7 +// RevokeTokensByProfileID revokes the Tokens associated with the Profile identified by the passed ID in 1.8 +// the tokenStore associated with the Context. 1.9 +func (c Context) RevokeTokensByProfileID(profileID uuid.ID) error { 1.10 + if c.tokens == nil { 1.11 + return ErrNoTokenStore 1.12 + } 1.13 + return c.tokens.revokeTokensByProfileID(profileID) 1.14 +} 1.15 + 1.16 // GetTokensByProfileID returns a slice of up to num Tokens with a ProfileID that matches the specified 1.17 // profileID from the tokenStore associated with the Context, skipping offset Tokens. 1.18 func (c Context) GetTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) { 1.19 @@ -362,6 +371,15 @@ 1.20 return c.sessions.terminateSession(id) 1.21 } 1.22 1.23 +// TerminateSessionsByProfile sets the Sessions associated with the passed Profile ID as inactive in the 1.24 +// sessionStore associated with the Context. 1.25 +func (c Context) TerminateSessionsByProfile(profile uuid.ID) error { 1.26 + if c.sessions == nil { 1.27 + return ErrNoSessionStore 1.28 + } 1.29 + return c.sessions.terminateSessionsByProfile(profile) 1.30 +} 1.31 + 1.32 // RemoveSession removes the Session identified by the passed ID from the sessionStore associated with 1.33 // the Context. 1.34 func (c Context) RemoveSession(id string) error {
2.1 --- a/profile.go Sat Apr 11 17:58:15 2015 -0400 2.2 +++ b/profile.go Sat Apr 11 19:07:26 2015 -0400 2.3 @@ -432,9 +432,16 @@ 2.4 if err != nil { 2.5 log.Printf("Error removing logins from profile %s: %+v\n", profile, err) 2.6 } 2.7 - // BUG(paddy): need to terminate all sessions associated with the Profile 2.8 - // BUG(paddy): need to invalidate all tokens associated with the Profile 2.9 + err = context.TerminateSessionsByProfile(profile) 2.10 + if err != nil { 2.11 + log.Printf("Error terminating sessions associated with profile %s: %+v\n", profile, err) 2.12 + } 2.13 + err = context.RevokeTokensByProfileID(profile) 2.14 + if err != nil { 2.15 + log.Printf("Error revoking tokens associated with profile %s: %+v\n", profile, err) 2.16 + } 2.17 // BUG(paddy): need to delete all the grants associated with the Profile 2.18 + // BUG(paddy): need to delete all clients associated with the Profile 2.19 } 2.20 2.21 // RegisterProfileHandlers adds handlers to the passed router to handle the profile endpoints, like registration and user retrieval.
3.1 --- a/session.go Sat Apr 11 17:58:15 2015 -0400 3.2 +++ b/session.go Sat Apr 11 19:07:26 2015 -0400 3.3 @@ -94,6 +94,7 @@ 3.4 terminateSession(id string) error 3.5 removeSession(id string) error 3.6 listSessions(profile uuid.ID, before time.Time, num int64) ([]Session, error) 3.7 + terminateSessionsByProfile(profile uuid.ID) error 3.8 } 3.9 3.10 func (m *memstore) createSession(session Session) error { 3.11 @@ -127,6 +128,23 @@ 3.12 return nil 3.13 } 3.14 3.15 +func (m *memstore) terminateSessionsByProfile(profile uuid.ID) error { 3.16 + m.sessionLock.RLock() 3.17 + defer m.sessionLock.RUnlock() 3.18 + var found bool 3.19 + for _, session := range m.sessions { 3.20 + if profile.Equal(session.ProfileID) { 3.21 + session.Active = false 3.22 + m.sessions[session.ID] = session 3.23 + found = true 3.24 + } 3.25 + } 3.26 + if !found { 3.27 + return ErrProfileNotFound 3.28 + } 3.29 + return nil 3.30 +} 3.31 + 3.32 func (m *memstore) removeSession(id string) error { 3.33 m.sessionLock.Lock() 3.34 defer m.sessionLock.Unlock()
4.1 --- a/session_postgres.go Sat Apr 11 17:58:15 2015 -0400 4.2 +++ b/session_postgres.go Sat Apr 11 19:07:26 2015 -0400 4.3 @@ -89,6 +89,31 @@ 4.4 return nil 4.5 } 4.6 4.7 +func (p *postgres) terminateSessionsByProfileSQL(profile uuid.ID) *pan.Query { 4.8 + var session Session 4.9 + query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(session)+" SET") 4.10 + query.Include(pan.GetUnquotedColumn(session, "Active")+" = ?", false) 4.11 + query.IncludeWhere() 4.12 + query.Include(pan.GetUnquotedColumn(session, "ProfileID")+" = ?", profile) 4.13 + return query.FlushExpressions(" ") 4.14 +} 4.15 + 4.16 +func (p *postgres) terminateSessionsByProfile(profile uuid.ID) error { 4.17 + query := p.terminateSessionsByProfileSQL(profile) 4.18 + res, err := p.db.Exec(query.String(), query.Args...) 4.19 + if err != nil { 4.20 + return err 4.21 + } 4.22 + rows, err := res.RowsAffected() 4.23 + if err != nil { 4.24 + return err 4.25 + } 4.26 + if rows < 1 { 4.27 + return ErrProfileNotFound 4.28 + } 4.29 + return nil 4.30 +} 4.31 + 4.32 func (p *postgres) removeSessionSQL(id string) *pan.Query { 4.33 var session Session 4.34 query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(session))
5.1 --- a/token.go Sat Apr 11 17:58:15 2015 -0400 5.2 +++ b/token.go Sat Apr 11 19:07:26 2015 -0400 5.3 @@ -55,6 +55,7 @@ 5.4 saveToken(token Token) error 5.5 revokeToken(token string, refresh bool) error 5.6 getTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) 5.7 + revokeTokensByProfileID(profileID uuid.ID) error 5.8 } 5.9 5.10 func (m *memstore) getToken(token string, refresh bool) (Token, error) { 5.11 @@ -116,6 +117,22 @@ 5.12 return nil 5.13 } 5.14 5.15 +func (m *memstore) revokeTokensByProfileID(profileID uuid.ID) error { 5.16 + ids, err := m.lookupTokensByProfileID(profileID.String()) 5.17 + if err != nil { 5.18 + return err 5.19 + } 5.20 + if len(ids) < 1 { 5.21 + return ErrProfileNotFound 5.22 + } 5.23 + m.tokenLock.Lock() 5.24 + defer m.tokenLock.Unlock() 5.25 + for _, id := range ids { 5.26 + delete(m.tokens, id) 5.27 + } 5.28 + return nil 5.29 +} 5.30 + 5.31 func (m *memstore) getTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) { 5.32 ids, err := m.lookupTokensByProfileID(profileID.String()) 5.33 if err != nil {
6.1 --- a/token_postgres.go Sat Apr 11 17:58:15 2015 -0400 6.2 +++ b/token_postgres.go Sat Apr 11 19:07:26 2015 -0400 6.3 @@ -142,6 +142,31 @@ 6.4 return nil 6.5 } 6.6 6.7 +func (p *postgres) revokeTokensByProfileIDSQL(profileID uuid.ID) *pan.Query { 6.8 + var t Token 6.9 + query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(t)+" SET ") 6.10 + query.Include(pan.GetUnquotedColumn(t, "Revoked")+" = ?", true) 6.11 + query.IncludeWhere() 6.12 + query.Include(pan.GetUnquotedColumn(t, "ProfileID")+" = ?", profileID) 6.13 + return query.FlushExpressions(" ") 6.14 +} 6.15 + 6.16 +func (p *postgres) revokeTokensByProfileID(profileID uuid.ID) error { 6.17 + query := p.revokeTokensByProfileIDSQL(profileID) 6.18 + res, err := p.db.Exec(query.String(), query.Args...) 6.19 + if err != nil { 6.20 + return err 6.21 + } 6.22 + rows, err := res.RowsAffected() 6.23 + if err != nil { 6.24 + return err 6.25 + } 6.26 + if rows == 0 { 6.27 + return ErrProfileNotFound 6.28 + } 6.29 + return nil 6.30 +} 6.31 + 6.32 func (p *postgres) getTokensByProfileIDSQL(profileID uuid.ID, num, offset int) *pan.Query { 6.33 var token Token 6.34 fields, _ := pan.GetFields(token)