diff options
Diffstat (limited to 'vendor/github.com/markbates/goth/gothic/gothic.go')
-rw-r--r-- | vendor/github.com/markbates/goth/gothic/gothic.go | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/vendor/github.com/markbates/goth/gothic/gothic.go b/vendor/github.com/markbates/goth/gothic/gothic.go new file mode 100644 index 0000000000..f6aaf2d117 --- /dev/null +++ b/vendor/github.com/markbates/goth/gothic/gothic.go @@ -0,0 +1,219 @@ +/* +Package gothic wraps common behaviour when using Goth. This makes it quick, and easy, to get up +and running with Goth. Of course, if you want complete control over how things flow, in regards +to the authentication process, feel free and use Goth directly. + +See https://github.com/markbates/goth/examples/main.go to see this in action. +*/ +package gothic + +import ( + "errors" + "fmt" + "net/http" + "os" + + "github.com/gorilla/mux" + "github.com/gorilla/sessions" + "github.com/markbates/goth" +) + +// SessionName is the key used to access the session store. +const SessionName = "_gothic_session" + +// Store can/should be set by applications using gothic. The default is a cookie store. +var Store sessions.Store +var defaultStore sessions.Store + +var keySet = false + +func init() { + key := []byte(os.Getenv("SESSION_SECRET")) + keySet = len(key) != 0 + Store = sessions.NewCookieStore([]byte(key)) + defaultStore = Store +} + +/* +BeginAuthHandler is a convienence handler for starting the authentication process. +It expects to be able to get the name of the provider from the query parameters +as either "provider" or ":provider". + +BeginAuthHandler will redirect the user to the appropriate authentication end-point +for the requested provider. + +See https://github.com/markbates/goth/examples/main.go to see this in action. +*/ +func BeginAuthHandler(res http.ResponseWriter, req *http.Request) { + url, err := GetAuthURL(res, req) + if err != nil { + res.WriteHeader(http.StatusBadRequest) + fmt.Fprintln(res, err) + return + } + + http.Redirect(res, req, url, http.StatusTemporaryRedirect) +} + +// SetState sets the state string associated with the given request. +// If no state string is associated with the request, one will be generated. +// This state is sent to the provider and can be retrieved during the +// callback. +var SetState = func(req *http.Request) string { + state := req.URL.Query().Get("state") + if len(state) > 0 { + return state + } + + return "state" + +} + +// GetState gets the state returned by the provider during the callback. +// This is used to prevent CSRF attacks, see +// http://tools.ietf.org/html/rfc6749#section-10.12 +var GetState = func(req *http.Request) string { + return req.URL.Query().Get("state") +} + +/* +GetAuthURL starts the authentication process with the requested provided. +It will return a URL that should be used to send users to. + +It expects to be able to get the name of the provider from the query parameters +as either "provider" or ":provider". + +I would recommend using the BeginAuthHandler instead of doing all of these steps +yourself, but that's entirely up to you. +*/ +func GetAuthURL(res http.ResponseWriter, req *http.Request) (string, error) { + + if !keySet && defaultStore == Store { + fmt.Println("goth/gothic: no SESSION_SECRET environment variable is set. The default cookie store is not available and any calls will fail. Ignore this warning if you are using a different store.") + } + + providerName, err := GetProviderName(req) + if err != nil { + return "", err + } + + provider, err := goth.GetProvider(providerName) + if err != nil { + return "", err + } + sess, err := provider.BeginAuth(SetState(req)) + if err != nil { + return "", err + } + + url, err := sess.GetAuthURL() + if err != nil { + return "", err + } + + err = storeInSession(providerName, sess.Marshal(), req, res) + + if err != nil { + return "", err + } + + return url, err +} + +/* +CompleteUserAuth does what it says on the tin. It completes the authentication +process and fetches all of the basic information about the user from the provider. + +It expects to be able to get the name of the provider from the query parameters +as either "provider" or ":provider". + +See https://github.com/markbates/goth/examples/main.go to see this in action. +*/ +var CompleteUserAuth = func(res http.ResponseWriter, req *http.Request) (goth.User, error) { + + if !keySet && defaultStore == Store { + fmt.Println("goth/gothic: no SESSION_SECRET environment variable is set. The default cookie store is not available and any calls will fail. Ignore this warning if you are using a different store.") + } + + providerName, err := GetProviderName(req) + if err != nil { + return goth.User{}, err + } + + provider, err := goth.GetProvider(providerName) + if err != nil { + return goth.User{}, err + } + + value, err := getFromSession(providerName, req) + if err != nil { + return goth.User{}, err + } + + sess, err := provider.UnmarshalSession(value) + if err != nil { + return goth.User{}, err + } + + user, err := provider.FetchUser(sess) + if err == nil { + // user can be found with existing session data + return user, err + } + + // get new token and retry fetch + _, err = sess.Authorize(provider, req.URL.Query()) + if err != nil { + return goth.User{}, err + } + + err = storeInSession(providerName, sess.Marshal(), req, res) + + if err != nil { + return goth.User{}, err + } + + return provider.FetchUser(sess) +} + +// GetProviderName is a function used to get the name of a provider +// for a given request. By default, this provider is fetched from +// the URL query string. If you provide it in a different way, +// assign your own function to this variable that returns the provider +// name for your request. +var GetProviderName = getProviderName + +func getProviderName(req *http.Request) (string, error) { + provider := req.URL.Query().Get("provider") + if provider == "" { + if p, ok := mux.Vars(req)["provider"]; ok { + return p, nil + } + } + if provider == "" { + provider = req.URL.Query().Get(":provider") + } + if provider == "" { + return provider, errors.New("you must select a provider") + } + return provider, nil +} + +func storeInSession(key string, value string, req *http.Request, res http.ResponseWriter) error { + session, _ := Store.Get(req, key + SessionName) + + session.Values[key] = value + + return session.Save(req, res) +} + +func getFromSession(key string, req *http.Request) (string, error) { + session, _ := Store.Get(req, key + SessionName) + + value := session.Values[key] + if value == nil { + return "", errors.New("could not find a matching session for this request") + } + + return value.(string), nil +}
\ No newline at end of file |