Enable terminating sessions through the API.
Add a terminateSession method to the sessionStore that sets the Active property
of the Session to false.
Create a Context.TerminateSession wrapper for the terminateSession method on the
sessionStore.
Add a Sessions property to our response type so we can return a []Session in API
responses.
Use the URL-safe encoding when base64 encoding our session ID and CSRFToken, so
the ID can be passed in the URL and so our encodings are consistent.
Add a TerminateSessionHandler function that will extract a Session ID from the
request URL, authenticate the user, check that the authenticated user owns the
session in question, and terminate the session.
Add implementations for our new terminateSession method for the memstore and
postgres types.
Test both the memstore and postgres implementation of our terminateSession
helper in session_test.go.
9 ErrNoScopeStore = errors.New("scopeStore not set in Context")
10 ErrScopeNotFound = errors.New("scope not found")
11 ErrScopeAlreadyExists = errors.New("scope already exists")
14 // Scope represents a limit on the access that a grant provides.
21 func (s *Scope) ApplyChange(change ScopeChange) {
22 if change.Name != nil {
25 if change.Description != nil {
26 s.Description = *change.Description
30 type sortedScopes []Scope
32 func (s sortedScopes) Len() int {
36 func (s sortedScopes) Swap(i, j int) {
37 s[i], s[j] = s[j], s[i]
40 func (s sortedScopes) Less(i, j int) bool {
41 return s[i].ID < s[j].ID
44 // ScopeChange represents a change to a Scope.
45 type ScopeChange struct {
50 func (s ScopeChange) Empty() bool {
51 return s.Name == nil && s.Description == nil
54 type scopeStore interface {
55 createScopes(scopes []Scope) error
56 getScopes(ids []string) ([]Scope, error)
57 updateScope(id string, change ScopeChange) error
58 removeScopes(ids []string) error
59 listScopes() ([]Scope, error)
62 func (m *memstore) createScopes(scopes []Scope) error {
64 defer m.scopeLock.Unlock()
66 for _, scope := range scopes {
67 if _, ok := m.scopes[scope.ID]; ok {
68 return ErrScopeAlreadyExists
71 for _, scope := range scopes {
72 m.scopes[scope.ID] = scope
77 func (m *memstore) getScopes(ids []string) ([]Scope, error) {
79 defer m.scopeLock.RUnlock()
82 for _, id := range ids {
83 scope, ok := m.scopes[id]
87 scopes = append(scopes, scope)
89 sorted := sortedScopes(scopes)
95 func (m *memstore) updateScope(id string, change ScopeChange) error {
97 defer m.scopeLock.Unlock()
99 scope, ok := m.scopes[id]
101 return ErrScopeNotFound
103 scope.ApplyChange(change)
108 func (m *memstore) removeScopes(ids []string) error {
110 defer m.scopeLock.Unlock()
112 for _, id := range ids {
113 if _, ok := m.scopes[id]; !ok {
114 return ErrScopeNotFound
117 for _, id := range ids {
123 func (m *memstore) listScopes() ([]Scope, error) {
125 defer m.scopeLock.RUnlock()
128 for _, scope := range m.scopes {
129 scopes = append(scopes, scope)
131 sorted := sortedScopes(scopes)