github.com/pusher/oauth2_proxy@v3.2.0+incompatible/providers/provider_default.go (about) 1 package providers 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io/ioutil" 9 "net/http" 10 "net/url" 11 12 "github.com/pusher/oauth2_proxy/cookie" 13 ) 14 15 // Redeem provides a default implementation of the OAuth2 token redemption process 16 func (p *ProviderData) Redeem(redirectURL, code string) (s *SessionState, err error) { 17 if code == "" { 18 err = errors.New("missing code") 19 return 20 } 21 22 params := url.Values{} 23 params.Add("redirect_uri", redirectURL) 24 params.Add("client_id", p.ClientID) 25 params.Add("client_secret", p.ClientSecret) 26 params.Add("code", code) 27 params.Add("grant_type", "authorization_code") 28 if p.ProtectedResource != nil && p.ProtectedResource.String() != "" { 29 params.Add("resource", p.ProtectedResource.String()) 30 } 31 32 var req *http.Request 33 req, err = http.NewRequest("POST", p.RedeemURL.String(), bytes.NewBufferString(params.Encode())) 34 if err != nil { 35 return 36 } 37 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 38 39 var resp *http.Response 40 resp, err = http.DefaultClient.Do(req) 41 if err != nil { 42 return nil, err 43 } 44 var body []byte 45 body, err = ioutil.ReadAll(resp.Body) 46 resp.Body.Close() 47 if err != nil { 48 return 49 } 50 51 if resp.StatusCode != 200 { 52 err = fmt.Errorf("got %d from %q %s", resp.StatusCode, p.RedeemURL.String(), body) 53 return 54 } 55 56 // blindly try json and x-www-form-urlencoded 57 var jsonResponse struct { 58 AccessToken string `json:"access_token"` 59 } 60 err = json.Unmarshal(body, &jsonResponse) 61 if err == nil { 62 s = &SessionState{ 63 AccessToken: jsonResponse.AccessToken, 64 } 65 return 66 } 67 68 var v url.Values 69 v, err = url.ParseQuery(string(body)) 70 if err != nil { 71 return 72 } 73 if a := v.Get("access_token"); a != "" { 74 s = &SessionState{AccessToken: a} 75 } else { 76 err = fmt.Errorf("no access token found %s", body) 77 } 78 return 79 } 80 81 // GetLoginURL with typical oauth parameters 82 func (p *ProviderData) GetLoginURL(redirectURI, state string) string { 83 var a url.URL 84 a = *p.LoginURL 85 params, _ := url.ParseQuery(a.RawQuery) 86 params.Set("redirect_uri", redirectURI) 87 params.Set("approval_prompt", p.ApprovalPrompt) 88 params.Add("scope", p.Scope) 89 params.Set("client_id", p.ClientID) 90 params.Set("response_type", "code") 91 params.Add("state", state) 92 a.RawQuery = params.Encode() 93 return a.String() 94 } 95 96 // CookieForSession serializes a session state for storage in a cookie 97 func (p *ProviderData) CookieForSession(s *SessionState, c *cookie.Cipher) (string, error) { 98 return s.EncodeSessionState(c) 99 } 100 101 // SessionFromCookie deserializes a session from a cookie value 102 func (p *ProviderData) SessionFromCookie(v string, c *cookie.Cipher) (s *SessionState, err error) { 103 return DecodeSessionState(v, c) 104 } 105 106 // GetEmailAddress returns the Account email address 107 func (p *ProviderData) GetEmailAddress(s *SessionState) (string, error) { 108 return "", errors.New("not implemented") 109 } 110 111 // GetUserName returns the Account username 112 func (p *ProviderData) GetUserName(s *SessionState) (string, error) { 113 return "", errors.New("not implemented") 114 } 115 116 // ValidateGroup validates that the provided email exists in the configured provider 117 // email group(s). 118 func (p *ProviderData) ValidateGroup(email string) bool { 119 return true 120 } 121 122 // ValidateSessionState validates the AccessToken 123 func (p *ProviderData) ValidateSessionState(s *SessionState) bool { 124 return validateToken(p, s.AccessToken, nil) 125 } 126 127 // RefreshSessionIfNeeded should refresh the user's session if required and 128 // do nothing if a refresh is not required 129 func (p *ProviderData) RefreshSessionIfNeeded(s *SessionState) (bool, error) { 130 return false, nil 131 }