auth

Paddy 2015-04-07 Parent:762953f6a7f2 Child:202e991accc2

156:2809016184f6 Browse Files

Implement postgres version of authCodeStore. Create an authCodeStore that keeps data in Postgres. Again, we run into the problem where Scopes can't be stored in Postgres arrays, as discussed in 762953f6a7f2. I wish we could do better, but for now, it will suffice. We also added the postgres authCodeStore to our slice of authCodeStores to test when the correct environment variables are present. Wrote initialization SQL for the tables required by the postgres authCodeStore. Added SQL to the SQL script that empties our database, to properly empty our new tables.

authcode.go authcode_postgres.go authcode_test.go sql/postgres_empty.sql sql/postgres_init.sql

     1.1 --- a/authcode.go	Tue Apr 07 01:00:26 2015 -0400
     1.2 +++ b/authcode.go	Tue Apr 07 02:51:13 2015 -0400
     1.3 @@ -37,7 +37,7 @@
     1.4  	Created     time.Time
     1.5  	ExpiresIn   int32
     1.6  	ClientID    uuid.ID
     1.7 -	Scopes      []string
     1.8 +	Scopes      []string `sql_column:"-"`
     1.9  	RedirectURI string
    1.10  	State       string
    1.11  	ProfileID   uuid.ID
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/authcode_postgres.go	Tue Apr 07 02:51:13 2015 -0400
     2.3 @@ -0,0 +1,180 @@
     2.4 +package auth
     2.5 +
     2.6 +import (
     2.7 +	"github.com/lib/pq"
     2.8 +	"github.com/secondbit/pan"
     2.9 +)
    2.10 +
    2.11 +type authCodeScope struct {
    2.12 +	Code  string
    2.13 +	Scope string
    2.14 +}
    2.15 +
    2.16 +func (acs authCodeScope) GetSQLTableName() string {
    2.17 +	return "authorization_codes_scopes"
    2.18 +}
    2.19 +
    2.20 +func (ac AuthorizationCode) GetSQLTableName() string {
    2.21 +	return "authorization_codes"
    2.22 +}
    2.23 +
    2.24 +func (p *postgres) getAuthorizationCodeSQL(code string) *pan.Query {
    2.25 +	var ac AuthorizationCode
    2.26 +	fields, _ := pan.GetFields(ac)
    2.27 +	query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(ac))
    2.28 +	query.IncludeWhere()
    2.29 +	query.Include(pan.GetUnquotedColumn(ac, "Code")+" = ?", code)
    2.30 +	return query.FlushExpressions(" ")
    2.31 +}
    2.32 +
    2.33 +func (p *postgres) getAuthorizationCodeScopesSQL(codes []string) *pan.Query {
    2.34 +	var acs authCodeScope
    2.35 +	fields, _ := pan.GetFields(acs)
    2.36 +	codesI := make([]interface{}, len(codes))
    2.37 +	for pos, code := range codes {
    2.38 +		codesI[pos] = code
    2.39 +	}
    2.40 +	query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(acs))
    2.41 +	query.IncludeWhere()
    2.42 +	query.Include(pan.GetUnquotedColumn(acs, "Code")+" IN ("+pan.VariableList(len(codesI))+")", codesI...)
    2.43 +	return query.FlushExpressions(" ")
    2.44 +}
    2.45 +
    2.46 +func (p *postgres) getAuthorizationCode(code string) (AuthorizationCode, error) {
    2.47 +	query := p.getAuthorizationCodeSQL(code)
    2.48 +	rows, err := p.db.Query(query.String(), query.Args...)
    2.49 +	if err != nil {
    2.50 +		return AuthorizationCode{}, err
    2.51 +	}
    2.52 +	var ac AuthorizationCode
    2.53 +	var found bool
    2.54 +	for rows.Next() {
    2.55 +		err := pan.Unmarshal(rows, &ac)
    2.56 +		if err != nil {
    2.57 +			return ac, err
    2.58 +		}
    2.59 +		found = true
    2.60 +	}
    2.61 +	if err = rows.Err(); err != nil {
    2.62 +		return ac, err
    2.63 +	}
    2.64 +	if !found {
    2.65 +		return ac, ErrAuthorizationCodeNotFound
    2.66 +	}
    2.67 +	query = p.getAuthorizationCodeScopesSQL([]string{code})
    2.68 +	rows, err = p.db.Query(query.String(), query.Args...)
    2.69 +	if err != nil {
    2.70 +		return ac, err
    2.71 +	}
    2.72 +	for rows.Next() {
    2.73 +		var acs authCodeScope
    2.74 +		err = pan.Unmarshal(rows, &acs)
    2.75 +		if err != nil {
    2.76 +			return ac, err
    2.77 +		}
    2.78 +		ac.Scopes = append(ac.Scopes, acs.Scope)
    2.79 +	}
    2.80 +	if err = rows.Err(); err != nil {
    2.81 +		return ac, err
    2.82 +	}
    2.83 +	return ac, nil
    2.84 +}
    2.85 +
    2.86 +func (p *postgres) saveAuthorizationCodeSQL(authCode AuthorizationCode) *pan.Query {
    2.87 +	fields, values := pan.GetFields(authCode)
    2.88 +	query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(authCode))
    2.89 +	query.Include("(" + pan.QueryList(fields) + ")")
    2.90 +	query.Include("VALUES")
    2.91 +	query.Include("("+pan.VariableList(len(values))+")", values...)
    2.92 +	return query.FlushExpressions(" ")
    2.93 +}
    2.94 +
    2.95 +func (p *postgres) saveAuthorizationCodeScopesSQL(authCodeScopes []authCodeScope) *pan.Query {
    2.96 +	fields, _ := pan.GetFields(authCodeScopes[0])
    2.97 +	query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(authCodeScopes[0]))
    2.98 +	query.Include("(" + pan.QueryList(fields) + ")")
    2.99 +	query.Include("VALUES")
   2.100 +	query.FlushExpressions(" ")
   2.101 +	for _, acs := range authCodeScopes {
   2.102 +		_, values := pan.GetFields(acs)
   2.103 +		query.Include("("+pan.VariableList(len(values))+")", values...)
   2.104 +	}
   2.105 +	return query.FlushExpressions(", ")
   2.106 +}
   2.107 +
   2.108 +func (p *postgres) saveAuthorizationCode(authCode AuthorizationCode) error {
   2.109 +	query := p.saveAuthorizationCodeSQL(authCode)
   2.110 +	_, err := p.db.Exec(query.String(), query.Args...)
   2.111 +	if e, ok := err.(*pq.Error); ok && e.Constraint == "authorization_codes_pkey" {
   2.112 +		err = ErrAuthorizationCodeAlreadyExists
   2.113 +	}
   2.114 +	if err != nil || len(authCode.Scopes) < 1 {
   2.115 +		return err
   2.116 +	}
   2.117 +	var acs []authCodeScope
   2.118 +	for _, scope := range authCode.Scopes {
   2.119 +		acs = append(acs, authCodeScope{Code: authCode.Code, Scope: scope})
   2.120 +	}
   2.121 +	query = p.saveAuthorizationCodeScopesSQL(acs)
   2.122 +	_, err = p.db.Exec(query.String(), query.Args...)
   2.123 +	return err
   2.124 +}
   2.125 +
   2.126 +func (p *postgres) deleteAuthorizationCodeSQL(code string) *pan.Query {
   2.127 +	var authCode AuthorizationCode
   2.128 +	query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(authCode))
   2.129 +	query.IncludeWhere()
   2.130 +	query.Include(pan.GetUnquotedColumn(authCode, "Code")+" = ?", code)
   2.131 +	return query.FlushExpressions(" ")
   2.132 +}
   2.133 +
   2.134 +func (p *postgres) deleteAuthorizationCodeScopesSQL(code string) *pan.Query {
   2.135 +	var acs authCodeScope
   2.136 +	query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(acs))
   2.137 +	query.IncludeWhere()
   2.138 +	query.Include(pan.GetUnquotedColumn(acs, "Code")+" = ?", code)
   2.139 +	return query.FlushExpressions(" ")
   2.140 +}
   2.141 +
   2.142 +func (p *postgres) deleteAuthorizationCode(code string) error {
   2.143 +	query := p.deleteAuthorizationCodeSQL(code)
   2.144 +	res, err := p.db.Exec(query.String(), query.Args...)
   2.145 +	if err != nil {
   2.146 +		return err
   2.147 +	}
   2.148 +	rows, err := res.RowsAffected()
   2.149 +	if err != nil {
   2.150 +		return err
   2.151 +	}
   2.152 +	if rows == 0 {
   2.153 +		return ErrAuthorizationCodeNotFound
   2.154 +	}
   2.155 +	query = p.deleteAuthorizationCodeScopesSQL(code)
   2.156 +	_, err = p.db.Exec(query.String(), query.Args...)
   2.157 +	return err
   2.158 +}
   2.159 +
   2.160 +func (p *postgres) useAuthorizationCodeSQL(code string) *pan.Query {
   2.161 +	var authCode AuthorizationCode
   2.162 +	query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(authCode)+" SET ")
   2.163 +	query.Include(pan.GetUnquotedColumn(authCode, "Used")+" = ?", true)
   2.164 +	query.IncludeWhere()
   2.165 +	query.Include(pan.GetUnquotedColumn(authCode, "Code")+" = ?", code)
   2.166 +	return query.FlushExpressions(" ")
   2.167 +}
   2.168 +
   2.169 +func (p *postgres) useAuthorizationCode(code string) error {
   2.170 +	query := p.useAuthorizationCodeSQL(code)
   2.171 +	res, err := p.db.Exec(query.String(), query.Args...)
   2.172 +	if err != nil {
   2.173 +		return err
   2.174 +	}
   2.175 +	rows, err := res.RowsAffected()
   2.176 +	if err != nil {
   2.177 +		return err
   2.178 +	}
   2.179 +	if rows == 0 {
   2.180 +		return ErrAuthorizationCodeNotFound
   2.181 +	}
   2.182 +	return nil
   2.183 +}
     3.1 --- a/authcode_test.go	Tue Apr 07 01:00:26 2015 -0400
     3.2 +++ b/authcode_test.go	Tue Apr 07 02:51:13 2015 -0400
     3.3 @@ -6,6 +6,7 @@
     3.4  	"net/http"
     3.5  	"net/http/httptest"
     3.6  	"net/url"
     3.7 +	"os"
     3.8  	"strings"
     3.9  	"testing"
    3.10  	"time"
    3.11 @@ -13,6 +14,16 @@
    3.12  	"code.secondbit.org/uuid.hg"
    3.13  )
    3.14  
    3.15 +func init() {
    3.16 +	if os.Getenv("PG_TEST_DB") != "" {
    3.17 +		p, err := NewPostgres(os.Getenv("PG_TEST_DB"))
    3.18 +		if err != nil {
    3.19 +			panic(err)
    3.20 +		}
    3.21 +		authCodeStores = append(authCodeStores, &p)
    3.22 +	}
    3.23 +}
    3.24 +
    3.25  var authCodeStores = []authorizationCodeStore{NewMemstore()}
    3.26  
    3.27  func compareAuthorizationCodes(authCode1, authCode2 AuthorizationCode) (success bool, field string, authCode1val, authCode2val interface{}) {
     4.1 --- a/sql/postgres_empty.sql	Tue Apr 07 01:00:26 2015 -0400
     4.2 +++ b/sql/postgres_empty.sql	Tue Apr 07 02:51:13 2015 -0400
     4.3 @@ -6,3 +6,5 @@
     4.4  TRUNCATE sessions;
     4.5  TRUNCATE tokens;
     4.6  TRUNCATE scopes_tokens;
     4.7 +TRUNCATE authorization_codes;
     4.8 +TRUNCATE authorization_codes_scopes;
     5.1 --- a/sql/postgres_init.sql	Tue Apr 07 01:00:26 2015 -0400
     5.2 +++ b/sql/postgres_init.sql	Tue Apr 07 02:51:13 2015 -0400
     5.3 @@ -77,3 +77,20 @@
     5.4  	scope VARCHAR(64) NOT NULL,
     5.5  	PRIMARY KEY(token, scope)
     5.6  );
     5.7 +
     5.8 +CREATE TABLE IF NOT EXISTS authorization_codes (
     5.9 +	code VARCHAR(36) PRIMARY KEY,
    5.10 +	created TIMESTAMPTZ NOT NULL,
    5.11 +	expires_in INTEGER NOT NULL,
    5.12 +	client_id VARCHAR(36) NOT NULL,
    5.13 +	redirect_uri TEXT NOT NULL,
    5.14 +	state TEXT NOT NULL,
    5.15 +	profile_id VARCHAR(36) NOT NULL,
    5.16 +	used BOOLEAN NOT NULL
    5.17 +);
    5.18 +
    5.19 +CREATE TABLE IF NOT EXISTS authorization_codes_scopes (
    5.20 +	code VARCHAR(36) NOT NULL,
    5.21 +	scope VARCHAR(64) NOT NULL,
    5.22 +	PRIMARY KEY(code, scope)
    5.23 +);