OAuth 2.0 Bearer: check revocation status

This commit is contained in:
Drew DeVault 2020-09-14 11:19:05 -04:00
parent 9c4efafa16
commit 0395c9720d
1 changed files with 87 additions and 4 deletions

View File

@ -1,6 +1,7 @@
package auth
import (
"bytes"
"context"
"crypto/sha512"
"database/sql"
@ -8,6 +9,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
@ -20,6 +22,7 @@ import (
"github.com/vaughan0/go-ini"
"github.com/vektah/gqlparser/gqlerror"
"git.sr.ht/~sircmpwn/gql.sr.ht/config"
"git.sr.ht/~sircmpwn/gql.sr.ht/crypto"
"git.sr.ht/~sircmpwn/gql.sr.ht/database"
)
@ -256,7 +259,7 @@ func OAuth2(db *sql.DB, token string, hash [64]byte,
// until they were necessary (e.g. resolving query { me })
query := database.
Select(context.TODO(), []string{
Select(r.Context(), []string{
`u.id`, `u.username`,
`u.created`, `u.updated`,
`u.email`,
@ -301,9 +304,89 @@ func OAuth2(db *sql.DB, token string, hash [64]byte,
go func() {
defer wg.Done()
// Fetch revocation status for this token
// TODO: Check if this token or client has been revoked
atomic.AddInt32(&res, 1)
conf := config.ForContext(r.Context())
meta, ok := conf.Get("meta.sr.ht", "origin")
if !ok {
panic(errors.New("No meta.sr.ht origin specified in config.ini"))
}
type GraphQLQuery struct {
Query string `json:"query"`
Variables map[string]interface{} `json:"variables"`
}
type GraphQLResponse struct {
Data struct {
RevocationStatus bool `json:"tokenRevocationStatus"`
} `json:"data"`
}
query := GraphQLQuery{
Query: `
query RevocationStatus($hash: String!, $clientId: String) {
tokenRevocationStatus(hash: $hash, clientId: $clientId)
}`,
Variables: map[string]interface{} {
"hash": hex.EncodeToString(hash[:]),
"clientId": ot.ClientID,
},
}
body, err := json.Marshal(query)
if err != nil {
panic(err) // Programmer error
}
reader := bytes.NewBuffer(body)
req, err := http.NewRequestWithContext(r.Context(),
"POST", fmt.Sprintf("%s/query", meta), reader)
if err != nil {
log.Printf("http.NewRequest: %e")
return
}
req.Header.Add("Content-Type", "application/json")
auth := InternalAuth{
Name: ot.Username,
// TODO: Populate these better
ClientID: "gql.sr.ht",
NodeID: "gql.sr.ht",
}
authBlob, err := json.Marshal(&auth)
if err != nil {
panic(err) // Programmer error
}
req.Header.Add("Authorization", fmt.Sprintf("Internal %s",
crypto.Encrypt(authBlob)))
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Printf("http.Do: %e", err)
return
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("ioutil.ReadAll: %e")
return
}
if resp.StatusCode != 200 {
log.Printf("meta.sr.ht returned status %d: %s",
resp.StatusCode, string(respBody))
return
}
var result GraphQLResponse
if err = json.Unmarshal(respBody, &result); err != nil {
log.Printf("json.Unmarshal: %e")
return
}
if !result.Data.RevocationStatus {
atomic.AddInt32(&res, 1)
}
}()
wg.Wait()
@ -339,7 +422,7 @@ func LegacyOAuth(db *sql.DB, bearer string, hash [64]byte,
user User
)
query := database.
Select(context.TODO(), []string{
Select(r.Context(), []string{
`ot.expires`,
`ot.scopes`,
`u.id`, `u.username`,