33045a792b
By setting this to "force", certain providers, like Google, will interject an additional prompt on every new session. With other values, like "auto", this prompt is not forced upon the user.
116 lines
2.8 KiB
Go
116 lines
2.8 KiB
Go
package providers
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/bitly/oauth2_proxy/cookie"
|
|
)
|
|
|
|
func (p *ProviderData) Redeem(redirectUrl, code string) (s *SessionState, err error) {
|
|
if code == "" {
|
|
err = errors.New("missing code")
|
|
return
|
|
}
|
|
|
|
params := url.Values{}
|
|
params.Add("redirect_uri", redirectUrl)
|
|
params.Add("client_id", p.ClientID)
|
|
params.Add("client_secret", p.ClientSecret)
|
|
params.Add("code", code)
|
|
params.Add("grant_type", "authorization_code")
|
|
var req *http.Request
|
|
req, err = http.NewRequest("POST", p.RedeemUrl.String(), bytes.NewBufferString(params.Encode()))
|
|
if err != nil {
|
|
return
|
|
}
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
var resp *http.Response
|
|
resp, err = http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var body []byte
|
|
body, err = ioutil.ReadAll(resp.Body)
|
|
resp.Body.Close()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if resp.StatusCode != 200 {
|
|
err = fmt.Errorf("got %d from %q %s", resp.StatusCode, p.RedeemUrl.String(), body)
|
|
return
|
|
}
|
|
|
|
// blindly try json and x-www-form-urlencoded
|
|
var jsonResponse struct {
|
|
AccessToken string `json:"access_token"`
|
|
}
|
|
err = json.Unmarshal(body, &jsonResponse)
|
|
if err == nil {
|
|
s = &SessionState{
|
|
AccessToken: jsonResponse.AccessToken,
|
|
}
|
|
return
|
|
}
|
|
|
|
var v url.Values
|
|
v, err = url.ParseQuery(string(body))
|
|
if err != nil {
|
|
return
|
|
}
|
|
if a := v.Get("access_token"); a != "" {
|
|
s = &SessionState{AccessToken: a}
|
|
} else {
|
|
err = fmt.Errorf("no access token found %s", body)
|
|
}
|
|
return
|
|
}
|
|
|
|
// GetLoginURL with typical oauth parameters
|
|
func (p *ProviderData) GetLoginURL(redirectURI, finalRedirect string) string {
|
|
var a url.URL
|
|
a = *p.LoginUrl
|
|
params, _ := url.ParseQuery(a.RawQuery)
|
|
params.Set("redirect_uri", redirectURI)
|
|
params.Set("approval_prompt", p.ApprovalPrompt)
|
|
params.Add("scope", p.Scope)
|
|
params.Set("client_id", p.ClientID)
|
|
params.Set("response_type", "code")
|
|
if strings.HasPrefix(finalRedirect, "/") {
|
|
params.Add("state", finalRedirect)
|
|
}
|
|
a.RawQuery = params.Encode()
|
|
return a.String()
|
|
}
|
|
|
|
// CookieForSession serializes a session state for storage in a cookie
|
|
func (p *ProviderData) CookieForSession(s *SessionState, c *cookie.Cipher) (string, error) {
|
|
return s.EncodeSessionState(c)
|
|
}
|
|
|
|
// SessionFromCookie deserializes a session from a cookie value
|
|
func (p *ProviderData) SessionFromCookie(v string, c *cookie.Cipher) (s *SessionState, err error) {
|
|
return DecodeSessionState(v, c)
|
|
}
|
|
|
|
func (p *ProviderData) GetEmailAddress(s *SessionState) (string, error) {
|
|
return "", errors.New("not implemented")
|
|
}
|
|
|
|
func (p *ProviderData) ValidateSessionState(s *SessionState) bool {
|
|
return validateToken(p, s.AccessToken, nil)
|
|
}
|
|
|
|
// RefreshSessionIfNeeded
|
|
func (p *ProviderData) RefreshSessionIfNeeded(s *SessionState) (bool, error) {
|
|
return false, nil
|
|
}
|