git.iko.soy/typeable/oauth2-proxy
on master help sign in
Create providers package with Google default
commite2931da85317217925dbc1826271c1aed9e2e86d authorMike Bland <michael.bland@gsa.gov> dateMon 30 Mar 2015, 15:30 (12 years ago) parent41044ec
4 files changed+188
providers/google.go+62 providers/google_test.go+94 providers/provider_data.go+14 providers/providers.go+18
providers/google.gonew file+62
@@ -0,0 +1,62 @@
1+package providers
2+
3+import (
4+ "encoding/base64"
5+ "net/url"
6+ "strings"
7+
8+ "github.com/bitly/go-simplejson"
9+)
10+
11+type GoogleProvider struct {
12+ *ProviderData
13+}
14+
15+func NewGoogleProvider(p *ProviderData) *GoogleProvider {
16+ if p.LoginUrl.String() == "" {
17+ p.LoginUrl = &url.URL{Scheme: "https",
18+ Host: "accounts.google.com",
19+ Path: "/o/oauth2/auth"}
20+ }
21+ if p.RedeemUrl.String() == "" {
22+ p.RedeemUrl = &url.URL{Scheme: "https",
23+ Host: "accounts.google.com",
24+ Path: "/o/oauth2/token"}
25+ }
26+ if p.Scope == "" {
27+ p.Scope = "profile email"
28+ }
29+ return &GoogleProvider{ProviderData: p}
30+}
31+
32+func (s *GoogleProvider) GetEmailAddress(auth_response *simplejson.Json,
33+ unused_access_token string) (string, error) {
34+ idToken, err := auth_response.Get("id_token").String()
35+ if err != nil {
36+ return "", err
37+ }
38+ // id_token is a base64 encode ID token payload
39+ // https://developers.google.com/accounts/docs/OAuth2Login#obtainuserinfo
40+ jwt := strings.Split(idToken, ".")
41+ b, err := jwtDecodeSegment(jwt[1])
42+ if err != nil {
43+ return "", err
44+ }
45+ data, err := simplejson.NewJson(b)
46+ if err != nil {
47+ return "", err
48+ }
49+ email, err := data.Get("email").String()
50+ if err != nil {
51+ return "", err
52+ }
53+ return email, nil
54+}
55+
56+func jwtDecodeSegment(seg string) ([]byte, error) {
57+ if l := len(seg) % 4; l > 0 {
58+ seg += strings.Repeat("=", 4-l)
59+ }
60+
61+ return base64.URLEncoding.DecodeString(seg)
62+}
providers/google_test.gonew file+94
@@ -0,0 +1,94 @@
1+package providers
2+
3+import (
4+ "encoding/base64"
5+ "github.com/bitly/go-simplejson"
6+ "github.com/bmizerany/assert"
7+ "net/url"
8+ "testing"
9+)
10+
11+func newGoogleProvider() *GoogleProvider {
12+ return NewGoogleProvider(
13+ &ProviderData{
14+ LoginUrl: &url.URL{},
15+ RedeemUrl: &url.URL{},
16+ ProfileUrl: &url.URL{},
17+ Scope: ""})
18+}
19+
20+func TestGoogleProviderDefaults(t *testing.T) {
21+ p := newGoogleProvider()
22+ assert.NotEqual(t, nil, p)
23+ assert.Equal(t, "https://accounts.google.com/o/oauth2/auth",
24+ p.Data().LoginUrl.String())
25+ assert.Equal(t, "https://accounts.google.com/o/oauth2/token",
26+ p.Data().RedeemUrl.String())
27+ assert.Equal(t, "", p.Data().ProfileUrl.String())
28+ assert.Equal(t, "profile email", p.Data().Scope)
29+}
30+
31+func TestGoogleProviderOverrides(t *testing.T) {
32+ p := NewGoogleProvider(
33+ &ProviderData{
34+ LoginUrl: &url.URL{
35+ Scheme: "https",
36+ Host: "example.com",
37+ Path: "/oauth/auth"},
38+ RedeemUrl: &url.URL{
39+ Scheme: "https",
40+ Host: "example.com",
41+ Path: "/oauth/token"},
42+ ProfileUrl: &url.URL{
43+ Scheme: "https",
44+ Host: "example.com",
45+ Path: "/oauth/profile"},
46+ Scope: "profile"})
47+ assert.NotEqual(t, nil, p)
48+ assert.Equal(t, "https://example.com/oauth/auth",
49+ p.Data().LoginUrl.String())
50+ assert.Equal(t, "https://example.com/oauth/token",
51+ p.Data().RedeemUrl.String())
52+ assert.Equal(t, "https://example.com/oauth/profile",
53+ p.Data().ProfileUrl.String())
54+ assert.Equal(t, "profile", p.Data().Scope)
55+}
56+
57+func TestGoogleProviderGetEmailAddress(t *testing.T) {
58+ p := newGoogleProvider()
59+ j := simplejson.New()
60+ j.Set("id_token", "ignored prefix."+base64.URLEncoding.EncodeToString(
61+ []byte("{\"email\": \"michael.bland@gsa.gov\"}")))
62+ email, err := p.GetEmailAddress(j, "ignored access_token")
63+ assert.Equal(t, "michael.bland@gsa.gov", email)
64+ assert.Equal(t, nil, err)
65+}
66+
67+func TestGoogleProviderGetEmailAddressInvalidEncoding(t *testing.T) {
68+ p := newGoogleProvider()
69+ j := simplejson.New()
70+ j.Set("id_token", "ignored prefix.{\"email\": \"michael.bland@gsa.gov\"}")
71+ email, err := p.GetEmailAddress(j, "ignored access_token")
72+ assert.Equal(t, "", email)
73+ assert.NotEqual(t, nil, err)
74+}
75+
76+func TestGoogleProviderGetEmailAddressInvalidJson(t *testing.T) {
77+ p := newGoogleProvider()
78+ j := simplejson.New()
79+ j.Set("id_token", "ignored prefix."+base64.URLEncoding.EncodeToString(
80+ []byte("{email: michael.bland@gsa.gov}")))
81+ email, err := p.GetEmailAddress(j, "ignored access_token")
82+ assert.Equal(t, "", email)
83+ assert.NotEqual(t, nil, err)
84+}
85+
86+func TestGoogleProviderGetEmailAddressEmailMissing(t *testing.T) {
87+ p := newGoogleProvider()
88+ j := simplejson.New()
89+ j.Set("id_token", "ignored prefix."+base64.URLEncoding.EncodeToString(
90+ []byte("{\"not_email\": \"missing!\"}")))
91+ email, err := p.GetEmailAddress(j, "ignored access_token")
92+ assert.Equal(t, "", email)
93+ assert.NotEqual(t, nil, err)
94+}
providers/provider_data.gonew file+14
@@ -0,0 +1,14 @@
1+package providers
2+
3+import (
4+ "net/url"
5+)
6+
7+type ProviderData struct {
8+ LoginUrl *url.URL
9+ RedeemUrl *url.URL
10+ ProfileUrl *url.URL
11+ Scope string
12+}
13+
14+func (p *ProviderData) Data() *ProviderData { return p }
providers/providers.gonew file+18
@@ -0,0 +1,18 @@
1+package providers
2+
3+import (
4+ "github.com/bitly/go-simplejson"
5+)
6+
7+type Provider interface {
8+ Data() *ProviderData
9+ GetEmailAddress(auth_response *simplejson.Json,
10+ access_token string) (string, error)
11+}
12+
13+func New(provider string, p *ProviderData) Provider {
14+ switch provider {
15+ default:
16+ return NewGoogleProvider(p)
17+ }
18+}