auth

Paddy 2014-11-02 Parent:b3cd7765a7c8 Child:42bc3e44f4fe

65:f97ca45d5657 Go to Latest

auth/context.go

Fix bug with response_type redirect, add tests. Test that we redirect with an error when an invalid response_type is supplied. Fix a bug that would not add any of our parameters to the redirect URL.

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@50 7 "time"
paddy@50 8
paddy@50 9 "code.secondbit.org/uuid"
paddy@50 10 )
paddy@50 11
paddy@57 12 // Context wraps the different storage interfaces and should
paddy@57 13 // be used as the main point of interaction for the data storage
paddy@57 14 // layer.
paddy@50 15 type Context struct {
paddy@50 16 template *template.Template
paddy@57 17 clients clientStore
paddy@57 18 grants grantStore
paddy@57 19 profiles profileStore
paddy@57 20 tokens tokenStore
paddy@50 21 }
paddy@50 22
paddy@57 23 // Render uses the HTML templates associated with the Context to render the
paddy@57 24 // template specified by name to out using data to fill any template variables.
paddy@55 25 func (c Context) Render(out io.Writer, name string, data interface{}) {
paddy@50 26 if c.template == nil {
paddy@57 27 log.Println("No template set on Context, can't render anything!")
paddy@57 28 return
paddy@50 29 }
paddy@55 30 err := c.template.ExecuteTemplate(out, name, data)
paddy@55 31 if err != nil {
paddy@55 32 log.Println("Error executing template", name, ":", err)
paddy@55 33 }
paddy@50 34 }
paddy@50 35
paddy@57 36 // GetClient returns a single Client by its ID from the
paddy@57 37 // clientStore associated with the Context.
paddy@50 38 func (c Context) GetClient(id uuid.ID) (Client, error) {
paddy@50 39 if c.clients == nil {
paddy@50 40 return Client{}, ErrNoClientStore
paddy@50 41 }
paddy@57 42 return c.clients.getClient(id)
paddy@50 43 }
paddy@50 44
paddy@57 45 // SaveClient stores the passed Client in the clientStore
paddy@57 46 // associated with the Context.
paddy@50 47 func (c Context) SaveClient(client Client) error {
paddy@50 48 if c.clients == nil {
paddy@50 49 return ErrNoClientStore
paddy@50 50 }
paddy@57 51 return c.clients.saveClient(client)
paddy@50 52 }
paddy@50 53
paddy@57 54 // UpdateClient applies the specified ClientChange to the Client
paddy@57 55 // with the specified ID in the clientStore associated with the
paddy@57 56 // Context.
paddy@50 57 func (c Context) UpdateClient(id uuid.ID, change ClientChange) error {
paddy@50 58 if c.clients == nil {
paddy@50 59 return ErrNoClientStore
paddy@50 60 }
paddy@57 61 return c.clients.updateClient(id, change)
paddy@50 62 }
paddy@50 63
paddy@57 64 // DeleteClient removes the client with the specified ID from the
paddy@57 65 // clientStore associated with the Context.
paddy@50 66 func (c Context) DeleteClient(id uuid.ID) error {
paddy@50 67 if c.clients == nil {
paddy@50 68 return ErrNoClientStore
paddy@50 69 }
paddy@57 70 return c.clients.deleteClient(id)
paddy@50 71 }
paddy@50 72
paddy@57 73 // ListClientsByOwner returns a slice of up to num Clients, starting at offset (inclusive)
paddy@57 74 // that have the specified OwnerID in the clientStore associated with the Context.
paddy@50 75 func (c Context) ListClientsByOwner(ownerID uuid.ID, num, offset int) ([]Client, error) {
paddy@50 76 if c.clients == nil {
paddy@50 77 return []Client{}, ErrNoClientStore
paddy@50 78 }
paddy@57 79 return c.clients.listClientsByOwner(ownerID, num, offset)
paddy@50 80 }
paddy@50 81
paddy@57 82 // AddEndpoint stores the specified Endpoint in the clientStore associated with the Context,
paddy@57 83 // and associates the newly-stored Endpoint with the Client specified by the passed ID.
paddy@50 84 func (c Context) AddEndpoint(client uuid.ID, endpoint Endpoint) error {
paddy@50 85 if c.clients == nil {
paddy@50 86 return ErrNoClientStore
paddy@50 87 }
paddy@57 88 return c.clients.addEndpoint(client, endpoint)
paddy@50 89 }
paddy@50 90
paddy@57 91 // RemoveEndpoint deletes the Endpoint with the specified ID from the clientStore associated
paddy@57 92 // with the Context, and disassociates the Endpoint from the specified Client.
paddy@50 93 func (c Context) RemoveEndpoint(client, endpoint uuid.ID) error {
paddy@50 94 if c.clients == nil {
paddy@50 95 return ErrNoClientStore
paddy@50 96 }
paddy@57 97 return c.clients.removeEndpoint(client, endpoint)
paddy@50 98 }
paddy@50 99
paddy@57 100 // CheckEndpoint finds Endpoints in the clientStore associated with the Context that belong
paddy@58 101 // to the Client specified by the passed ID and match the URI passed. URI matches must be
paddy@58 102 // performed according to RFC 3986 Section 6.
paddy@58 103 func (c Context) CheckEndpoint(client uuid.ID, URI string) (bool, error) {
paddy@50 104 if c.clients == nil {
paddy@50 105 return false, ErrNoClientStore
paddy@50 106 }
paddy@58 107 return c.clients.checkEndpoint(client, URI)
paddy@50 108 }
paddy@50 109
paddy@57 110 // ListEndpoints finds Endpoints in the clientStore associated with the Context that belong
paddy@57 111 // to the Client specified by the passed ID. It returns up to num endpoints, starting at offset,
paddy@57 112 // exclusive.
paddy@50 113 func (c Context) ListEndpoints(client uuid.ID, num, offset int) ([]Endpoint, error) {
paddy@50 114 if c.clients == nil {
paddy@50 115 return []Endpoint{}, ErrNoClientStore
paddy@50 116 }
paddy@57 117 return c.clients.listEndpoints(client, num, offset)
paddy@50 118 }
paddy@50 119
paddy@57 120 // CountEndpoints returns the number of Endpoints the are associated with the Client specified by the
paddy@57 121 // passed ID in the clientStore associated with the Context.
paddy@55 122 func (c Context) CountEndpoints(client uuid.ID) (int64, error) {
paddy@55 123 if c.clients == nil {
paddy@55 124 return 0, ErrNoClientStore
paddy@55 125 }
paddy@57 126 return c.clients.countEndpoints(client)
paddy@55 127 }
paddy@55 128
paddy@57 129 // GetGrant returns the Grant specified by the provided code from the grantStore associated with the
paddy@57 130 // Context.
paddy@50 131 func (c Context) GetGrant(code string) (Grant, error) {
paddy@50 132 if c.grants == nil {
paddy@50 133 return Grant{}, ErrNoGrantStore
paddy@50 134 }
paddy@57 135 return c.grants.getGrant(code)
paddy@50 136 }
paddy@50 137
paddy@57 138 // SaveGrant stores the passed Grant in the grantStore associated with the Context.
paddy@50 139 func (c Context) SaveGrant(grant Grant) error {
paddy@50 140 if c.grants == nil {
paddy@50 141 return ErrNoGrantStore
paddy@50 142 }
paddy@57 143 return c.grants.saveGrant(grant)
paddy@50 144 }
paddy@50 145
paddy@57 146 // DeleteGrant removes the Grant specified by the provided code from the grantStore associated with
paddy@57 147 // the Context.
paddy@50 148 func (c Context) DeleteGrant(code string) error {
paddy@50 149 if c.grants == nil {
paddy@50 150 return ErrNoGrantStore
paddy@50 151 }
paddy@57 152 return c.grants.deleteGrant(code)
paddy@50 153 }
paddy@50 154
paddy@57 155 // GetProfileByID returns the Profile specified by the provided ID from the profileStore associated with
paddy@57 156 // the Context.
paddy@50 157 func (c Context) GetProfileByID(id uuid.ID) (Profile, error) {
paddy@50 158 if c.profiles == nil {
paddy@50 159 return Profile{}, ErrNoProfileStore
paddy@50 160 }
paddy@57 161 return c.profiles.getProfileByID(id)
paddy@50 162 }
paddy@50 163
paddy@57 164 // GetProfileByLogin returns the Profile associated with the specified Login from the profileStore associated
paddy@57 165 // with the Context.
paddy@50 166 func (c Context) GetProfileByLogin(loginType, value string) (Profile, error) {
paddy@50 167 if c.profiles == nil {
paddy@50 168 return Profile{}, ErrNoProfileStore
paddy@50 169 }
paddy@57 170 return c.profiles.getProfileByLogin(loginType, value)
paddy@50 171 }
paddy@50 172
paddy@57 173 // SaveProfile inserts the passed Profile into the profileStore associated with the Context.
paddy@50 174 func (c Context) SaveProfile(profile Profile) error {
paddy@50 175 if c.profiles == nil {
paddy@50 176 return ErrNoProfileStore
paddy@50 177 }
paddy@57 178 return c.profiles.saveProfile(profile)
paddy@50 179 }
paddy@50 180
paddy@57 181 // UpdateProfile applies the supplied ProfileChange to the Profile that matches the specified ID
paddy@57 182 // in the profileStore associated with the Context.
paddy@50 183 func (c Context) UpdateProfile(id uuid.ID, change ProfileChange) error {
paddy@50 184 if c.profiles == nil {
paddy@50 185 return ErrNoProfileStore
paddy@50 186 }
paddy@57 187 return c.profiles.updateProfile(id, change)
paddy@50 188 }
paddy@50 189
paddy@57 190 // UpdateProfiles applies the supplied BulkProfileChange to every Profile that matches one of the
paddy@57 191 // specified IDs in the profileStore associated with the Context.
paddy@50 192 func (c Context) UpdateProfiles(ids []uuid.ID, change BulkProfileChange) error {
paddy@50 193 if c.profiles == nil {
paddy@50 194 return ErrNoProfileStore
paddy@50 195 }
paddy@57 196 return c.profiles.updateProfiles(ids, change)
paddy@50 197 }
paddy@50 198
paddy@57 199 // DeleteProfile removes the Profile specified by the passed ID from the profileStore associated
paddy@57 200 // with the Context.
paddy@50 201 func (c Context) DeleteProfile(id uuid.ID) error {
paddy@50 202 if c.profiles == nil {
paddy@50 203 return ErrNoProfileStore
paddy@50 204 }
paddy@57 205 return c.profiles.deleteProfile(id)
paddy@50 206 }
paddy@50 207
paddy@57 208 // AddLogin stores the passed Login in the profileStore associated with the Context. It also associates
paddy@57 209 // the newly-created Login with the Orofile in login.ProfileID.
paddy@50 210 func (c Context) AddLogin(login Login) error {
paddy@50 211 if c.profiles == nil {
paddy@50 212 return ErrNoProfileStore
paddy@50 213 }
paddy@57 214 return c.profiles.addLogin(login)
paddy@50 215 }
paddy@50 216
paddy@57 217 // RemoveLogin removes the specified Login from the profileStore associated with the Context, provided
paddy@57 218 // the Login has a ProfileID property that matches the profile ID passed in. It also disassociates the
paddy@57 219 // deleted Login from the Profile in login.ProfileID.
paddy@50 220 func (c Context) RemoveLogin(loginType, value string, profile uuid.ID) error {
paddy@50 221 if c.profiles == nil {
paddy@50 222 return ErrNoProfileStore
paddy@50 223 }
paddy@57 224 return c.profiles.removeLogin(loginType, value, profile)
paddy@50 225 }
paddy@50 226
paddy@57 227 // RecordLoginUse sets the LastUsed property of the Login specified in the profileStore associated with
paddy@57 228 // the Context to the value passed in as when.
paddy@50 229 func (c Context) RecordLoginUse(loginType, value string, when time.Time) error {
paddy@50 230 if c.profiles == nil {
paddy@50 231 return ErrNoProfileStore
paddy@50 232 }
paddy@57 233 return c.profiles.recordLoginUse(loginType, value, when)
paddy@50 234 }
paddy@50 235
paddy@57 236 // ListLogins returns a slice of up to num Logins associated with the specified Profile from the profileStore
paddy@57 237 // associated with the Context, skipping offset Profiles.
paddy@50 238 func (c Context) ListLogins(profile uuid.ID, num, offset int) ([]Login, error) {
paddy@50 239 if c.profiles == nil {
paddy@50 240 return []Login{}, ErrNoProfileStore
paddy@50 241 }
paddy@57 242 return c.profiles.listLogins(profile, num, offset)
paddy@50 243 }
paddy@50 244
paddy@57 245 // GetToken returns the Token specified from the tokenStore associated with the Context.
paddy@57 246 // If refresh is true, the token input should be compared against the refresh tokens, not the
paddy@57 247 // access tokens.
paddy@50 248 func (c Context) GetToken(token string, refresh bool) (Token, error) {
paddy@50 249 if c.tokens == nil {
paddy@50 250 return Token{}, ErrNoTokenStore
paddy@50 251 }
paddy@57 252 return c.tokens.getToken(token, refresh)
paddy@50 253 }
paddy@50 254
paddy@57 255 // SaveToken stores the passed Token in the tokenStore associated with the Context.
paddy@50 256 func (c Context) SaveToken(token Token) error {
paddy@50 257 if c.tokens == nil {
paddy@50 258 return ErrNoTokenStore
paddy@50 259 }
paddy@57 260 return c.tokens.saveToken(token)
paddy@50 261 }
paddy@50 262
paddy@57 263 // RemoveToken removes the Token identified by the passed token string from the tokenStore associated
paddy@57 264 // with the Context.
paddy@50 265 func (c Context) RemoveToken(token string) error {
paddy@50 266 if c.tokens == nil {
paddy@50 267 return ErrNoTokenStore
paddy@50 268 }
paddy@57 269 return c.tokens.removeToken(token)
paddy@50 270 }
paddy@50 271
paddy@57 272 // GetTokensByProfileID returns a slice of up to num Tokens with a ProfileID that matches the specified
paddy@57 273 // profileID from the tokenStore associated with the Context, skipping offset Tokens.
paddy@50 274 func (c Context) GetTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) {
paddy@50 275 if c.tokens == nil {
paddy@50 276 return []Token{}, ErrNoTokenStore
paddy@50 277 }
paddy@57 278 return c.tokens.getTokensByProfileID(profileID, num, offset)
paddy@50 279 }