auth

Paddy 2014-12-14 Parent:267483f168b5 Child:c03b5eb3179e

104:bc77a315f823 Go to Latest

auth/context.go

Add request helpers. Fix a typo in the requestErrConflict constant. Create a response type that is used to build responses before sending them down the wire. Create vars for a few common types of error responses that never change. Create a negotiate middleware function that will respond with a 406 error if the client requests an encoding that we can't support. Create an encode helper that determines the requested encoding and uses it to send the data down the wire. Move our wrap middleware from the oauth2.go file to the request.go file, where it's more likely to be looked for.

History
1 package auth
3 import (
4 "html/template"
5 "io"
6 "log"
7 "net/url"
8 "time"
10 "code.secondbit.org/uuid"
11 )
13 // Context wraps the different storage interfaces and should
14 // be used as the main point of interaction for the data storage
15 // layer.
16 type Context struct {
17 template *template.Template
18 loginURI *url.URL
19 clients clientStore
20 authCodes authorizationCodeStore
21 profiles profileStore
22 tokens tokenStore
23 sessions sessionStore
24 config Config
25 }
27 // NewContext takes a Config instance and uses it to bootstrap a Context
28 // using the information provided in the Config variable.
29 func NewContext(config Config) (Context, error) {
30 if config.iterations == 0 {
31 return Context{}, ErrConfigNotInitialized
32 }
33 context := Context{
34 clients: config.ClientStore,
35 authCodes: config.AuthCodeStore,
36 profiles: config.ProfileStore,
37 tokens: config.TokenStore,
38 sessions: config.SessionStore,
39 template: config.Template,
40 config: config,
41 }
42 var err error
43 context.loginURI, err = url.Parse(config.LoginURI)
44 if err != nil {
45 log.Println(err)
46 return Context{}, ErrInvalidLoginURI
47 }
48 return context, nil
49 }
51 // Render uses the HTML templates associated with the Context to render the
52 // template specified by name to out using data to fill any template variables.
53 func (c Context) Render(out io.Writer, name string, data interface{}) {
54 if c.template == nil {
55 log.Println("No template set on Context, can't render anything!")
56 return
57 }
58 err := c.template.ExecuteTemplate(out, name, data)
59 if err != nil {
60 log.Println("Error executing template", name, ":", err)
61 }
62 }
64 // GetClient returns a single Client by its ID from the
65 // clientStore associated with the Context.
66 func (c Context) GetClient(id uuid.ID) (Client, error) {
67 if c.clients == nil {
68 return Client{}, ErrNoClientStore
69 }
70 return c.clients.getClient(id)
71 }
73 // SaveClient stores the passed Client in the clientStore
74 // associated with the Context.
75 func (c Context) SaveClient(client Client) error {
76 if c.clients == nil {
77 return ErrNoClientStore
78 }
79 return c.clients.saveClient(client)
80 }
82 // UpdateClient applies the specified ClientChange to the Client
83 // with the specified ID in the clientStore associated with the
84 // Context.
85 func (c Context) UpdateClient(id uuid.ID, change ClientChange) error {
86 if c.clients == nil {
87 return ErrNoClientStore
88 }
89 return c.clients.updateClient(id, change)
90 }
92 // DeleteClient removes the client with the specified ID from the
93 // clientStore associated with the Context.
94 func (c Context) DeleteClient(id uuid.ID) error {
95 if c.clients == nil {
96 return ErrNoClientStore
97 }
98 return c.clients.deleteClient(id)
99 }
101 // ListClientsByOwner returns a slice of up to num Clients, starting at offset (inclusive)
102 // that have the specified OwnerID in the clientStore associated with the Context.
103 func (c Context) ListClientsByOwner(ownerID uuid.ID, num, offset int) ([]Client, error) {
104 if c.clients == nil {
105 return []Client{}, ErrNoClientStore
106 }
107 return c.clients.listClientsByOwner(ownerID, num, offset)
108 }
110 // AddEndpoint stores the specified Endpoint in the clientStore associated with the Context,
111 // and associates the newly-stored Endpoint with the Client specified by the passed ID.
112 func (c Context) AddEndpoint(client uuid.ID, endpoint Endpoint) error {
113 if c.clients == nil {
114 return ErrNoClientStore
115 }
116 return c.clients.addEndpoint(client, endpoint)
117 }
119 // RemoveEndpoint deletes the Endpoint with the specified ID from the clientStore associated
120 // with the Context, and disassociates the Endpoint from the specified Client.
121 func (c Context) RemoveEndpoint(client, endpoint uuid.ID) error {
122 if c.clients == nil {
123 return ErrNoClientStore
124 }
125 return c.clients.removeEndpoint(client, endpoint)
126 }
128 // CheckEndpoint finds Endpoints in the clientStore associated with the Context that belong
129 // to the Client specified by the passed ID and match the URI passed. URI matches must be
130 // performed according to RFC 3986 Section 6.
131 func (c Context) CheckEndpoint(client uuid.ID, URI string) (bool, error) {
132 if c.clients == nil {
133 return false, ErrNoClientStore
134 }
135 return c.clients.checkEndpoint(client, URI)
136 }
138 // ListEndpoints finds Endpoints in the clientStore associated with the Context that belong
139 // to the Client specified by the passed ID. It returns up to num endpoints, starting at offset,
140 // exclusive.
141 func (c Context) ListEndpoints(client uuid.ID, num, offset int) ([]Endpoint, error) {
142 if c.clients == nil {
143 return []Endpoint{}, ErrNoClientStore
144 }
145 return c.clients.listEndpoints(client, num, offset)
146 }
148 // CountEndpoints returns the number of Endpoints the are associated with the Client specified by the
149 // passed ID in the clientStore associated with the Context.
150 func (c Context) CountEndpoints(client uuid.ID) (int64, error) {
151 if c.clients == nil {
152 return 0, ErrNoClientStore
153 }
154 return c.clients.countEndpoints(client)
155 }
157 // GetAuthorizationCode returns the AuthorizationCode specified by the provided code from the authorizationCodeStore associated with the
158 // Context.
159 func (c Context) GetAuthorizationCode(code string) (AuthorizationCode, error) {
160 if c.authCodes == nil {
161 return AuthorizationCode{}, ErrNoAuthorizationCodeStore
162 }
163 return c.authCodes.getAuthorizationCode(code)
164 }
166 // SaveAuthorizationCode stores the passed AuthorizationCode in the authorizationCodeStore associated with the Context.
167 func (c Context) SaveAuthorizationCode(authCode AuthorizationCode) error {
168 if c.authCodes == nil {
169 return ErrNoAuthorizationCodeStore
170 }
171 return c.authCodes.saveAuthorizationCode(authCode)
172 }
174 // DeleteAuthorizationCode removes the AuthorizationCode specified by the provided code from the authorizationCodeStore associated with
175 // the Context.
176 func (c Context) DeleteAuthorizationCode(code string) error {
177 if c.authCodes == nil {
178 return ErrNoAuthorizationCodeStore
179 }
180 return c.authCodes.deleteAuthorizationCode(code)
181 }
183 // UseAuthorizationCode marks the AuthorizationCode specified by the provided code as used in the authorizationCodeStore associated with
184 // the Context. Once an AuthorizationCode is marked as used, its Used property will be set to true when retrieved from the authorizationCodeStore.
185 func (c Context) UseAuthorizationCode(code string) error {
186 if c.authCodes == nil {
187 return ErrNoAuthorizationCodeStore
188 }
189 return c.authCodes.useAuthorizationCode(code)
190 }
192 // GetProfileByID returns the Profile specified by the provided ID from the profileStore associated with
193 // the Context.
194 func (c Context) GetProfileByID(id uuid.ID) (Profile, error) {
195 if c.profiles == nil {
196 return Profile{}, ErrNoProfileStore
197 }
198 return c.profiles.getProfileByID(id)
199 }
201 // GetProfileByLogin returns the Profile associated with the specified Login from the profileStore associated
202 // with the Context.
203 func (c Context) GetProfileByLogin(value string) (Profile, error) {
204 if c.profiles == nil {
205 return Profile{}, ErrNoProfileStore
206 }
207 return c.profiles.getProfileByLogin(value)
208 }
210 // SaveProfile inserts the passed Profile into the profileStore associated with the Context.
211 func (c Context) SaveProfile(profile Profile) error {
212 if c.profiles == nil {
213 return ErrNoProfileStore
214 }
215 return c.profiles.saveProfile(profile)
216 }
218 // UpdateProfile applies the supplied ProfileChange to the Profile that matches the specified ID
219 // in the profileStore associated with the Context.
220 func (c Context) UpdateProfile(id uuid.ID, change ProfileChange) error {
221 if c.profiles == nil {
222 return ErrNoProfileStore
223 }
224 return c.profiles.updateProfile(id, change)
225 }
227 // UpdateProfiles applies the supplied BulkProfileChange to every Profile that matches one of the
228 // specified IDs in the profileStore associated with the Context.
229 func (c Context) UpdateProfiles(ids []uuid.ID, change BulkProfileChange) error {
230 if c.profiles == nil {
231 return ErrNoProfileStore
232 }
233 return c.profiles.updateProfiles(ids, change)
234 }
236 // DeleteProfile removes the Profile specified by the passed ID from the profileStore associated
237 // with the Context.
238 func (c Context) DeleteProfile(id uuid.ID) error {
239 if c.profiles == nil {
240 return ErrNoProfileStore
241 }
242 return c.profiles.deleteProfile(id)
243 }
245 // AddLogin stores the passed Login in the profileStore associated with the Context. It also associates
246 // the newly-created Login with the Orofile in login.ProfileID.
247 func (c Context) AddLogin(login Login) error {
248 if c.profiles == nil {
249 return ErrNoProfileStore
250 }
251 return c.profiles.addLogin(login)
252 }
254 // RemoveLogin removes the specified Login from the profileStore associated with the Context, provided
255 // the Login has a ProfileID property that matches the profile ID passed in. It also disassociates the
256 // deleted Login from the Profile in login.ProfileID.
257 func (c Context) RemoveLogin(value string, profile uuid.ID) error {
258 if c.profiles == nil {
259 return ErrNoProfileStore
260 }
261 return c.profiles.removeLogin(value, profile)
262 }
264 // RecordLoginUse sets the LastUsed property of the Login specified in the profileStore associated with
265 // the Context to the value passed in as when.
266 func (c Context) RecordLoginUse(value string, when time.Time) error {
267 if c.profiles == nil {
268 return ErrNoProfileStore
269 }
270 return c.profiles.recordLoginUse(value, when)
271 }
273 // ListLogins returns a slice of up to num Logins associated with the specified Profile from the profileStore
274 // associated with the Context, skipping offset Profiles.
275 func (c Context) ListLogins(profile uuid.ID, num, offset int) ([]Login, error) {
276 if c.profiles == nil {
277 return []Login{}, ErrNoProfileStore
278 }
279 return c.profiles.listLogins(profile, num, offset)
280 }
282 // GetToken returns the Token specified from the tokenStore associated with the Context.
283 // If refresh is true, the token input should be compared against the refresh tokens, not the
284 // access tokens.
285 func (c Context) GetToken(token string, refresh bool) (Token, error) {
286 if c.tokens == nil {
287 return Token{}, ErrNoTokenStore
288 }
289 return c.tokens.getToken(token, refresh)
290 }
292 // SaveToken stores the passed Token in the tokenStore associated with the Context.
293 func (c Context) SaveToken(token Token) error {
294 if c.tokens == nil {
295 return ErrNoTokenStore
296 }
297 return c.tokens.saveToken(token)
298 }
300 // RemoveToken removes the Token identified by the passed token string from the tokenStore associated
301 // with the Context.
302 func (c Context) RemoveToken(token string) error {
303 if c.tokens == nil {
304 return ErrNoTokenStore
305 }
306 return c.tokens.removeToken(token)
307 }
309 // RevokeToken revokes the Token identfied by the passed token string from the tokenStore associated
310 // with the context. If refresh is true, the token input should be compared against the refresh tokens,
311 // not the access tokens.
312 func (c Context) RevokeToken(token string, refresh bool) error {
313 if c.tokens == nil {
314 return ErrNoTokenStore
315 }
316 return c.tokens.revokeToken(token, refresh)
317 }
319 // GetTokensByProfileID returns a slice of up to num Tokens with a ProfileID that matches the specified
320 // profileID from the tokenStore associated with the Context, skipping offset Tokens.
321 func (c Context) GetTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) {
322 if c.tokens == nil {
323 return []Token{}, ErrNoTokenStore
324 }
325 return c.tokens.getTokensByProfileID(profileID, num, offset)
326 }
328 // CreateSession stores the passed Session in the sessionStore associated with the Context.
329 func (c Context) CreateSession(session Session) error {
330 if c.sessions == nil {
331 return ErrNoSessionStore
332 }
333 return c.sessions.createSession(session)
334 }
336 // GetSession returns the Session specified from the sessionStore associated with the Context.
337 func (c Context) GetSession(id string) (Session, error) {
338 if c.sessions == nil {
339 return Session{}, ErrNoSessionStore
340 }
341 return c.sessions.getSession(id)
342 }
344 // RemoveSession removes the Session identified by the passed ID from the sessionStore associated with
345 // the Context.
346 func (c Context) RemoveSession(id string) error {
347 if c.sessions == nil {
348 return ErrNoSessionStore
349 }
350 return c.sessions.removeSession(id)
351 }
353 // ListSessions returns a slice of up to num Sessions from the sessionStore associated with the Context,
354 // ordered by the date they were created, descending. If before.IsZero() returns false, only Sessions
355 // that were created before that time will be returned. If profile is not nil, only Sessions belonging to
356 // that Profile will be returned.
357 func (c Context) ListSessions(profile uuid.ID, before time.Time, num int64) ([]Session, error) {
358 if c.sessions != nil {
359 return []Session{}, ErrNoSessionStore
360 }
361 return c.sessions.listSessions(profile, before, num)
362 }