Add Bitbucket provider. (#201)
Add a new provider for Bitbucket, can be configured from the options specifying team and/or repository that the user must be part/have access to in order to grant login.
This commit is contained in:
		
							parent
							
								
									a165928458
								
							
						
					
					
						commit
						fa6c4792a1
					
				|  | @ -10,3 +10,7 @@ | ||||||
| # or the public devops channel at https://chat.18f.gov/). | # or the public devops channel at https://chat.18f.gov/). | ||||||
| providers/logingov.go @timothy-spencer | providers/logingov.go @timothy-spencer | ||||||
| providers/logingov_test.go @timothy-spencer | providers/logingov_test.go @timothy-spencer | ||||||
|  | 
 | ||||||
|  | # Bitbucket provider | ||||||
|  | providers/bitbucket.go @aledeganopix4d | ||||||
|  | providers/bitbucket_test.go @aledeganopix4d | ||||||
|  |  | ||||||
|  | @ -96,6 +96,10 @@ | ||||||
| - [#198](https://github.com/pusher/oauth2_proxy/pull/198) Switch from gometalinter to golangci-lint (@steakunderscore) | - [#198](https://github.com/pusher/oauth2_proxy/pull/198) Switch from gometalinter to golangci-lint (@steakunderscore) | ||||||
| - [#159](https://github.com/pusher/oauth2_proxy/pull/159) Add option to skip the OIDC provider verified email check: `--insecure-oidc-allow-unverified-email` | - [#159](https://github.com/pusher/oauth2_proxy/pull/159) Add option to skip the OIDC provider verified email check: `--insecure-oidc-allow-unverified-email` | ||||||
| - [#210](https://github.com/pusher/oauth2_proxy/pull/210) Update base image from Alpine 3.9 to 3.10 (@steakunderscore) | - [#210](https://github.com/pusher/oauth2_proxy/pull/210) Update base image from Alpine 3.9 to 3.10 (@steakunderscore) | ||||||
|  | - [#201](https://github.com/pusher/oauth2_proxy/pull/201) Add Bitbucket as new OAuth2 provider, accepts email, team and repository permissions to determine authorization (@aledeganopix4d) | ||||||
|  |   - Implement flags to enable Bitbucket authentication: | ||||||
|  |     - `-bitbucket-repository` Restrict authorization to users that can access this repository | ||||||
|  |     - `-bitbucket-team` Restrict authorization to users that are part of this Bitbucket team | ||||||
| - [#211](https://github.com/pusher/oauth2_proxy/pull/211) Switch from dep to go modules (@steakunderscore) | - [#211](https://github.com/pusher/oauth2_proxy/pull/211) Switch from dep to go modules (@steakunderscore) | ||||||
| - [#145](https://github.com/pusher/oauth2_proxy/pull/145) Add support for OIDC UserInfo endpoint email verification (@rtluckie) | - [#145](https://github.com/pusher/oauth2_proxy/pull/145) Add support for OIDC UserInfo endpoint email verification (@rtluckie) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								main.go
								
								
								
								
							
							
						
						
									
										2
									
								
								main.go
								
								
								
								
							|  | @ -56,6 +56,8 @@ func main() { | ||||||
| 	flagSet.Var(&emailDomains, "email-domain", "authenticate emails with the specified domain (may be given multiple times). Use * to authenticate any email") | 	flagSet.Var(&emailDomains, "email-domain", "authenticate emails with the specified domain (may be given multiple times). Use * to authenticate any email") | ||||||
| 	flagSet.Var(&whitelistDomains, "whitelist-domain", "allowed domains for redirection after authentication. Prefix domain with a . to allow subdomains (eg .example.com)") | 	flagSet.Var(&whitelistDomains, "whitelist-domain", "allowed domains for redirection after authentication. Prefix domain with a . to allow subdomains (eg .example.com)") | ||||||
| 	flagSet.String("azure-tenant", "common", "go to a tenant-specific or common (tenant-independent) endpoint.") | 	flagSet.String("azure-tenant", "common", "go to a tenant-specific or common (tenant-independent) endpoint.") | ||||||
|  | 	flagSet.String("bitbucket-team", "", "restrict logins to members of this team") | ||||||
|  | 	flagSet.String("bitbucket-repository", "", "restrict logins to user with access to this repository") | ||||||
| 	flagSet.String("github-org", "", "restrict logins to members of this organisation") | 	flagSet.String("github-org", "", "restrict logins to members of this organisation") | ||||||
| 	flagSet.String("github-team", "", "restrict logins to members of this team") | 	flagSet.String("github-team", "", "restrict logins to members of this team") | ||||||
| 	flagSet.String("gitlab-group", "", "restrict logins to members of this group") | 	flagSet.String("gitlab-group", "", "restrict logins to members of this group") | ||||||
|  |  | ||||||
|  | @ -42,6 +42,8 @@ type Options struct { | ||||||
| 
 | 
 | ||||||
| 	AuthenticatedEmailsFile  string   `flag:"authenticated-emails-file" cfg:"authenticated_emails_file" env:"OAUTH2_PROXY_AUTHENTICATED_EMAILS_FILE"` | 	AuthenticatedEmailsFile  string   `flag:"authenticated-emails-file" cfg:"authenticated_emails_file" env:"OAUTH2_PROXY_AUTHENTICATED_EMAILS_FILE"` | ||||||
| 	AzureTenant              string   `flag:"azure-tenant" cfg:"azure_tenant" env:"OAUTH2_PROXY_AZURE_TENANT"` | 	AzureTenant              string   `flag:"azure-tenant" cfg:"azure_tenant" env:"OAUTH2_PROXY_AZURE_TENANT"` | ||||||
|  | 	BitbucketTeam            string   `flag:"bitbucket-team" cfg:"bitbucket_team" env:"OAUTH2_PROXY_BITBUCKET_TEAM"` | ||||||
|  | 	BitbucketRepository      string   `flag:"bitbucket-repository" cfg:"bitbucket_repository" env:"OAUTH2_PROXY_BITBUCKET_REPOSITORY"` | ||||||
| 	EmailDomains             []string `flag:"email-domain" cfg:"email_domains" env:"OAUTH2_PROXY_EMAIL_DOMAINS"` | 	EmailDomains             []string `flag:"email-domain" cfg:"email_domains" env:"OAUTH2_PROXY_EMAIL_DOMAINS"` | ||||||
| 	WhitelistDomains         []string `flag:"whitelist-domain" cfg:"whitelist_domains" env:"OAUTH2_PROXY_WHITELIST_DOMAINS"` | 	WhitelistDomains         []string `flag:"whitelist-domain" cfg:"whitelist_domains" env:"OAUTH2_PROXY_WHITELIST_DOMAINS"` | ||||||
| 	GitHubOrg                string   `flag:"github-org" cfg:"github_org" env:"OAUTH2_PROXY_GITHUB_ORG"` | 	GitHubOrg                string   `flag:"github-org" cfg:"github_org" env:"OAUTH2_PROXY_GITHUB_ORG"` | ||||||
|  | @ -405,6 +407,9 @@ func parseProviderInfo(o *Options, msgs []string) []string { | ||||||
| 				p.SetGroupRestriction(o.GoogleGroups, o.GoogleAdminEmail, file) | 				p.SetGroupRestriction(o.GoogleGroups, o.GoogleAdminEmail, file) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	case *providers.BitbucketProvider: | ||||||
|  | 		p.SetTeam(o.BitbucketTeam) | ||||||
|  | 		p.SetRepository(o.BitbucketRepository) | ||||||
| 	case *providers.OIDCProvider: | 	case *providers.OIDCProvider: | ||||||
| 		p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail | 		p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail | ||||||
| 		if o.oidcVerifier == nil { | 		if o.oidcVerifier == nil { | ||||||
|  |  | ||||||
|  | @ -0,0 +1,163 @@ | ||||||
|  | package providers | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"net/http" | ||||||
|  | 	"net/url" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"github.com/pusher/oauth2_proxy/pkg/apis/sessions" | ||||||
|  | 	"github.com/pusher/oauth2_proxy/pkg/logger" | ||||||
|  | 	"github.com/pusher/oauth2_proxy/pkg/requests" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // BitbucketProvider represents an Bitbucket based Identity Provider
 | ||||||
|  | type BitbucketProvider struct { | ||||||
|  | 	*ProviderData | ||||||
|  | 	Team       string | ||||||
|  | 	Repository string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewBitbucketProvider initiates a new BitbucketProvider
 | ||||||
|  | func NewBitbucketProvider(p *ProviderData) *BitbucketProvider { | ||||||
|  | 	p.ProviderName = "Bitbucket" | ||||||
|  | 	if p.LoginURL == nil || p.LoginURL.String() == "" { | ||||||
|  | 		p.LoginURL = &url.URL{ | ||||||
|  | 			Scheme: "https", | ||||||
|  | 			Host:   "bitbucket.org", | ||||||
|  | 			Path:   "/site/oauth2/authorize", | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if p.RedeemURL == nil || p.RedeemURL.String() == "" { | ||||||
|  | 		p.RedeemURL = &url.URL{ | ||||||
|  | 			Scheme: "https", | ||||||
|  | 			Host:   "bitbucket.org", | ||||||
|  | 			Path:   "/site/oauth2/access_token", | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if p.ValidateURL == nil || p.ValidateURL.String() == "" { | ||||||
|  | 		p.ValidateURL = &url.URL{ | ||||||
|  | 			Scheme: "https", | ||||||
|  | 			Host:   "api.bitbucket.org", | ||||||
|  | 			Path:   "/2.0/user/emails", | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if p.Scope == "" { | ||||||
|  | 		p.Scope = "email" | ||||||
|  | 	} | ||||||
|  | 	return &BitbucketProvider{ProviderData: p} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetTeam defines the Bitbucket team the user must be part of
 | ||||||
|  | func (p *BitbucketProvider) SetTeam(team string) { | ||||||
|  | 	p.Team = team | ||||||
|  | 	if !strings.Contains(p.Scope, "team") { | ||||||
|  | 		p.Scope += " team" | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetRepository defines the repository the user must have access to
 | ||||||
|  | func (p *BitbucketProvider) SetRepository(repository string) { | ||||||
|  | 	p.Repository = repository | ||||||
|  | 	if !strings.Contains(p.Scope, "repository") { | ||||||
|  | 		p.Scope += " repository" | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetEmailAddress returns the email of the authenticated user
 | ||||||
|  | func (p *BitbucketProvider) GetEmailAddress(s *sessions.SessionState) (string, error) { | ||||||
|  | 
 | ||||||
|  | 	var emails struct { | ||||||
|  | 		Values []struct { | ||||||
|  | 			Email   string `json:"email"` | ||||||
|  | 			Primary bool   `json:"is_primary"` | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	var teams struct { | ||||||
|  | 		Values []struct { | ||||||
|  | 			Name string `json:"username"` | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	var repositories struct { | ||||||
|  | 		Values []struct { | ||||||
|  | 			FullName string `json:"full_name"` | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	req, err := http.NewRequest("GET", | ||||||
|  | 		p.ValidateURL.String()+"?access_token="+s.AccessToken, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Printf("failed building request %s", err) | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	err = requests.RequestJSON(req, &emails) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Printf("failed making request %s", err) | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if p.Team != "" { | ||||||
|  | 		teamURL := &url.URL{} | ||||||
|  | 		*teamURL = *p.ValidateURL | ||||||
|  | 		teamURL.Path = "/2.0/teams" | ||||||
|  | 		req, err = http.NewRequest("GET", | ||||||
|  | 			teamURL.String()+"?role=member&access_token="+s.AccessToken, nil) | ||||||
|  | 		if err != nil { | ||||||
|  | 			logger.Printf("failed building request %s", err) | ||||||
|  | 			return "", err | ||||||
|  | 		} | ||||||
|  | 		err = requests.RequestJSON(req, &teams) | ||||||
|  | 		if err != nil { | ||||||
|  | 			logger.Printf("failed requesting teams membership %s", err) | ||||||
|  | 			return "", err | ||||||
|  | 		} | ||||||
|  | 		var found = false | ||||||
|  | 		for _, team := range teams.Values { | ||||||
|  | 			if p.Team == team.Name { | ||||||
|  | 				found = true | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if found != true { | ||||||
|  | 			logger.Print("team membership test failed, access denied") | ||||||
|  | 			return "", nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if p.Repository != "" { | ||||||
|  | 		repositoriesURL := &url.URL{} | ||||||
|  | 		*repositoriesURL = *p.ValidateURL | ||||||
|  | 		repositoriesURL.Path = "/2.0/repositories/" + strings.Split(p.Repository, "/")[0] | ||||||
|  | 		req, err = http.NewRequest("GET", | ||||||
|  | 			repositoriesURL.String()+"?role=contributor"+ | ||||||
|  | 				"&q=full_name="+url.QueryEscape("\""+p.Repository+"\"")+ | ||||||
|  | 				"&access_token="+s.AccessToken, | ||||||
|  | 			nil) | ||||||
|  | 		if err != nil { | ||||||
|  | 			logger.Printf("failed building request %s", err) | ||||||
|  | 			return "", err | ||||||
|  | 		} | ||||||
|  | 		err = requests.RequestJSON(req, &repositories) | ||||||
|  | 		if err != nil { | ||||||
|  | 			logger.Printf("failed checking repository access %s", err) | ||||||
|  | 			return "", err | ||||||
|  | 		} | ||||||
|  | 		var found = false | ||||||
|  | 		for _, repository := range repositories.Values { | ||||||
|  | 			if p.Repository == repository.FullName { | ||||||
|  | 				found = true | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if found != true { | ||||||
|  | 			logger.Print("repository access test failed, access denied") | ||||||
|  | 			return "", nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, email := range emails.Values { | ||||||
|  | 		if email.Primary { | ||||||
|  | 			return email.Email, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return "", nil | ||||||
|  | } | ||||||
|  | @ -0,0 +1,170 @@ | ||||||
|  | package providers | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"log" | ||||||
|  | 	"net/http" | ||||||
|  | 	"net/http/httptest" | ||||||
|  | 	"net/url" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | 
 | ||||||
|  | 	"github.com/pusher/oauth2_proxy/pkg/apis/sessions" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func testBitbucketProvider(hostname, team string, repository string) *BitbucketProvider { | ||||||
|  | 	p := NewBitbucketProvider( | ||||||
|  | 		&ProviderData{ | ||||||
|  | 			ProviderName: "", | ||||||
|  | 			LoginURL:     &url.URL{}, | ||||||
|  | 			RedeemURL:    &url.URL{}, | ||||||
|  | 			ProfileURL:   &url.URL{}, | ||||||
|  | 			ValidateURL:  &url.URL{}, | ||||||
|  | 			Scope:        ""}) | ||||||
|  | 
 | ||||||
|  | 	if team != "" { | ||||||
|  | 		p.SetTeam(team) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if repository != "" { | ||||||
|  | 		p.SetRepository(repository) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if hostname != "" { | ||||||
|  | 		updateURL(p.Data().LoginURL, hostname) | ||||||
|  | 		updateURL(p.Data().RedeemURL, hostname) | ||||||
|  | 		updateURL(p.Data().ProfileURL, hostname) | ||||||
|  | 		updateURL(p.Data().ValidateURL, hostname) | ||||||
|  | 	} | ||||||
|  | 	return p | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testBitbucketBackend(payload string) *httptest.Server { | ||||||
|  | 	paths := map[string]bool{ | ||||||
|  | 		"/2.0/user/emails": true, | ||||||
|  | 		"/2.0/teams":       true, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return httptest.NewServer(http.HandlerFunc( | ||||||
|  | 		func(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 			url := r.URL | ||||||
|  | 			if !paths[url.Path] { | ||||||
|  | 				log.Printf("%s not in %+v\n", url.Path, paths) | ||||||
|  | 				w.WriteHeader(404) | ||||||
|  | 			} else if r.URL.Query().Get("access_token") != "imaginary_access_token" { | ||||||
|  | 				w.WriteHeader(403) | ||||||
|  | 			} else { | ||||||
|  | 				w.WriteHeader(200) | ||||||
|  | 				w.Write([]byte(payload)) | ||||||
|  | 			} | ||||||
|  | 		})) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestBitbucketProviderDefaults(t *testing.T) { | ||||||
|  | 	p := testBitbucketProvider("", "", "") | ||||||
|  | 	assert.NotEqual(t, nil, p) | ||||||
|  | 	assert.Equal(t, "Bitbucket", p.Data().ProviderName) | ||||||
|  | 	assert.Equal(t, "https://bitbucket.org/site/oauth2/authorize", | ||||||
|  | 		p.Data().LoginURL.String()) | ||||||
|  | 	assert.Equal(t, "https://bitbucket.org/site/oauth2/access_token", | ||||||
|  | 		p.Data().RedeemURL.String()) | ||||||
|  | 	assert.Equal(t, "https://api.bitbucket.org/2.0/user/emails", | ||||||
|  | 		p.Data().ValidateURL.String()) | ||||||
|  | 	assert.Equal(t, "email", p.Data().Scope) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestBitbucketProviderScopeAdjustForTeam(t *testing.T) { | ||||||
|  | 	p := testBitbucketProvider("", "test-team", "") | ||||||
|  | 	assert.NotEqual(t, nil, p) | ||||||
|  | 	assert.Equal(t, "email team", p.Data().Scope) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestBitbucketProviderScopeAdjustForRepository(t *testing.T) { | ||||||
|  | 	p := testBitbucketProvider("", "", "rest-repo") | ||||||
|  | 	assert.NotEqual(t, nil, p) | ||||||
|  | 	assert.Equal(t, "email repository", p.Data().Scope) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestBitbucketProviderOverrides(t *testing.T) { | ||||||
|  | 	p := NewBitbucketProvider( | ||||||
|  | 		&ProviderData{ | ||||||
|  | 			LoginURL: &url.URL{ | ||||||
|  | 				Scheme: "https", | ||||||
|  | 				Host:   "example.com", | ||||||
|  | 				Path:   "/oauth/auth"}, | ||||||
|  | 			RedeemURL: &url.URL{ | ||||||
|  | 				Scheme: "https", | ||||||
|  | 				Host:   "example.com", | ||||||
|  | 				Path:   "/oauth/token"}, | ||||||
|  | 			ValidateURL: &url.URL{ | ||||||
|  | 				Scheme: "https", | ||||||
|  | 				Host:   "example.com", | ||||||
|  | 				Path:   "/api/v3/user"}, | ||||||
|  | 			Scope: "profile"}) | ||||||
|  | 	assert.NotEqual(t, nil, p) | ||||||
|  | 	assert.Equal(t, "Bitbucket", p.Data().ProviderName) | ||||||
|  | 	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/api/v3/user", | ||||||
|  | 		p.Data().ValidateURL.String()) | ||||||
|  | 	assert.Equal(t, "profile", p.Data().Scope) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestBitbucketProviderGetEmailAddress(t *testing.T) { | ||||||
|  | 	b := testBitbucketBackend("{\"values\": [ { \"email\": \"michael.bland@gsa.gov\", \"is_primary\": true } ] }") | ||||||
|  | 	defer b.Close() | ||||||
|  | 
 | ||||||
|  | 	bURL, _ := url.Parse(b.URL) | ||||||
|  | 	p := testBitbucketProvider(bURL.Host, "", "") | ||||||
|  | 
 | ||||||
|  | 	session := &sessions.SessionState{AccessToken: "imaginary_access_token"} | ||||||
|  | 	email, err := p.GetEmailAddress(session) | ||||||
|  | 	assert.Equal(t, nil, err) | ||||||
|  | 	assert.Equal(t, "michael.bland@gsa.gov", email) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestBitbucketProviderGetEmailAddressAndGroup(t *testing.T) { | ||||||
|  | 	b := testBitbucketBackend("{\"values\": [ { \"email\": \"michael.bland@gsa.gov\", \"is_primary\": true, \"username\": \"bioinformatics\" } ] }") | ||||||
|  | 	defer b.Close() | ||||||
|  | 
 | ||||||
|  | 	bURL, _ := url.Parse(b.URL) | ||||||
|  | 	p := testBitbucketProvider(bURL.Host, "bioinformatics", "") | ||||||
|  | 
 | ||||||
|  | 	session := &sessions.SessionState{AccessToken: "imaginary_access_token"} | ||||||
|  | 	email, err := p.GetEmailAddress(session) | ||||||
|  | 	assert.Equal(t, nil, err) | ||||||
|  | 	assert.Equal(t, "michael.bland@gsa.gov", email) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Note that trying to trigger the "failed building request" case is not
 | ||||||
|  | // practical, since the only way it can fail is if the URL fails to parse.
 | ||||||
|  | func TestBitbucketProviderGetEmailAddressFailedRequest(t *testing.T) { | ||||||
|  | 	b := testBitbucketBackend("unused payload") | ||||||
|  | 	defer b.Close() | ||||||
|  | 
 | ||||||
|  | 	bURL, _ := url.Parse(b.URL) | ||||||
|  | 	p := testBitbucketProvider(bURL.Host, "", "") | ||||||
|  | 
 | ||||||
|  | 	// We'll trigger a request failure by using an unexpected access
 | ||||||
|  | 	// token. Alternatively, we could allow the parsing of the payload as
 | ||||||
|  | 	// JSON to fail.
 | ||||||
|  | 	session := &sessions.SessionState{AccessToken: "unexpected_access_token"} | ||||||
|  | 	email, err := p.GetEmailAddress(session) | ||||||
|  | 	assert.NotEqual(t, nil, err) | ||||||
|  | 	assert.Equal(t, "", email) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestBitbucketProviderGetEmailAddressEmailNotPresentInPayload(t *testing.T) { | ||||||
|  | 	b := testBitbucketBackend("{\"foo\": \"bar\"}") | ||||||
|  | 	defer b.Close() | ||||||
|  | 
 | ||||||
|  | 	bURL, _ := url.Parse(b.URL) | ||||||
|  | 	p := testBitbucketProvider(bURL.Host, "", "") | ||||||
|  | 
 | ||||||
|  | 	session := &sessions.SessionState{AccessToken: "imaginary_access_token"} | ||||||
|  | 	email, err := p.GetEmailAddress(session) | ||||||
|  | 	assert.Equal(t, "", email) | ||||||
|  | 	assert.Equal(t, nil, err) | ||||||
|  | } | ||||||
|  | @ -36,6 +36,8 @@ func New(provider string, p *ProviderData) Provider { | ||||||
| 		return NewOIDCProvider(p) | 		return NewOIDCProvider(p) | ||||||
| 	case "login.gov": | 	case "login.gov": | ||||||
| 		return NewLoginGovProvider(p) | 		return NewLoginGovProvider(p) | ||||||
|  | 	case "bitbucket": | ||||||
|  | 		return NewBitbucketProvider(p) | ||||||
| 	default: | 	default: | ||||||
| 		return NewGoogleProvider(p) | 		return NewGoogleProvider(p) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue