Skip to content

Commit 24af0d9

Browse files
committed
refactor(token): move HTTP OAuth middleware into token pkg
Asmir mentioned in review that we use this in a number of places, move it down & add a "add to request" method for populating the client side of request construction
1 parent 608540a commit 24af0d9

File tree

6 files changed

+56
-36
lines changed

6 files changed

+56
-36
lines changed

api/api.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/gorilla/schema"
1616
golog "github.com/ipfs/go-log"
1717
apiutil "github.com/qri-io/qri/api/util"
18+
"github.com/qri-io/qri/auth/token"
1819
"github.com/qri-io/qri/lib"
1920
"github.com/qri-io/qri/version"
2021
)
@@ -244,7 +245,7 @@ func NewServerRoutes(s Server) *mux.Router {
244245
}
245246

246247
m.Use(refStringMiddleware)
247-
m.Use(OAuthTokenMiddleware)
248+
m.Use(token.OAuthTokenMiddleware)
248249

249250
return m
250251
}

api/middleware.go

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ package api
33
import (
44
"fmt"
55
"net/http"
6-
"strings"
76
"time"
87

98
"github.com/gorilla/mux"
109
"github.com/qri-io/qri/api/util"
11-
"github.com/qri-io/qri/auth/token"
1210
"github.com/qri-io/qri/dsref"
1311
)
1412

@@ -98,33 +96,3 @@ func stripServerSideQueryParams(r *http.Request) {
9896
q.Del("refstr")
9997
r.URL.RawQuery = q.Encode()
10098
}
101-
102-
const (
103-
bearerPrefix = "Bearer "
104-
authorizationHeader = "authorization"
105-
)
106-
107-
// OAuthTokenMiddleware parses any "authorization" header containing a Bearer
108-
// token & adds it to the request context
109-
func OAuthTokenMiddleware(next http.Handler) http.Handler {
110-
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
111-
reqToken := r.Header.Get(authorizationHeader)
112-
if reqToken == "" && r.FormValue(authorizationHeader) != "" {
113-
reqToken = r.FormValue(authorizationHeader)
114-
}
115-
if reqToken == "" {
116-
next.ServeHTTP(w, r)
117-
return
118-
}
119-
120-
if !strings.HasPrefix(reqToken, bearerPrefix) {
121-
util.WriteErrResponse(w, http.StatusBadRequest, fmt.Errorf("bad token"))
122-
return
123-
}
124-
tokenStr := strings.TrimPrefix(reqToken, bearerPrefix)
125-
ctx := token.AddToContext(r.Context(), tokenStr)
126-
127-
r = r.WithContext(ctx)
128-
next.ServeHTTP(w, r)
129-
})
130-
}

auth/token/context.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ package token
22

33
import (
44
"context"
5+
"fmt"
6+
"net/http"
7+
"strings"
8+
9+
"github.com/qri-io/qri/api/util"
510
)
611

712
// CtxKey defines a distinct type for context keys used by the access
@@ -25,3 +30,48 @@ func FromCtx(ctx context.Context) string {
2530
}
2631
return ""
2732
}
33+
34+
const (
35+
// httpAuthorizationHeader is the http header field to check for tokens,
36+
// follows OAuth 2.0 spec
37+
httpAuthorizationHeader = "authorization"
38+
// httpAuthorizationBearerPrefix is a prefix before a token in the
39+
// Authorization header field. Follows OAuth 2.0 spec
40+
httpAuthorizationBearerPrefix = "Bearer "
41+
)
42+
43+
// OAuthTokenMiddleware parses any "authorization" header containing a Bearer
44+
// token & adds it to the request context
45+
func OAuthTokenMiddleware(next http.Handler) http.Handler {
46+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
47+
reqToken := r.Header.Get(httpAuthorizationHeader)
48+
if reqToken == "" && r.FormValue(httpAuthorizationHeader) != "" {
49+
reqToken = r.FormValue(httpAuthorizationHeader)
50+
}
51+
if reqToken == "" {
52+
next.ServeHTTP(w, r)
53+
return
54+
}
55+
56+
if !strings.HasPrefix(reqToken, httpAuthorizationBearerPrefix) {
57+
util.WriteErrResponse(w, http.StatusBadRequest, fmt.Errorf("bad token"))
58+
return
59+
}
60+
61+
tokenStr := strings.TrimPrefix(reqToken, httpAuthorizationBearerPrefix)
62+
ctx := AddToContext(r.Context(), tokenStr)
63+
64+
r = r.WithContext(ctx)
65+
next.ServeHTTP(w, r)
66+
})
67+
}
68+
69+
// AddContextTokenToRequest checks the supplied context for an auth token and
70+
// adds it to an http request, returns true if a token is added
71+
func AddContextTokenToRequest(ctx context.Context, r *http.Request) (*http.Request, bool) {
72+
if s := FromCtx(ctx); s != "" {
73+
r.Header.Set(httpAuthorizationHeader, strings.Join([]string{httpAuthorizationBearerPrefix, s}, ""))
74+
return r, true
75+
}
76+
return r, false
77+
}

lib/http.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ func (c HTTPClient) do(ctx context.Context, addr string, httpMethod string, mime
112112
req.Header.Set("Content-Type", mimeType)
113113
req.Header.Set("Accept", mimeType)
114114

115-
if s := token.FromCtx(ctx); s != "" {
116-
req.Header.Set("authorization", fmt.Sprintf("Bearer %s", s))
115+
req, added := token.AddContextTokenToRequest(ctx, req)
116+
if !added {
117+
log.Debugw("No token was set on an http client request. Unauthenticated requests may fail", "httpMethod", httpMethod, "addr", addr)
117118
}
118119

119120
res, err := http.DefaultClient.Do(req)

lib/logbook.qfb

-420 Bytes
Binary file not shown.

p2p/resolve_ref_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func TestResolveRef(t *testing.T) {
126126

127127
dsrefspec.AssertResolverSpec(t, p2pRefResolver, func(r dsref.Ref, author profile.Author, _ *oplog.Log) error {
128128
builder := dscache.NewBuilder()
129-
pid, err := key.IDFromPub(author.AuthorPubKey())
129+
pid, err := key.IDFromPubKey(author.AuthorPubKey())
130130
builder.AddUser(r.Username, pid)
131131
if err != nil {
132132
return err

0 commit comments

Comments
 (0)