You've already forked oauth2-proxy
mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2025-07-13 01:40:48 +02:00
fix gitea token validation by allowing custom validation url and extracting the proper base api url for github cloud, github enterprise and gitea (#2194)
This commit is contained in:
@ -9,9 +9,10 @@
|
|||||||
## Changes since v7.5.0
|
## Changes since v7.5.0
|
||||||
- [#2220](https://github.com/oauth2-proxy/oauth2-proxy/pull/2220) Added binary and docker release platforms (@kvanzuijlen)
|
- [#2220](https://github.com/oauth2-proxy/oauth2-proxy/pull/2220) Added binary and docker release platforms (@kvanzuijlen)
|
||||||
- [#2221](https://github.com/oauth2-proxy/oauth2-proxy/pull/2221) Backwards compatible fix for wrong environment variable name (OAUTH2_PROXY_GOOGLE_GROUPS) (@kvanzuijlen)
|
- [#2221](https://github.com/oauth2-proxy/oauth2-proxy/pull/2221) Backwards compatible fix for wrong environment variable name (OAUTH2_PROXY_GOOGLE_GROUPS) (@kvanzuijlen)
|
||||||
- [#1989](https://github.com/oauth2-proxy/oauth2-proxy/pull/1989) Fix default scope for keycloak-oidc provider
|
- [#1989](https://github.com/oauth2-proxy/oauth2-proxy/pull/1989) Fix default scope for keycloak-oidc provider (@tuunit)
|
||||||
- [#2217](https://github.com/oauth2-proxy/oauth2-proxy/pull/2217) Upgrade alpine to version 3.18 (@polarctos)
|
- [#2217](https://github.com/oauth2-proxy/oauth2-proxy/pull/2217) Upgrade alpine to version 3.18 (@polarctos)
|
||||||
- [#2229](https://github.com/oauth2-proxy/oauth2-proxy/pull/2229) bugfix: default scopes for OIDCProvider based providers
|
- [#2229](https://github.com/oauth2-proxy/oauth2-proxy/pull/2229) bugfix: default scopes for OIDCProvider based providers (@tuunit)
|
||||||
|
- [#2194](https://github.com/oauth2-proxy/oauth2-proxy/pull/2194) Fix Gitea token validation (@tuunit)
|
||||||
|
|
||||||
# V7.5.0
|
# V7.5.0
|
||||||
|
|
||||||
|
@ -1,34 +1,42 @@
|
|||||||
.PHONY: up
|
.PHONY: up
|
||||||
up:
|
up:
|
||||||
docker-compose up -d
|
docker compose up -d
|
||||||
|
|
||||||
.PHONY: %
|
.PHONY: %
|
||||||
%:
|
%:
|
||||||
docker-compose $*
|
docker compose $*
|
||||||
|
|
||||||
.PHONY: alpha-config-up
|
.PHONY: alpha-config-up
|
||||||
alpha-config-up:
|
alpha-config-up:
|
||||||
docker-compose -f docker-compose.yaml -f docker-compose-alpha-config.yaml up -d
|
docker compose -f docker-compose.yaml -f docker-compose-alpha-config.yaml up -d
|
||||||
|
|
||||||
.PHONY: alpha-config-%
|
.PHONY: alpha-config-%
|
||||||
alpha-config-%:
|
alpha-config-%:
|
||||||
docker-compose -f docker-compose.yaml -f docker-compose-alpha-config.yaml $*
|
docker compose -f docker-compose.yaml -f docker-compose-alpha-config.yaml $*
|
||||||
|
|
||||||
.PHONY: nginx-up
|
.PHONY: nginx-up
|
||||||
nginx-up:
|
nginx-up:
|
||||||
docker-compose -f docker-compose.yaml -f docker-compose-nginx.yaml up -d
|
docker compose -f docker-compose.yaml -f docker-compose-nginx.yaml up -d
|
||||||
|
|
||||||
.PHONY: nginx-%
|
.PHONY: nginx-%
|
||||||
nginx-%:
|
nginx-%:
|
||||||
docker-compose -f docker-compose.yaml -f docker-compose-nginx.yaml $*
|
docker compose -f docker-compose.yaml -f docker-compose-nginx.yaml $*
|
||||||
|
|
||||||
.PHONY: keycloak-up
|
.PHONY: keycloak-up
|
||||||
keycloak-up:
|
keycloak-up:
|
||||||
docker-compose -f docker-compose-keycloak.yaml up -d
|
docker compose -f docker-compose-keycloak.yaml up -d
|
||||||
|
|
||||||
.PHONY: keycloak-%
|
.PHONY: keycloak-%
|
||||||
keycloak-%:
|
keycloak-%:
|
||||||
docker-compose -f docker-compose-keycloak.yaml $*
|
docker compose -f docker-compose-keycloak.yaml $*
|
||||||
|
|
||||||
|
.PHONY: gitea-up
|
||||||
|
gitea-up:
|
||||||
|
docker compose -f docker-compose-gitea.yaml up -d
|
||||||
|
|
||||||
|
.PHONY: gitea-%
|
||||||
|
gitea-%:
|
||||||
|
docker compose -f docker-compose-gitea.yaml $*
|
||||||
|
|
||||||
.PHONY: kubernetes-up
|
.PHONY: kubernetes-up
|
||||||
kubernetes-up:
|
kubernetes-up:
|
||||||
@ -41,8 +49,8 @@ kubernetes-down:
|
|||||||
|
|
||||||
.PHONY: traefik-up
|
.PHONY: traefik-up
|
||||||
traefik-up:
|
traefik-up:
|
||||||
docker-compose -f docker-compose.yaml -f docker-compose-traefik.yaml up -d
|
docker compose -f docker-compose.yaml -f docker-compose-traefik.yaml up -d
|
||||||
|
|
||||||
.PHONY: traefik-%
|
.PHONY: traefik-%
|
||||||
traefik-%:
|
traefik-%:
|
||||||
docker-compose -f docker-compose.yaml -f docker-compose-traefik.yaml $*
|
docker compose -f docker-compose.yaml -f docker-compose-traefik.yaml $*
|
||||||
|
65
contrib/local-environment/docker-compose-gitea.yaml
Normal file
65
contrib/local-environment/docker-compose-gitea.yaml
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# This docker-compose file can be used to bring up an example instance of oauth2-proxy
|
||||||
|
# for manual testing and exploration of features.
|
||||||
|
# Alongside OAuth2-Proxy, this file also starts Gitea to act as the identity provider,
|
||||||
|
# HTTPBin as an example upstream.
|
||||||
|
#
|
||||||
|
# This can either be created using docker-compose
|
||||||
|
# docker-compose -f docker-compose-gitea.yaml <command>
|
||||||
|
# Or:
|
||||||
|
# make gitea-<command> (eg. make gitea-up, make gitea-down)
|
||||||
|
#
|
||||||
|
# Access http://oauth2-proxy.localtest.me:4180 to initiate a login cycle using user=admin@example.com, password=password
|
||||||
|
# Access http://gitea.localtest.me:3000 with the same credentials to check out the settings
|
||||||
|
version: '3.0'
|
||||||
|
services:
|
||||||
|
oauth2-proxy:
|
||||||
|
container_name: oauth2-proxy
|
||||||
|
image: gitea-oauth #quay.io/oauth2-proxy/oauth2-proxy:v7.4.0
|
||||||
|
command: --config /oauth2-proxy.cfg
|
||||||
|
hostname: oauth2-proxy
|
||||||
|
volumes:
|
||||||
|
- "./oauth2-proxy-gitea.cfg:/oauth2-proxy.cfg"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
gitea: {}
|
||||||
|
httpbin: {}
|
||||||
|
oauth2-proxy: {}
|
||||||
|
depends_on:
|
||||||
|
- httpbin
|
||||||
|
- gitea
|
||||||
|
ports:
|
||||||
|
- 4180:4180/tcp
|
||||||
|
|
||||||
|
httpbin:
|
||||||
|
container_name: httpbin
|
||||||
|
image: kennethreitz/httpbin:latest
|
||||||
|
hostname: httpbin
|
||||||
|
ports:
|
||||||
|
- 8080:80
|
||||||
|
networks:
|
||||||
|
httpbin:
|
||||||
|
aliases:
|
||||||
|
- httpbin.localtest.me
|
||||||
|
|
||||||
|
gitea:
|
||||||
|
image: gitea/gitea:latest
|
||||||
|
container_name: gitea
|
||||||
|
environment:
|
||||||
|
- USER_UID=1000
|
||||||
|
- USER_GID=1000
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
gitea:
|
||||||
|
aliases:
|
||||||
|
- gitea.localtest.me
|
||||||
|
volumes:
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
- "222:22"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
httpbin: {}
|
||||||
|
gitea: {}
|
||||||
|
oauth2-proxy: {}
|
19
contrib/local-environment/oauth2-proxy-gitea.cfg
Normal file
19
contrib/local-environment/oauth2-proxy-gitea.cfg
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
http_address="0.0.0.0:4180"
|
||||||
|
cookie_secret="OQINaROshtE9TcZkNAm-5Zs2Pv3xaWytBmc5W7sPX7w="
|
||||||
|
email_domains=["localhost"]
|
||||||
|
cookie_secure="false"
|
||||||
|
upstreams="http://httpbin"
|
||||||
|
cookie_domains=[".localtest.me"] # Required so cookie can be read on all subdomains.
|
||||||
|
whitelist_domains=[".localtest.me"] # Required to allow redirection back to original requested target.
|
||||||
|
|
||||||
|
client_id="ef0c2b91-2e38-4fa8-908d-067a35dbb71c"
|
||||||
|
client_secret="gto_qdppomn2p26su5x46tyixj7bcny5m5er2s67xhrponq2qtp66f3a"
|
||||||
|
redirect_url="http://oauth2-proxy.localtest.me:4180/oauth2/callback"
|
||||||
|
|
||||||
|
# gitea provider
|
||||||
|
provider="github"
|
||||||
|
provider_display_name="Gitea"
|
||||||
|
login_url="http://gitea.localtest.me:3000/login/oauth/authorize"
|
||||||
|
redeem_url="http://gitea.localtest.me:3000/login/oauth/access_token"
|
||||||
|
validate_url="http://gitea.localtest.me:3000/api/v1/user/emails"
|
||||||
|
|
@ -12,6 +12,7 @@ Valid providers are :
|
|||||||
- [ADFS](#adfs-auth-provider)
|
- [ADFS](#adfs-auth-provider)
|
||||||
- [Facebook](#facebook-auth-provider)
|
- [Facebook](#facebook-auth-provider)
|
||||||
- [GitHub](#github-auth-provider)
|
- [GitHub](#github-auth-provider)
|
||||||
|
- [Gitea](#gitea-auth-provider)
|
||||||
- [Keycloak](#keycloak-auth-provider)
|
- [Keycloak](#keycloak-auth-provider)
|
||||||
- [GitLab](#gitlab-auth-provider)
|
- [GitLab](#gitlab-auth-provider)
|
||||||
- [LinkedIn](#linkedin-auth-provider)
|
- [LinkedIn](#linkedin-auth-provider)
|
||||||
@ -21,7 +22,6 @@ Valid providers are :
|
|||||||
- [Nextcloud](#nextcloud-provider)
|
- [Nextcloud](#nextcloud-provider)
|
||||||
- [DigitalOcean](#digitalocean-auth-provider)
|
- [DigitalOcean](#digitalocean-auth-provider)
|
||||||
- [Bitbucket](#bitbucket-auth-provider)
|
- [Bitbucket](#bitbucket-auth-provider)
|
||||||
- [Gitea](#gitea-auth-provider)
|
|
||||||
|
|
||||||
The provider can be selected using the `provider` configuration value.
|
The provider can be selected using the `provider` configuration value.
|
||||||
|
|
||||||
@ -177,6 +177,25 @@ If you are using GitHub enterprise, make sure you set the following to the appro
|
|||||||
-redeem-url="http(s)://<enterprise github host>/login/oauth/access_token"
|
-redeem-url="http(s)://<enterprise github host>/login/oauth/access_token"
|
||||||
-validate-url="http(s)://<enterprise github host>/api/v3"
|
-validate-url="http(s)://<enterprise github host>/api/v3"
|
||||||
|
|
||||||
|
### Gitea Auth Provider
|
||||||
|
|
||||||
|
1. Create a new application: `https://< your gitea host >/user/settings/applications`
|
||||||
|
2. Under `Redirect URI` enter the correct URL i.e. `https://<proxied host>/oauth2/callback`
|
||||||
|
3. Note the Client ID and Client Secret.
|
||||||
|
4. Pass the following options to the proxy:
|
||||||
|
|
||||||
|
```
|
||||||
|
--provider="github"
|
||||||
|
--redirect-url="https://<proxied host>/oauth2/callback"
|
||||||
|
--provider-display-name="Gitea"
|
||||||
|
--client-id="< client_id as generated by Gitea >"
|
||||||
|
--client-secret="< client_secret as generated by Gitea >"
|
||||||
|
--login-url="https://< your gitea host >/login/oauth/authorize"
|
||||||
|
--redeem-url="https://< your gitea host >/login/oauth/access_token"
|
||||||
|
--validate-url="https://< your gitea host >/api/v1/user/emails"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Keycloak Auth Provider
|
### Keycloak Auth Provider
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
@ -660,24 +679,6 @@ To use the provider, pass the following options:
|
|||||||
The default configuration allows everyone with Bitbucket account to authenticate. To restrict the access to the team members use additional configuration option: `--bitbucket-team=<Team name>`. To restrict the access to only these users who has access to one selected repository use `--bitbucket-repository=<Repository name>`.
|
The default configuration allows everyone with Bitbucket account to authenticate. To restrict the access to the team members use additional configuration option: `--bitbucket-team=<Team name>`. To restrict the access to only these users who has access to one selected repository use `--bitbucket-repository=<Repository name>`.
|
||||||
|
|
||||||
|
|
||||||
### Gitea Auth Provider
|
|
||||||
|
|
||||||
1. Create a new application: `https://< your gitea host >/user/settings/applications`
|
|
||||||
2. Under `Redirect URI` enter the correct URL i.e. `https://<proxied host>/oauth2/callback`
|
|
||||||
3. Note the Client ID and Client Secret.
|
|
||||||
4. Pass the following options to the proxy:
|
|
||||||
|
|
||||||
```
|
|
||||||
--provider="github"
|
|
||||||
--redirect-url="https://<proxied host>/oauth2/callback"
|
|
||||||
--provider-display-name="Gitea"
|
|
||||||
--client-id="< client_id as generated by Gitea >"
|
|
||||||
--client-secret="< client_secret as generated by Gitea >"
|
|
||||||
--login-url="https://< your gitea host >/login/oauth/authorize"
|
|
||||||
--redeem-url="https://< your gitea host >/login/oauth/access_token"
|
|
||||||
--validate-url="https://< your gitea host >/api/v1"
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Email Authentication
|
## Email Authentication
|
||||||
|
|
||||||
|
98
providers/gitea_test.go
Normal file
98
providers/gitea_test.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package providers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testGiteaProvider(hostname string, opts options.GitHubOptions) *GitHubProvider {
|
||||||
|
p := NewGitHubProvider(
|
||||||
|
&ProviderData{
|
||||||
|
ProviderName: "Gitea",
|
||||||
|
LoginURL: &url.URL{},
|
||||||
|
RedeemURL: &url.URL{},
|
||||||
|
ProfileURL: &url.URL{},
|
||||||
|
ValidateURL: &url.URL{Path: "/api/v1/user/emails"},
|
||||||
|
Scope: ""},
|
||||||
|
opts)
|
||||||
|
p.ProviderName = "Gitea"
|
||||||
|
|
||||||
|
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 testGiteaBackend(payloads map[string][]string) *httptest.Server {
|
||||||
|
pathToQueryMap := map[string][]string{
|
||||||
|
"/api/v1/repos/oauth2-proxy/oauth2-proxy": {""},
|
||||||
|
"/api/v1/repos/oauth2-proxy/oauth2-proxy/collaborators/mbland": {""},
|
||||||
|
"/api/v1/user": {""},
|
||||||
|
"/api/v1/user/emails": {""},
|
||||||
|
"/api/v1/user/orgs": {"page=1&per_page=100", "page=2&per_page=100", "page=3&per_page=100"},
|
||||||
|
}
|
||||||
|
|
||||||
|
return httptest.NewServer(http.HandlerFunc(
|
||||||
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
query, ok := pathToQueryMap[r.URL.Path]
|
||||||
|
validQuery := false
|
||||||
|
index := 0
|
||||||
|
for i, q := range query {
|
||||||
|
if q == r.URL.RawQuery {
|
||||||
|
validQuery = true
|
||||||
|
index = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
payload := []string{}
|
||||||
|
if ok && validQuery {
|
||||||
|
payload, ok = payloads[r.URL.Path]
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
w.WriteHeader(404)
|
||||||
|
} else if !validQuery {
|
||||||
|
w.WriteHeader(404)
|
||||||
|
} else if payload[index] == "" {
|
||||||
|
w.WriteHeader(204)
|
||||||
|
} else {
|
||||||
|
w.WriteHeader(200)
|
||||||
|
w.Write([]byte(payload[index]))
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGiteaProvider_ValidateSessionWithBaseUrl(t *testing.T) {
|
||||||
|
b := testGiteaBackend(map[string][]string{})
|
||||||
|
defer b.Close()
|
||||||
|
|
||||||
|
bURL, _ := url.Parse(b.URL)
|
||||||
|
p := testGiteaProvider(bURL.Host, options.GitHubOptions{})
|
||||||
|
|
||||||
|
session := CreateAuthorizedSession()
|
||||||
|
|
||||||
|
valid := p.ValidateSession(context.Background(), session)
|
||||||
|
assert.False(t, valid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGiteaProvider_ValidateSessionWithUserEmails(t *testing.T) {
|
||||||
|
b := testGiteaBackend(map[string][]string{
|
||||||
|
"/api/v1/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
|
||||||
|
})
|
||||||
|
defer b.Close()
|
||||||
|
|
||||||
|
bURL, _ := url.Parse(b.URL)
|
||||||
|
p := testGiteaProvider(bURL.Host, options.GitHubOptions{})
|
||||||
|
|
||||||
|
session := CreateAuthorizedSession()
|
||||||
|
|
||||||
|
valid := p.ValidateSession(context.Background(), session)
|
||||||
|
assert.True(t, valid)
|
||||||
|
}
|
@ -89,6 +89,27 @@ func makeGitHubHeader(accessToken string) http.Header {
|
|||||||
return makeAuthorizationHeader(tokenTypeToken, accessToken, extraHeaders)
|
return makeAuthorizationHeader(tokenTypeToken, accessToken, extraHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *GitHubProvider) makeGitHubAPIEndpoint(endpoint string, params *url.Values) *url.URL {
|
||||||
|
basePath := p.ValidateURL.Path
|
||||||
|
|
||||||
|
re := regexp.MustCompile(`^/api/v\d+`)
|
||||||
|
match := re.FindString(p.ValidateURL.Path)
|
||||||
|
if match != "" {
|
||||||
|
basePath = match
|
||||||
|
}
|
||||||
|
|
||||||
|
if params == nil {
|
||||||
|
params = &url.Values{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &url.URL{
|
||||||
|
Scheme: p.ValidateURL.Scheme,
|
||||||
|
Host: p.ValidateURL.Host,
|
||||||
|
Path: path.Join(basePath, endpoint),
|
||||||
|
RawQuery: params.Encode(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// setOrgTeam adds GitHub org reading parameters to the OAuth2 scope
|
// setOrgTeam adds GitHub org reading parameters to the OAuth2 scope
|
||||||
func (p *GitHubProvider) setOrgTeam(org, team string) {
|
func (p *GitHubProvider) setOrgTeam(org, team string) {
|
||||||
p.Org = org
|
p.Org = org
|
||||||
@ -141,12 +162,7 @@ func (p *GitHubProvider) hasOrg(ctx context.Context, accessToken string) (bool,
|
|||||||
"page": {strconv.Itoa(pn)},
|
"page": {strconv.Itoa(pn)},
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint := &url.URL{
|
endpoint := p.makeGitHubAPIEndpoint("/user/orgs", ¶ms)
|
||||||
Scheme: p.ValidateURL.Scheme,
|
|
||||||
Host: p.ValidateURL.Host,
|
|
||||||
Path: path.Join(p.ValidateURL.Path, "/user/orgs"),
|
|
||||||
RawQuery: params.Encode(),
|
|
||||||
}
|
|
||||||
|
|
||||||
var op orgsPage
|
var op orgsPage
|
||||||
err := requests.New(endpoint.String()).
|
err := requests.New(endpoint.String()).
|
||||||
@ -206,12 +222,7 @@ func (p *GitHubProvider) hasOrgAndTeam(ctx context.Context, accessToken string)
|
|||||||
"page": {strconv.Itoa(pn)},
|
"page": {strconv.Itoa(pn)},
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint := &url.URL{
|
endpoint := p.makeGitHubAPIEndpoint("/user/teams", ¶ms)
|
||||||
Scheme: p.ValidateURL.Scheme,
|
|
||||||
Host: p.ValidateURL.Host,
|
|
||||||
Path: path.Join(p.ValidateURL.Path, "/user/teams"),
|
|
||||||
RawQuery: params.Encode(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// bodyclose cannot detect that the body is being closed later in requests.Into,
|
// bodyclose cannot detect that the body is being closed later in requests.Into,
|
||||||
// so have to skip the linting for the next line.
|
// so have to skip the linting for the next line.
|
||||||
@ -309,11 +320,7 @@ func (p *GitHubProvider) hasRepo(ctx context.Context, accessToken string) (bool,
|
|||||||
Private bool `json:"private"`
|
Private bool `json:"private"`
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint := &url.URL{
|
endpoint := p.makeGitHubAPIEndpoint("/repos/"+p.Repo, nil)
|
||||||
Scheme: p.ValidateURL.Scheme,
|
|
||||||
Host: p.ValidateURL.Host,
|
|
||||||
Path: path.Join(p.ValidateURL.Path, "/repos/", p.Repo),
|
|
||||||
}
|
|
||||||
|
|
||||||
var repo repository
|
var repo repository
|
||||||
err := requests.New(endpoint.String()).
|
err := requests.New(endpoint.String()).
|
||||||
@ -338,11 +345,7 @@ func (p *GitHubProvider) hasUser(ctx context.Context, accessToken string) (bool,
|
|||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint := &url.URL{
|
endpoint := p.makeGitHubAPIEndpoint("/user", nil)
|
||||||
Scheme: p.ValidateURL.Scheme,
|
|
||||||
Host: p.ValidateURL.Host,
|
|
||||||
Path: path.Join(p.ValidateURL.Path, "/user"),
|
|
||||||
}
|
|
||||||
|
|
||||||
err := requests.New(endpoint.String()).
|
err := requests.New(endpoint.String()).
|
||||||
WithContext(ctx).
|
WithContext(ctx).
|
||||||
@ -362,11 +365,7 @@ func (p *GitHubProvider) hasUser(ctx context.Context, accessToken string) (bool,
|
|||||||
func (p *GitHubProvider) isCollaborator(ctx context.Context, username, accessToken string) (bool, error) {
|
func (p *GitHubProvider) isCollaborator(ctx context.Context, username, accessToken string) (bool, error) {
|
||||||
//https://developer.github.com/v3/repos/collaborators/#check-if-a-user-is-a-collaborator
|
//https://developer.github.com/v3/repos/collaborators/#check-if-a-user-is-a-collaborator
|
||||||
|
|
||||||
endpoint := &url.URL{
|
endpoint := p.makeGitHubAPIEndpoint("/repos/"+p.Repo+"/collaborators/"+username, nil)
|
||||||
Scheme: p.ValidateURL.Scheme,
|
|
||||||
Host: p.ValidateURL.Host,
|
|
||||||
Path: path.Join(p.ValidateURL.Path, "/repos/", p.Repo, "/collaborators/", username),
|
|
||||||
}
|
|
||||||
result := requests.New(endpoint.String()).
|
result := requests.New(endpoint.String()).
|
||||||
WithContext(ctx).
|
WithContext(ctx).
|
||||||
WithHeaders(makeGitHubHeader(accessToken)).
|
WithHeaders(makeGitHubHeader(accessToken)).
|
||||||
@ -426,11 +425,7 @@ func (p *GitHubProvider) getEmail(ctx context.Context, s *sessions.SessionState)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint := &url.URL{
|
endpoint := p.makeGitHubAPIEndpoint("/user/emails", nil)
|
||||||
Scheme: p.ValidateURL.Scheme,
|
|
||||||
Host: p.ValidateURL.Host,
|
|
||||||
Path: path.Join(p.ValidateURL.Path, "/user/emails"),
|
|
||||||
}
|
|
||||||
err := requests.New(endpoint.String()).
|
err := requests.New(endpoint.String()).
|
||||||
WithContext(ctx).
|
WithContext(ctx).
|
||||||
WithHeaders(makeGitHubHeader(s.AccessToken)).
|
WithHeaders(makeGitHubHeader(s.AccessToken)).
|
||||||
@ -459,11 +454,7 @@ func (p *GitHubProvider) getUser(ctx context.Context, s *sessions.SessionState)
|
|||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint := &url.URL{
|
endpoint := p.makeGitHubAPIEndpoint("/user", nil)
|
||||||
Scheme: p.ValidateURL.Scheme,
|
|
||||||
Host: p.ValidateURL.Host,
|
|
||||||
Path: path.Join(p.ValidateURL.Path, "/user"),
|
|
||||||
}
|
|
||||||
|
|
||||||
err := requests.New(endpoint.String()).
|
err := requests.New(endpoint.String()).
|
||||||
WithContext(ctx).
|
WithContext(ctx).
|
||||||
|
@ -34,11 +34,15 @@ func testGitHubProvider(hostname string, opts options.GitHubOptions) *GitHubProv
|
|||||||
|
|
||||||
func testGitHubBackend(payloads map[string][]string) *httptest.Server {
|
func testGitHubBackend(payloads map[string][]string) *httptest.Server {
|
||||||
pathToQueryMap := map[string][]string{
|
pathToQueryMap := map[string][]string{
|
||||||
"/repos/oauth2-proxy/oauth2-proxy": {""},
|
"/": {""},
|
||||||
|
"/repos/oauth2-proxy/oauth2-proxy": {""},
|
||||||
"/repos/oauth2-proxy/oauth2-proxy/collaborators/mbland": {""},
|
"/repos/oauth2-proxy/oauth2-proxy/collaborators/mbland": {""},
|
||||||
"/user": {""},
|
"/user": {""},
|
||||||
"/user/emails": {""},
|
"/user/emails": {""},
|
||||||
"/user/orgs": {"page=1&per_page=100", "page=2&per_page=100", "page=3&per_page=100"},
|
"/user/orgs": {"page=1&per_page=100", "page=2&per_page=100", "page=3&per_page=100"},
|
||||||
|
// GitHub Enterprise Server API
|
||||||
|
"/api/v3": {""},
|
||||||
|
"/api/v3/user/emails": {""},
|
||||||
}
|
}
|
||||||
|
|
||||||
return httptest.NewServer(http.HandlerFunc(
|
return httptest.NewServer(http.HandlerFunc(
|
||||||
@ -75,10 +79,10 @@ func TestNewGitHubProvider(t *testing.T) {
|
|||||||
// Test that defaults are set when calling for a new provider with nothing set
|
// Test that defaults are set when calling for a new provider with nothing set
|
||||||
providerData := NewGitHubProvider(&ProviderData{}, options.GitHubOptions{}).Data()
|
providerData := NewGitHubProvider(&ProviderData{}, options.GitHubOptions{}).Data()
|
||||||
g.Expect(providerData.ProviderName).To(Equal("GitHub"))
|
g.Expect(providerData.ProviderName).To(Equal("GitHub"))
|
||||||
g.Expect(providerData.LoginURL.String()).To(Equal("https://github.com/login/oauth/authorize"))
|
g.Expect(providerData.LoginURL.String()).To(Equal(githubDefaultLoginURL.String()))
|
||||||
g.Expect(providerData.RedeemURL.String()).To(Equal("https://github.com/login/oauth/access_token"))
|
g.Expect(providerData.RedeemURL.String()).To(Equal(githubDefaultRedeemURL.String()))
|
||||||
g.Expect(providerData.ProfileURL.String()).To(Equal(""))
|
g.Expect(providerData.ProfileURL.String()).To(Equal(""))
|
||||||
g.Expect(providerData.ValidateURL.String()).To(Equal("https://api.github.com/"))
|
g.Expect(providerData.ValidateURL.String()).To(Equal(githubDefaultValidateURL.String()))
|
||||||
g.Expect(providerData.Scope).To(Equal("user:email"))
|
g.Expect(providerData.Scope).To(Equal("user:email"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,3 +444,50 @@ func TestGitHubProvider_getEmailWithUsernameAndNoAccessToPrivateRepo(t *testing.
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "michael.bland@gsa.gov", session.Email)
|
assert.Equal(t, "michael.bland@gsa.gov", session.Email)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGitHubProvider_ValidateSessionWithBaseUrl(t *testing.T) {
|
||||||
|
b := testGitHubBackend(map[string][]string{
|
||||||
|
"/": {`[]`},
|
||||||
|
})
|
||||||
|
defer b.Close()
|
||||||
|
|
||||||
|
bURL, _ := url.Parse(b.URL)
|
||||||
|
p := testGitHubProvider(bURL.Host, options.GitHubOptions{})
|
||||||
|
|
||||||
|
session := CreateAuthorizedSession()
|
||||||
|
|
||||||
|
valid := p.ValidateSession(context.Background(), session)
|
||||||
|
assert.True(t, valid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGitHubProvider_ValidateSessionWithEnterpriseBaseUrl(t *testing.T) {
|
||||||
|
b := testGitHubBackend(map[string][]string{
|
||||||
|
"/api/v3": {`[]`},
|
||||||
|
})
|
||||||
|
defer b.Close()
|
||||||
|
|
||||||
|
bURL, _ := url.Parse(b.URL)
|
||||||
|
p := testGitHubProvider(bURL.Host, options.GitHubOptions{})
|
||||||
|
p.ValidateURL.Path = "/api/v3"
|
||||||
|
|
||||||
|
session := CreateAuthorizedSession()
|
||||||
|
|
||||||
|
valid := p.ValidateSession(context.Background(), session)
|
||||||
|
assert.True(t, valid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGitHubProvider_ValidateSessionWithUserEmails(t *testing.T) {
|
||||||
|
b := testGitHubBackend(map[string][]string{
|
||||||
|
"/user/emails": {`[ {"email": "michael.bland@gsa.gov", "verified": true, "primary": true} ]`},
|
||||||
|
})
|
||||||
|
defer b.Close()
|
||||||
|
|
||||||
|
bURL, _ := url.Parse(b.URL)
|
||||||
|
p := testGitHubProvider(bURL.Host, options.GitHubOptions{})
|
||||||
|
p.ValidateURL.Path = "/user/emails"
|
||||||
|
|
||||||
|
session := CreateAuthorizedSession()
|
||||||
|
|
||||||
|
valid := p.ValidateSession(context.Background(), session)
|
||||||
|
assert.True(t, valid)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user