X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/ec88c9eee4d0e4827e28f015c464adef43773005..22361307cf41f916afd562e7f33fcdaacefe5f9d:/sdk/go/auth/auth.go diff --git a/sdk/go/auth/auth.go b/sdk/go/auth/auth.go index 730989b3a3..da9b4ea5b8 100644 --- a/sdk/go/auth/auth.go +++ b/sdk/go/auth/auth.go @@ -5,6 +5,7 @@ package auth import ( + "context" "encoding/base64" "net/http" "net/url" @@ -15,11 +16,24 @@ type Credentials struct { Tokens []string } -func NewCredentials() *Credentials { - return &Credentials{Tokens: []string{}} +func NewCredentials(tokens ...string) *Credentials { + return &Credentials{Tokens: tokens} } -func NewCredentialsFromHTTPRequest(r *http.Request) *Credentials { +func NewContext(ctx context.Context, c *Credentials) context.Context { + return context.WithValue(ctx, contextKeyCredentials{}, c) +} + +func FromContext(ctx context.Context) (*Credentials, bool) { + c, ok := ctx.Value(contextKeyCredentials{}).(*Credentials) + return c, ok +} + +func CredentialsFromRequest(r *http.Request) *Credentials { + if c, ok := FromContext(r.Context()); ok { + // preloaded by middleware + return c + } c := NewCredentials() c.LoadTokensFromHTTPRequest(r) return c @@ -34,19 +48,19 @@ var EncodeTokenCookie func([]byte) string = base64.URLEncoding.EncodeToString // token. var DecodeTokenCookie func(string) ([]byte, error) = base64.URLEncoding.DecodeString -// LoadTokensFromHttpRequest loads all tokens it can find in the +// LoadTokensFromHTTPRequest loads all tokens it can find in the // headers and query string of an http query. func (a *Credentials) LoadTokensFromHTTPRequest(r *http.Request) { // Load plain token from "Authorization: OAuth2 ..." header // (typically used by smart API clients) - if toks := strings.SplitN(r.Header.Get("Authorization"), " ", 2); len(toks) == 2 && toks[0] == "OAuth2" { - a.Tokens = append(a.Tokens, toks[1]) + if toks := strings.SplitN(r.Header.Get("Authorization"), " ", 2); len(toks) == 2 && (toks[0] == "OAuth2" || toks[0] == "Bearer") { + a.Tokens = append(a.Tokens, strings.TrimSpace(toks[1])) } // Load base64-encoded token from "Authorization: Basic ..." // header (typically used by git via credential helper) if _, password, ok := r.BasicAuth(); ok { - a.Tokens = append(a.Tokens, password) + a.Tokens = append(a.Tokens, strings.TrimSpace(password)) } // Load tokens from query string. It's generally not a good @@ -62,7 +76,9 @@ func (a *Credentials) LoadTokensFromHTTPRequest(r *http.Request) { // find/report decoding errors in a suitable way. qvalues, _ := url.ParseQuery(r.URL.RawQuery) if val, ok := qvalues["api_token"]; ok { - a.Tokens = append(a.Tokens, val...) + for _, token := range val { + a.Tokens = append(a.Tokens, strings.TrimSpace(token)) + } } a.loadTokenFromCookie(r) @@ -80,10 +96,24 @@ func (a *Credentials) loadTokenFromCookie(r *http.Request) { if err != nil { return } - a.Tokens = append(a.Tokens, string(token)) + a.Tokens = append(a.Tokens, strings.TrimSpace(string(token))) } -// TODO: LoadTokensFromHttpRequestBody(). We can't assume in -// LoadTokensFromHttpRequest() that [or how] we should read and parse -// the request body. This has to be requested explicitly by the -// application. +// LoadTokensFromHTTPRequestBody loads credentials from the request +// body. +// +// This is separate from LoadTokensFromHTTPRequest() because it's not +// always desirable to read the request body. This has to be requested +// explicitly by the application. +func (a *Credentials) LoadTokensFromHTTPRequestBody(r *http.Request) error { + if r.Header.Get("Content-Type") != "application/x-www-form-urlencoded" { + return nil + } + if err := r.ParseForm(); err != nil { + return err + } + if t := r.PostFormValue("api_token"); t != "" { + a.Tokens = append(a.Tokens, strings.TrimSpace(t)) + } + return nil +}