auth

Paddy 2015-06-29 Parent:8ecb60d29b0d

174:9e3ceddf29ad Go to Latest

auth/profile_postgres.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@148 1 package auth
paddy@148 2
paddy@148 3 import (
paddy@148 4 "time"
paddy@148 5
paddy@148 6 "code.secondbit.org/uuid.hg"
paddy@149 7 "github.com/lib/pq"
paddy@148 8 "github.com/secondbit/pan"
paddy@148 9 )
paddy@148 10
paddy@148 11 func (p Profile) GetSQLTableName() string {
paddy@148 12 return "profiles"
paddy@148 13 }
paddy@148 14
paddy@148 15 func (l Login) GetSQLTableName() string {
paddy@148 16 return "logins"
paddy@148 17 }
paddy@148 18
paddy@148 19 func (p *postgres) getProfileByIDSQL(id uuid.ID) *pan.Query {
paddy@148 20 var profile Profile
paddy@149 21 fields, _ := pan.GetFields(profile)
paddy@148 22 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(profile))
paddy@148 23 query.IncludeWhere()
paddy@161 24 query.Include(pan.GetUnquotedColumn(profile, "ID")+" = ?", id)
paddy@148 25 return query.FlushExpressions(" ")
paddy@148 26 }
paddy@148 27
paddy@148 28 func (p *postgres) getProfileByID(id uuid.ID) (Profile, error) {
paddy@148 29 query := p.getProfileByIDSQL(id)
paddy@148 30 rows, err := p.db.Query(query.String(), query.Args...)
paddy@148 31 if err != nil {
paddy@148 32 return Profile{}, err
paddy@148 33 }
paddy@148 34 var profile Profile
paddy@149 35 var found bool
paddy@148 36 for rows.Next() {
paddy@148 37 err := pan.Unmarshal(rows, &profile)
paddy@148 38 if err != nil {
paddy@148 39 return Profile{}, err
paddy@148 40 }
paddy@149 41 found = true
paddy@148 42 }
paddy@148 43 if err := rows.Err(); err != nil {
paddy@148 44 return Profile{}, err
paddy@148 45 }
paddy@149 46 if !found {
paddy@149 47 return profile, ErrProfileNotFound
paddy@149 48 }
paddy@148 49 return profile, nil
paddy@148 50 }
paddy@148 51
paddy@148 52 func (p *postgres) getProfileByLoginSQL(value string) *pan.Query {
paddy@148 53 var profile Profile
paddy@148 54 var login Login
paddy@149 55 fields, _ := pan.GetUnquotedAbsoluteFields(profile)
paddy@148 56 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(profile))
paddy@148 57 query.Include("INNER JOIN " + pan.GetTableName(login))
paddy@149 58 query.Include("ON " + pan.GetUnquotedAbsoluteColumn(profile, "ID") + " = " + pan.GetUnquotedAbsoluteColumn(login, "ProfileID"))
paddy@148 59 query.IncludeWhere()
paddy@161 60 query.Include(pan.GetUnquotedAbsoluteColumn(login, "Value")+" = ?", value)
paddy@148 61 return query.FlushExpressions(" ")
paddy@148 62 }
paddy@148 63
paddy@148 64 func (p *postgres) getProfileByLogin(value string) (Profile, error) {
paddy@148 65 query := p.getProfileByLoginSQL(value)
paddy@148 66 rows, err := p.db.Query(query.String(), query.Args...)
paddy@148 67 if err != nil {
paddy@148 68 return Profile{}, err
paddy@148 69 }
paddy@148 70 var profile Profile
paddy@149 71 var found bool
paddy@148 72 for rows.Next() {
paddy@148 73 err := pan.Unmarshal(rows, &profile)
paddy@148 74 if err != nil {
paddy@148 75 return Profile{}, err
paddy@148 76 }
paddy@149 77 found = true
paddy@148 78 }
paddy@148 79 if err := rows.Err(); err != nil {
paddy@148 80 return Profile{}, err
paddy@148 81 }
paddy@149 82 if !found {
paddy@149 83 return profile, ErrProfileNotFound
paddy@149 84 }
paddy@148 85 return profile, nil
paddy@148 86 }
paddy@148 87
paddy@148 88 func (p *postgres) saveProfileSQL(profile Profile) *pan.Query {
paddy@149 89 fields, values := pan.GetFields(profile)
paddy@148 90 query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(profile))
paddy@148 91 query.Include("(" + pan.QueryList(fields) + ")")
paddy@148 92 query.Include("VALUES")
paddy@148 93 query.Include("("+pan.VariableList(len(values))+")", values...)
paddy@148 94 return query.FlushExpressions(" ")
paddy@148 95 }
paddy@148 96
paddy@148 97 func (p *postgres) saveProfile(profile Profile) error {
paddy@148 98 query := p.saveProfileSQL(profile)
paddy@148 99 _, err := p.db.Exec(query.String(), query.Args...)
paddy@149 100 if e, ok := err.(*pq.Error); ok && e.Constraint == "profiles_pkey" {
paddy@149 101 err = ErrProfileAlreadyExists
paddy@149 102 }
paddy@148 103 return err
paddy@148 104 }
paddy@148 105
paddy@148 106 func (p *postgres) updateProfileSQL(id uuid.ID, change ProfileChange) *pan.Query {
paddy@148 107 var profile Profile
paddy@148 108 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(profile)+" SET ")
paddy@149 109 query.IncludeIfNotNil(pan.GetUnquotedColumn(profile, "Name")+" = ?", change.Name)
paddy@149 110 query.IncludeIfNotNil(pan.GetUnquotedColumn(profile, "Passphrase")+" = ?", change.Passphrase)
paddy@149 111 query.IncludeIfNotNil(pan.GetUnquotedColumn(profile, "Iterations")+" = ?", change.Iterations)
paddy@149 112 query.IncludeIfNotNil(pan.GetUnquotedColumn(profile, "Salt")+" = ?", change.Salt)
paddy@149 113 query.IncludeIfNotNil(pan.GetUnquotedColumn(profile, "PassphraseScheme")+" = ?", change.PassphraseScheme)
paddy@149 114 query.IncludeIfNotNil(pan.GetUnquotedColumn(profile, "Compromised")+" = ?", change.Compromised)
paddy@149 115 query.IncludeIfNotNil(pan.GetUnquotedColumn(profile, "LockedUntil")+" = ?", change.LockedUntil)
paddy@149 116 query.IncludeIfNotNil(pan.GetUnquotedColumn(profile, "PassphraseReset")+" = ?", change.PassphraseReset)
paddy@149 117 query.IncludeIfNotNil(pan.GetUnquotedColumn(profile, "PassphraseResetCreated")+" = ?", change.PassphraseResetCreated)
paddy@149 118 query.IncludeIfNotNil(pan.GetUnquotedColumn(profile, "LastSeen")+" = ?", change.LastSeen)
paddy@148 119 query.FlushExpressions(", ")
paddy@148 120 query.IncludeWhere()
paddy@150 121 query.Include(pan.GetUnquotedColumn(profile, "ID")+" = ?", id)
paddy@148 122 return query.FlushExpressions(" ")
paddy@148 123 }
paddy@148 124
paddy@148 125 func (p *postgres) updateProfile(id uuid.ID, change ProfileChange) error {
paddy@149 126 if change.Empty() {
paddy@149 127 return nil
paddy@149 128 }
paddy@148 129 query := p.updateProfileSQL(id, change)
paddy@148 130 _, err := p.db.Exec(query.String(), query.Args...)
paddy@148 131 return err
paddy@148 132 }
paddy@148 133
paddy@148 134 func (p *postgres) updateProfilesSQL(ids []uuid.ID, change BulkProfileChange) *pan.Query {
paddy@149 135 if change.Empty() {
paddy@149 136 return nil
paddy@149 137 }
paddy@148 138 var profile Profile
paddy@148 139 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(profile)+" SET ")
paddy@149 140 query.IncludeIfNotNil(pan.GetUnquotedColumn(profile, "Compromised")+" = ?", change.Compromised)
paddy@148 141 query.FlushExpressions(", ")
paddy@148 142 query.IncludeWhere()
paddy@148 143 intids := make([]interface{}, len(ids))
paddy@148 144 for pos, id := range ids {
paddy@148 145 intids[pos] = id
paddy@148 146 }
paddy@149 147 query.Include(pan.GetUnquotedColumn(profile, "ID")+" IN ("+pan.VariableList(len(ids))+")", intids...)
paddy@148 148 return query.FlushExpressions(" ")
paddy@148 149 }
paddy@148 150
paddy@148 151 func (p *postgres) updateProfiles(ids []uuid.ID, change BulkProfileChange) error {
paddy@148 152 query := p.updateProfilesSQL(ids, change)
paddy@148 153 _, err := p.db.Exec(query.String(), query.Args...)
paddy@148 154 return err
paddy@148 155 }
paddy@148 156
paddy@161 157 func (p *postgres) deleteProfileSQL(id uuid.ID) *pan.Query {
paddy@161 158 var profile Profile
paddy@161 159 query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(profile))
paddy@161 160 query.IncludeWhere()
paddy@161 161 query.Include(pan.GetUnquotedColumn(profile, "ID")+" = ?", id)
paddy@161 162 return query.FlushExpressions(" ")
paddy@161 163 }
paddy@161 164
paddy@161 165 func (p *postgres) deleteProfile(id uuid.ID) error {
paddy@161 166 query := p.deleteProfileSQL(id)
paddy@161 167 res, err := p.db.Exec(query.String(), query.Args...)
paddy@161 168 if err != nil {
paddy@161 169 return err
paddy@161 170 }
paddy@161 171 rows, err := res.RowsAffected()
paddy@161 172 if err != nil {
paddy@161 173 return err
paddy@161 174 }
paddy@161 175 if rows == 0 {
paddy@161 176 return ErrProfileNotFound
paddy@161 177 }
paddy@161 178 return nil
paddy@161 179 }
paddy@161 180
paddy@148 181 func (p *postgres) addLoginSQL(login Login) *pan.Query {
paddy@149 182 fields, values := pan.GetFields(login)
paddy@148 183 query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(login))
paddy@148 184 query.Include("(" + pan.QueryList(fields) + ")")
paddy@148 185 query.Include("VALUES")
paddy@148 186 query.Include("("+pan.VariableList(len(values))+")", values...)
paddy@148 187 return query.FlushExpressions(" ")
paddy@148 188 }
paddy@148 189
paddy@148 190 func (p *postgres) addLogin(login Login) error {
paddy@148 191 query := p.addLoginSQL(login)
paddy@148 192 _, err := p.db.Exec(query.String(), query.Args...)
paddy@149 193 if e, ok := err.(*pq.Error); ok && e.Constraint == "logins_pkey" {
paddy@149 194 return ErrLoginAlreadyExists
paddy@149 195 }
paddy@148 196 return err
paddy@148 197 }
paddy@148 198
paddy@160 199 func (p *postgres) removeLoginsByProfileSQL(profile uuid.ID) *pan.Query {
paddy@160 200 var login Login
paddy@160 201 query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(login))
paddy@160 202 query.IncludeWhere()
paddy@160 203 query.Include(pan.GetUnquotedColumn(login, "ProfileID")+" = ?", profile)
paddy@160 204 return query.FlushExpressions(" ")
paddy@160 205 }
paddy@160 206
paddy@160 207 func (p *postgres) removeLoginsByProfile(profile uuid.ID) error {
paddy@160 208 query := p.removeLoginsByProfileSQL(profile)
paddy@160 209 res, err := p.db.Exec(query.String(), query.Args...)
paddy@160 210 if err != nil {
paddy@160 211 return err
paddy@160 212 }
paddy@160 213 rows, err := res.RowsAffected()
paddy@160 214 if err != nil {
paddy@160 215 return err
paddy@160 216 }
paddy@160 217 if rows == 0 {
paddy@160 218 return ErrProfileNotFound
paddy@160 219 }
paddy@160 220 return nil
paddy@160 221 }
paddy@160 222
paddy@148 223 func (p *postgres) removeLoginSQL(value string, profile uuid.ID) *pan.Query {
paddy@148 224 var login Login
paddy@148 225 query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(login))
paddy@148 226 query.IncludeWhere()
paddy@150 227 query.Include(pan.GetUnquotedColumn(login, "Value")+" = ? AND "+pan.GetUnquotedColumn(login, "ProfileID")+" = ?", value, profile)
paddy@148 228 return query.FlushExpressions(" ")
paddy@148 229 }
paddy@148 230
paddy@148 231 func (p *postgres) removeLogin(value string, profile uuid.ID) error {
paddy@148 232 query := p.removeLoginSQL(value, profile)
paddy@149 233 res, err := p.db.Exec(query.String(), query.Args...)
paddy@149 234 if err != nil {
paddy@149 235 return err
paddy@149 236 }
paddy@149 237 rows, err := res.RowsAffected()
paddy@149 238 if err != nil {
paddy@149 239 return err
paddy@149 240 }
paddy@149 241 if rows == 0 {
paddy@149 242 return ErrLoginNotFound
paddy@149 243 }
paddy@149 244 return nil
paddy@148 245 }
paddy@148 246
paddy@148 247 func (p *postgres) recordLoginUseSQL(value string, when time.Time) *pan.Query {
paddy@148 248 var login Login
paddy@148 249 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(login)+" SET ")
paddy@150 250 query.Include(pan.GetUnquotedColumn(login, "LastUsed")+" = ?", when)
paddy@148 251 query.IncludeWhere()
paddy@150 252 query.Include(pan.GetUnquotedColumn(login, "Value")+" = ?", value)
paddy@148 253 return query.FlushExpressions(" ")
paddy@148 254 }
paddy@148 255
paddy@148 256 func (p *postgres) recordLoginUse(value string, when time.Time) error {
paddy@148 257 query := p.recordLoginUseSQL(value, when)
paddy@148 258 _, err := p.db.Exec(query.String(), query.Args...)
paddy@148 259 return err
paddy@148 260 }
paddy@148 261
paddy@172 262 func (p *postgres) verifyLoginSQL(value, verification string) *pan.Query {
paddy@172 263 var login Login
paddy@172 264 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(login)+" SET ")
paddy@172 265 query.Include(pan.GetUnquotedColumn(login, "Verified")+" = ?", true)
paddy@172 266 query.IncludeWhere()
paddy@172 267 query.FlushExpressions(" ")
paddy@172 268 query.Include(pan.GetUnquotedColumn(login, "Value")+" = ?", value)
paddy@172 269 query.Include(pan.GetUnquotedColumn(login, "Verification")+" = ?", verification)
paddy@172 270 return query.FlushExpressions(" AND ")
paddy@172 271 }
paddy@172 272
paddy@172 273 func (p *postgres) verifyLogin(value, verification string) error {
paddy@172 274 query := p.verifyLoginSQL(value, verification)
paddy@172 275 res, err := p.db.Exec(query.String(), query.Args...)
paddy@172 276 if err != nil {
paddy@172 277 return err
paddy@172 278 }
paddy@172 279 rows, err := res.RowsAffected()
paddy@172 280 if err != nil {
paddy@172 281 return err
paddy@172 282 }
paddy@172 283 if rows == 0 {
paddy@172 284 return ErrLoginVerificationInvalid
paddy@172 285 }
paddy@172 286 return nil
paddy@172 287 }
paddy@172 288
paddy@172 289 func (p *postgres) getLoginSQL(value string) *pan.Query {
paddy@172 290 var login Login
paddy@172 291 fields, _ := pan.GetFields(login)
paddy@172 292 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(login))
paddy@172 293 query.IncludeWhere()
paddy@172 294 query.Include(pan.GetUnquotedColumn(login, "Value")+" = ?", value)
paddy@172 295 return query.FlushExpressions(" ")
paddy@172 296 }
paddy@172 297
paddy@172 298 func (p *postgres) getLogin(value string) (Login, error) {
paddy@172 299 query := p.getLoginSQL(value)
paddy@172 300 rows, err := p.db.Query(query.String(), query.Args...)
paddy@172 301 if err != nil {
paddy@172 302 return Login{}, err
paddy@172 303 }
paddy@172 304 var login Login
paddy@172 305 var found bool
paddy@172 306 for rows.Next() {
paddy@172 307 err := pan.Unmarshal(rows, &login)
paddy@172 308 if err != nil {
paddy@172 309 return Login{}, err
paddy@172 310 }
paddy@172 311 found = true
paddy@172 312 }
paddy@172 313 if err := rows.Err(); err != nil {
paddy@172 314 return Login{}, err
paddy@172 315 }
paddy@172 316 if !found {
paddy@172 317 return login, ErrLoginNotFound
paddy@172 318 }
paddy@172 319 return login, nil
paddy@172 320 }
paddy@172 321
paddy@148 322 func (p *postgres) listLoginsSQL(profile uuid.ID, num, offset int) *pan.Query {
paddy@148 323 var login Login
paddy@149 324 fields, _ := pan.GetFields(login)
paddy@148 325 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(login))
paddy@148 326 query.IncludeWhere()
paddy@150 327 query.Include(pan.GetUnquotedColumn(login, "ProfileID")+" = ?", profile)
paddy@148 328 query.IncludeLimit(int64(num))
paddy@148 329 query.IncludeOffset(int64(offset))
paddy@148 330 return query.FlushExpressions(" ")
paddy@148 331 }
paddy@148 332
paddy@148 333 func (p *postgres) listLogins(profile uuid.ID, num, offset int) ([]Login, error) {
paddy@148 334 query := p.listLoginsSQL(profile, num, offset)
paddy@148 335 rows, err := p.db.Query(query.String(), query.Args...)
paddy@148 336 if err != nil {
paddy@148 337 return []Login{}, err
paddy@148 338 }
paddy@148 339 var logins []Login
paddy@148 340 for rows.Next() {
paddy@148 341 var login Login
paddy@148 342 err = pan.Unmarshal(rows, &login)
paddy@148 343 if err != nil {
paddy@148 344 return logins, err
paddy@148 345 }
paddy@148 346 logins = append(logins, login)
paddy@148 347 }
paddy@148 348 if err := rows.Err(); err != nil {
paddy@148 349 return logins, err
paddy@148 350 }
paddy@148 351 return logins, nil
paddy@148 352 }