auth

Paddy 2015-06-29 Parent:8ecb60d29b0d Child:0a2c3d677161

174:9e3ceddf29ad Go to Latest

auth/context.go

Use an environment variable to set the JWT secret. When setting up the authd server, populate the JWT secret using a JWT_SECRET environment variable. Incidentally, we also included the subscriptions scope, for testing purposes while creating code.secondbit.org/ducky/subscriptions. We now also log the port we're listening on, listen on all interfaces (instead of just 127.0.0.1), and changed the port to 9000 instead of 8080.

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