auth

Paddy 2015-05-11 Parent:cf1aef6eb81f Child:581c60f8dd23

166:c45b946abe78 Go to Latest

auth/token_postgres.go

Implement a GetProfileHandler. Create a Handler that will allow us to return details about a Profile. Right now, you only get a single Profile at a time, which is problematic, because it will lead to N+1 requests. But we have no reason to retrieve anyone _else_'s Profile, so it's not like you need to be fetching any Profile other than your own. Also, this requires a Token issued for the Profile in question, which means you're limited to one Profile per request, anyways. Future avenues for exploration may be an admin Token granting access to many Profiles, the unspecified service flow for accessing the API, or simply accepting that name, join date, last active date, and ID are "public information".

History
paddy@155 1 package auth
paddy@155 2
paddy@155 3 import (
paddy@155 4 "code.secondbit.org/uuid.hg"
paddy@155 5
paddy@155 6 "github.com/lib/pq"
paddy@155 7 "github.com/secondbit/pan"
paddy@155 8 )
paddy@155 9
paddy@155 10 func (t Token) GetSQLTableName() string {
paddy@155 11 return "tokens"
paddy@155 12 }
paddy@155 13
paddy@155 14 func (p *postgres) getTokenSQL(token string, refresh bool) *pan.Query {
paddy@155 15 var t Token
paddy@155 16 fields, _ := pan.GetFields(t)
paddy@155 17 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(t))
paddy@155 18 query.IncludeWhere()
paddy@155 19 if !refresh {
paddy@155 20 query.Include(pan.GetUnquotedColumn(t, "AccessToken")+" = ?", token)
paddy@155 21 } else {
paddy@155 22 query.Include(pan.GetUnquotedColumn(t, "RefreshToken")+" = ?", token)
paddy@155 23 }
paddy@155 24 return query.FlushExpressions(" ")
paddy@155 25 }
paddy@155 26
paddy@155 27 func (p *postgres) getToken(token string, refresh bool) (Token, error) {
paddy@155 28 query := p.getTokenSQL(token, refresh)
paddy@155 29 rows, err := p.db.Query(query.String(), query.Args...)
paddy@155 30 if err != nil {
paddy@155 31 return Token{}, err
paddy@155 32 }
paddy@155 33 var t Token
paddy@155 34 var found bool
paddy@155 35 for rows.Next() {
paddy@155 36 err := pan.Unmarshal(rows, &t)
paddy@155 37 if err != nil {
paddy@155 38 return t, err
paddy@155 39 }
paddy@155 40 found = true
paddy@155 41 }
paddy@155 42 if err = rows.Err(); err != nil {
paddy@155 43 return t, err
paddy@155 44 }
paddy@155 45 if !found {
paddy@155 46 return t, ErrTokenNotFound
paddy@155 47 }
paddy@155 48 return t, nil
paddy@155 49 }
paddy@155 50
paddy@155 51 func (p *postgres) saveTokenSQL(token Token) *pan.Query {
paddy@155 52 fields, values := pan.GetFields(token)
paddy@155 53 query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(token))
paddy@155 54 query.Include("(" + pan.QueryList(fields) + ")")
paddy@155 55 query.Include("VALUES")
paddy@155 56 query.Include("("+pan.VariableList(len(values))+")", values...)
paddy@155 57 return query.FlushExpressions(" ")
paddy@155 58 }
paddy@155 59
paddy@155 60 func (p *postgres) saveToken(token Token) error {
paddy@155 61 query := p.saveTokenSQL(token)
paddy@155 62 _, err := p.db.Exec(query.String(), query.Args...)
paddy@155 63 if e, ok := err.(*pq.Error); ok && e.Constraint == "tokens_pkey" {
paddy@155 64 err = ErrTokenAlreadyExists
paddy@155 65 }
paddy@155 66 if err != nil || len(token.Scopes) < 1 {
paddy@155 67 return err
paddy@155 68 }
paddy@155 69 return err
paddy@155 70 }
paddy@155 71
paddy@155 72 func (p *postgres) revokeTokenSQL(token string, refresh bool) *pan.Query {
paddy@155 73 var t Token
paddy@155 74 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(t)+" SET ")
paddy@155 75 query.Include(pan.GetUnquotedColumn(t, "Revoked")+" = ?", true)
paddy@155 76 query.IncludeWhere()
paddy@155 77 if !refresh {
paddy@155 78 query.Include(pan.GetUnquotedColumn(t, "AccessToken")+" = ?", token)
paddy@155 79 } else {
paddy@155 80 query.Include(pan.GetUnquotedColumn(t, "RefreshToken")+" = ?", token)
paddy@155 81 }
paddy@155 82 return query.FlushExpressions(" ")
paddy@155 83 }
paddy@155 84
paddy@155 85 func (p *postgres) revokeToken(token string, refresh bool) error {
paddy@155 86 query := p.revokeTokenSQL(token, refresh)
paddy@155 87 res, err := p.db.Exec(query.String(), query.Args...)
paddy@155 88 if err != nil {
paddy@155 89 return err
paddy@155 90 }
paddy@155 91 rows, err := res.RowsAffected()
paddy@155 92 if err != nil {
paddy@155 93 return err
paddy@155 94 }
paddy@155 95 if rows == 0 {
paddy@155 96 return ErrTokenNotFound
paddy@155 97 }
paddy@155 98 return nil
paddy@155 99 }
paddy@155 100
paddy@162 101 func (p *postgres) revokeTokensByProfileIDSQL(profileID uuid.ID) *pan.Query {
paddy@162 102 var t Token
paddy@162 103 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(t)+" SET ")
paddy@162 104 query.Include(pan.GetUnquotedColumn(t, "Revoked")+" = ?", true)
paddy@162 105 query.IncludeWhere()
paddy@162 106 query.Include(pan.GetUnquotedColumn(t, "ProfileID")+" = ?", profileID)
paddy@162 107 return query.FlushExpressions(" ")
paddy@162 108 }
paddy@162 109
paddy@162 110 func (p *postgres) revokeTokensByProfileID(profileID uuid.ID) error {
paddy@162 111 query := p.revokeTokensByProfileIDSQL(profileID)
paddy@162 112 res, err := p.db.Exec(query.String(), query.Args...)
paddy@162 113 if err != nil {
paddy@162 114 return err
paddy@162 115 }
paddy@162 116 rows, err := res.RowsAffected()
paddy@162 117 if err != nil {
paddy@162 118 return err
paddy@162 119 }
paddy@162 120 if rows == 0 {
paddy@162 121 return ErrProfileNotFound
paddy@162 122 }
paddy@162 123 return nil
paddy@162 124 }
paddy@162 125
paddy@164 126 func (p *postgres) revokeTokensByClientIDSQL(clientID uuid.ID) *pan.Query {
paddy@164 127 var t Token
paddy@164 128 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(t)+" SET ")
paddy@164 129 query.Include(pan.GetUnquotedColumn(t, "Revoked")+" = ?", true)
paddy@164 130 query.IncludeWhere()
paddy@164 131 query.Include(pan.GetUnquotedColumn(t, "ClientID")+" = ?", clientID)
paddy@164 132 return query.FlushExpressions(" ")
paddy@164 133 }
paddy@164 134
paddy@164 135 func (p *postgres) revokeTokensByClientID(clientID uuid.ID) error {
paddy@164 136 query := p.revokeTokensByClientIDSQL(clientID)
paddy@164 137 res, err := p.db.Exec(query.String(), query.Args...)
paddy@164 138 if err != nil {
paddy@164 139 return err
paddy@164 140 }
paddy@164 141 rows, err := res.RowsAffected()
paddy@164 142 if err != nil {
paddy@164 143 return err
paddy@164 144 }
paddy@164 145 if rows == 0 {
paddy@164 146 return ErrClientNotFound
paddy@164 147 }
paddy@164 148 return nil
paddy@164 149 }
paddy@164 150
paddy@155 151 func (p *postgres) getTokensByProfileIDSQL(profileID uuid.ID, num, offset int) *pan.Query {
paddy@155 152 var token Token
paddy@155 153 fields, _ := pan.GetFields(token)
paddy@155 154 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(token))
paddy@155 155 query.IncludeWhere()
paddy@155 156 query.Include(pan.GetUnquotedColumn(token, "ProfileID")+" = ?", profileID)
paddy@155 157 query.IncludeLimit(int64(num))
paddy@155 158 query.IncludeOffset(int64(offset))
paddy@155 159 return query.FlushExpressions(" ")
paddy@155 160 }
paddy@155 161
paddy@155 162 func (p *postgres) getTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) {
paddy@155 163 query := p.getTokensByProfileIDSQL(profileID, num, offset)
paddy@155 164 rows, err := p.db.Query(query.String(), query.Args...)
paddy@155 165 if err != nil {
paddy@155 166 return []Token{}, err
paddy@155 167 }
paddy@155 168 var tokens []Token
paddy@155 169 var tokenIDs []string
paddy@155 170 for rows.Next() {
paddy@155 171 var token Token
paddy@155 172 err = pan.Unmarshal(rows, &token)
paddy@155 173 if err != nil {
paddy@155 174 return tokens, err
paddy@155 175 }
paddy@155 176 tokens = append(tokens, token)
paddy@155 177 tokenIDs = append(tokenIDs, token.AccessToken)
paddy@155 178 }
paddy@155 179 if err = rows.Err(); err != nil {
paddy@155 180 return tokens, err
paddy@155 181 }
paddy@155 182 return tokens, nil
paddy@155 183 }