auth
2014-09-01
Parent:1aa3a85ff853
auth/util.go.old
Rough out tokens and begin the memstore. Rough out the Token type for working with OAuth2 access and refresh tokens. Rough out the TokenStore interface that dictates how Tokens will be stored and retrieved. Write tests for the successful (in the working-as-intended sense) calls to TokenStore. Begin a Memstore type that stores data in memory. Implement the TokenStore interface for Memstore.
| paddy@23 | 1 package auth |
| paddy@23 | 2 |
| paddy@23 | 3 import ( |
| paddy@23 | 4 "encoding/base64" |
| paddy@23 | 5 "errors" |
| paddy@23 | 6 "fmt" |
| paddy@23 | 7 "net/http" |
| paddy@23 | 8 "net/url" |
| paddy@23 | 9 "strings" |
| paddy@23 | 10 |
| paddy@23 | 11 "code.google.com/p/go-uuid/uuid" |
| paddy@23 | 12 ) |
| paddy@23 | 13 |
| paddy@23 | 14 var ( |
| paddy@23 | 15 BasicAuthNotSetError = errors.New("Authorization header not set.") |
| paddy@23 | 16 InvalidBasicAuthTypeError = errors.New("Invalid basic auth type.") |
| paddy@23 | 17 InvalidBasicAuthMessage = errors.New("Invalid basic auth format.") |
| paddy@23 | 18 ) |
| paddy@23 | 19 |
| paddy@23 | 20 // Parse basic authentication header |
| paddy@23 | 21 type BasicAuth struct { |
| paddy@23 | 22 Username string |
| paddy@23 | 23 Password string |
| paddy@23 | 24 } |
| paddy@23 | 25 |
| paddy@23 | 26 // Return authorization header data |
| paddy@23 | 27 func CheckBasicAuth(r *http.Request) (BasicAuth, error) { |
| paddy@23 | 28 if r.Header.Get("Authorization") == "" { |
| paddy@23 | 29 return BasicAuth{}, BasicAuthNotSetError |
| paddy@23 | 30 } |
| paddy@23 | 31 |
| paddy@23 | 32 s := strings.SplitN(r.Header.Get("Authorization"), " ", 2) |
| paddy@23 | 33 if len(s) != 2 || s[0] != "Basic" { |
| paddy@23 | 34 return BasicAuth{}, InvalidBasicAuthTypeError |
| paddy@23 | 35 } |
| paddy@23 | 36 |
| paddy@23 | 37 b, err := base64.StdEncoding.DecodeString(s[1]) |
| paddy@23 | 38 if err != nil { |
| paddy@23 | 39 return BasicAuth{}, err |
| paddy@23 | 40 } |
| paddy@23 | 41 pair := strings.SplitN(string(b), ":", 2) |
| paddy@23 | 42 if len(pair) != 2 { |
| paddy@23 | 43 return BasicAuth{}, InvalidBasicAuthMessage |
| paddy@23 | 44 } |
| paddy@23 | 45 |
| paddy@23 | 46 return BasicAuth{Username: pair[0], Password: pair[1]}, nil |
| paddy@23 | 47 } |
| paddy@23 | 48 |
| paddy@23 | 49 // getClientAuth checks client basic authentication in params if allowed, |
| paddy@23 | 50 // otherwise gets it from the header. |
| paddy@23 | 51 func getClientAuth(r *http.Request, allowQueryParams bool) (BasicAuth, error) { |
| paddy@23 | 52 |
| paddy@23 | 53 if allowQueryParams { |
| paddy@23 | 54 // Allow for auth without password |
| paddy@23 | 55 if _, hasSecret := r.Form["client_secret"]; hasSecret { |
| paddy@23 | 56 auth := BasicAuth{ |
| paddy@23 | 57 Username: r.Form.Get("client_id"), |
| paddy@23 | 58 Password: r.Form.Get("client_secret"), |
| paddy@23 | 59 } |
| paddy@23 | 60 if auth.Username != "" { |
| paddy@23 | 61 return auth, nil |
| paddy@23 | 62 } |
| paddy@23 | 63 } |
| paddy@23 | 64 } |
| paddy@23 | 65 |
| paddy@23 | 66 return CheckBasicAuth(r) |
| paddy@23 | 67 } |
| paddy@23 | 68 |
| paddy@23 | 69 func newToken() string { |
| paddy@23 | 70 return base64.StdEncoding.EncodeToString([]byte(uuid.New())) |
| paddy@23 | 71 } |
| paddy@23 | 72 |
| paddy@23 | 73 // validateURI validates that redirectURI is contained in baseURI |
| paddy@23 | 74 func validateURI(baseURI string, redirectURI string) error { |
| paddy@23 | 75 if baseURI == "" || redirectURI == "" { |
| paddy@23 | 76 return errors.New("urls cannot be blank.") |
| paddy@23 | 77 } |
| paddy@23 | 78 |
| paddy@23 | 79 // parse base url |
| paddy@23 | 80 base, err := url.Parse(baseURI) |
| paddy@23 | 81 if err != nil { |
| paddy@23 | 82 return err |
| paddy@23 | 83 } |
| paddy@23 | 84 |
| paddy@23 | 85 // parse passed url |
| paddy@23 | 86 redirect, err := url.Parse(redirectURI) |
| paddy@23 | 87 if err != nil { |
| paddy@23 | 88 return err |
| paddy@23 | 89 } |
| paddy@23 | 90 |
| paddy@23 | 91 // must not have fragment |
| paddy@23 | 92 if base.Fragment != "" || redirect.Fragment != "" { |
| paddy@23 | 93 return errors.New("url must not include fragment.") |
| paddy@23 | 94 } |
| paddy@23 | 95 |
| paddy@23 | 96 // check if urls match |
| paddy@23 | 97 if base.Scheme == redirect.Scheme && base.Host == redirect.Host && len(redirect.Path) >= len(base.Path) && strings.HasPrefix(redirect.Path, base.Path) { |
| paddy@23 | 98 return nil |
| paddy@23 | 99 } |
| paddy@23 | 100 |
| paddy@23 | 101 return errors.New(fmt.Sprintf("urls don't validate: %s / %s\n", baseURI, redirectURI)) |
| paddy@23 | 102 } |