auth

Paddy 2015-04-11 Parent:de5e09680f6b Child:cf6c1f05eb21

157:202e991accc2 Go to Latest

auth/context.go

Wire up the postgres database for authd. Have authd use the AUTH_PG_DB environment variable to detect support for the postgres *Stores, and if postgres is supported, use it. If postgres isn't supported, fall back on the in-memory store. Also create-if-not-exists the test scopes, instead of panicking when the scope already exists.

History
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 // AddEndpoints stores the specified Endpoints in the clientStore associated with the Context.
104 func (c Context) AddEndpoints(endpoints []Endpoint) error {
105 if c.clients == nil {
106 return ErrNoClientStore
107 }
108 for pos, endpoint := range endpoints {
109 u, err := normalizeURIString(endpoint.URI)
110 if err != nil {
111 return err
112 }
113 endpoint.NormalizedURI = u
114 endpoints[pos] = endpoint
115 }
116 return c.clients.addEndpoints(endpoints)
117 }
119 // GetEndpoint retrieves the Endpoint with the specified ID from the clientStore associated
120 // with the Context, if and only if it belongs to the Client with the specified ID.
121 func (c Context) GetEndpoint(client, endpoint uuid.ID) (Endpoint, error) {
122 if c.clients == nil {
123 return Endpoint{}, ErrNoClientStore
124 }
125 return c.clients.getEndpoint(client, endpoint)
126 }
128 // RemoveEndpoint deletes the Endpoint with the specified ID from the clientStore associated
129 // with the Context, and disassociates the Endpoint from the specified Client.
130 func (c Context) RemoveEndpoint(client, endpoint uuid.ID) error {
131 if c.clients == nil {
132 return ErrNoClientStore
133 }
134 return c.clients.removeEndpoint(client, endpoint)
135 }
137 // CheckEndpoint finds Endpoints in the clientStore associated with the Context that belong
138 // to the Client specified by the passed ID and match the URI passed. URI matches must be
139 // performed according to RFC 3986 Section 6.
140 func (c Context) CheckEndpoint(client uuid.ID, URI string) (bool, error) {
141 if c.clients == nil {
142 return false, ErrNoClientStore
143 }
144 u, err := normalizeURIString(URI)
145 if err != nil {
146 return false, err
147 }
148 return c.clients.checkEndpoint(client, u)
149 }
151 // ListEndpoints finds Endpoints in the clientStore associated with the Context that belong
152 // to the Client specified by the passed ID. It returns up to num endpoints, starting at offset,
153 // exclusive.
154 func (c Context) ListEndpoints(client uuid.ID, num, offset int) ([]Endpoint, error) {
155 if c.clients == nil {
156 return []Endpoint{}, ErrNoClientStore
157 }
158 return c.clients.listEndpoints(client, num, offset)
159 }
161 // CountEndpoints returns the number of Endpoints the are associated with the Client specified by the
162 // passed ID in the clientStore associated with the Context.
163 func (c Context) CountEndpoints(client uuid.ID) (int64, error) {
164 if c.clients == nil {
165 return 0, ErrNoClientStore
166 }
167 return c.clients.countEndpoints(client)
168 }
170 // GetAuthorizationCode returns the AuthorizationCode specified by the provided code from the authorizationCodeStore associated with the
171 // Context.
172 func (c Context) GetAuthorizationCode(code string) (AuthorizationCode, error) {
173 if c.authCodes == nil {
174 return AuthorizationCode{}, ErrNoAuthorizationCodeStore
175 }
176 return c.authCodes.getAuthorizationCode(code)
177 }
179 // SaveAuthorizationCode stores the passed AuthorizationCode in the authorizationCodeStore associated with the Context.
180 func (c Context) SaveAuthorizationCode(authCode AuthorizationCode) error {
181 if c.authCodes == nil {
182 return ErrNoAuthorizationCodeStore
183 }
184 return c.authCodes.saveAuthorizationCode(authCode)
185 }
187 // DeleteAuthorizationCode removes the AuthorizationCode specified by the provided code from the authorizationCodeStore associated with
188 // the Context.
189 func (c Context) DeleteAuthorizationCode(code string) error {
190 if c.authCodes == nil {
191 return ErrNoAuthorizationCodeStore
192 }
193 return c.authCodes.deleteAuthorizationCode(code)
194 }
196 // UseAuthorizationCode marks the AuthorizationCode specified by the provided code as used in the authorizationCodeStore associated with
197 // the Context. Once an AuthorizationCode is marked as used, its Used property will be set to true when retrieved from the authorizationCodeStore.
198 func (c Context) UseAuthorizationCode(code string) error {
199 if c.authCodes == nil {
200 return ErrNoAuthorizationCodeStore
201 }
202 return c.authCodes.useAuthorizationCode(code)
203 }
205 // GetProfileByID returns the Profile specified by the provided ID from the profileStore associated with
206 // the Context.
207 func (c Context) GetProfileByID(id uuid.ID) (Profile, error) {
208 if c.profiles == nil {
209 return Profile{}, ErrNoProfileStore
210 }
211 return c.profiles.getProfileByID(id)
212 }
214 // GetProfileByLogin returns the Profile associated with the specified Login from the profileStore associated
215 // with the Context.
216 func (c Context) GetProfileByLogin(value string) (Profile, error) {
217 if c.profiles == nil {
218 return Profile{}, ErrNoProfileStore
219 }
220 return c.profiles.getProfileByLogin(value)
221 }
223 // SaveProfile inserts the passed Profile into the profileStore associated with the Context.
224 func (c Context) SaveProfile(profile Profile) error {
225 if c.profiles == nil {
226 return ErrNoProfileStore
227 }
228 return c.profiles.saveProfile(profile)
229 }
231 // UpdateProfile applies the supplied ProfileChange to the Profile that matches the specified ID
232 // in the profileStore associated with the Context.
233 func (c Context) UpdateProfile(id uuid.ID, change ProfileChange) error {
234 if c.profiles == nil {
235 return ErrNoProfileStore
236 }
237 return c.profiles.updateProfile(id, change)
238 }
240 // UpdateProfiles applies the supplied BulkProfileChange to every Profile that matches one of the
241 // specified IDs in the profileStore associated with the Context.
242 func (c Context) UpdateProfiles(ids []uuid.ID, change BulkProfileChange) error {
243 if c.profiles == nil {
244 return ErrNoProfileStore
245 }
246 return c.profiles.updateProfiles(ids, change)
247 }
249 // AddLogin stores the passed Login in the profileStore associated with the Context. It also associates
250 // the newly-created Login with the Orofile in login.ProfileID.
251 func (c Context) AddLogin(login Login) error {
252 if c.profiles == nil {
253 return ErrNoProfileStore
254 }
255 return c.profiles.addLogin(login)
256 }
258 // RemoveLogin removes the specified Login from the profileStore associated with the Context, provided
259 // the Login has a ProfileID property that matches the profile ID passed in. It also disassociates the
260 // deleted Login from the Profile in login.ProfileID.
261 func (c Context) RemoveLogin(value string, profile uuid.ID) error {
262 if c.profiles == nil {
263 return ErrNoProfileStore
264 }
265 return c.profiles.removeLogin(value, profile)
266 }
268 // RecordLoginUse sets the LastUsed property of the Login specified in the profileStore associated with
269 // the Context to the value passed in as when.
270 func (c Context) RecordLoginUse(value string, when time.Time) error {
271 if c.profiles == nil {
272 return ErrNoProfileStore
273 }
274 return c.profiles.recordLoginUse(value, when)
275 }
277 // ListLogins returns a slice of up to num Logins associated with the specified Profile from the profileStore
278 // associated with the Context, skipping offset Profiles.
279 func (c Context) ListLogins(profile uuid.ID, num, offset int) ([]Login, error) {
280 if c.profiles == nil {
281 return []Login{}, ErrNoProfileStore
282 }
283 return c.profiles.listLogins(profile, num, offset)
284 }
286 // GetToken returns the Token specified from the tokenStore associated with the Context.
287 // If refresh is true, the token input should be compared against the refresh tokens, not the
288 // access tokens.
289 func (c Context) GetToken(token string, refresh bool) (Token, error) {
290 if c.tokens == nil {
291 return Token{}, ErrNoTokenStore
292 }
293 return c.tokens.getToken(token, refresh)
294 }
296 // SaveToken stores the passed Token in the tokenStore associated with the Context.
297 func (c Context) SaveToken(token Token) error {
298 if c.tokens == nil {
299 return ErrNoTokenStore
300 }
301 return c.tokens.saveToken(token)
302 }
304 // RevokeToken revokes the Token identfied by the passed token string from the tokenStore associated
305 // with the context. If refresh is true, the token input should be compared against the refresh tokens,
306 // not the access tokens.
307 func (c Context) RevokeToken(token string, refresh bool) error {
308 if c.tokens == nil {
309 return ErrNoTokenStore
310 }
311 return c.tokens.revokeToken(token, refresh)
312 }
314 // GetTokensByProfileID returns a slice of up to num Tokens with a ProfileID that matches the specified
315 // profileID from the tokenStore associated with the Context, skipping offset Tokens.
316 func (c Context) GetTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) {
317 if c.tokens == nil {
318 return []Token{}, ErrNoTokenStore
319 }
320 return c.tokens.getTokensByProfileID(profileID, num, offset)
321 }
323 // CreateSession stores the passed Session in the sessionStore associated with the Context.
324 func (c Context) CreateSession(session Session) error {
325 if c.sessions == nil {
326 return ErrNoSessionStore
327 }
328 return c.sessions.createSession(session)
329 }
331 // GetSession returns the Session specified from the sessionStore associated with the Context.
332 func (c Context) GetSession(id string) (Session, error) {
333 if c.sessions == nil {
334 return Session{}, ErrNoSessionStore
335 }
336 return c.sessions.getSession(id)
337 }
339 // RemoveSession removes the Session identified by the passed ID from the sessionStore associated with
340 // the Context.
341 func (c Context) RemoveSession(id string) error {
342 if c.sessions == nil {
343 return ErrNoSessionStore
344 }
345 return c.sessions.removeSession(id)
346 }
348 // ListSessions returns a slice of up to num Sessions from the sessionStore associated with the Context,
349 // ordered by the date they were created, descending. If before.IsZero() returns false, only Sessions
350 // that were created before that time will be returned. If profile is not nil, only Sessions belonging to
351 // that Profile will be returned.
352 func (c Context) ListSessions(profile uuid.ID, before time.Time, num int64) ([]Session, error) {
353 if c.sessions == nil {
354 return []Session{}, ErrNoSessionStore
355 }
356 return c.sessions.listSessions(profile, before, num)
357 }
359 func (c Context) CreateScopes(scopes []Scope) error {
360 if c.scopes == nil {
361 return ErrNoScopeStore
362 }
363 return c.scopes.createScopes(scopes)
364 }
366 func (c Context) GetScopes(ids []string) ([]Scope, error) {
367 if c.scopes == nil {
368 return []Scope{}, ErrNoScopeStore
369 }
370 return c.scopes.getScopes(ids)
371 }
373 func (c Context) UpdateScope(id string, change ScopeChange) error {
374 if c.scopes == nil {
375 return ErrNoScopeStore
376 }
377 return c.scopes.updateScope(id, change)
378 }
380 func (c Context) RemoveScopes(ids []string) error {
381 if c.scopes == nil {
382 return ErrNoScopeStore
383 }
384 return c.scopes.removeScopes(ids)
385 }
387 func (c Context) ListScopes() ([]Scope, error) {
388 if c.scopes == nil {
389 return []Scope{}, ErrNoScopeStore
390 }
391 return c.scopes.listScopes()
392 }