Merge branch '6934-pam' refs #6934
[arvados.git] / sdk / go / auth / auth.go
1 package auth
2
3 import (
4         "net/http"
5         "net/url"
6         "strings"
7 )
8
9 type Credentials struct {
10         Tokens []string
11 }
12
13 func NewCredentials() *Credentials {
14         return &Credentials{Tokens: []string{}}
15 }
16
17 func NewCredentialsFromHTTPRequest(r *http.Request) *Credentials {
18         c := NewCredentials()
19         c.LoadTokensFromHTTPRequest(r)
20         return c
21 }
22
23 // LoadTokensFromHttpRequest loads all tokens it can find in the
24 // headers and query string of an http query.
25 func (a *Credentials) LoadTokensFromHTTPRequest(r *http.Request) {
26         // Load plain token from "Authorization: OAuth2 ..." header
27         // (typically used by smart API clients)
28         if toks := strings.SplitN(r.Header.Get("Authorization"), " ", 2); len(toks) == 2 && toks[0] == "OAuth2" {
29                 a.Tokens = append(a.Tokens, toks[1])
30         }
31
32         // Load base64-encoded token from "Authorization: Basic ..."
33         // header (typically used by git via credential helper)
34         if _, password, ok := BasicAuth(r); ok {
35                 a.Tokens = append(a.Tokens, password)
36         }
37
38         // Load tokens from query string. It's generally not a good
39         // idea to pass tokens around this way, but passing a narrowly
40         // scoped token is a reasonable way to implement "secret link
41         // to an object" in a generic way.
42         //
43         // ParseQuery always returns a non-nil map which might have
44         // valid parameters, even when a decoding error causes it to
45         // return a non-nil err. We ignore err; hopefully the caller
46         // will also need to parse the query string for
47         // application-specific purposes and will therefore
48         // find/report decoding errors in a suitable way.
49         qvalues, _ := url.ParseQuery(r.URL.RawQuery)
50         if val, ok := qvalues["api_token"]; ok {
51                 a.Tokens = append(a.Tokens, val...)
52         }
53
54         // TODO: Load token from Rails session cookie (if Rails site
55         // secret is known)
56 }
57
58 // TODO: LoadTokensFromHttpRequestBody(). We can't assume in
59 // LoadTokensFromHttpRequest() that [or how] we should read and parse
60 // the request body. This has to be requested explicitly by the
61 // application.