auth

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

167:0ff23f3a4ede Go to Latest

auth/token_postgres.go

Implement an endpoint for token information. Implement an endpoint that allows us to look up information on a token. We strip the refresh token before the response is sent to avoid leaking the response token.

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 }