auth

Paddy 2015-01-18 Parent:e000b1c24fc0 Child:b714af0578dc

120:118a69954621 Go to Latest

auth/context.go

Validate client when doing credential grants. When granting a token based on user credentials, I forgot to validate the client credentials that were sent. So implement that.

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