Create providers package with Google default
This commit is contained in:
		
							parent
							
								
									41044ecac0
								
							
						
					
					
						commit
						e2931da853
					
				|  | @ -0,0 +1,62 @@ | |||
| package providers | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/bitly/go-simplejson" | ||||
| ) | ||||
| 
 | ||||
| type GoogleProvider struct { | ||||
| 	*ProviderData | ||||
| } | ||||
| 
 | ||||
| func NewGoogleProvider(p *ProviderData) *GoogleProvider { | ||||
| 	if p.LoginUrl.String() == "" { | ||||
| 		p.LoginUrl = &url.URL{Scheme: "https", | ||||
| 			Host: "accounts.google.com", | ||||
| 			Path: "/o/oauth2/auth"} | ||||
| 	} | ||||
| 	if p.RedeemUrl.String() == "" { | ||||
| 		p.RedeemUrl = &url.URL{Scheme: "https", | ||||
| 			Host: "accounts.google.com", | ||||
| 			Path: "/o/oauth2/token"} | ||||
| 	} | ||||
| 	if p.Scope == "" { | ||||
| 		p.Scope = "profile email" | ||||
| 	} | ||||
| 	return &GoogleProvider{ProviderData: p} | ||||
| } | ||||
| 
 | ||||
| func (s *GoogleProvider) GetEmailAddress(auth_response *simplejson.Json, | ||||
| 	unused_access_token string) (string, error) { | ||||
| 	idToken, err := auth_response.Get("id_token").String() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	// id_token is a base64 encode ID token payload
 | ||||
| 	// https://developers.google.com/accounts/docs/OAuth2Login#obtainuserinfo
 | ||||
| 	jwt := strings.Split(idToken, ".") | ||||
| 	b, err := jwtDecodeSegment(jwt[1]) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	data, err := simplejson.NewJson(b) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	email, err := data.Get("email").String() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return email, nil | ||||
| } | ||||
| 
 | ||||
| func jwtDecodeSegment(seg string) ([]byte, error) { | ||||
| 	if l := len(seg) % 4; l > 0 { | ||||
| 		seg += strings.Repeat("=", 4-l) | ||||
| 	} | ||||
| 
 | ||||
| 	return base64.URLEncoding.DecodeString(seg) | ||||
| } | ||||
|  | @ -0,0 +1,94 @@ | |||
| package providers | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"github.com/bitly/go-simplejson" | ||||
| 	"github.com/bmizerany/assert" | ||||
| 	"net/url" | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| func newGoogleProvider() *GoogleProvider { | ||||
| 	return NewGoogleProvider( | ||||
| 		&ProviderData{ | ||||
| 			LoginUrl:   &url.URL{}, | ||||
| 			RedeemUrl:  &url.URL{}, | ||||
| 			ProfileUrl: &url.URL{}, | ||||
| 			Scope:      ""}) | ||||
| } | ||||
| 
 | ||||
| func TestGoogleProviderDefaults(t *testing.T) { | ||||
| 	p := newGoogleProvider() | ||||
| 	assert.NotEqual(t, nil, p) | ||||
| 	assert.Equal(t, "https://accounts.google.com/o/oauth2/auth", | ||||
| 		p.Data().LoginUrl.String()) | ||||
| 	assert.Equal(t, "https://accounts.google.com/o/oauth2/token", | ||||
| 		p.Data().RedeemUrl.String()) | ||||
| 	assert.Equal(t, "", p.Data().ProfileUrl.String()) | ||||
| 	assert.Equal(t, "profile email", p.Data().Scope) | ||||
| } | ||||
| 
 | ||||
