snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
This commit is contained in:
30
server/vendor/github.com/markbates/goth/.gitignore
generated
vendored
Normal file
30
server/vendor/github.com/markbates/goth/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
*.log
|
||||
.DS_Store
|
||||
doc
|
||||
tmp
|
||||
pkg
|
||||
*.gem
|
||||
*.pid
|
||||
coverage
|
||||
coverage.data
|
||||
build/*
|
||||
*.pbxuser
|
||||
*.mode1v3
|
||||
.svn
|
||||
profile
|
||||
.console_history
|
||||
.sass-cache/*
|
||||
.rake_tasks~
|
||||
*.log.lck
|
||||
solr/
|
||||
.jhw-cache/
|
||||
jhw.*
|
||||
*.sublime*
|
||||
node_modules/
|
||||
dist/
|
||||
generated/
|
||||
.vendor/
|
||||
*.swp
|
||||
.vscode/launch.json
|
||||
.vscode/settings.json
|
||||
.idea
|
||||
22
server/vendor/github.com/markbates/goth/LICENSE.txt
generated
vendored
Normal file
22
server/vendor/github.com/markbates/goth/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
Copyright (c) 2014 Mark Bates
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
155
server/vendor/github.com/markbates/goth/README.md
generated
vendored
Normal file
155
server/vendor/github.com/markbates/goth/README.md
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
# Goth: Multi-Provider Authentication for Go [](https://godoc.org/github.com/markbates/goth) [](https://github.com/markbates/goth/actions) [](https://goreportcard.com/report/github.com/markbates/goth)
|
||||
|
||||
Package goth provides a simple, clean, and idiomatic way to write authentication
|
||||
packages for Go web applications.
|
||||
|
||||
Unlike other similar packages, Goth, lets you write OAuth, OAuth2, or any other
|
||||
protocol providers, as long as they implement the `Provider` and `Session` interfaces.
|
||||
|
||||
This package was inspired by [https://github.com/intridea/omniauth](https://github.com/intridea/omniauth).
|
||||
|
||||
## Installation
|
||||
|
||||
```text
|
||||
$ go get github.com/markbates/goth
|
||||
```
|
||||
|
||||
## Supported Providers
|
||||
|
||||
* Amazon
|
||||
* Apple
|
||||
* Auth0
|
||||
* Azure AD
|
||||
* Battle.net
|
||||
* Bitbucket
|
||||
* Box
|
||||
* Cloud Foundry
|
||||
* Dailymotion
|
||||
* Deezer
|
||||
* DigitalOcean
|
||||
* Discord
|
||||
* Dropbox
|
||||
* Eve Online
|
||||
* Facebook
|
||||
* Fitbit
|
||||
* Gitea
|
||||
* GitHub
|
||||
* Gitlab
|
||||
* Google
|
||||
* Google+ (deprecated)
|
||||
* Heroku
|
||||
* InfluxCloud
|
||||
* Instagram
|
||||
* Intercom
|
||||
* Kakao
|
||||
* Lastfm
|
||||
* Linkedin
|
||||
* LINE
|
||||
* Mailru
|
||||
* Meetup
|
||||
* MicrosoftOnline
|
||||
* Naver
|
||||
* Nextcloud
|
||||
* Okta
|
||||
* OneDrive
|
||||
* OpenID Connect (auto discovery)
|
||||
* Oura
|
||||
* Paypal
|
||||
* SalesForce
|
||||
* Shopify
|
||||
* Slack
|
||||
* Soundcloud
|
||||
* Spotify
|
||||
* Steam
|
||||
* Strava
|
||||
* Stripe
|
||||
* TikTok
|
||||
* Tumblr
|
||||
* Twitch
|
||||
* Twitter
|
||||
* Typetalk
|
||||
* Uber
|
||||
* VK
|
||||
* Wepay
|
||||
* WeCom
|
||||
* Xero
|
||||
* Yahoo
|
||||
* Yammer
|
||||
* Yandex
|
||||
* Zoom
|
||||
|
||||
## Examples
|
||||
|
||||
See the [examples](examples) folder for a working application that lets users authenticate
|
||||
through Twitter, Facebook, Google Plus etc.
|
||||
|
||||
To run the example either clone the source from GitHub
|
||||
|
||||
```text
|
||||
$ git clone git@github.com:markbates/goth.git
|
||||
```
|
||||
or use
|
||||
```text
|
||||
$ go get github.com/markbates/goth
|
||||
```
|
||||
```text
|
||||
$ cd goth/examples
|
||||
$ go get -v
|
||||
$ go build
|
||||
$ ./examples
|
||||
```
|
||||
|
||||
Now open up your browser and go to [http://localhost:3000](http://localhost:3000) to see the example.
|
||||
|
||||
To actually use the different providers, please make sure you set environment variables. Example given in the examples/main.go file
|
||||
|
||||
## Security Notes
|
||||
|
||||
By default, gothic uses a `CookieStore` from the `gorilla/sessions` package to store session data.
|
||||
|
||||
As configured, this default store (`gothic.Store`) will generate cookies with `Options`:
|
||||
|
||||
```go
|
||||
&Options{
|
||||
Path: "/",
|
||||
Domain: "",
|
||||
MaxAge: 86400 * 30,
|
||||
HttpOnly: true,
|
||||
Secure: false,
|
||||
}
|
||||
```
|
||||
|
||||
To tailor these fields for your application, you can override the `gothic.Store` variable at startup.
|
||||
|
||||
The following snippet shows one way to do this:
|
||||
|
||||
```go
|
||||
key := "" // Replace with your SESSION_SECRET or similar
|
||||
maxAge := 86400 * 30 // 30 days
|
||||
isProd := false // Set to true when serving over https
|
||||
|
||||
store := sessions.NewCookieStore([]byte(key))
|
||||
store.MaxAge(maxAge)
|
||||
store.Options.Path = "/"
|
||||
store.Options.HttpOnly = true // HttpOnly should always be enabled
|
||||
store.Options.Secure = isProd
|
||||
|
||||
gothic.Store = store
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
Issues always stand a significantly better chance of getting fixed if they are accompanied by a
|
||||
pull request.
|
||||
|
||||
## Contributing
|
||||
|
||||
Would I love to see more providers? Certainly! Would you love to contribute one? Hopefully, yes!
|
||||
|
||||
1. Fork it
|
||||
2. Create your feature branch (git checkout -b my-new-feature)
|
||||
3. Write Tests!
|
||||
4. Make sure the codebase adhere to the Go coding standards by executing `gofmt -s -w ./`
|
||||
5. Commit your changes (git commit -am 'Add some feature')
|
||||
6. Push to the branch (git push origin my-new-feature)
|
||||
7. Create new Pull Request
|
||||
10
server/vendor/github.com/markbates/goth/doc.go
generated
vendored
Normal file
10
server/vendor/github.com/markbates/goth/doc.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
Package goth provides a simple, clean, and idiomatic way to write authentication
|
||||
packages for Go web applications.
|
||||
|
||||
This package was inspired by https://github.com/intridea/omniauth.
|
||||
|
||||
See the examples folder for a working application that lets users authenticate
|
||||
through Twitter or Facebook.
|
||||
*/
|
||||
package goth
|
||||
367
server/vendor/github.com/markbates/goth/gothic/gothic.go
generated
vendored
Normal file
367
server/vendor/github.com/markbates/goth/gothic/gothic.go
generated
vendored
Normal file
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
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/blob/master/examples/main.go to see this in action.
|
||||
*/
|
||||
package gothic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"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
|
||||
|
||||
type key int
|
||||
|
||||
// ProviderParamKey can be used as a key in context when passing in a provider
|
||||
const ProviderParamKey key = iota
|
||||
|
||||
func init() {
|
||||
key := []byte(os.Getenv("SESSION_SECRET"))
|
||||
keySet = len(key) != 0
|
||||
|
||||
cookieStore := sessions.NewCookieStore([]byte(key))
|
||||
cookieStore.Options.HttpOnly = true
|
||||
Store = cookieStore
|
||||
defaultStore = Store
|
||||
}
|
||||
|
||||
/*
|
||||
BeginAuthHandler is a convenience 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
|
||||
}
|
||||
|
||||
// If a state query param is not passed in, generate a random
|
||||
// base64-encoded nonce so that the state on the auth URL
|
||||
// is unguessable, preventing CSRF attacks, as described in
|
||||
//
|
||||
// https://auth0.com/docs/protocols/oauth2/oauth-state#keep-reading
|
||||
nonceBytes := make([]byte, 64)
|
||||
_, err := io.ReadFull(rand.Reader, nonceBytes)
|
||||
if err != nil {
|
||||
panic("gothic: source of randomness unavailable: " + err.Error())
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(nonceBytes)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
params := req.URL.Query()
|
||||
if params.Encode() == "" && req.Method == http.MethodPost {
|
||||
return req.FormValue("state")
|
||||
}
|
||||
return params.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
|
||||
}
|
||||
defer Logout(res, req)
|
||||
sess, err := provider.UnmarshalSession(value)
|
||||
if err != nil {
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
err = validateState(req, sess)
|
||||
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
|
||||
}
|
||||
|
||||
params := req.URL.Query()
|
||||
if params.Encode() == "" && req.Method == "POST" {
|
||||
req.ParseForm()
|
||||
params = req.Form
|
||||
}
|
||||
|
||||
// get new token and retry fetch
|
||||
_, err = sess.Authorize(provider, params)
|
||||
if err != nil {
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
err = StoreInSession(providerName, sess.Marshal(), req, res)
|
||||
|
||||
if err != nil {
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
gu, err := provider.FetchUser(sess)
|
||||
return gu, err
|
||||
}
|
||||
|
||||
// validateState ensures that the state token param from the original
|
||||
// AuthURL matches the one included in the current (callback) request.
|
||||
func validateState(req *http.Request, sess goth.Session) error {
|
||||
rawAuthURL, err := sess.GetAuthURL()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authURL, err := url.Parse(rawAuthURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reqState := GetState(req)
|
||||
|
||||
originalState := authURL.Query().Get("state")
|
||||
if originalState != "" && (originalState != reqState) {
|
||||
return errors.New("state token mismatch")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Logout invalidates a user session.
|
||||
func Logout(res http.ResponseWriter, req *http.Request) error {
|
||||
session, err := Store.Get(req, SessionName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.Options.MaxAge = -1
|
||||
session.Values = make(map[interface{}]interface{})
|
||||
err = session.Save(req, res)
|
||||
if err != nil {
|
||||
return errors.New("Could not delete user session ")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
// try to get it from the url param "provider"
|
||||
if p := req.URL.Query().Get("provider"); p != "" {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// try to get it from the url param ":provider"
|
||||
if p := req.URL.Query().Get(":provider"); p != "" {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// try to get it from the context's value of "provider" key
|
||||
if p, ok := mux.Vars(req)["provider"]; ok {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// try to get it from the go-context's value of "provider" key
|
||||
if p, ok := req.Context().Value("provider").(string); ok {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// try to get it from the go-context's value of providerContextKey key
|
||||
if p, ok := req.Context().Value(ProviderParamKey).(string); ok {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// As a fallback, loop over the used providers, if we already have a valid session for any provider (ie. user has already begun authentication with a provider), then return that provider name
|
||||
providers := goth.GetProviders()
|
||||
session, _ := Store.Get(req, SessionName)
|
||||
for _, provider := range providers {
|
||||
p := provider.Name()
|
||||
value := session.Values[p]
|
||||
if _, ok := value.(string); ok {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
// if not found then return an empty string with the corresponding error
|
||||
return "", errors.New("you must select a provider")
|
||||
}
|
||||
|
||||
// GetContextWithProvider returns a new request context containing the provider
|
||||
func GetContextWithProvider(req *http.Request, provider string) *http.Request {
|
||||
return req.WithContext(context.WithValue(req.Context(), ProviderParamKey, provider))
|
||||
}
|
||||
|
||||
// StoreInSession stores a specified key/value pair in the session.
|
||||
func StoreInSession(key string, value string, req *http.Request, res http.ResponseWriter) error {
|
||||
session, _ := Store.New(req, SessionName)
|
||||
|
||||
if err := updateSessionValue(session, key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return session.Save(req, res)
|
||||
}
|
||||
|
||||
// GetFromSession retrieves a previously-stored value from the session.
|
||||
// If no value has previously been stored at the specified key, it will return an error.
|
||||
func GetFromSession(key string, req *http.Request) (string, error) {
|
||||
session, _ := Store.Get(req, SessionName)
|
||||
value, err := getSessionValue(session, key)
|
||||
if err != nil {
|
||||
return "", errors.New("could not find a matching session for this request")
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func getSessionValue(session *sessions.Session, key string) (string, error) {
|
||||
value := session.Values[key]
|
||||
if value == nil {
|
||||
return "", fmt.Errorf("could not find a matching session for this request")
|
||||
}
|
||||
|
||||
rdata := strings.NewReader(value.(string))
|
||||
r, err := gzip.NewReader(rdata)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
s, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(s), nil
|
||||
}
|
||||
|
||||
func updateSessionValue(session *sessions.Session, key, value string) error {
|
||||
var b bytes.Buffer
|
||||
gz := gzip.NewWriter(&b)
|
||||
if _, err := gz.Write([]byte(value)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gz.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gz.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session.Values[key] = b.String()
|
||||
return nil
|
||||
}
|
||||
75
server/vendor/github.com/markbates/goth/provider.go
generated
vendored
Normal file
75
server/vendor/github.com/markbates/goth/provider.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
package goth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// Provider needs to be implemented for each 3rd party authentication provider
|
||||
// e.g. Facebook, Twitter, etc...
|
||||
type Provider interface {
|
||||
Name() string
|
||||
SetName(name string)
|
||||
BeginAuth(state string) (Session, error)
|
||||
UnmarshalSession(string) (Session, error)
|
||||
FetchUser(Session) (User, error)
|
||||
Debug(bool)
|
||||
RefreshToken(refreshToken string) (*oauth2.Token, error) //Get new access token based on the refresh token
|
||||
RefreshTokenAvailable() bool //Refresh token is provided by auth provider or not
|
||||
}
|
||||
|
||||
const NoAuthUrlErrorMessage = "an AuthURL has not been set"
|
||||
|
||||
// Providers is list of known/available providers.
|
||||
type Providers map[string]Provider
|
||||
|
||||
var providers = Providers{}
|
||||
|
||||
// UseProviders adds a list of available providers for use with Goth.
|
||||
// Can be called multiple times. If you pass the same provider more
|
||||
// than once, the last will be used.
|
||||
func UseProviders(viders ...Provider) {
|
||||
for _, provider := range viders {
|
||||
providers[provider.Name()] = provider
|
||||
}
|
||||
}
|
||||
|
||||
// GetProviders returns a list of all the providers currently in use.
|
||||
func GetProviders() Providers {
|
||||
return providers
|
||||
}
|
||||
|
||||
// GetProvider returns a previously created provider. If Goth has not
|
||||
// been told to use the named provider it will return an error.
|
||||
func GetProvider(name string) (Provider, error) {
|
||||
provider := providers[name]
|
||||
if provider == nil {
|
||||
return nil, fmt.Errorf("no provider for %s exists", name)
|
||||
}
|
||||
return provider, nil
|
||||
}
|
||||
|
||||
// ClearProviders will remove all providers currently in use.
|
||||
// This is useful, mostly, for testing purposes.
|
||||
func ClearProviders() {
|
||||
providers = Providers{}
|
||||
}
|
||||
|
||||
// ContextForClient provides a context for use with oauth2.
|
||||
func ContextForClient(h *http.Client) context.Context {
|
||||
if h == nil {
|
||||
return oauth2.NoContext
|
||||
}
|
||||
return context.WithValue(oauth2.NoContext, oauth2.HTTPClient, h)
|
||||
}
|
||||
|
||||
// HTTPClientWithFallBack to be used in all fetch operations.
|
||||
func HTTPClientWithFallBack(h *http.Client) *http.Client {
|
||||
if h != nil {
|
||||
return h
|
||||
}
|
||||
return http.DefaultClient
|
||||
}
|
||||
216
server/vendor/github.com/markbates/goth/providers/facebook/facebook.go
generated
vendored
Normal file
216
server/vendor/github.com/markbates/goth/providers/facebook/facebook.go
generated
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
// Package facebook implements the OAuth2 protocol for authenticating users through Facebook.
|
||||
// This package can be used as a reference implementation of an OAuth2 provider for Goth.
|
||||
package facebook
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const (
|
||||
authURL string = "https://www.facebook.com/dialog/oauth"
|
||||
tokenURL string = "https://graph.facebook.com/oauth/access_token"
|
||||
endpointProfile string = "https://graph.facebook.com/me?fields="
|
||||
)
|
||||
|
||||
// New creates a new Facebook provider, and sets up important connection details.
|
||||
// You should always call `facebook.New` to get a new Provider. Never try to create
|
||||
// one manually.
|
||||
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
|
||||
p := &Provider{
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "facebook",
|
||||
}
|
||||
p.config = newConfig(p, scopes)
|
||||
p.Fields = "email,first_name,last_name,link,about,id,name,picture,location"
|
||||
return p
|
||||
}
|
||||
|
||||
// Provider is the implementation of `goth.Provider` for accessing Facebook.
|
||||
type Provider struct {
|
||||
ClientKey string
|
||||
Secret string
|
||||
CallbackURL string
|
||||
HTTPClient *http.Client
|
||||
Fields string
|
||||
config *oauth2.Config
|
||||
providerName string
|
||||
}
|
||||
|
||||
// Name is the name used to retrieve this provider later.
|
||||
func (p *Provider) Name() string {
|
||||
return p.providerName
|
||||
}
|
||||
|
||||
// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
|
||||
func (p *Provider) SetName(name string) {
|
||||
p.providerName = name
|
||||
}
|
||||
|
||||
// SetCustomFields sets the fields used to return information
|
||||
// for a user.
|
||||
//
|
||||
// A list of available field values can be found at
|
||||
// https://developers.facebook.com/docs/graph-api/reference/user
|
||||
func (p *Provider) SetCustomFields(fields []string) *Provider {
|
||||
p.Fields = strings.Join(fields, ",")
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Provider) Client() *http.Client {
|
||||
return goth.HTTPClientWithFallBack(p.HTTPClient)
|
||||
}
|
||||
|
||||
// Debug is a no-op for the facebook package.
|
||||
func (p *Provider) Debug(debug bool) {}
|
||||
|
||||
// BeginAuth asks Facebook for an authentication end-point.
|
||||
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
|
||||
authUrl := p.config.AuthCodeURL(state)
|
||||
session := &Session{
|
||||
AuthURL: authUrl,
|
||||
}
|
||||
return session, nil
|
||||
}
|
||||
|
||||
// FetchUser will go to Facebook and access basic information about the user.
|
||||
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
|
||||
sess := session.(*Session)
|
||||
user := goth.User{
|
||||
AccessToken: sess.AccessToken,
|
||||
Provider: p.Name(),
|
||||
ExpiresAt: sess.ExpiresAt,
|
||||
}
|
||||
|
||||
if user.AccessToken == "" {
|
||||
// data is not yet retrieved since accessToken is still empty
|
||||
return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName)
|
||||
}
|
||||
|
||||
// always add appsecretProof to make calls more protected
|
||||
// https://github.com/markbates/goth/issues/96
|
||||
// https://developers.facebook.com/docs/graph-api/securing-requests
|
||||
hash := hmac.New(sha256.New, []byte(p.Secret))
|
||||
hash.Write([]byte(sess.AccessToken))
|
||||
appsecretProof := hex.EncodeToString(hash.Sum(nil))
|
||||
|
||||
reqUrl := fmt.Sprint(
|
||||
endpointProfile,
|
||||
p.Fields,
|
||||
"&access_token=",
|
||||
url.QueryEscape(sess.AccessToken),
|
||||
"&appsecret_proof=",
|
||||
appsecretProof,
|
||||
)
|
||||
response, err := p.Client().Get(reqUrl)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, response.StatusCode)
|
||||
}
|
||||
|
||||
bits, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(bytes.NewReader(bits)).Decode(&user.RawData)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
err = userFromReader(bytes.NewReader(bits), &user)
|
||||
return user, err
|
||||
}
|
||||
|
||||
func userFromReader(reader io.Reader, user *goth.User) error {
|
||||
u := struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
About string `json:"about"`
|
||||
Name string `json:"name"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Link string `json:"link"`
|
||||
Picture struct {
|
||||
Data struct {
|
||||
URL string `json:"url"`
|
||||
} `json:"data"`
|
||||
} `json:"picture"`
|
||||
Location struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"location"`
|
||||
}{}
|
||||
|
||||
err := json.NewDecoder(reader).Decode(&u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user.Name = u.Name
|
||||
user.FirstName = u.FirstName
|
||||
user.LastName = u.LastName
|
||||
user.NickName = u.Name
|
||||
user.Email = u.Email
|
||||
user.Description = u.About
|
||||
user.AvatarURL = u.Picture.Data.URL
|
||||
user.UserID = u.ID
|
||||
user.Location = u.Location.Name
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func newConfig(provider *Provider, scopes []string) *oauth2.Config {
|
||||
c := &oauth2.Config{
|
||||
ClientID: provider.ClientKey,
|
||||
ClientSecret: provider.Secret,
|
||||
RedirectURL: provider.CallbackURL,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: authURL,
|
||||
TokenURL: tokenURL,
|
||||
},
|
||||
Scopes: []string{
|
||||
"email",
|
||||
},
|
||||
}
|
||||
|
||||
defaultScopes := map[string]struct{}{
|
||||
"email": {},
|
||||
}
|
||||
|
||||
for _, scope := range scopes {
|
||||
if _, exists := defaultScopes[scope]; !exists {
|
||||
c.Scopes = append(c.Scopes, scope)
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
//RefreshToken refresh token is not provided by facebook
|
||||
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
|
||||
return nil, errors.New("Refresh token is not provided by facebook")
|
||||
}
|
||||
|
||||
//RefreshTokenAvailable refresh token is not provided by facebook
|
||||
func (p *Provider) RefreshTokenAvailable() bool {
|
||||
return false
|
||||
}
|
||||
59
server/vendor/github.com/markbates/goth/providers/facebook/session.go
generated
vendored
Normal file
59
server/vendor/github.com/markbates/goth/providers/facebook/session.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
package facebook
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
)
|
||||
|
||||
// Session stores data during the auth process with Facebook.
|
||||
type Session struct {
|
||||
AuthURL string
|
||||
AccessToken string
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
// GetAuthURL will return the URL set by calling the `BeginAuth` function on the Facebook provider.
|
||||
func (s Session) GetAuthURL() (string, error) {
|
||||
if s.AuthURL == "" {
|
||||
return "", errors.New(goth.NoAuthUrlErrorMessage)
|
||||
}
|
||||
return s.AuthURL, nil
|
||||
}
|
||||
|
||||
// Authorize the session with Facebook and return the access token to be stored for future use.
|
||||
func (s *Session) Authorize(provider goth.Provider, params goth.Params) (string, error) {
|
||||
p := provider.(*Provider)
|
||||
token, err := p.config.Exchange(goth.ContextForClient(p.Client()), params.Get("code"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !token.Valid() {
|
||||
return "", errors.New("Invalid token received from provider")
|
||||
}
|
||||
|
||||
s.AccessToken = token.AccessToken
|
||||
s.ExpiresAt = token.Expiry
|
||||
return token.AccessToken, err
|
||||
}
|
||||
|
||||
// Marshal the session into a string
|
||||
func (s Session) Marshal() string {
|
||||
b, _ := json.Marshal(s)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (s Session) String() string {
|
||||
return s.Marshal()
|
||||
}
|
||||
|
||||
// UnmarshalSession will unmarshal a JSON string into a session.
|
||||
func (p *Provider) UnmarshalSession(data string) (goth.Session, error) {
|
||||
sess := &Session{}
|
||||
err := json.NewDecoder(strings.NewReader(data)).Decode(sess)
|
||||
return sess, err
|
||||
}
|
||||
239
server/vendor/github.com/markbates/goth/providers/github/github.go
generated
vendored
Normal file
239
server/vendor/github.com/markbates/goth/providers/github/github.go
generated
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
// Package github implements the OAuth2 protocol for authenticating users through Github.
|
||||
// This package can be used as a reference implementation of an OAuth2 provider for Goth.
|
||||
package github
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// These vars define the Authentication, Token, and API URLS for GitHub. If
|
||||
// using GitHub enterprise you should change these values before calling New.
|
||||
//
|
||||
// Examples:
|
||||
// github.AuthURL = "https://github.acme.com/login/oauth/authorize
|
||||
// github.TokenURL = "https://github.acme.com/login/oauth/access_token
|
||||
// github.ProfileURL = "https://github.acme.com/api/v3/user
|
||||
// github.EmailURL = "https://github.acme.com/api/v3/user/emails
|
||||
var (
|
||||
AuthURL = "https://github.com/login/oauth/authorize"
|
||||
TokenURL = "https://github.com/login/oauth/access_token"
|
||||
ProfileURL = "https://api.github.com/user"
|
||||
EmailURL = "https://api.github.com/user/emails"
|
||||
)
|
||||
|
||||
// New creates a new Github provider, and sets up important connection details.
|
||||
// You should always call `github.New` to get a new Provider. Never try to create
|
||||
// one manually.
|
||||
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
|
||||
return NewCustomisedURL(clientKey, secret, callbackURL, AuthURL, TokenURL, ProfileURL, EmailURL, scopes...)
|
||||
}
|
||||
|
||||
// NewCustomisedURL is similar to New(...) but can be used to set custom URLs to connect to
|
||||
func NewCustomisedURL(clientKey, secret, callbackURL, authURL, tokenURL, profileURL, emailURL string, scopes ...string) *Provider {
|
||||
p := &Provider{
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "github",
|
||||
profileURL: profileURL,
|
||||
emailURL: emailURL,
|
||||
}
|
||||
p.config = newConfig(p, authURL, tokenURL, scopes)
|
||||
return p
|
||||
}
|
||||
|
||||
// Provider is the implementation of `goth.Provider` for accessing Github.
|
||||
type Provider struct {
|
||||
ClientKey string
|
||||
Secret string
|
||||
CallbackURL string
|
||||
HTTPClient *http.Client
|
||||
config *oauth2.Config
|
||||
providerName string
|
||||
profileURL string
|
||||
emailURL string
|
||||
}
|
||||
|
||||
// Name is the name used to retrieve this provider later.
|
||||
func (p *Provider) Name() string {
|
||||
return p.providerName
|
||||
}
|
||||
|
||||
// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
|
||||
func (p *Provider) SetName(name string) {
|
||||
p.providerName = name
|
||||
}
|
||||
|
||||
func (p *Provider) Client() *http.Client {
|
||||
return goth.HTTPClientWithFallBack(p.HTTPClient)
|
||||
}
|
||||
|
||||
// Debug is a no-op for the github package.
|
||||
func (p *Provider) Debug(debug bool) {}
|
||||
|
||||
// BeginAuth asks Github for an authentication end-point.
|
||||
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
|
||||
url := p.config.AuthCodeURL(state)
|
||||
session := &Session{
|
||||
AuthURL: url,
|
||||
}
|
||||
return session, nil
|
||||
}
|
||||
|
||||
// FetchUser will go to Github and access basic information about the user.
|
||||
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
|
||||
sess := session.(*Session)
|
||||
user := goth.User{
|
||||
AccessToken: sess.AccessToken,
|
||||
Provider: p.Name(),
|
||||
}
|
||||
|
||||
if user.AccessToken == "" {
|
||||
// data is not yet retrieved since accessToken is still empty
|
||||
return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", p.profileURL, nil)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
req.Header.Add("Authorization", "Bearer "+sess.AccessToken)
|
||||
response, err := p.Client().Do(req)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return user, fmt.Errorf("GitHub API responded with a %d trying to fetch user information", response.StatusCode)
|
||||
}
|
||||
|
||||
bits, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
err = json.NewDecoder(bytes.NewReader(bits)).Decode(&user.RawData)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
err = userFromReader(bytes.NewReader(bits), &user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
if user.Email == "" {
|
||||
for _, scope := range p.config.Scopes {
|
||||
if strings.TrimSpace(scope) == "user" || strings.TrimSpace(scope) == "user:email" {
|
||||
user.Email, err = getPrivateMail(p, sess)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return user, err
|
||||
}
|
||||
|
||||
func userFromReader(reader io.Reader, user *goth.User) error {
|
||||
u := struct {
|
||||
ID int `json:"id"`
|
||||
Email string `json:"email"`
|
||||
Bio string `json:"bio"`
|
||||
Name string `json:"name"`
|
||||
Login string `json:"login"`
|
||||
Picture string `json:"avatar_url"`
|
||||
Location string `json:"location"`
|
||||
}{}
|
||||
|
||||
err := json.NewDecoder(reader).Decode(&u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user.Name = u.Name
|
||||
user.NickName = u.Login
|
||||
user.Email = u.Email
|
||||
user.Description = u.Bio
|
||||
user.AvatarURL = u.Picture
|
||||
user.UserID = strconv.Itoa(u.ID)
|
||||
user.Location = u.Location
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func getPrivateMail(p *Provider, sess *Session) (email string, err error) {
|
||||
req, err := http.NewRequest("GET", p.emailURL, nil)
|
||||
req.Header.Add("Authorization", "Bearer "+sess.AccessToken)
|
||||
response, err := p.Client().Do(req)
|
||||
if err != nil {
|
||||
if response != nil {
|
||||
response.Body.Close()
|
||||
}
|
||||
return email, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return email, fmt.Errorf("GitHub API responded with a %d trying to fetch user email", response.StatusCode)
|
||||
}
|
||||
|
||||
var mailList = []struct {
|
||||
Email string `json:"email"`
|
||||
Primary bool `json:"primary"`
|
||||
Verified bool `json:"verified"`
|
||||
}{}
|
||||
err = json.NewDecoder(response.Body).Decode(&mailList)
|
||||
if err != nil {
|
||||
return email, err
|
||||
}
|
||||
for _, v := range mailList {
|
||||
if v.Primary && v.Verified {
|
||||
return v.Email, nil
|
||||
}
|
||||
}
|
||||
return email, fmt.Errorf("The user does not have a verified, primary email address on GitHub")
|
||||
}
|
||||
|
||||
func newConfig(provider *Provider, authURL, tokenURL string, scopes []string) *oauth2.Config {
|
||||
c := &oauth2.Config{
|
||||
ClientID: provider.ClientKey,
|
||||
ClientSecret: provider.Secret,
|
||||
RedirectURL: provider.CallbackURL,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: authURL,
|
||||
TokenURL: tokenURL,
|
||||
},
|
||||
Scopes: []string{},
|
||||
}
|
||||
|
||||
for _, scope := range scopes {
|
||||
c.Scopes = append(c.Scopes, scope)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
//RefreshToken refresh token is not provided by github
|
||||
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
|
||||
return nil, errors.New("Refresh token is not provided by github")
|
||||
}
|
||||
|
||||
//RefreshTokenAvailable refresh token is not provided by github
|
||||
func (p *Provider) RefreshTokenAvailable() bool {
|
||||
return false
|
||||
}
|
||||
56
server/vendor/github.com/markbates/goth/providers/github/session.go
generated
vendored
Normal file
56
server/vendor/github.com/markbates/goth/providers/github/session.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package github
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
)
|
||||
|
||||
// Session stores data during the auth process with Github.
|
||||
type Session struct {
|
||||
AuthURL string
|
||||
AccessToken string
|
||||
}
|
||||
|
||||
// GetAuthURL will return the URL set by calling the `BeginAuth` function on the Github provider.
|
||||
func (s Session) GetAuthURL() (string, error) {
|
||||
if s.AuthURL == "" {
|
||||
return "", errors.New(goth.NoAuthUrlErrorMessage)
|
||||
}
|
||||
return s.AuthURL, nil
|
||||
}
|
||||
|
||||
// Authorize the session with Github and return the access token to be stored for future use.
|
||||
func (s *Session) Authorize(provider goth.Provider, params goth.Params) (string, error) {
|
||||
p := provider.(*Provider)
|
||||
token, err := p.config.Exchange(goth.ContextForClient(p.Client()), params.Get("code"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !token.Valid() {
|
||||
return "", errors.New("Invalid token received from provider")
|
||||
}
|
||||
|
||||
s.AccessToken = token.AccessToken
|
||||
return token.AccessToken, err
|
||||
}
|
||||
|
||||
// Marshal the session into a string
|
||||
func (s Session) Marshal() string {
|
||||
b, _ := json.Marshal(s)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (s Session) String() string {
|
||||
return s.Marshal()
|
||||
}
|
||||
|
||||
// UnmarshalSession will unmarshal a JSON string into a session.
|
||||
func (p *Provider) UnmarshalSession(data string) (goth.Session, error) {
|
||||
sess := &Session{}
|
||||
err := json.NewDecoder(strings.NewReader(data)).Decode(sess)
|
||||
return sess, err
|
||||
}
|
||||
11
server/vendor/github.com/markbates/goth/providers/google/endpoint.go
generated
vendored
Normal file
11
server/vendor/github.com/markbates/goth/providers/google/endpoint.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
//go:build go1.9
|
||||
// +build go1.9
|
||||
|
||||
package google
|
||||
|
||||
import (
|
||||
goog "golang.org/x/oauth2/google"
|
||||
)
|
||||
|
||||
// Endpoint is Google's OAuth 2.0 endpoint.
|
||||
var Endpoint = goog.Endpoint
|
||||
14
server/vendor/github.com/markbates/goth/providers/google/endpoint_legacy.go
generated
vendored
Normal file
14
server/vendor/github.com/markbates/goth/providers/google/endpoint_legacy.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
//go:build !go1.9
|
||||
// +build !go1.9
|
||||
|
||||
package google
|
||||
|
||||
import (
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// Endpoint is Google's OAuth 2.0 endpoint.
|
||||
var Endpoint = oauth2.Endpoint{
|
||||
AuthURL: "https://accounts.google.com/o/oauth2/auth",
|
||||
TokenURL: "https://accounts.google.com/o/oauth2/token",
|
||||
}
|
||||
211
server/vendor/github.com/markbates/goth/providers/google/google.go
generated
vendored
Normal file
211
server/vendor/github.com/markbates/goth/providers/google/google.go
generated
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
// Package google implements the OAuth2 protocol for authenticating users
|
||||
// through Google.
|
||||
package google
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const endpointProfile string = "https://www.googleapis.com/oauth2/v2/userinfo"
|
||||
|
||||
// New creates a new Google provider, and sets up important connection details.
|
||||
// You should always call `google.New` to get a new Provider. Never try to create
|
||||
// one manually.
|
||||
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
|
||||
p := &Provider{
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "google",
|
||||
|
||||
// We can get a refresh token from Google by this option.
|
||||
// See https://developers.google.com/identity/protocols/oauth2/openid-connect#access-type-param
|
||||
authCodeOptions: []oauth2.AuthCodeOption{
|
||||
oauth2.AccessTypeOffline,
|
||||
},
|
||||
}
|
||||
p.config = newConfig(p, scopes)
|
||||
return p
|
||||
}
|
||||
|
||||
// Provider is the implementation of `goth.Provider` for accessing Google.
|
||||
type Provider struct {
|
||||
ClientKey string
|
||||
Secret string
|
||||
CallbackURL string
|
||||
HTTPClient *http.Client
|
||||
config *oauth2.Config
|
||||
authCodeOptions []oauth2.AuthCodeOption
|
||||
providerName string
|
||||
}
|
||||
|
||||
// Name is the name used to retrieve this provider later.
|
||||
func (p *Provider) Name() string {
|
||||
return p.providerName
|
||||
}
|
||||
|
||||
// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
|
||||
func (p *Provider) SetName(name string) {
|
||||
p.providerName = name
|
||||
}
|
||||
|
||||
// Client returns an HTTP client to be used in all fetch operations.
|
||||
func (p *Provider) Client() *http.Client {
|
||||
return goth.HTTPClientWithFallBack(p.HTTPClient)
|
||||
}
|
||||
|
||||
// Debug is a no-op for the google package.
|
||||
func (p *Provider) Debug(debug bool) {}
|
||||
|
||||
// BeginAuth asks Google for an authentication endpoint.
|
||||
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
|
||||
url := p.config.AuthCodeURL(state, p.authCodeOptions...)
|
||||
session := &Session{
|
||||
AuthURL: url,
|
||||
}
|
||||
return session, nil
|
||||
}
|
||||
|
||||
type googleUser struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
FirstName string `json:"given_name"`
|
||||
LastName string `json:"family_name"`
|
||||
Link string `json:"link"`
|
||||
Picture string `json:"picture"`
|
||||
}
|
||||
|
||||
// FetchUser will go to Google and access basic information about the user.
|
||||
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
|
||||
sess := session.(*Session)
|
||||
user := goth.User{
|
||||
AccessToken: sess.AccessToken,
|
||||
Provider: p.Name(),
|
||||
RefreshToken: sess.RefreshToken,
|
||||
ExpiresAt: sess.ExpiresAt,
|
||||
IDToken: sess.IDToken,
|
||||
}
|
||||
|
||||
if user.AccessToken == "" {
|
||||
// Data is not yet retrieved, since accessToken is still empty.
|
||||
return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName)
|
||||
}
|
||||
|
||||
response, err := p.Client().Get(endpointProfile + "?access_token=" + url.QueryEscape(sess.AccessToken))
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, response.StatusCode)
|
||||
}
|
||||
|
||||
responseBytes, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
var u googleUser
|
||||
if err := json.Unmarshal(responseBytes, &u); err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
// Extract the user data we got from Google into our goth.User.
|
||||
user.Name = u.Name
|
||||
user.FirstName = u.FirstName
|
||||
user.LastName = u.LastName
|
||||
user.NickName = u.Name
|
||||
user.Email = u.Email
|
||||
user.AvatarURL = u.Picture
|
||||
user.UserID = u.ID
|
||||
// Google provides other useful fields such as 'hd'; get them from RawData
|
||||
if err := json.Unmarshal(responseBytes, &user.RawData); err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func newConfig(provider *Provider, scopes []string) *oauth2.Config {
|
||||
c := &oauth2.Config{
|
||||
ClientID: provider.ClientKey,
|
||||
ClientSecret: provider.Secret,
|
||||
RedirectURL: provider.CallbackURL,
|
||||
Endpoint: Endpoint,
|
||||
Scopes: []string{},
|
||||
}
|
||||
|
||||
if len(scopes) > 0 {
|
||||
c.Scopes = append(c.Scopes, scopes...)
|
||||
} else {
|
||||
c.Scopes = []string{"email"}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// RefreshTokenAvailable refresh token is provided by auth provider or not
|
||||
func (p *Provider) RefreshTokenAvailable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// RefreshToken get new access token based on the refresh token
|
||||
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
|
||||
token := &oauth2.Token{RefreshToken: refreshToken}
|
||||
ts := p.config.TokenSource(goth.ContextForClient(p.Client()), token)
|
||||
newToken, err := ts.Token()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newToken, err
|
||||
}
|
||||
|
||||
// SetPrompt sets the prompt values for the google OAuth call. Use this to
|
||||
// force users to choose and account every time by passing "select_account",
|
||||
// for example.
|
||||
// See https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters
|
||||
func (p *Provider) SetPrompt(prompt ...string) {
|
||||
if len(prompt) == 0 {
|
||||
return
|
||||
}
|
||||
p.authCodeOptions = append(p.authCodeOptions, oauth2.SetAuthURLParam("prompt", strings.Join(prompt, " ")))
|
||||
}
|
||||
|
||||
// SetHostedDomain sets the hd parameter for google OAuth call.
|
||||
// Use this to force user to pick user from specific hosted domain.
|
||||
// See https://developers.google.com/identity/protocols/oauth2/openid-connect#hd-param
|
||||
func (p *Provider) SetHostedDomain(hd string) {
|
||||
if hd == "" {
|
||||
return
|
||||
}
|
||||
p.authCodeOptions = append(p.authCodeOptions, oauth2.SetAuthURLParam("hd", hd))
|
||||
}
|
||||
|
||||
// SetLoginHint sets the login_hint parameter for the google OAuth call.
|
||||
// Use this to prompt the user to login with a specific account.
|
||||
// See https://developers.google.com/identity/protocols/oauth2/openid-connect#login-hint
|
||||
func (p *Provider) SetLoginHint(loginHint string) {
|
||||
if loginHint == "" {
|
||||
return
|
||||
}
|
||||
p.authCodeOptions = append(p.authCodeOptions, oauth2.SetAuthURLParam("login_hint", loginHint))
|
||||
}
|
||||
|
||||
// SetAccessType sets the access_type parameter for the google OAuth call.
|
||||
// If an access token is being requested, the client does not receive a refresh token unless a value of offline is specified.
|
||||
// See https://developers.google.com/identity/protocols/oauth2/openid-connect#access-type-param
|
||||
func (p *Provider) SetAccessType(at string) {
|
||||
if at == "" {
|
||||
return
|
||||
}
|
||||
p.authCodeOptions = append(p.authCodeOptions, oauth2.SetAuthURLParam("access_type", at))
|
||||
}
|
||||
63
server/vendor/github.com/markbates/goth/providers/google/session.go
generated
vendored
Normal file
63
server/vendor/github.com/markbates/goth/providers/google/session.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
)
|
||||
|
||||
// Session stores data during the auth process with Google.
|
||||
type Session struct {
|
||||
AuthURL string
|
||||
AccessToken string
|
||||
RefreshToken string
|
||||
ExpiresAt time.Time
|
||||
IDToken string
|
||||
}
|
||||
|
||||
// GetAuthURL will return the URL set by calling the `BeginAuth` function on the Google provider.
|
||||
func (s Session) GetAuthURL() (string, error) {
|
||||
if s.AuthURL == "" {
|
||||
return "", errors.New(goth.NoAuthUrlErrorMessage)
|
||||
}
|
||||
return s.AuthURL, nil
|
||||
}
|
||||
|
||||
// Authorize the session with Google and return the access token to be stored for future use.
|
||||
func (s *Session) Authorize(provider goth.Provider, params goth.Params) (string, error) {
|
||||
p := provider.(*Provider)
|
||||
token, err := p.config.Exchange(goth.ContextForClient(p.Client()), params.Get("code"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !token.Valid() {
|
||||
return "", errors.New("Invalid token received from provider")
|
||||
}
|
||||
|
||||
s.AccessToken = token.AccessToken
|
||||
s.RefreshToken = token.RefreshToken
|
||||
s.ExpiresAt = token.Expiry
|
||||
s.IDToken = token.Extra("id_token").(string)
|
||||
return token.AccessToken, err
|
||||
}
|
||||
|
||||
// Marshal the session into a string
|
||||
func (s Session) Marshal() string {
|
||||
b, _ := json.Marshal(s)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (s Session) String() string {
|
||||
return s.Marshal()
|
||||
}
|
||||
|
||||
// UnmarshalSession will unmarshal a JSON string into a session.
|
||||
func (p *Provider) UnmarshalSession(data string) (goth.Session, error) {
|
||||
sess := &Session{}
|
||||
err := json.NewDecoder(strings.NewReader(data)).Decode(sess)
|
||||
return sess, err
|
||||
}
|
||||
278
server/vendor/github.com/markbates/goth/providers/linkedin/linkedin.go
generated
vendored
Normal file
278
server/vendor/github.com/markbates/goth/providers/linkedin/linkedin.go
generated
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
// Package linkedin implements the OAuth2 protocol for authenticating users through Linkedin.
|
||||
package linkedin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// more details about linkedin fields:
|
||||
// User Profile and Email Address - https://docs.microsoft.com/en-gb/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin
|
||||
// User Avatar - https://docs.microsoft.com/en-gb/linkedin/shared/references/v2/digital-media-asset
|
||||
|
||||
const (
|
||||
authURL string = "https://www.linkedin.com/oauth/v2/authorization"
|
||||
tokenURL string = "https://www.linkedin.com/oauth/v2/accessToken"
|
||||
|
||||
//userEndpoint requires scope "r_liteprofile"
|
||||
userEndpoint string = "//api.linkedin.com/v2/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))"
|
||||
//emailEndpoint requires scope "r_emailaddress"
|
||||
emailEndpoint string = "//api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))"
|
||||
)
|
||||
|
||||
// New creates a new linkedin provider, and sets up important connection details.
|
||||
// You should always call `linkedin.New` to get a new Provider. Never try to create
|
||||
// one manually.
|
||||
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
|
||||
p := &Provider{
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
providerName: "linkedin",
|
||||
}
|
||||
p.config = newConfig(p, scopes)
|
||||
return p
|
||||
}
|
||||
|
||||
// Provider is the implementation of `goth.Provider` for accessing Linkedin.
|
||||
type Provider struct {
|
||||
ClientKey string
|
||||
Secret string
|
||||
CallbackURL string
|
||||
HTTPClient *http.Client
|
||||
config *oauth2.Config
|
||||
providerName string
|
||||
}
|
||||
|
||||
// Name is the name used to retrieve this provider later.
|
||||
func (p *Provider) Name() string {
|
||||
return p.providerName
|
||||
}
|
||||
|
||||
// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
|
||||
func (p *Provider) SetName(name string) {
|
||||
p.providerName = name
|
||||
}
|
||||
|
||||
// Client returns an HTTPClientWithFallback
|
||||
func (p *Provider) Client() *http.Client {
|
||||
return goth.HTTPClientWithFallBack(p.HTTPClient)
|
||||
}
|
||||
|
||||
// Debug is a no-op for the linkedin package.
|
||||
func (p *Provider) Debug(debug bool) {}
|
||||
|
||||
// BeginAuth asks Linkedin for an authentication end-point.
|
||||
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
|
||||
url := p.config.AuthCodeURL(state)
|
||||
session := &Session{
|
||||
AuthURL: url,
|
||||
}
|
||||
return session, nil
|
||||
}
|
||||
|
||||
// FetchUser will go to Linkedin and access basic information about the user.
|
||||
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
|
||||
s := session.(*Session)
|
||||
user := goth.User{
|
||||
AccessToken: s.AccessToken,
|
||||
Provider: p.Name(),
|
||||
ExpiresAt: s.ExpiresAt,
|
||||
}
|
||||
|
||||
if user.AccessToken == "" {
|
||||
// data is not yet retrieved since accessToken is still empty
|
||||
return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName)
|
||||
}
|
||||
|
||||
// create request for user r_liteprofile
|
||||
req, err := http.NewRequest("GET", "", nil)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
// add url as opaque to avoid escaping of "("
|
||||
req.URL = &url.URL{
|
||||
Scheme: "https",
|
||||
Host: "api.linkedin.com",
|
||||
Opaque: userEndpoint,
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", "Bearer "+s.AccessToken)
|
||||
resp, err := p.Client().Do(req)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return user, fmt.Errorf("%s responded with a %d trying to fetch user profile", p.providerName, resp.StatusCode)
|
||||
}
|
||||
|
||||
// read r_liteprofile information
|
||||
err = userFromReader(resp.Body, &user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
// create request for user r_emailaddress
|
||||
reqEmail, err := http.NewRequest("GET", "", nil)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
// add url as opaque to avoid escaping of "("
|
||||
reqEmail.URL = &url.URL{
|
||||
Scheme: "https",
|
||||
Host: "api.linkedin.com",
|
||||
Opaque: emailEndpoint,
|
||||
}
|
||||
|
||||
reqEmail.Header.Set("Authorization", "Bearer "+s.AccessToken)
|
||||
respEmail, err := p.Client().Do(reqEmail)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
defer respEmail.Body.Close()
|
||||
|
||||
if respEmail.StatusCode != http.StatusOK {
|
||||
return user, fmt.Errorf("%s responded with a %d trying to fetch user email", p.providerName, respEmail.StatusCode)
|
||||
}
|
||||
|
||||
// read r_emailaddress information
|
||||
err = emailFromReader(respEmail.Body, &user)
|
||||
|
||||
return user, err
|
||||
}
|
||||
|
||||
func userFromReader(reader io.Reader, user *goth.User) error {
|
||||
u := struct {
|
||||
ID string `json:"id"`
|
||||
FirstName struct {
|
||||
PreferredLocale struct {
|
||||
Country string `json:"country"`
|
||||
Language string `json:"language"`
|
||||
} `json:"preferredLocale"`
|
||||
Localized map[string]string `json:"localized"`
|
||||
} `json:"firstName"`
|
||||
LastName struct {
|
||||
Localized map[string]string
|
||||
PreferredLocale struct {
|
||||
Country string `json:"country"`
|
||||
Language string `json:"language"`
|
||||
} `json:"preferredLocale"`
|
||||
} `json:"lastName"`
|
||||
ProfilePicture struct {
|
||||
DisplayImage struct {
|
||||
Elements []struct {
|
||||
AuthorizationMethod string `json:"authorizationMethod"`
|
||||
Identifiers []struct {
|
||||
Identifier string `json:"identifier"`
|
||||
IdentifierType string `json:"identifierType"`
|
||||
} `json:"identifiers"`
|
||||
} `json:"elements"`
|
||||
} `json:"displayImage~"`
|
||||
} `json:"profilePicture"`
|
||||
}{}
|
||||
|
||||
err := json.NewDecoder(reader).Decode(&u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user.FirstName = u.FirstName.Localized[u.FirstName.PreferredLocale.Language+"_"+u.FirstName.PreferredLocale.Country]
|
||||
user.LastName = u.LastName.Localized[u.LastName.PreferredLocale.Language+"_"+u.LastName.PreferredLocale.Country]
|
||||
user.Name = user.FirstName + " " + user.LastName
|
||||
user.NickName = user.FirstName
|
||||
user.UserID = u.ID
|
||||
|
||||
avatarURL := ""
|
||||
// loop all displayimage elements
|
||||
for _, element := range u.ProfilePicture.DisplayImage.Elements {
|
||||
// only retrieve data where the authorization method allows public (unauthorized) access
|
||||
if element.AuthorizationMethod == "PUBLIC" {
|
||||
for _, identifier := range element.Identifiers {
|
||||
// check to ensure the identifer type is a url linking to the image
|
||||
if identifier.IdentifierType == "EXTERNAL_URL" {
|
||||
avatarURL = identifier.Identifier
|
||||
// we only need the first image url
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we have a valid image, exit the loop as we only support a single avatar image
|
||||
if len(avatarURL) > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
user.AvatarURL = avatarURL
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func emailFromReader(reader io.Reader, user *goth.User) error {
|
||||
e := struct {
|
||||
Elements []struct {
|
||||
Handle struct {
|
||||
EmailAddress string `json:"emailAddress"`
|
||||
} `json:"handle~"`
|
||||
} `json:"elements"`
|
||||
}{}
|
||||
|
||||
err := json.NewDecoder(reader).Decode(&e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(e.Elements) > 0 {
|
||||
user.Email = e.Elements[0].Handle.EmailAddress
|
||||
}
|
||||
|
||||
if len(user.Email) == 0 {
|
||||
return errors.New("Unable to retrieve email address")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func newConfig(provider *Provider, scopes []string) *oauth2.Config {
|
||||
c := &oauth2.Config{
|
||||
ClientID: provider.ClientKey,
|
||||
ClientSecret: provider.Secret,
|
||||
RedirectURL: provider.CallbackURL,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: authURL,
|
||||
TokenURL: tokenURL,
|
||||
},
|
||||
Scopes: []string{},
|
||||
}
|
||||
|
||||
if len(scopes) == 0 {
|
||||
// add helper as new API requires the scope to be specified and these are the minimum to retrieve profile information and user's email address
|
||||
scopes = append(scopes, "r_liteprofile", "r_emailaddress")
|
||||
}
|
||||
|
||||
for _, scope := range scopes {
|
||||
c.Scopes = append(c.Scopes, scope)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
//RefreshToken refresh token is not provided by linkedin
|
||||
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
|
||||
return nil, errors.New("Refresh token is not provided by linkedin")
|
||||
}
|
||||
|
||||
//RefreshTokenAvailable refresh token is not provided by linkedin
|
||||
func (p *Provider) RefreshTokenAvailable() bool {
|
||||
return false
|
||||
}
|
||||
58
server/vendor/github.com/markbates/goth/providers/linkedin/session.go
generated
vendored
Normal file
58
server/vendor/github.com/markbates/goth/providers/linkedin/session.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package linkedin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
)
|
||||
|
||||
// Session stores data during the auth process with Linkedin.
|
||||
type Session struct {
|
||||
AuthURL string
|
||||
AccessToken string
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
// GetAuthURL will return the URL set by calling the `BeginAuth` function on the Linkedin provider.
|
||||
func (s Session) GetAuthURL() (string, error) {
|
||||
if s.AuthURL == "" {
|
||||
return "", errors.New(goth.NoAuthUrlErrorMessage)
|
||||
}
|
||||
return s.AuthURL, nil
|
||||
}
|
||||
|
||||
// Authorize the session with Linkedin and return the access token to be stored for future use.
|
||||
func (s *Session) Authorize(provider goth.Provider, params goth.Params) (string, error) {
|
||||
p := provider.(*Provider)
|
||||
token, err := p.config.Exchange(goth.ContextForClient(p.Client()), params.Get("code"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !token.Valid() {
|
||||
return "", errors.New("Invalid token received from provider")
|
||||
}
|
||||
|
||||
s.AccessToken = token.AccessToken
|
||||
s.ExpiresAt = token.Expiry
|
||||
return token.AccessToken, err
|
||||
}
|
||||
|
||||
// Marshal the session into a string
|
||||
func (s Session) Marshal() string {
|
||||
b, _ := json.Marshal(s)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (s Session) String() string {
|
||||
return s.Marshal()
|
||||
}
|
||||
|
||||
// UnmarshalSession will unmarshal a JSON string into a session.
|
||||
func (p *Provider) UnmarshalSession(data string) (goth.Session, error) {
|
||||
s := Session{}
|
||||
err := json.Unmarshal([]byte(data), &s)
|
||||
return &s, err
|
||||
}
|
||||
474
server/vendor/github.com/markbates/goth/providers/openidConnect/openidConnect.go
generated
vendored
Normal file
474
server/vendor/github.com/markbates/goth/providers/openidConnect/openidConnect.go
generated
vendored
Normal file
@@ -0,0 +1,474 @@
|
||||
package openidConnect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const (
|
||||
// Standard Claims http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
|
||||
// fixed, cannot be changed
|
||||
subjectClaim = "sub"
|
||||
expiryClaim = "exp"
|
||||
audienceClaim = "aud"
|
||||
issuerClaim = "iss"
|
||||
|
||||
PreferredUsernameClaim = "preferred_username"
|
||||
EmailClaim = "email"
|
||||
NameClaim = "name"
|
||||
NicknameClaim = "nickname"
|
||||
PictureClaim = "picture"
|
||||
GivenNameClaim = "given_name"
|
||||
FamilyNameClaim = "family_name"
|
||||
AddressClaim = "address"
|
||||
|
||||
// Unused but available to set in Provider claims
|
||||
MiddleNameClaim = "middle_name"
|
||||
ProfileClaim = "profile"
|
||||
WebsiteClaim = "website"
|
||||
EmailVerifiedClaim = "email_verified"
|
||||
GenderClaim = "gender"
|
||||
BirthdateClaim = "birthdate"
|
||||
ZoneinfoClaim = "zoneinfo"
|
||||
LocaleClaim = "locale"
|
||||
PhoneNumberClaim = "phone_number"
|
||||
PhoneNumberVerifiedClaim = "phone_number_verified"
|
||||
UpdatedAtClaim = "updated_at"
|
||||
|
||||
clockSkew = 10 * time.Second
|
||||
)
|
||||
|
||||
// Provider is the implementation of `goth.Provider` for accessing OpenID Connect provider
|
||||
type Provider struct {
|
||||
ClientKey string
|
||||
Secret string
|
||||
CallbackURL string
|
||||
HTTPClient *http.Client
|
||||
OpenIDConfig *OpenIDConfig
|
||||
config *oauth2.Config
|
||||
providerName string
|
||||
|
||||
UserIdClaims []string
|
||||
NameClaims []string
|
||||
NickNameClaims []string
|
||||
EmailClaims []string
|
||||
AvatarURLClaims []string
|
||||
FirstNameClaims []string
|
||||
LastNameClaims []string
|
||||
LocationClaims []string
|
||||
|
||||
SkipUserInfoRequest bool
|
||||
}
|
||||
|
||||
type OpenIDConfig struct {
|
||||
AuthEndpoint string `json:"authorization_endpoint"`
|
||||
TokenEndpoint string `json:"token_endpoint"`
|
||||
UserInfoEndpoint string `json:"userinfo_endpoint"`
|
||||
|
||||
// If OpenID discovery is enabled, the end_session_endpoint field can optionally be provided
|
||||
// in the discovery endpoint response according to OpenID spec. See:
|
||||
// https://openid.net/specs/openid-connect-session-1_0-17.html#OPMetadata
|
||||
EndSessionEndpoint string `json:"end_session_endpoint, omitempty"`
|
||||
Issuer string `json:"issuer"`
|
||||
}
|
||||
|
||||
type RefreshTokenResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
|
||||
// The OpenID spec defines the ID token as an optional response field in the
|
||||
// refresh token flow. As a result, a new ID token may not be returned in a successful
|
||||
// response.
|
||||
// See more: https://openid.net/specs/openid-connect-core-1_0.html#RefreshingAccessToken
|
||||
IdToken string `json:"id_token, omitempty"`
|
||||
|
||||
// The OAuth spec defines the refresh token as an optional response field in the
|
||||
// refresh token flow. As a result, a new refresh token may not be returned in a successful
|
||||
// response.
|
||||
//See more: https://www.oauth.com/oauth2-servers/making-authenticated-requests/refreshing-an-access-token/
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
}
|
||||
|
||||
// New creates a new OpenID Connect provider, and sets up important connection details.
|
||||
// You should always call `openidConnect.New` to get a new Provider. Never try to create
|
||||
// one manually.
|
||||
// New returns an implementation of an OpenID Connect Authorization Code Flow
|
||||
// See http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
|
||||
// ID Token decryption is not (yet) supported
|
||||
// UserInfo decryption is not (yet) supported
|
||||
func New(clientKey, secret, callbackURL, openIDAutoDiscoveryURL string, scopes ...string) (*Provider, error) {
|
||||
p := &Provider{
|
||||
ClientKey: clientKey,
|
||||
Secret: secret,
|
||||
CallbackURL: callbackURL,
|
||||
|
||||
UserIdClaims: []string{subjectClaim},
|
||||
NameClaims: []string{NameClaim},
|
||||
NickNameClaims: []string{NicknameClaim, PreferredUsernameClaim},
|
||||
EmailClaims: []string{EmailClaim},
|
||||
AvatarURLClaims: []string{PictureClaim},
|
||||
FirstNameClaims: []string{GivenNameClaim},
|
||||
LastNameClaims: []string{FamilyNameClaim},
|
||||
LocationClaims: []string{AddressClaim},
|
||||
|
||||
providerName: "openid-connect",
|
||||
}
|
||||
|
||||
openIDConfig, err := getOpenIDConfig(p, openIDAutoDiscoveryURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.OpenIDConfig = openIDConfig
|
||||
|
||||
p.config = newConfig(p, scopes, openIDConfig)
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Name is the name used to retrieve this provider later.
|
||||
func (p *Provider) Name() string {
|
||||
return p.providerName
|
||||
}
|
||||
|
||||
// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
|
||||
func (p *Provider) SetName(name string) {
|
||||
p.providerName = name
|
||||
}
|
||||
|
||||
func (p *Provider) Client() *http.Client {
|
||||
return goth.HTTPClientWithFallBack(p.HTTPClient)
|
||||
}
|
||||
|
||||
// Debug is a no-op for the openidConnect package.
|
||||
func (p *Provider) Debug(debug bool) {}
|
||||
|
||||
// BeginAuth asks the OpenID Connect provider for an authentication end-point.
|
||||
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
|
||||
url := p.config.AuthCodeURL(state)
|
||||
session := &Session{
|
||||
AuthURL: url,
|
||||
}
|
||||
return session, nil
|
||||
}
|
||||
|
||||
// FetchUser will use the the id_token and access requested information about the user.
|
||||
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
|
||||
sess := session.(*Session)
|
||||
|
||||
expiresAt := sess.ExpiresAt
|
||||
|
||||
if sess.IDToken == "" {
|
||||
return goth.User{}, fmt.Errorf("%s cannot get user information without id_token", p.providerName)
|
||||
}
|
||||
|
||||
// decode returned id token to get expiry
|
||||
claims, err := decodeJWT(sess.IDToken)
|
||||
|
||||
if err != nil {
|
||||
return goth.User{}, fmt.Errorf("oauth2: error decoding JWT token: %v", err)
|
||||
}
|
||||
|
||||
expiry, err := p.validateClaims(claims)
|
||||
if err != nil {
|
||||
return goth.User{}, fmt.Errorf("oauth2: error validating JWT token: %v", err)
|
||||
}
|
||||
|
||||
if expiry.Before(expiresAt) {
|
||||
expiresAt = expiry
|
||||
}
|
||||
|
||||
if err := p.getUserInfo(sess.AccessToken, claims); err != nil {
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
user := goth.User{
|
||||
AccessToken: sess.AccessToken,
|
||||
Provider: p.Name(),
|
||||
RefreshToken: sess.RefreshToken,
|
||||
ExpiresAt: expiresAt,
|
||||
RawData: claims,
|
||||
IDToken: sess.IDToken,
|
||||
}
|
||||
|
||||
p.userFromClaims(claims, &user)
|
||||
return user, err
|
||||
}
|
||||
|
||||
//RefreshTokenAvailable refresh token is provided by auth provider or not
|
||||
func (p *Provider) RefreshTokenAvailable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
//RefreshToken get new access token based on the refresh token
|
||||
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
|
||||
token := &oauth2.Token{RefreshToken: refreshToken}
|
||||
ts := p.config.TokenSource(oauth2.NoContext, token)
|
||||
newToken, err := ts.Token()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newToken, err
|
||||
}
|
||||
|
||||
// The ID token is a fundamental part of the OpenID connect refresh token flow but is not part of the OAuth flow.
|
||||
// The existing RefreshToken function leverages the OAuth library's refresh token mechanism, ignoring the refreshed
|
||||
// ID token. As a result, a new function needs to be exposed (rather than changing the existing function, for backwards
|
||||
// compatibility purposes) that also returns the id_token in the OpenID refresh token flow API response
|
||||
// Learn more about ID tokens: https://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
func (p *Provider) RefreshTokenWithIDToken(refreshToken string) (*RefreshTokenResponse, error) {
|
||||
urlValues := url.Values{
|
||||
"grant_type": {"refresh_token"},
|
||||
"refresh_token": {refreshToken},
|
||||
"client_id": {p.ClientKey},
|
||||
"client_secret": {p.Secret},
|
||||
}
|
||||
req, err := http.NewRequest("POST", p.OpenIDConfig.TokenEndpoint, strings.NewReader(urlValues.Encode()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
resp, err := p.Client().Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("Non-200 response from RefreshToken: %d, WWW-Authenticate=%s", resp.StatusCode, resp.Header.Get("WWW-Authenticate"))
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
refreshTokenResponse := &RefreshTokenResponse{}
|
||||
|
||||
err = json.Unmarshal(body, refreshTokenResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return refreshTokenResponse, nil
|
||||
}
|
||||
|
||||
// validate according to standard, returns expiry
|
||||
// http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
||||
func (p *Provider) validateClaims(claims map[string]interface{}) (time.Time, error) {
|
||||
audience := getClaimValue(claims, []string{audienceClaim})
|
||||
if audience != p.ClientKey {
|
||||
found := false
|
||||
audiences := getClaimValues(claims, []string{audienceClaim})
|
||||
for _, aud := range audiences {
|
||||
if aud == p.ClientKey {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return time.Time{}, errors.New("audience in token does not match client key")
|
||||
}
|
||||
}
|
||||
|
||||
issuer := getClaimValue(claims, []string{issuerClaim})
|
||||
if issuer != p.OpenIDConfig.Issuer {
|
||||
return time.Time{}, errors.New("issuer in token does not match issuer in OpenIDConfig discovery")
|
||||
}
|
||||
|
||||
// expiry is required for JWT, not for UserInfoResponse
|
||||
// is actually a int64, so force it in to that type
|
||||
expiryClaim := int64(claims[expiryClaim].(float64))
|
||||
expiry := time.Unix(expiryClaim, 0)
|
||||
if expiry.Add(clockSkew).Before(time.Now()) {
|
||||
return time.Time{}, errors.New("user info JWT token is expired")
|
||||
}
|
||||
return expiry, nil
|
||||
}
|
||||
|
||||
func (p *Provider) userFromClaims(claims map[string]interface{}, user *goth.User) {
|
||||
// required
|
||||
user.UserID = getClaimValue(claims, p.UserIdClaims)
|
||||
|
||||
user.Name = getClaimValue(claims, p.NameClaims)
|
||||
user.NickName = getClaimValue(claims, p.NickNameClaims)
|
||||
user.Email = getClaimValue(claims, p.EmailClaims)
|
||||
user.AvatarURL = getClaimValue(claims, p.AvatarURLClaims)
|
||||
user.FirstName = getClaimValue(claims, p.FirstNameClaims)
|
||||
user.LastName = getClaimValue(claims, p.LastNameClaims)
|
||||
user.Location = getClaimValue(claims, p.LocationClaims)
|
||||
}
|
||||
|
||||
func (p *Provider) getUserInfo(accessToken string, claims map[string]interface{}) error {
|
||||
// skip if there is no UserInfoEndpoint or is explicitly disabled
|
||||
if p.OpenIDConfig.UserInfoEndpoint == "" || p.SkipUserInfoRequest {
|
||||
return nil
|
||||
}
|
||||
|
||||
userInfoClaims, err := p.fetchUserInfo(p.OpenIDConfig.UserInfoEndpoint, accessToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The sub (subject) Claim MUST always be returned in the UserInfo Response.
|
||||
// http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
|
||||
userInfoSubject := getClaimValue(userInfoClaims, []string{subjectClaim})
|
||||
if userInfoSubject == "" {
|
||||
return fmt.Errorf("userinfo response did not contain a 'sub' claim: %#v", userInfoClaims)
|
||||
}
|
||||
|
||||
// The sub Claim in the UserInfo Response MUST be verified to exactly match the sub Claim in the ID Token;
|
||||
// if they do not match, the UserInfo Response values MUST NOT be used.
|
||||
// http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
|
||||
subject := getClaimValue(claims, []string{subjectClaim})
|
||||
if userInfoSubject != subject {
|
||||
return fmt.Errorf("userinfo 'sub' claim (%s) did not match id_token 'sub' claim (%s)", userInfoSubject, subject)
|
||||
}
|
||||
|
||||
// Merge in userinfo claims in case id_token claims contained some that userinfo did not
|
||||
for k, v := range userInfoClaims {
|
||||
claims[k] = v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// fetch and decode JSON from the given UserInfo URL
|
||||
func (p *Provider) fetchUserInfo(url, accessToken string) (map[string]interface{}, error) {
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
|
||||
|
||||
resp, err := p.Client().Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("Non-200 response from UserInfo: %d, WWW-Authenticate=%s", resp.StatusCode, resp.Header.Get("WWW-Authenticate"))
|
||||
}
|
||||
|
||||
// The UserInfo Claims MUST be returned as the members of a JSON object
|
||||
// http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return unMarshal(data)
|
||||
}
|
||||
|
||||
func getOpenIDConfig(p *Provider, openIDAutoDiscoveryURL string) (*OpenIDConfig, error) {
|
||||
res, err := p.Client().Get(openIDAutoDiscoveryURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
openIDConfig := &OpenIDConfig{}
|
||||
err = json.Unmarshal(body, openIDConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return openIDConfig, nil
|
||||
}
|
||||
|
||||
func newConfig(provider *Provider, scopes []string, openIDConfig *OpenIDConfig) *oauth2.Config {
|
||||
c := &oauth2.Config{
|
||||
ClientID: provider.ClientKey,
|
||||
ClientSecret: provider.Secret,
|
||||
RedirectURL: provider.CallbackURL,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: openIDConfig.AuthEndpoint,
|
||||
TokenURL: openIDConfig.TokenEndpoint,
|
||||
},
|
||||
Scopes: []string{},
|
||||
}
|
||||
|
||||
if len(scopes) > 0 {
|
||||
foundOpenIDScope := false
|
||||
|
||||
for _, scope := range scopes {
|
||||
if scope == "openid" {
|
||||
foundOpenIDScope = true
|
||||
}
|
||||
c.Scopes = append(c.Scopes, scope)
|
||||
}
|
||||
|
||||
if !foundOpenIDScope {
|
||||
c.Scopes = append(c.Scopes, "openid")
|
||||
}
|
||||
} else {
|
||||
c.Scopes = []string{"openid"}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func getClaimValue(data map[string]interface{}, claims []string) string {
|
||||
for _, claim := range claims {
|
||||
if value, ok := data[claim]; ok {
|
||||
if stringValue, ok := value.(string); ok && len(stringValue) > 0 {
|
||||
return stringValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func getClaimValues(data map[string]interface{}, claims []string) []string {
|
||||
var result []string
|
||||
|
||||
for _, claim := range claims {
|
||||
if value, ok := data[claim]; ok {
|
||||
if stringValues, ok := value.([]interface{}); ok {
|
||||
for _, stringValue := range stringValues {
|
||||
if s, ok := stringValue.(string); ok && len(s) > 0 {
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// decodeJWT decodes a JSON Web Token into a simple map
|
||||
// http://openid.net/specs/draft-jones-json-web-token-07.html
|
||||
func decodeJWT(jwt string) (map[string]interface{}, error) {
|
||||
jwtParts := strings.Split(jwt, ".")
|
||||
if len(jwtParts) != 3 {
|
||||
return nil, errors.New("jws: invalid token received, not all parts available")
|
||||
}
|
||||
|
||||
decodedPayload, err := base64.URLEncoding.WithPadding(base64.NoPadding).DecodeString(jwtParts[1])
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return unMarshal(decodedPayload)
|
||||
}
|
||||
|
||||
func unMarshal(payload []byte) (map[string]interface{}, error) {
|
||||
data := make(map[string]interface{})
|
||||
|
||||
return data, json.NewDecoder(bytes.NewBuffer(payload)).Decode(&data)
|
||||
}
|
||||
63
server/vendor/github.com/markbates/goth/providers/openidConnect/session.go
generated
vendored
Normal file
63
server/vendor/github.com/markbates/goth/providers/openidConnect/session.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package openidConnect
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/markbates/goth"
|
||||
"golang.org/x/oauth2"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Session stores data during the auth process with the OpenID Connect provider.
|
||||
type Session struct {
|
||||
AuthURL string
|
||||
AccessToken string
|
||||
RefreshToken string
|
||||
ExpiresAt time.Time
|
||||
IDToken string
|
||||
}
|
||||
|
||||
// GetAuthURL will return the URL set by calling the `BeginAuth` function on the OpenID Connect provider.
|
||||
func (s Session) GetAuthURL() (string, error) {
|
||||
if s.AuthURL == "" {
|
||||
return "", errors.New("an AuthURL has not be set")
|
||||
}
|
||||
return s.AuthURL, nil
|
||||
}
|
||||
|
||||
// Authorize the session with the OpenID Connect provider and return the access token to be stored for future use.
|
||||
func (s *Session) Authorize(provider goth.Provider, params goth.Params) (string, error) {
|
||||
p := provider.(*Provider)
|
||||
token, err := p.config.Exchange(oauth2.NoContext, params.Get("code"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !token.Valid() {
|
||||
return "", errors.New("Invalid token received from provider")
|
||||
}
|
||||
|
||||
s.AccessToken = token.AccessToken
|
||||
s.RefreshToken = token.RefreshToken
|
||||
s.ExpiresAt = token.Expiry
|
||||
s.IDToken = token.Extra("id_token").(string)
|
||||
return token.AccessToken, err
|
||||
}
|
||||
|
||||
// Marshal the session into a string
|
||||
func (s Session) Marshal() string {
|
||||
b, _ := json.Marshal(s)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (s Session) String() string {
|
||||
return s.Marshal()
|
||||
}
|
||||
|
||||
// UnmarshalSession will unmarshal a JSON string into a session.
|
||||
func (p *Provider) UnmarshalSession(data string) (goth.Session, error) {
|
||||
sess := &Session{}
|
||||
err := json.NewDecoder(strings.NewReader(data)).Decode(sess)
|
||||
return sess, err
|
||||
}
|
||||
21
server/vendor/github.com/markbates/goth/session.go
generated
vendored
Normal file
21
server/vendor/github.com/markbates/goth/session.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package goth
|
||||
|
||||
// Params is used to pass data to sessions for authorization. An existing
|
||||
// implementation, and the one most likely to be used, is `url.Values`.
|
||||
type Params interface {
|
||||
Get(string) string
|
||||
}
|
||||
|
||||
// Session needs to be implemented as part of the provider package.
|
||||
// It will be marshaled and persisted between requests to "tie"
|
||||
// the start and the end of the authorization process with a
|
||||
// 3rd party provider.
|
||||
type Session interface {
|
||||
// GetAuthURL returns the URL for the authentication end-point for the provider.
|
||||
GetAuthURL() (string, error)
|
||||
// Marshal generates a string representation of the Session for storing between requests.
|
||||
Marshal() string
|
||||
// Authorize should validate the data from the provider and return an access token
|
||||
// that can be stored for later access to the provider.
|
||||
Authorize(Provider, Params) (string, error)
|
||||
}
|
||||
31
server/vendor/github.com/markbates/goth/user.go
generated
vendored
Normal file
31
server/vendor/github.com/markbates/goth/user.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package goth
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register(User{})
|
||||
}
|
||||
|
||||
// User contains the information common amongst most OAuth and OAuth2 providers.
|
||||
// All of the "raw" datafrom the provider can be found in the `RawData` field.
|
||||
type User struct {
|
||||
RawData map[string]interface{}
|
||||
Provider string
|
||||
Email string
|
||||
Name string
|
||||
FirstName string
|
||||
LastName string
|
||||
NickName string
|
||||
Description string
|
||||
UserID string
|
||||
AvatarURL string
|
||||
Location string
|
||||
AccessToken string
|
||||
AccessTokenSecret string
|
||||
RefreshToken string
|
||||
ExpiresAt time.Time
|
||||
IDToken string
|
||||
}
|
||||
Reference in New Issue
Block a user