auth
auth/context.go
Add login verification to Config. Keep track of how we're going to verify logins using the Config struct.
1 package auth
3 import (
4 "html/template"
5 "io"
6 "log"
7 "net/url"
8 "time"
10 "code.secondbit.org/uuid.hg"
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 scopes scopeStore
25 config Config
26 }
28 // NewContext takes a Config instance and uses it to bootstrap a Context
29 // using the information provided in the Config variable.
30 func NewContext(config Config) (Context, error) {
31 if config.iterations == 0 {
32 return Context{}, ErrConfigNotInitialized
33 }
34 context := Context{
35 clients: config.ClientStore,
36 authCodes: config.AuthCodeStore,
37 profiles: config.ProfileStore,
38 tokens: config.TokenStore,
39 sessions: config.SessionStore,
40 scopes: config.ScopeStore,
41 template: config.Template,
42 config: config,
43 }
44 var err error
45 context.loginURI, err = url.Parse(config.LoginURI)
46 if err != nil {
47 log.Println(err)
48 return Context{}, ErrInvalidLoginURI
49 }
50 return context, nil
51 }
53 // Render uses the HTML templates associated with the Context to render the
54 // template specified by name to out using data to fill any template variables.
55 func (c Context) Render(out io.Writer, name string, data interface{}) {
56 if c.template == nil {
57 log.Println("No template set on Context, can't render anything!")
58 return
59 }
60 err := c.template.ExecuteTemplate(out, name, data)
61 if err != nil {
62 log.Println("Error executing template", name, ":", err)
63 }
64 }
66 // GetClient returns a single Client by its ID from the
67 // clientStore associated with the Context.
68 func (c Context) GetClient(id uuid.ID) (Client, error) {
69 if c.clients == nil {
70 return Client{}, ErrNoClientStore
71 }
72 return c.clients.getClient(id)
73 }
75 // SaveClient stores the passed Client in the clientStore
76 // associated with the Context.
77 func (c Context) SaveClient(client Client) error {
78 if c.clients == nil {
79 return ErrNoClientStore
80 }
81 return c.clients.saveClient(client)
82 }
84 // UpdateClient applies the specified ClientChange to the Client
85 // with the specified ID in the clientStore associated with the
86 // Context.
87 func (c Context) UpdateClient(id uuid.ID, change ClientChange) error {
88 if c.clients == nil {
89 return ErrNoClientStore
90 }
91 return c.clients.updateClient(id, change)
92 }
94 // ListClientsByOwner returns a slice of up to num Clients, starting at offset (inclusive)
95 // that have the specified OwnerID in the clientStore associated with the Context.
96 func (c Context) ListClientsByOwner(ownerID uuid.ID, num, offset int) ([]Client, error) {
97 if c.clients == nil {
98 return []Client{}, ErrNoClientStore
99 }
100 return c.clients.listClientsByOwner(ownerID, num, offset)
101 }
103 func (c Context) DeleteClientsByOwner(ownerID uuid.ID) error {
104 if c.clients == nil {
105 return ErrNoClientStore
106 }
107 return c.clients.deleteClientsByOwner(ownerID)
108 }
110 // AddEndpoints stores the specified Endpoints in the clientStore associated with the Context.
111 func (c Context) AddEndpoints(endpoints []Endpoint) error {
112 if c.clients == nil {
113 return ErrNoClientStore
114 }
115 for pos, endpoint := range endpoints {
116 u, err := normalizeURIString(endpoint.URI)
117 if err != nil {
118 return err
119 }
120 endpoint.NormalizedURI = u
121 endpoints[pos] = endpoint
122 }
123 return c.clients.addEndpoints(endpoints)
124 }
126 // GetEndpoint retrieves the Endpoint with the specified ID from the clientStore associated
127 // with the Context, if and only if it belongs to the Client with the specified ID.
128 func (c Context) GetEndpoint(client, endpoint uuid.ID) (Endpoint, error) {
129 if c.clients == nil {
130 return Endpoint{}, ErrNoClientStore
131 }
132 return c.clients.getEndpoint(client, endpoint)
133 }
135 // RemoveEndpoint deletes the Endpoint with the specified ID from the clientStore associated
136 // with the Context, and disassociates the Endpoint from the specified Client.
137 func (c Context) RemoveEndpoint(client, endpoint uuid.ID) error {
138 if c.clients == nil {
139 return ErrNoClientStore
140 }
141 return c.clients.removeEndpoint(client, endpoint)
142 }
144 // CheckEndpoint finds Endpoints in the clientStore associated with the Context that belong
145 // to the Client specified by the passed ID and match the URI passed. URI matches must be
146 // performed according to RFC 3986 Section 6.
147 func (c Context) CheckEndpoint(client uuid.ID, URI string) (bool, error) {
148 if c.clients == nil {
149 return false, ErrNoClientStore
150 }
151 u, err := normalizeURIString(URI)
152 if err != nil {
153 return false, err
154 }
155 return c.clients.checkEndpoint(client, u)
156 }
158 // ListEndpoints finds Endpoints in the clientStore associated with the Context that belong
159 // to the Client specified by the passed ID. It returns up to num endpoints, starting at offset,
160 // exclusive.
161 func (c Context) ListEndpoints(client uuid.ID, num, offset int) ([]Endpoint, error) {
162 if c.clients == nil {
163 return []Endpoint{}, ErrNoClientStore
164 }
165 return c.clients.listEndpoints(client, num, offset)
166 }
168 func (c Context) RemoveEndpointsByClientID(client uuid.ID) error {
169 if c.clients == nil {
170 return ErrNoClientStore
171 }
172 return c.clients.removeEndpointsByClientID(client)
173 }
175 // CountEndpoints returns the number of Endpoints the are associated with the Client specified by the
176 // passed ID in the clientStore associated with the Context.
177 func (c Context) CountEndpoints(client uuid.ID) (int64, error) {
178 if c.clients == nil {
179 return 0, ErrNoClientStore
180 }
181 return c.clients.countEndpoints(client)
182 }
184 // GetAuthorizationCode returns the AuthorizationCode specified by the provided code from the authorizationCodeStore associated with the
185 // Context.
186 func (c Context) GetAuthorizationCode(code string) (AuthorizationCode, error) {
187 if c.authCodes == nil {
188 return AuthorizationCode{}, ErrNoAuthorizationCodeStore
189 }
190 return c.authCodes.getAuthorizationCode(code)
191 }
193 // SaveAuthorizationCode stores the passed AuthorizationCode in the authorizationCodeStore associated with the Context.
194 func (c Context) SaveAuthorizationCode(authCode AuthorizationCode) error {
195 if c.authCodes == nil {
196 return ErrNoAuthorizationCodeStore
197 }
198 return c.authCodes.saveAuthorizationCode(authCode)
199 }
201 // DeleteAuthorizationCode removes the AuthorizationCode specified by the provided code from the authorizationCodeStore associated with
202 // the Context.
203 func (c Context) DeleteAuthorizationCode(code string) error {
204 if c.authCodes == nil {
205 return ErrNoAuthorizationCodeStore
206 }
207 return c.authCodes.deleteAuthorizationCode(code)
208 }
210 // DeleteAuthorizationCodesByProfileID removes the AuthorizationCodes associated with the Profile specified by the provided ID from the
211 // authorizationCodeStore associated with the Context.
212 func (c Context) DeleteAuthorizationCodesByProfileID(profileID uuid.ID) error {
213 if c.authCodes == nil {
214 return ErrNoAuthorizationCodeStore
215 }
216 return c.authCodes.deleteAuthorizationCodesByProfileID(profileID)
217 }
219 func (c Context) DeleteAuthorizationCodesByClientID(clientID uuid.ID) error {
220 if c.authCodes == nil {
221 return ErrNoAuthorizationCodeStore
222 }
223 return c.authCodes.deleteAuthorizationCodesByClientID(clientID)
224 }
226 // UseAuthorizationCode marks the AuthorizationCode specified by the provided code as used in the authorizationCodeStore associated with
227 // the Context. Once an AuthorizationCode is marked as used, its Used property will be set to true when retrieved from the authorizationCodeStore.
228 func (c Context) UseAuthorizationCode(code string) error {
229 if c.authCodes == nil {
230 return ErrNoAuthorizationCodeStore
231 }
232 return c.authCodes.useAuthorizationCode(code)
233 }
235 // GetProfileByID returns the Profile specified by the provided ID from the profileStore associated with
236 // the Context.
237 func (c Context) GetProfileByID(id uuid.ID) (Profile, error) {
238 if c.profiles == nil {
239 return Profile{}, ErrNoProfileStore
240 }
241 return c.profiles.getProfileByID(id)
242 }
244 // GetProfileByLogin returns the Profile associated with the specified Login from the profileStore associated
245 // with the Context.
246 func (c Context) GetProfileByLogin(value string) (Profile, error) {
247 if c.profiles == nil {
248 return Profile{}, ErrNoProfileStore
249 }
250 return c.profiles.getProfileByLogin(value)
251 }
253 // SaveProfile inserts the passed Profile into the profileStore associated with the Context.
254 func (c Context) SaveProfile(profile Profile) error {
255 if c.profiles == nil {
256 return ErrNoProfileStore
257 }
258 return c.profiles.saveProfile(profile)
259 }
261 // UpdateProfile applies the supplied ProfileChange to the Profile that matches the specified ID
262 // in the profileStore associated with the Context.
263 func (c Context) UpdateProfile(id uuid.ID, change ProfileChange) error {
264 if c.profiles == nil {
265 return ErrNoProfileStore
266 }
267 return c.profiles.updateProfile(id, change)
268 }
270 // UpdateProfiles applies the supplied BulkProfileChange to every Profile that matches one of the
271 // specified IDs in the profileStore associated with the Context.
272 func (c Context) UpdateProfiles(ids []uuid.ID, change BulkProfileChange) error {
273 if c.profiles == nil {
274 return ErrNoProfileStore
275 }
276 return c.profiles.updateProfiles(ids, change)
277 }
279 // DeleteProfile removes the specified Profile from the profileStore associated with the Context.
280 func (c Context) DeleteProfile(id uuid.ID) error {
281 if c.profiles == nil {
282 return ErrNoProfileStore
283 }
284 return c.profiles.deleteProfile(id)
285 }
287 // AddLogin stores the passed Login in the profileStore associated with the Context. It also associates
288 // the newly-created Login with the Orofile in login.ProfileID.
289 func (c Context) AddLogin(login Login) error {
290 if c.profiles == nil {
291 return ErrNoProfileStore
292 }
293 return c.profiles.addLogin(login)
294 }
296 // RemoveLogin removes the specified Login from the profileStore associated with the Context, provided
297 // the Login has a ProfileID property that matches the profile ID passed in. It also disassociates the
298 // deleted Login from the Profile in login.ProfileID.
299 func (c Context) RemoveLogin(value string, profile uuid.ID) error {
300 if c.profiles == nil {
301 return ErrNoProfileStore
302 }
303 return c.profiles.removeLogin(value, profile)
304 }
306 // RemoveLoginsByProfile removes all Logins connected to the specified Profile in the profileStore
307 // associated with the Context and disassociates them from the Profile.
308 func (c Context) RemoveLoginsByProfile(profile uuid.ID) error {
309 if c.profiles == nil {
310 return ErrNoProfileStore
311 }
312 return c.profiles.removeLoginsByProfile(profile)
313 }
315 // RecordLoginUse sets the LastUsed property of the Login specified in the profileStore associated with
316 // the Context to the value passed in as when.
317 func (c Context) RecordLoginUse(value string, when time.Time) error {
318 if c.profiles == nil {
319 return ErrNoProfileStore
320 }
321 return c.profiles.recordLoginUse(value, when)
322 }
324 // ListLogins returns a slice of up to num Logins associated with the specified Profile from the profileStore
325 // associated with the Context, skipping offset Profiles.
326 func (c Context) ListLogins(profile uuid.ID, num, offset int) ([]Login, error) {
327 if c.profiles == nil {
328 return []Login{}, ErrNoProfileStore
329 }
330 return c.profiles.listLogins(profile, num, offset)
331 }
333 // GetToken returns the Token specified from the tokenStore associated with the Context.
334 // If refresh is true, the token input should be compared against the refresh tokens, not the
335 // access tokens.
336 func (c Context) GetToken(token string, refresh bool) (Token, error) {
337 if c.tokens == nil {
338 return Token{}, ErrNoTokenStore
339 }
340 return c.tokens.getToken(token, refresh)
341 }
343 // SaveToken stores the passed Token in the tokenStore associated with the Context.
344 func (c Context) SaveToken(token Token) error {
345 if c.tokens == nil {
346 return ErrNoTokenStore
347 }
348 return c.tokens.saveToken(token)
349 }
351 // RevokeToken revokes the Token identfied by the passed token string from the tokenStore associated
352 // with the context.
353 func (c Context) RevokeToken(token string) error {
354 if c.tokens == nil {
355 return ErrNoTokenStore
356 }
357 return c.tokens.revokeToken(token)
358 }
360 // RevokeTokensByProfileID revokes the Tokens associated with the Profile identified by the passed ID in
361 // the tokenStore associated with the Context.
362 func (c Context) RevokeTokensByProfileID(profileID uuid.ID) error {
363 if c.tokens == nil {
364 return ErrNoTokenStore
365 }
366 return c.tokens.revokeTokensByProfileID(profileID)
367 }
369 func (c Context) RevokeTokensByClientID(clientID uuid.ID) error {
370 if c.tokens == nil {
371 return ErrNoTokenStore
372 }
373 return c.tokens.revokeTokensByClientID(clientID)
374 }
376 // GetTokensByProfileID returns a slice of up to num Tokens with a ProfileID that matches the specified
377 // profileID from the tokenStore associated with the Context, skipping offset Tokens.
378 func (c Context) GetTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) {
379 if c.tokens == nil {
380 return []Token{}, ErrNoTokenStore
381 }
382 return c.tokens.getTokensByProfileID(profileID, num, offset)
383 }
385 // CreateSession stores the passed Session in the sessionStore associated with the Context.
386 func (c Context) CreateSession(session Session) error {
387 if c.sessions == nil {
388 return ErrNoSessionStore
389 }
390 return c.sessions.createSession(session)
391 }
393 // GetSession returns the Session specified from the sessionStore associated with the Context.
394 func (c Context) GetSession(id string) (Session, error) {
395 if c.sessions == nil {
396 return Session{}, ErrNoSessionStore
397 }
398 return c.sessions.getSession(id)
399 }
401 // TerminateSession sets the Session identified by the passed ID as inactive in the sessionStore assocated
402 // with the Context.
403 func (c Context) TerminateSession(id string) error {
404 if c.sessions == nil {
405 return ErrNoSessionStore
406 }
407 return c.sessions.terminateSession(id)
408 }
410 // TerminateSessionsByProfile sets the Sessions associated with the passed Profile ID as inactive in the
411 // sessionStore associated with the Context.
412 func (c Context) TerminateSessionsByProfile(profile uuid.ID) error {
413 if c.sessions == nil {
414 return ErrNoSessionStore
415 }
416 return c.sessions.terminateSessionsByProfile(profile)
417 }
419 // RemoveSession removes the Session identified by the passed ID from the sessionStore associated with
420 // the Context.
421 func (c Context) RemoveSession(id string) error {
422 if c.sessions == nil {
423 return ErrNoSessionStore
424 }
425 return c.sessions.removeSession(id)
426 }
428 // ListSessions returns a slice of up to num Sessions from the sessionStore associated with the Context,
429 // ordered by the date they were created, descending. If before.IsZero() returns false, only Sessions
430 // that were created before that time will be returned. If profile is not nil, only Sessions belonging to
431 // that Profile will be returned.
432 func (c Context) ListSessions(profile uuid.ID, before time.Time, num int64) ([]Session, error) {
433 if c.sessions == nil {
434 return []Session{}, ErrNoSessionStore
435 }
436 return c.sessions.listSessions(profile, before, num)
437 }
439 func (c Context) CreateScopes(scopes []Scope) error {
440 if c.scopes == nil {
441 return ErrNoScopeStore
442 }
443 return c.scopes.createScopes(scopes)
444 }
446 func (c Context) GetScopes(ids []string) ([]Scope, error) {
447 if c.scopes == nil {
448 return []Scope{}, ErrNoScopeStore
449 }
450 return c.scopes.getScopes(ids)
451 }
453 func (c Context) UpdateScope(id string, change ScopeChange) error {
454 if c.scopes == nil {
455 return ErrNoScopeStore
456 }
457 return c.scopes.updateScope(id, change)
458 }
460 func (c Context) RemoveScopes(ids []string) error {
461 if c.scopes == nil {
462 return ErrNoScopeStore
463 }
464 return c.scopes.removeScopes(ids)
465 }
467 func (c Context) ListScopes() ([]Scope, error) {
468 if c.scopes == nil {
469 return []Scope{}, ErrNoScopeStore
470 }
471 return c.scopes.listScopes()
472 }