mirror of
https://github.com/wahyd4/loginsrv.git
synced 2026-08-09 04:46:29 +10:00
154 lines
3.7 KiB
Go
154 lines
3.7 KiB
Go
package oauth2
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/tarent/loginsrv/model"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
// Manager has the responsibility to handle the user user requests in an oauth flow.
|
|
// It has to pick the right configuration and start the oauth redirecting.
|
|
type Manager struct {
|
|
configs map[string]Config
|
|
startFlow func(cfg Config, w http.ResponseWriter)
|
|
authenticate func(cfg Config, r *http.Request) (TokenInfo, error)
|
|
}
|
|
|
|
// NewManager creates a new Manager
|
|
func NewManager() *Manager {
|
|
return &Manager{
|
|
configs: map[string]Config{},
|
|
startFlow: StartFlow,
|
|
authenticate: Authenticate,
|
|
}
|
|
}
|
|
|
|
// Handle is managing the oauth flow.
|
|
// Dependent on the code parameter of the url, the oauth flow is started or
|
|
// the call is interpreted as the redirect callback and the token exchange is done.
|
|
// Return parameters:
|
|
// startedFlow - true, if this was the initial call to start the oauth flow
|
|
// authenticated - if the authentication was successful or not
|
|
// userInfo - the user info from the provider in case of a successful authentication
|
|
// err - an error
|
|
func (manager *Manager) Handle(w http.ResponseWriter, r *http.Request) (
|
|
startedFlow bool,
|
|
authenticated bool,
|
|
userInfo model.UserInfo,
|
|
err error) {
|
|
|
|
if r.FormValue("error") != "" {
|
|
return false, false, model.UserInfo{}, fmt.Errorf("error: %v", r.FormValue("error"))
|
|
}
|
|
|
|
cfg, err := manager.GetConfigFromRequest(r)
|
|
if err != nil {
|
|
return false, false, model.UserInfo{}, err
|
|
}
|
|
|
|
if r.FormValue("code") != "" {
|
|
tokenInfo, err := manager.authenticate(cfg, r)
|
|
if err != nil {
|
|
return false, false, model.UserInfo{}, err
|
|
}
|
|
|
|
userInfo, _, err := cfg.Provider.GetUserInfo(tokenInfo)
|
|
if err != nil {
|
|
return false, false, model.UserInfo{}, err
|
|
}
|
|
return false, true, userInfo, err
|
|
}
|
|
|
|
manager.startFlow(cfg, w)
|
|
return true, false, model.UserInfo{}, nil
|
|
}
|
|
|
|
// GetConfigFromRequest returns the oauth configuration matching the current path.
|
|
// The configuration name is taken from the last path segment.
|
|
func (manager *Manager) GetConfigFromRequest(r *http.Request) (Config, error) {
|
|
configName := manager.getConfigNameFromPath(r.URL.Path)
|
|
cfg, exist := manager.configs[configName]
|
|
if !exist {
|
|
return Config{}, fmt.Errorf("no oauth configuration for %v", configName)
|
|
}
|
|
|
|
if cfg.RedirectURI == "" {
|
|
cfg.RedirectURI = redirectURIFromRequest(r)
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
func (manager *Manager) getConfigNameFromPath(path string) string {
|
|
parts := strings.Split(path, "/")
|
|
return parts[len(parts)-1]
|
|
}
|
|
|
|
// AddConfig for a provider
|
|
func (manager *Manager) AddConfig(providerName string, opts map[string]string) error {
|
|
p, exist := GetProvider(providerName)
|
|
|
|
if !exist {
|
|
return fmt.Errorf("no provider for name %v", providerName)
|
|
}
|
|
|
|
cfg := Config{
|
|
Provider: p,
|
|
AuthURL: p.AuthURL,
|
|
TokenURL: p.TokenURL,
|
|
}
|
|
|
|
clientID, exist := opts["client_id"]
|
|
if !exist {
|
|
return fmt.Errorf("missing parameter client_id")
|
|
}
|
|
cfg.ClientID = clientID
|
|
|
|
clientSecret, exist := opts["client_secret"]
|
|
if !exist {
|
|
return fmt.Errorf("missing parameter client_secret")
|
|
}
|
|
cfg.ClientSecret = clientSecret
|
|
|
|
if scope, exist := opts["scope"]; exist {
|
|
cfg.Scope = scope
|
|
}
|
|
|
|
if redirectURI, exist := opts["redirect_uri"]; exist {
|
|
cfg.RedirectURI = redirectURI
|
|
}
|
|
|
|
manager.configs[providerName] = cfg
|
|
return nil
|
|
}
|
|
|
|
// GetConfigs of the manager
|
|
func (manager *Manager) GetConfigs() map[string]Config {
|
|
return manager.configs
|
|
}
|
|
|
|
func redirectURIFromRequest(r *http.Request) string {
|
|
u := url.URL{}
|
|
u.Path = r.URL.Path
|
|
|
|
if ffh := r.Header.Get("X-Forwarded-Host"); ffh == "" {
|
|
u.Host = r.Host
|
|
} else {
|
|
u.Host = ffh
|
|
}
|
|
|
|
if ffp := r.Header.Get("X-Forwarded-Proto"); ffp == "" {
|
|
if r.TLS != nil {
|
|
u.Scheme = "https"
|
|
} else {
|
|
u.Scheme = "http"
|
|
}
|
|
} else {
|
|
u.Scheme = ffp
|
|
}
|
|
|
|
return u.String()
|
|
}
|