auth

Paddy 2015-04-07 Parent:3e8964a914ef Child:73e12d5a1124

155:762953f6a7f2 Go to Latest

auth/scope_postgres.go

Implement postgres version of the tokenStore. Create a postgres implementation for the tokenStore. Note that because pq doesn't support Postgres' array types (see https://github.com/lib/pq/issues/49), we couldn't just store the token.Scopes field as a Postgres array of varchars, which would have been the ideal. Instead, we need a many-to-many table that maps tokens to scopes. This meant we needed a special tokenScope type for our database mapping, and we needed to complicate the token storage/retrieval functions a little bit. It's kind of ugly, I'm not a huge fan of it, and I'd much rather be using the Postgres array types, but... well, here we are. We also added the postgres tokenStore to our slice of tokenStores to test when the correct environment variables are present. We wrote initialization SQL for the tables required by the postgres tokenStore. Also, added a helper script for emptying the test database, because I got tired of doing it by hand. We should be doing that in an automated fashion in the tests themselves, but that would mean extending the *Store interfaces.

History
paddy@152 1 package auth
paddy@152 2
paddy@152 3 import (
paddy@153 4 "github.com/lib/pq"
paddy@152 5 "github.com/secondbit/pan"
paddy@152 6 )
paddy@152 7
paddy@152 8 func (s Scope) GetSQLTableName() string {
paddy@152 9 return "scopes"
paddy@152 10 }
paddy@152 11
paddy@152 12 func (p *postgres) createScopesSQL(scopes []Scope) *pan.Query {
paddy@152 13 fields, _ := pan.GetFields(scopes[0])
paddy@152 14 query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(scopes[0]))
paddy@152 15 query.Include("(" + pan.QueryList(fields) + ")")
paddy@152 16 query.Include("VALUES")
paddy@153 17 query.FlushExpressions(" ")
paddy@152 18 for _, scope := range scopes {
paddy@152 19 _, values := pan.GetFields(scope)
paddy@152 20 query.Include("("+pan.VariableList(len(values))+")", values...)
paddy@152 21 }
paddy@153 22 return query.FlushExpressions(", ")
paddy@152 23 }
paddy@152 24
paddy@152 25 func (p *postgres) createScopes(scopes []Scope) error {
paddy@152 26 if len(scopes) < 1 {
paddy@152 27 return nil
paddy@152 28 }
paddy@152 29 query := p.createScopesSQL(scopes)
paddy@152 30 _, err := p.db.Exec(query.String(), query.Args...)
paddy@153 31 if e, ok := err.(*pq.Error); ok && e.Constraint == "scopes_pkey" {
paddy@153 32 err = ErrScopeAlreadyExists
paddy@153 33 }
paddy@152 34 return err
paddy@152 35 }
paddy@152 36
paddy@152 37 func (p *postgres) getScopesSQL(ids []string) *pan.Query {
paddy@152 38 var scope Scope
paddy@152 39 intids := make([]interface{}, len(ids))
paddy@152 40 for pos, id := range ids {
paddy@152 41 intids[pos] = id
paddy@152 42 }
paddy@152 43 fields, _ := pan.GetFields(scope)
paddy@152 44 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(scope))
paddy@152 45 query.IncludeWhere()
paddy@152 46 query.Include(pan.GetUnquotedColumn(scope, "ID") + " IN")
paddy@152 47 query.Include("("+pan.VariableList(len(ids))+")", intids...)
paddy@152 48 return query.FlushExpressions(" ")
paddy@152 49 }
paddy@152 50
paddy@152 51 func (p *postgres) getScopes(ids []string) ([]Scope, error) {
paddy@152 52 query := p.getScopesSQL(ids)
paddy@152 53 rows, err := p.db.Query(query.String(), query.Args...)
paddy@152 54 if err != nil {
paddy@152 55 return []Scope{}, err
paddy@152 56 }
paddy@152 57 var scopes []Scope
paddy@152 58 for rows.Next() {
paddy@152 59 var scope Scope
paddy@152 60 err := pan.Unmarshal(rows, &scope)
paddy@152 61 if err != nil {
paddy@152 62 return scopes, err
paddy@152 63 }
paddy@152 64 scopes = append(scopes, scope)
paddy@152 65 }
paddy@152 66 if err = rows.Err(); err != nil {
paddy@152 67 return scopes, err
paddy@152 68 }
paddy@152 69 return scopes, nil
paddy@152 70 }
paddy@152 71
paddy@152 72 func (p *postgres) updateScopeSQL(id string, change ScopeChange) *pan.Query {
paddy@152 73 var scope Scope
paddy@152 74 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(scope)+" SET ")
paddy@152 75 query.IncludeIfNotNil(pan.GetUnquotedColumn(scope, "Name")+" = ?", change.Name)
paddy@152 76 query.IncludeIfNotNil(pan.GetUnquotedColumn(scope, "Description")+" = ?", change.Description)
paddy@152 77 query.FlushExpressions(", ")
paddy@152 78 query.IncludeWhere()
paddy@152 79 query.Include(pan.GetUnquotedColumn(scope, "ID")+" = ?", id)
paddy@152 80 return query.FlushExpressions(" ")
paddy@152 81 }
paddy@152 82
paddy@152 83 func (p *postgres) updateScope(id string, change ScopeChange) error {
paddy@152 84 if change.Empty() {
paddy@152 85 return nil
paddy@152 86 }
paddy@152 87 query := p.updateScopeSQL(id, change)
paddy@153 88 res, err := p.db.Exec(query.String(), query.Args...)
paddy@153 89 if err != nil {
paddy@153 90 return err
paddy@153 91 }
paddy@153 92 rows, err := res.RowsAffected()
paddy@153 93 if err != nil {
paddy@153 94 return err
paddy@153 95 }
paddy@153 96 if rows < 1 {
paddy@153 97 return ErrScopeNotFound
paddy@153 98 }
paddy@152 99 return err
paddy@152 100 }
paddy@152 101
paddy@152 102 func (p *postgres) removeScopesSQL(ids []string) *pan.Query {
paddy@152 103 var scope Scope
paddy@152 104 intids := make([]interface{}, len(ids))
paddy@152 105 for pos, id := range ids {
paddy@152 106 intids[pos] = id
paddy@152 107 }
paddy@152 108 query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(scope))
paddy@152 109 query.IncludeWhere()
paddy@152 110 query.Include(pan.GetUnquotedColumn(scope, "ID") + " IN")
paddy@152 111 query.Include("("+pan.VariableList(len(ids))+")", intids...)
paddy@152 112 return query.FlushExpressions(" ")
paddy@152 113 }
paddy@152 114
paddy@152 115 func (p *postgres) removeScopes(ids []string) error {
paddy@152 116 query := p.removeScopesSQL(ids)
paddy@153 117 res, err := p.db.Exec(query.String(), query.Args...)
paddy@152 118 if err != nil {
paddy@152 119 return err
paddy@152 120 }
paddy@153 121 rows, err := res.RowsAffected()
paddy@153 122 if err != nil {
paddy@153 123 return err
paddy@153 124 }
paddy@153 125 if rows < 1 {
paddy@153 126 return ErrScopeNotFound
paddy@153 127 }
paddy@152 128 return nil
paddy@152 129 }
paddy@152 130
paddy@152 131 func (p *postgres) listScopesSQL() *pan.Query {
paddy@152 132 var scope Scope
paddy@152 133 fields, _ := pan.GetFields(scope)
paddy@152 134 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(scope))
paddy@152 135 return query.FlushExpressions(" ")
paddy@152 136 }
paddy@152 137
paddy@152 138 func (p *postgres) listScopes() ([]Scope, error) {
paddy@152 139 query := p.listScopesSQL()
paddy@152 140 rows, err := p.db.Query(query.String(), query.Args...)
paddy@152 141 if err != nil {
paddy@152 142 return []Scope{}, err
paddy@152 143 }
paddy@152 144 var scopes []Scope
paddy@152 145 for rows.Next() {
paddy@152 146 var scope Scope
paddy@152 147 err = pan.Unmarshal(rows, &scope)
paddy@152 148 if err != nil {
paddy@152 149 return scopes, err
paddy@152 150 }
paddy@152 151 scopes = append(scopes, scope)
paddy@152 152 }
paddy@152 153 if err = rows.Err(); err != nil {
paddy@152 154 return scopes, err
paddy@152 155 }
paddy@152 156 return scopes, nil
paddy@152 157 }