git.iko.soy/typeable/oauth2-proxy
on master help sign in
update to new scopes
commit98fb800de44f7631e6ca4dfdedfdff5928ee512c authorJehiah Czebotar <jehiah@gmail.com> dateThu 7 Aug 2014, 16:16 (12 years ago) parent715656d
2 files changed+36−39
main.go+1−1 oauthproxy.go+35−38
main.go+1−1
@@ -5,9 +5,9 @@ import (
55 "fmt"
66 "log"
77 "net"
8− "os"
98 "net/http"
109 "net/url"
10+ "os"
1111 "strings"
1212)
1313
oauthproxy.go+35−38
@@ -5,7 +5,6 @@ import (
55 "encoding/base64"
66 "errors"
77 "fmt"
8− "github.com/bitly/go-simplejson"
98 "io/ioutil"
109 "log"
1110 "net/http"
@@ -13,6 +12,8 @@ import (
1312 "net/url"
1413 "strings"
1514 "time"
15+
16+ "github.com/bitly/go-simplejson"
1617)
1718
1819const signInPath = "/oauth2/sign_in"
@@ -27,7 +28,6 @@ type OauthProxy struct {
2728 redirectUrl *url.URL // the url to receive requests at
2829 oauthRedemptionUrl *url.URL // endpoint to redeem the code
2930 oauthLoginUrl *url.URL // to redirect the user to
30− oauthUserInfoUrl *url.URL
3131 oauthScope string
3232 clientID string
3333 clientSecret string
@@ -39,7 +39,6 @@ type OauthProxy struct {
3939func NewOauthProxy(proxyUrls []*url.URL, clientID string, clientSecret string, validator func(string) bool) *OauthProxy {
4040 login, _ := url.Parse("https://accounts.google.com/o/oauth2/auth")
4141 redeem, _ := url.Parse("https://accounts.google.com/o/oauth2/token")
42− info, _ := url.Parse("https://www.googleapis.com/oauth2/v2/userinfo")
4342 serveMux := http.NewServeMux()
4443 for _, u := range proxyUrls {
4544 path := u.Path
@@ -54,10 +53,9 @@ func NewOauthProxy(proxyUrls []*url.URL, clientID string, clientSecret string, v
5453
5554 clientID: clientID,
5655 clientSecret: clientSecret,
57− oauthScope: "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
56+ oauthScope: "profile email",
5857 oauthRedemptionUrl: redeem,
5958 oauthLoginUrl: login,
60− oauthUserInfoUrl: info,
6159 serveMux: serveMux,
6260 }
6361}
@@ -102,9 +100,9 @@ func apiRequest(req *http.Request) (*simplejson.Json, error) {
102100 return data, nil
103101}
104102
105−func (p *OauthProxy) redeemCode(code string) (string, error) {
103+func (p *OauthProxy) redeemCode(code string) (string, string, error) {
106104 if code == "" {
107− return "", errors.New("missing code")
105+ return "", "", errors.New("missing code")
108106 }
109107 params := url.Values{}
110108 params.Add("redirect_uri", p.redirectUrl.String())
@@ -112,46 +110,52 @@ func (p *OauthProxy) redeemCode(code string) (string, error) {
112110 params.Add("client_secret", p.clientSecret)
113111 params.Add("code", code)
114112 params.Add("grant_type", "authorization_code")
115− log.Printf("body is %s", params.Encode())
116113 req, err := http.NewRequest("POST", p.oauthRedemptionUrl.String(), bytes.NewBufferString(params.Encode()))
117114 if err != nil {
118115 log.Printf("failed building request %s", err.Error())
119− return "", err
116+ return "", "", err
120117 }
121118 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
122119 json, err := apiRequest(req)
123120 if err != nil {
124− log.Printf("failed making request %s", err.Error())
125− return "", err
121+ log.Printf("failed making request %s", err)
122+ return "", "", err
126123 }
127124 access_token, err := json.Get("access_token").String()
128125 if err != nil {
129− return "", err
126+ return "", "", err
130127 }
131− return access_token, nil
132−}
133128
134−func (p *OauthProxy) getUserInfo(token string) (string, error) {
135− params := url.Values{}
136− params.Add("access_token", token)
137− endpoint := fmt.Sprintf("%s?%s", p.oauthUserInfoUrl.String(), params.Encode())
138− log.Printf("calling %s", endpoint)
139− req, err := http.NewRequest("GET", endpoint, nil)
129+ idToken, err := json.Get("id_token").String()
140130 if err != nil {
141− log.Printf("failed building request %s", err.Error())
142− return "", err
131+ return "", "", err
143132 }
144− json, err := apiRequest(req)
133+
134+ // id_token is a base64 encode ID token payload
135+ // https://developers.google.com/accounts/docs/OAuth2Login#obtainuserinfo
136+ jwt := strings.Split(idToken, ".")
137+ b, err := jwtDecodeSegment(jwt[1])
145138 if err != nil {
146− log.Printf("failed making request %s", err.Error())
147− return "", err
139+ return "", "", err
148140 }
149− email, err := json.Get("email").String()
141+ data, err := simplejson.NewJson(b)
150142 if err != nil {
151− log.Printf("failed getting email from response %s", err.Error())
152− return "", err
143+ return "", "", err
144+ }
145+ email, err := data.Get("email").String()
146+ if err != nil {
147+ return "", "", err
148+ }
149+
150+ return access_token, email, nil
151+}
152+
153+func jwtDecodeSegment(seg string) ([]byte, error) {
154+ if l := len(seg) % 4; l > 0 {
155+ seg += strings.Repeat("=", 4-l)
153156 }
154− return email, nil
157+
158+ return base64.URLEncoding.DecodeString(seg)
155159}
156160
157161func (p *OauthProxy) ClearCookie(rw http.ResponseWriter, req *http.Request) {
@@ -301,16 +305,9 @@ func (p *OauthProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
301305 return
302306 }
303307
304− token, err := p.redeemCode(req.Form.Get("code"))
305− if err != nil {
306− log.Printf("error redeeming code %s", err.Error())
307− p.ErrorPage(rw, 500, "Internal Error", err.Error())
308− return
309− }
310− // validate user
311− email, err := p.getUserInfo(token)
308+ _, email, err := p.redeemCode(req.Form.Get("code"))
312309 if err != nil {
313− log.Printf("error redeeming code %s", err.Error())
310+ log.Printf("error redeeming code %s", err)
314311 p.ErrorPage(rw, 500, "Internal Error", err.Error())
315312 return
316313 }