auth

Paddy 2015-03-18 Parent:3aeadd2201e9 Child:06fb735031bb

146:b5432f50f057 Go to Latest

auth/context.go

Fix tests. It made no sense to have the Profile's Passphrase length check in the Validate call of the ProfileChange type, because the ProfileChange had that property being applied as the _hashed_ passphrase. And We want to validate the _cleartext_ passphrase. So we removed that in e660a38fa936. But we forgot to update the tests. So I'm updating now.

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