auth

Paddy 2014-09-01 Parent:1aa3a85ff853

28:75cf37088852 Go to Latest

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.

History
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 }