X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/f96550cc40f340c79339338d1da81394bfcb64ad..dece16822124a86dd2f57b7d3b25ca1aa7d75600:/sdk/go/auth/auth.go diff --git a/sdk/go/auth/auth.go b/sdk/go/auth/auth.go index 4a719e922d..de3b1e9523 100644 --- a/sdk/go/auth/auth.go +++ b/sdk/go/auth/auth.go @@ -1,6 +1,11 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + package auth import ( + "encoding/base64" "net/http" "net/url" "strings" @@ -14,24 +19,37 @@ func NewCredentials() *Credentials { return &Credentials{Tokens: []string{}} } -func NewCredentialsFromHTTPRequest(r *http.Request) *Credentials { +func CredentialsFromRequest(r *http.Request) *Credentials { + if c, ok := r.Context().Value(ContextKeyCredentials).(*Credentials); ok { + // preloaded by middleware + return c + } c := NewCredentials() c.LoadTokensFromHTTPRequest(r) return c } -// LoadTokensFromHttpRequest loads all tokens it can find in the +// EncodeTokenCookie accepts a token and returns a byte slice suitable +// for use as a cookie value, such that it will be decoded correctly +// by LoadTokensFromHTTPRequest. +var EncodeTokenCookie func([]byte) string = base64.URLEncoding.EncodeToString + +// DecodeTokenCookie accepts a cookie value and returns the encoded +// token. +var DecodeTokenCookie func(string) ([]byte, error) = base64.URLEncoding.DecodeString + +// 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" { + if toks := strings.SplitN(r.Header.Get("Authorization"), " ", 2); len(toks) == 2 && (toks[0] == "OAuth2" || toks[0] == "Bearer") { a.Tokens = append(a.Tokens, toks[1]) } // Load base64-encoded token from "Authorization: Basic ..." // header (typically used by git via credential helper) - if _, password, ok := BasicAuth(r); ok { + if _, password, ok := r.BasicAuth(); ok { a.Tokens = append(a.Tokens, password) } @@ -51,11 +69,39 @@ func (a *Credentials) LoadTokensFromHTTPRequest(r *http.Request) { a.Tokens = append(a.Tokens, val...) } + a.loadTokenFromCookie(r) + // TODO: Load token from Rails session cookie (if Rails site // secret is known) } -// 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. +func (a *Credentials) loadTokenFromCookie(r *http.Request) { + cookie, err := r.Cookie("arvados_api_token") + if err != nil || len(cookie.Value) == 0 { + return + } + token, err := DecodeTokenCookie(cookie.Value) + if err != nil { + return + } + a.Tokens = append(a.Tokens, string(token)) +} + +// 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, t) + } + return nil +}