auth
auth/scope_postgres.go
Enable terminating sessions through the API. Add a terminateSession method to the sessionStore that sets the Active property of the Session to false. Create a Context.TerminateSession wrapper for the terminateSession method on the sessionStore. Add a Sessions property to our response type so we can return a []Session in API responses. Use the URL-safe encoding when base64 encoding our session ID and CSRFToken, so the ID can be passed in the URL and so our encodings are consistent. Add a TerminateSessionHandler function that will extract a Session ID from the request URL, authenticate the user, check that the authenticated user owns the session in question, and terminate the session. Add implementations for our new terminateSession method for the memstore and postgres types. Test both the memstore and postgres implementation of our terminateSession helper in session_test.go.
| 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 } |