auth

Paddy 2014-09-18 Parent:607708cd8829 Child:113ccb15b919

39:690561c6619a Go to Latest

auth/client.go

Include client updates and tests. Flesh out updating clients, and include unit tests to ensure that clientstores actually update appropriately. Add TODO comments where functionality is planned but stubbed out.

History
1 package auth
3 import (
4 "errors"
6 "secondbit.org/uuid"
7 )
9 var (
10 ErrClientNotFound = errors.New("Client not found in ClientStore.")
11 ErrClientAlreadyExists = errors.New("Client already exists in ClientStore.")
12 )
14 // Client represents a client that grants access
15 // to the auth server, exchanging grants for tokens,
16 // and tokens for access.
17 type Client struct {
18 ID uuid.ID
19 Secret string
20 RedirectURI string
21 OwnerID uuid.ID
22 Name string
23 Logo string
24 Website string
25 }
27 func (c *Client) ApplyChange(change ClientChange) {
28 if change.Secret != nil {
29 c.Secret = *change.Secret
30 }
31 if change.RedirectURI != nil {
32 c.RedirectURI = *change.RedirectURI
33 }
34 if change.OwnerID != nil {
35 c.OwnerID = change.OwnerID
36 }
37 if change.Name != nil {
38 c.Name = *change.Name
39 }
40 if change.Logo != nil {
41 c.Logo = *change.Logo
42 }
43 if change.Website != nil {
44 c.Website = *change.Website
45 }
46 }
48 type ClientChange struct {
49 Secret *string
50 RedirectURI *string
51 OwnerID uuid.ID
52 Name *string
53 Logo *string
54 Website *string
55 }
57 func (c ClientChange) Validate() error {
58 // TODO: validate client changes
59 return nil
60 }
62 // ClientStore abstracts the storage interface for
63 // storing and retrieving Clients.
64 type ClientStore interface {
65 GetClient(id uuid.ID) (Client, error)
66 SaveClient(client Client) error
67 UpdateClient(id uuid.ID, change ClientChange) error
68 DeleteClient(id uuid.ID) error
69 ListClientsByOwner(ownerID uuid.ID, num, offset int) ([]Client, error)
70 }
72 func (m *Memstore) GetClient(id uuid.ID) (Client, error) {
73 m.clientLock.RLock()
74 defer m.clientLock.RUnlock()
75 c, ok := m.clients[id.String()]
76 if !ok {
77 return Client{}, ErrClientNotFound
78 }
79 return c, nil
80 }
82 func (m *Memstore) SaveClient(client Client) error {
83 m.clientLock.Lock()
84 defer m.clientLock.Unlock()
85 if _, ok := m.clients[client.ID.String()]; ok {
86 return ErrClientAlreadyExists
87 }
88 m.clients[client.ID.String()] = client
89 m.profileClientLookup[client.OwnerID.String()] = append(m.profileClientLookup[client.OwnerID.String()], client.ID)
90 return nil
91 }
93 func (m *Memstore) UpdateClient(id uuid.ID, change ClientChange) error {
94 m.clientLock.Lock()
95 defer m.clientLock.Unlock()
96 c, ok := m.clients[id.String()]
97 if !ok {
98 return ErrClientNotFound
99 }
100 c.ApplyChange(change)
101 m.clients[id.String()] = c
102 return nil
103 }
105 func (m *Memstore) DeleteClient(id uuid.ID) error {
106 client, err := m.GetClient(id)
107 if err != nil {
108 return err
109 }
110 m.clientLock.Lock()
111 defer m.clientLock.Unlock()
112 delete(m.clients, id.String())
113 pos := -1
114 for p, item := range m.profileClientLookup[client.OwnerID.String()] {
115 if item.Equal(id) {
116 pos = p
117 break
118 }
119 }
120 if pos >= 0 {
121 m.profileClientLookup[client.OwnerID.String()] = append(m.profileClientLookup[client.OwnerID.String()][:pos], m.profileClientLookup[client.OwnerID.String()][pos+1:]...)
122 }
123 return nil
124 }
126 func (m *Memstore) ListClientsByOwner(ownerID uuid.ID, num, offset int) ([]Client, error) {
127 ids := m.lookupClientsByProfileID(ownerID.String())
128 if len(ids) > num+offset {
129 ids = ids[offset : num+offset]
130 } else if len(ids) > offset {
131 ids = ids[offset:]
132 } else {
133 return []Client{}, nil
134 }
135 clients := []Client{}
136 for _, id := range ids {
137 client, err := m.GetClient(id)
138 if err != nil {
139 return []Client{}, err
140 }
141 clients = append(clients, client)
142 }
143 return clients, nil
144 }