auth
auth/scope.go
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.
| paddy@134 | 1 package auth |
| paddy@134 | 2 |
| paddy@134 | 3 import ( |
| paddy@134 | 4 "errors" |
| paddy@134 | 5 "sort" |
| paddy@134 | 6 ) |
| paddy@134 | 7 |
| paddy@134 | 8 var ( |
| paddy@153 | 9 ErrNoScopeStore = errors.New("scopeStore not set in Context") |
| paddy@153 | 10 ErrScopeNotFound = errors.New("scope not found") |
| paddy@153 | 11 ErrScopeAlreadyExists = errors.New("scope already exists") |
| paddy@134 | 12 ) |
| paddy@134 | 13 |
| paddy@134 | 14 // Scope represents a limit on the access that a grant provides. |
| paddy@134 | 15 type Scope struct { |
| paddy@134 | 16 ID string |
| paddy@134 | 17 Name string |
| paddy@134 | 18 Description string |
| paddy@134 | 19 } |
| paddy@134 | 20 |
| paddy@134 | 21 func (s *Scope) ApplyChange(change ScopeChange) { |
| paddy@134 | 22 if change.Name != nil { |
| paddy@134 | 23 s.Name = *change.Name |
| paddy@134 | 24 } |
| paddy@134 | 25 if change.Description != nil { |
| paddy@134 | 26 s.Description = *change.Description |
| paddy@134 | 27 } |
| paddy@134 | 28 } |
| paddy@134 | 29 |
| paddy@134 | 30 type sortedScopes []Scope |
| paddy@134 | 31 |
| paddy@134 | 32 func (s sortedScopes) Len() int { |
| paddy@134 | 33 return len(s) |
| paddy@134 | 34 } |
| paddy@134 | 35 |
| paddy@134 | 36 func (s sortedScopes) Swap(i, j int) { |
| paddy@134 | 37 s[i], s[j] = s[j], s[i] |
| paddy@134 | 38 } |
| paddy@134 | 39 |
| paddy@134 | 40 func (s sortedScopes) Less(i, j int) bool { |
| paddy@134 | 41 return s[i].ID < s[j].ID |
| paddy@134 | 42 } |
| paddy@134 | 43 |
| paddy@134 | 44 // ScopeChange represents a change to a Scope. |
| paddy@134 | 45 type ScopeChange struct { |
| paddy@134 | 46 Name *string |
| paddy@134 | 47 Description *string |
| paddy@134 | 48 } |
| paddy@134 | 49 |
| paddy@152 | 50 func (s ScopeChange) Empty() bool { |
| paddy@152 | 51 return s.Name == nil && s.Description == nil |
| paddy@152 | 52 } |
| paddy@152 | 53 |
| paddy@134 | 54 type scopeStore interface { |
| paddy@134 | 55 createScopes(scopes []Scope) error |
| paddy@134 | 56 getScopes(ids []string) ([]Scope, error) |
| paddy@152 | 57 updateScope(id string, change ScopeChange) error |
| paddy@134 | 58 removeScopes(ids []string) error |
| paddy@134 | 59 listScopes() ([]Scope, error) |
| paddy@134 | 60 } |
| paddy@134 | 61 |
| paddy@134 | 62 func (m *memstore) createScopes(scopes []Scope) error { |
| paddy@134 | 63 m.scopeLock.Lock() |
| paddy@134 | 64 defer m.scopeLock.Unlock() |
| paddy@134 | 65 |
| paddy@153 | 66 for _, scope := range scopes { |
| paddy@134 | 67 if _, ok := m.scopes[scope.ID]; ok { |
| paddy@153 | 68 return ErrScopeAlreadyExists |
| paddy@134 | 69 } |
| paddy@134 | 70 } |
| paddy@134 | 71 for _, scope := range scopes { |
| paddy@134 | 72 m.scopes[scope.ID] = scope |
| paddy@134 | 73 } |
| paddy@134 | 74 return nil |
| paddy@134 | 75 } |
| paddy@134 | 76 |
| paddy@134 | 77 func (m *memstore) getScopes(ids []string) ([]Scope, error) { |
| paddy@134 | 78 m.scopeLock.RLock() |
| paddy@134 | 79 defer m.scopeLock.RUnlock() |
| paddy@134 | 80 |
| paddy@134 | 81 scopes := []Scope{} |
| paddy@153 | 82 for _, id := range ids { |
| paddy@134 | 83 scope, ok := m.scopes[id] |
| paddy@134 | 84 if !ok { |
| paddy@153 | 85 continue |
| paddy@134 | 86 } |
| paddy@134 | 87 scopes = append(scopes, scope) |
| paddy@134 | 88 } |
| paddy@134 | 89 sorted := sortedScopes(scopes) |
| paddy@134 | 90 sort.Sort(sorted) |
| paddy@134 | 91 scopes = sorted |
| paddy@134 | 92 return scopes, nil |
| paddy@134 | 93 } |
| paddy@134 | 94 |
| paddy@152 | 95 func (m *memstore) updateScope(id string, change ScopeChange) error { |
| paddy@134 | 96 m.scopeLock.Lock() |
| paddy@134 | 97 defer m.scopeLock.Unlock() |
| paddy@134 | 98 |
| paddy@152 | 99 scope, ok := m.scopes[id] |
| paddy@152 | 100 if !ok { |
| paddy@153 | 101 return ErrScopeNotFound |
| paddy@134 | 102 } |
| paddy@152 | 103 scope.ApplyChange(change) |
| paddy@152 | 104 m.scopes[id] = scope |
| paddy@152 | 105 return nil |
| paddy@134 | 106 } |
| paddy@134 | 107 |
| paddy@134 | 108 func (m *memstore) removeScopes(ids []string) error { |
| paddy@134 | 109 m.scopeLock.Lock() |
| paddy@134 | 110 defer m.scopeLock.Unlock() |
| paddy@134 | 111 |
| paddy@153 | 112 for _, id := range ids { |
| paddy@134 | 113 if _, ok := m.scopes[id]; !ok { |
| paddy@153 | 114 return ErrScopeNotFound |
| paddy@134 | 115 } |
| paddy@134 | 116 } |
| paddy@134 | 117 for _, id := range ids { |
| paddy@134 | 118 delete(m.scopes, id) |
| paddy@134 | 119 } |
| paddy@134 | 120 return nil |
| paddy@134 | 121 } |
| paddy@134 | 122 |
| paddy@134 | 123 func (m *memstore) listScopes() ([]Scope, error) { |
| paddy@134 | 124 m.scopeLock.RLock() |
| paddy@134 | 125 defer m.scopeLock.RUnlock() |
| paddy@134 | 126 |
| paddy@134 | 127 scopes := []Scope{} |
| paddy@134 | 128 for _, scope := range m.scopes { |
| paddy@134 | 129 scopes = append(scopes, scope) |
| paddy@134 | 130 } |
| paddy@134 | 131 sorted := sortedScopes(scopes) |
| paddy@134 | 132 sort.Sort(sorted) |
| paddy@134 | 133 scopes = sorted |
| paddy@134 | 134 return scopes, nil |
| paddy@134 | 135 } |