auth

Paddy 2014-08-13 Parent:7b9e0fc20256 Child:3423c552e249

5:7ae3f16002c1 Go to Latest

auth/util.go

Handle more errors. Handle client errors. Match redirect handling with the spec.

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