| func TestGoogleProviderOverrides(t *testing.T) { | ||||
| 	p := NewGoogleProvider( | ||||
| 		&ProviderData{ | ||||
| 			LoginUrl: &url.URL{ | ||||
| 				Scheme: "https", | ||||
| 				Host:   "example.com", | ||||
| 				Path:   "/oauth/auth"}, | ||||
| 			RedeemUrl: &url.URL{ | ||||
| 				Scheme: "https", | ||||
| 				Host:   "example.com", | ||||
| 				Path:   "/oauth/token"}, | ||||
| 			ProfileUrl: &url.URL{ | ||||
| 				Scheme: "https", | ||||
| 				Host:   "example.com", | ||||
| 				Path:   "/oauth/profile"}, | ||||
| 			Scope: "profile"}) | ||||
| 	assert.NotEqual(t, nil, p) | ||||
| 	assert.Equal(t, "https://example.com/oauth/auth", | ||||
| 		p.Data().LoginUrl.String()) | ||||
| 	assert.Equal(t, "https://example.com/oauth/token", | ||||
| 		p.Data().RedeemUrl.String()) | ||||
| 	assert.Equal(t, "https://example.com/oauth/profile", | ||||
| 		p.Data().ProfileUrl.String()) | ||||
| 	assert.Equal(t, "profile", p.Data().Scope) | ||||
| } | ||||
| 
 | ||||
| func TestGoogleProviderGetEmailAddress(t *testing.T) { | ||||
| 	p := newGoogleProvider() | ||||
| 	j := simplejson.New() | ||||
| 	j.Set("id_token", "ignored prefix."+base64.URLEncoding.EncodeToString( | ||||
| 		[]byte("{\"email\": \"michael.bland@gsa.gov\"}"))) | ||||
| 	email, err := p.GetEmailAddress(j, "ignored access_token") | ||||
| 	assert.Equal(t, "michael.bland@gsa.gov", email) | ||||
| 	assert.Equal(t, nil, err) | ||||
| } | ||||
| 
 | ||||
| func TestGoogleProviderGetEmailAddressInvalidEncoding(t *testing.T) { | ||||
| 	p := newGoogleProvider() | ||||
| 	j := simplejson.New() | ||||
| 	j.Set("id_token", "ignored prefix.{\"email\": \"michael.bland@gsa.gov\"}") | ||||
| 	email, err := p.GetEmailAddress(j, "ignored access_token") | ||||
| 	assert.Equal(t, "", email) | ||||
| 	assert.NotEqual(t, nil, err) | ||||
| } | ||||
| 
 | ||||
| func TestGoogleProviderGetEmailAddressInvalidJson(t *testing.T) { | ||||
| 	p := newGoogleProvider() | ||||
| 	j := simplejson.New() | ||||
| 	j.Set("id_token", "ignored prefix."+base64.URLEncoding.EncodeToString( | ||||
| 		[]byte("{email: michael.bland@gsa.gov}"))) | ||||
| 	email, err := p.GetEmailAddress(j, "ignored access_token") | ||||
| 	assert.Equal(t, "", email) | ||||
| 	assert.NotEqual(t, nil, err) | ||||
| } | ||||
| 
 | ||||
| func TestGoogleProviderGetEmailAddressEmailMissing(t *testing.T) { | ||||
| 	p := newGoogleProvider() | ||||
| 	j := simplejson.New() | ||||
| 	j.Set("id_token", "ignored prefix."+base64.URLEncoding.EncodeToString( | ||||
| 		[]byte("{\"not_email\": \"missing!\"}"))) | ||||
| 	email, err := p.GetEmailAddress(j, "ignored access_token") | ||||
| 	assert.Equal(t, "", email) | ||||
| 	assert.NotEqual(t, nil, err) | ||||
| } | ||||
|  | @ -0,0 +1,14 @@ | |||
| package providers | ||||
| 
 | ||||
| import ( | ||||
| 	"net/url" | ||||
| ) | ||||
| 
 | ||||
| type ProviderData struct { | ||||
| 	LoginUrl   *url.URL | ||||
| 	RedeemUrl  *url.URL | ||||
| 	ProfileUrl *url.URL | ||||
| 	Scope      string | ||||
| } | ||||
| 
 | ||||
| func (p *ProviderData) Data() *ProviderData { return p } | ||||
|  | @ -0,0 +1,18 @@ | |||
| package providers | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/bitly/go-simplejson" | ||||
| ) | ||||
| 
 | ||||
| type Provider interface { | ||||
| 	Data() *ProviderData | ||||
| 	GetEmailAddress(auth_response *simplejson.Json, | ||||
| 		access_token string) (string, error) | ||||
| } | ||||
| 
 | ||||
| func New(provider string, p *ProviderData) Provider { | ||||
| 	switch provider { | ||||
| 	default: | ||||
| 		return NewGoogleProvider(p) | ||||
| 	} | ||||
| } | ||||
		Loading…
	
		Reference in New Issue