Test our GetClientHandler function, add isAuthError helper.
Add a helper that identifies whether the error passed to it is an authentication
error or is some other type of error. This is useful fo checking whether or not
an internal error occurred while authenticating users.
Update all instances where we call our authentication helper to make them use
the new error helper. All tests continue to pass.
Add a new test case for retrieving a client as an unauthenticated user. This
clears the client's secret from the response before sending it.
Update the GetClientHandler function to return the secret when the owner of the
client used Basic Auth in the request.
Add a new test case for retrieving a client as an authenticated user, both the
owner and a non-owner user. This makes sure the secret is divulged only in the
appropriate cases.
10 ErrNoScopeStore = errors.New("scopeStore not set in Context")
13 type ErrScopeNotFound struct {
18 func (e ErrScopeNotFound) Error() string {
19 return fmt.Sprintf("scope %s couldn't be found", e.ID)
22 type ErrScopeAlreadyExists struct {
27 func (e ErrScopeAlreadyExists) Error() string {
28 return fmt.Sprintf("scope %s already exists", e.ID)
31 // Scope represents a limit on the access that a grant provides.
38 func (s *Scope) ApplyChange(change ScopeChange) {
39 if change.Name != nil {
42 if change.Description != nil {
43 s.Description = *change.Description
47 type sortedScopes []Scope
49 func (s sortedScopes) Len() int {
53 func (s sortedScopes) Swap(i, j int) {
54 s[i], s[j] = s[j], s[i]
57 func (s sortedScopes) Less(i, j int) bool {
58 return s[i].ID < s[j].ID
61 // ScopeChange represents a change to a Scope.
62 type ScopeChange struct {
68 type scopeStore interface {
69 createScopes(scopes []Scope) error
70 getScopes(ids []string) ([]Scope, error)
71 updateScopes(changes []ScopeChange) ([]Scope, error)
72 removeScopes(ids []string) error
73 listScopes() ([]Scope, error)
76 func (m *memstore) createScopes(scopes []Scope) error {
78 defer m.scopeLock.Unlock()
80 for pos, scope := range scopes {
81 if _, ok := m.scopes[scope.ID]; ok {
82 return ErrScopeAlreadyExists{Pos: pos, ID: scope.ID}
85 for _, scope := range scopes {
86 m.scopes[scope.ID] = scope
91 func (m *memstore) getScopes(ids []string) ([]Scope, error) {
93 defer m.scopeLock.RUnlock()
96 for pos, id := range ids {
97 scope, ok := m.scopes[id]
99 return []Scope{}, ErrScopeNotFound{ID: id, Pos: pos}
101 scopes = append(scopes, scope)
103 sorted := sortedScopes(scopes)
109 func (m *memstore) updateScopes(changes []ScopeChange) ([]Scope, error) {
111 defer m.scopeLock.Unlock()
115 for pos, change := range changes {
116 if _, ok := m.scopes[change.ID]; !ok {
117 return []Scope{}, ErrScopeNotFound{Pos: pos, ID: change.ID}
120 for _, change := range changes {
121 scope := m.scopes[change.ID]
122 scope.ApplyChange(change)
123 m.scopes[change.ID] = scope
124 scopes = append(scopes, scope)
126 sorted := sortedScopes(scopes)
132 func (m *memstore) removeScopes(ids []string) error {
134 defer m.scopeLock.Unlock()
136 for pos, id := range ids {
137 if _, ok := m.scopes[id]; !ok {
138 return ErrScopeNotFound{Pos: pos, ID: id}
141 for _, id := range ids {
147 func (m *memstore) listScopes() ([]Scope, error) {
149 defer m.scopeLock.RUnlock()
152 for _, scope := range m.scopes {
153 scopes = append(scopes, scope)
155 sorted := sortedScopes(scopes)