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.
5 "github.com/secondbit/pan"
8 type authCodeScope struct {
13 func (acs authCodeScope) GetSQLTableName() string {
14 return "authorization_codes_scopes"
17 func (ac AuthorizationCode) GetSQLTableName() string {
18 return "authorization_codes"
21 func (p *postgres) getAuthorizationCodeSQL(code string) *pan.Query {
22 var ac AuthorizationCode
23 fields, _ := pan.GetFields(ac)
24 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(ac))
26 query.Include(pan.GetUnquotedColumn(ac, "Code")+" = ?", code)
27 return query.FlushExpressions(" ")
30 func (p *postgres) getAuthorizationCodeScopesSQL(codes []string) *pan.Query {
32 fields, _ := pan.GetFields(acs)
33 codesI := make([]interface{}, len(codes))
34 for pos, code := range codes {
37 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(acs))
39 query.Include(pan.GetUnquotedColumn(acs, "Code")+" IN ("+pan.VariableList(len(codesI))+")", codesI...)
40 return query.FlushExpressions(" ")
43 func (p *postgres) getAuthorizationCode(code string) (AuthorizationCode, error) {
44 query := p.getAuthorizationCodeSQL(code)
45 rows, err := p.db.Query(query.String(), query.Args...)
47 return AuthorizationCode{}, err
49 var ac AuthorizationCode
52 err := pan.Unmarshal(rows, &ac)
58 if err = rows.Err(); err != nil {
62 return ac, ErrAuthorizationCodeNotFound
64 query = p.getAuthorizationCodeScopesSQL([]string{code})
65 rows, err = p.db.Query(query.String(), query.Args...)
71 err = pan.Unmarshal(rows, &acs)
75 ac.Scopes = append(ac.Scopes, acs.Scope)
77 if err = rows.Err(); err != nil {
83 func (p *postgres) saveAuthorizationCodeSQL(authCode AuthorizationCode) *pan.Query {
84 fields, values := pan.GetFields(authCode)
85 query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(authCode))
86 query.Include("(" + pan.QueryList(fields) + ")")
87 query.Include("VALUES")
88 query.Include("("+pan.VariableList(len(values))+")", values...)
89 return query.FlushExpressions(" ")
92 func (p *postgres) saveAuthorizationCodeScopesSQL(authCodeScopes []authCodeScope) *pan.Query {
93 fields, _ := pan.GetFields(authCodeScopes[0])
94 query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(authCodeScopes[0]))
95 query.Include("(" + pan.QueryList(fields) + ")")
96 query.Include("VALUES")
97 query.FlushExpressions(" ")
98 for _, acs := range authCodeScopes {
99 _, values := pan.GetFields(acs)
100 query.Include("("+pan.VariableList(len(values))+")", values...)
102 return query.FlushExpressions(", ")
105 func (p *postgres) saveAuthorizationCode(authCode AuthorizationCode) error {
106 query := p.saveAuthorizationCodeSQL(authCode)
107 _, err := p.db.Exec(query.String(), query.Args...)
108 if e, ok := err.(*pq.Error); ok && e.Constraint == "authorization_codes_pkey" {
109 err = ErrAuthorizationCodeAlreadyExists
111 if err != nil || len(authCode.Scopes) < 1 {
114 var acs []authCodeScope
115 for _, scope := range authCode.Scopes {
116 acs = append(acs, authCodeScope{Code: authCode.Code, Scope: scope})
118 query = p.saveAuthorizationCodeScopesSQL(acs)
119 _, err = p.db.Exec(query.String(), query.Args...)
123 func (p *postgres) deleteAuthorizationCodeSQL(code string) *pan.Query {
124 var authCode AuthorizationCode
125 query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(authCode))
127 query.Include(pan.GetUnquotedColumn(authCode, "Code")+" = ?", code)
128 return query.FlushExpressions(" ")
131 func (p *postgres) deleteAuthorizationCodeScopesSQL(code string) *pan.Query {
132 var acs authCodeScope
133 query := pan.New(pan.POSTGRES, "DELETE FROM "+pan.GetTableName(acs))
135 query.Include(pan.GetUnquotedColumn(acs, "Code")+" = ?", code)
136 return query.FlushExpressions(" ")
139 func (p *postgres) deleteAuthorizationCode(code string) error {
140 query := p.deleteAuthorizationCodeSQL(code)
141 res, err := p.db.Exec(query.String(), query.Args...)
145 rows, err := res.RowsAffected()
150 return ErrAuthorizationCodeNotFound
152 query = p.deleteAuthorizationCodeScopesSQL(code)
153 _, err = p.db.Exec(query.String(), query.Args...)
157 func (p *postgres) useAuthorizationCodeSQL(code string) *pan.Query {
158 var authCode AuthorizationCode
159 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(authCode)+" SET ")
160 query.Include(pan.GetUnquotedColumn(authCode, "Used")+" = ?", true)
162 query.Include(pan.GetUnquotedColumn(authCode, "Code")+" = ?", code)
163 return query.FlushExpressions(" ")
166 func (p *postgres) useAuthorizationCode(code string) error {
167 query := p.useAuthorizationCodeSQL(code)
168 res, err := p.db.Exec(query.String(), query.Args...)
172 rows, err := res.RowsAffected()
177 return ErrAuthorizationCodeNotFound