fix gitea oauth
This commit is contained in:
@@ -21,6 +21,7 @@ SSL_CERTIFICATE_KEY_FILE=privkey.pem
|
|||||||
TAPM_DATABASE_DSN=file:/data/tapm.db?_pragma=busy_timeout(5000)&_pragma=foreign_keys(1)&_pragma=journal_mode(WAL)
|
TAPM_DATABASE_DSN=file:/data/tapm.db?_pragma=busy_timeout(5000)&_pragma=foreign_keys(1)&_pragma=journal_mode(WAL)
|
||||||
TAPM_PUBLIC_URL=http://broker.example.com:8680
|
TAPM_PUBLIC_URL=http://broker.example.com:8680
|
||||||
TAPM_GITEA_URL=http://git.example.com:8680
|
TAPM_GITEA_URL=http://git.example.com:8680
|
||||||
|
TAPM_GITEA_INTERNAL_URL=http://gitea:3000
|
||||||
# These values are intentionally blank during initial Gitea bootstrap.
|
# These values are intentionally blank during initial Gitea bootstrap.
|
||||||
# Run ./manage.sh configure-broker before starting the broker.
|
# Run ./manage.sh configure-broker before starting the broker.
|
||||||
TAPM_GITEA_CLIENT_ID=
|
TAPM_GITEA_CLIENT_ID=
|
||||||
|
|||||||
@@ -119,6 +119,11 @@ The broker is deliberately not started during the first bootstrap. Blank
|
|||||||
OAuth/package values are valid for Gitea-only setup, while `start` refuses to
|
OAuth/package values are valid for Gitea-only setup, while `start` refuses to
|
||||||
launch the broker until all required credentials are present.
|
launch the broker until all required credentials are present.
|
||||||
|
|
||||||
|
`TAPM_GITEA_URL` is the public browser-facing Gitea URL.
|
||||||
|
`TAPM_GITEA_INTERNAL_URL` defaults to `http://gitea:3000` in installations so
|
||||||
|
OAuth token exchange and package traffic stay on the private Compose network.
|
||||||
|
Do not publish Gitea's internal port to make broker authentication work.
|
||||||
|
|
||||||
For troubleshooting, use `./manage.sh diagnostics`. Do not share unredacted
|
For troubleshooting, use `./manage.sh diagnostics`. Do not share unredacted
|
||||||
`docker compose config` output: Compose resolves the broker's `.env` file and
|
`docker compose config` output: Compose resolves the broker's `.env` file and
|
||||||
can print cookie, OAuth, and package secrets. If configuration output is
|
can print cookie, OAuth, and package secrets. If configuration output is
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ umask 077
|
|||||||
printf 'TAPM_DATABASE_DSN=file:/data/tapm.db?_pragma=busy_timeout(5000)&_pragma=foreign_keys(1)&_pragma=journal_mode(WAL)\n'
|
printf 'TAPM_DATABASE_DSN=file:/data/tapm.db?_pragma=busy_timeout(5000)&_pragma=foreign_keys(1)&_pragma=journal_mode(WAL)\n'
|
||||||
printf 'TAPM_PUBLIC_URL=%s://%s%s\n' "$public_scheme" "$broker_domain" "$public_port_suffix"
|
printf 'TAPM_PUBLIC_URL=%s://%s%s\n' "$public_scheme" "$broker_domain" "$public_port_suffix"
|
||||||
printf 'TAPM_GITEA_URL=%s://%s%s\n' "$public_scheme" "$gitea_domain" "$public_port_suffix"
|
printf 'TAPM_GITEA_URL=%s://%s%s\n' "$public_scheme" "$gitea_domain" "$public_port_suffix"
|
||||||
|
printf 'TAPM_GITEA_INTERNAL_URL=http://gitea:3000\n'
|
||||||
printf 'TAPM_GITEA_CLIENT_ID=\n'
|
printf 'TAPM_GITEA_CLIENT_ID=\n'
|
||||||
printf 'TAPM_GITEA_CLIENT_SECRET=\n'
|
printf 'TAPM_GITEA_CLIENT_SECRET=\n'
|
||||||
printf 'TAPM_GITEA_PACKAGE_OWNER=TAI\n'
|
printf 'TAPM_GITEA_PACKAGE_OWNER=TAI\n'
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -90,6 +91,7 @@ func (s *Server) handleCallback(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
user, err := s.exchangeOAuthCode(r.Context(), code)
|
user, err := s.exchangeOAuthCode(r.Context(), code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("Gitea OAuth code exchange failed: %v", err)
|
||||||
http.Error(w, "Gitea sign-in failed", http.StatusBadGateway)
|
http.Error(w, "Gitea sign-in failed", http.StatusBadGateway)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -154,7 +156,7 @@ func (s *Server) exchangeOAuthCode(ctx context.Context, code string) (giteaUser,
|
|||||||
request, err := http.NewRequestWithContext(
|
request, err := http.NewRequestWithContext(
|
||||||
ctx,
|
ctx,
|
||||||
http.MethodPost,
|
http.MethodPost,
|
||||||
joinURL(s.cfg.GiteaURL, "/login/oauth/access_token"),
|
joinURL(s.cfg.GiteaInternalURL, "/login/oauth/access_token"),
|
||||||
strings.NewReader(form.Encode()),
|
strings.NewReader(form.Encode()),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -181,7 +183,7 @@ func (s *Server) exchangeOAuthCode(ctx context.Context, code string) (giteaUser,
|
|||||||
request, err = http.NewRequestWithContext(
|
request, err = http.NewRequestWithContext(
|
||||||
ctx,
|
ctx,
|
||||||
http.MethodGet,
|
http.MethodGet,
|
||||||
joinURL(s.cfg.GiteaURL, "/api/v1/user"),
|
joinURL(s.cfg.GiteaInternalURL, "/api/v1/user"),
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+13
-1
@@ -15,6 +15,7 @@ type Config struct {
|
|||||||
PublicURL *url.URL
|
PublicURL *url.URL
|
||||||
DatabaseDSN string
|
DatabaseDSN string
|
||||||
GiteaURL *url.URL
|
GiteaURL *url.URL
|
||||||
|
GiteaInternalURL *url.URL
|
||||||
GiteaClientID string
|
GiteaClientID string
|
||||||
GiteaClientSecret string
|
GiteaClientSecret string
|
||||||
GiteaPackageOwner string
|
GiteaPackageOwner string
|
||||||
@@ -65,6 +66,14 @@ func LoadConfig() (Config, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return cfg, err
|
return cfg, err
|
||||||
}
|
}
|
||||||
|
cfg.GiteaInternalURL, err = parseURLValue(
|
||||||
|
"TAPM_GITEA_INTERNAL_URL",
|
||||||
|
envDefault("TAPM_GITEA_INTERNAL_URL", "http://gitea:3000"),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, err
|
||||||
|
}
|
||||||
cfg.CookieSecure = cfg.PublicURL.Scheme == "https"
|
cfg.CookieSecure = cfg.PublicURL.Scheme == "https"
|
||||||
|
|
||||||
cfg.DefaultDuration, err = time.ParseDuration(
|
cfg.DefaultDuration, err = time.ParseDuration(
|
||||||
@@ -137,7 +146,10 @@ func LoadConfig() (Config, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseAbsoluteURL(name string, allowInsecureHTTP bool) (*url.URL, error) {
|
func parseAbsoluteURL(name string, allowInsecureHTTP bool) (*url.URL, error) {
|
||||||
raw := os.Getenv(name)
|
return parseURLValue(name, os.Getenv(name), allowInsecureHTTP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseURLValue(name string, raw string, allowInsecureHTTP bool) (*url.URL, error) {
|
||||||
parsed, err := url.Parse(raw)
|
parsed, err := url.Parse(raw)
|
||||||
validScheme := parsed != nil && parsed.Scheme == "https"
|
validScheme := parsed != nil && parsed.Scheme == "https"
|
||||||
if allowInsecureHTTP && parsed != nil && parsed.Scheme == "http" {
|
if allowInsecureHTTP && parsed != nil && parsed.Scheme == "http" {
|
||||||
|
|||||||
@@ -47,4 +47,19 @@ func TestHTTPSConfigUsesSecureCookies(t *testing.T) {
|
|||||||
if !cfg.CookieSecure {
|
if !cfg.CookieSecure {
|
||||||
t.Fatal("HTTPS mode did not enable secure cookies")
|
t.Fatal("HTTPS mode did not enable secure cookies")
|
||||||
}
|
}
|
||||||
|
if got := cfg.GiteaInternalURL.String(); got != "http://gitea:3000" {
|
||||||
|
t.Fatalf("GiteaInternalURL = %q, want private Compose URL", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigAcceptsExplicitInternalGiteaURL(t *testing.T) {
|
||||||
|
setRequiredConfigEnvironment(t, "https")
|
||||||
|
t.Setenv("TAPM_GITEA_INTERNAL_URL", "http://gitea-test:3000")
|
||||||
|
cfg, err := LoadConfig()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if got := cfg.GiteaInternalURL.String(); got != "http://gitea-test:3000" {
|
||||||
|
t.Fatalf("GiteaInternalURL = %q, want configured private URL", got)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ func (s *Server) handlePackageDownload(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
registryURL := joinURL(
|
registryURL := joinURL(
|
||||||
s.cfg.GiteaURL,
|
s.cfg.GiteaInternalURL,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"/api/packages/%s/generic/%s/%s/%s",
|
"/api/packages/%s/generic/%s/%s/%s",
|
||||||
url.PathEscape(s.cfg.GiteaPackageOwner),
|
url.PathEscape(s.cfg.GiteaPackageOwner),
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ func (s *Server) streamPackageToGitea(
|
|||||||
source io.Reader,
|
source io.Reader,
|
||||||
) (string, int64, int, error) {
|
) (string, int64, int, error) {
|
||||||
registryURL := joinURL(
|
registryURL := joinURL(
|
||||||
s.cfg.GiteaURL,
|
s.cfg.GiteaInternalURL,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"/api/packages/%s/generic/%s/%s/%s",
|
"/api/packages/%s/generic/%s/%s/%s",
|
||||||
url.PathEscape(s.cfg.GiteaPackageOwner),
|
url.PathEscape(s.cfg.GiteaPackageOwner),
|
||||||
@@ -289,7 +289,7 @@ func (s *Server) deletePackageVersion(
|
|||||||
packageVersion string,
|
packageVersion string,
|
||||||
) error {
|
) error {
|
||||||
registryURL := joinURL(
|
registryURL := joinURL(
|
||||||
s.cfg.GiteaURL,
|
s.cfg.GiteaInternalURL,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"/api/packages/%s/generic/%s/%s",
|
"/api/packages/%s/generic/%s/%s",
|
||||||
url.PathEscape(s.cfg.GiteaPackageOwner),
|
url.PathEscape(s.cfg.GiteaPackageOwner),
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ func TestStreamPackageToGitea(t *testing.T) {
|
|||||||
server := &Server{
|
server := &Server{
|
||||||
cfg: Config{
|
cfg: Config{
|
||||||
GiteaURL: registryURL,
|
GiteaURL: registryURL,
|
||||||
|
GiteaInternalURL: registryURL,
|
||||||
GiteaPackageOwner: "TAI",
|
GiteaPackageOwner: "TAI",
|
||||||
GiteaWriteUser: "publisher",
|
GiteaWriteUser: "publisher",
|
||||||
GiteaWriteToken: "write-token",
|
GiteaWriteToken: "write-token",
|
||||||
@@ -112,6 +113,7 @@ func TestDeletePackageVersion(t *testing.T) {
|
|||||||
server := &Server{
|
server := &Server{
|
||||||
cfg: Config{
|
cfg: Config{
|
||||||
GiteaURL: registryURL,
|
GiteaURL: registryURL,
|
||||||
|
GiteaInternalURL: registryURL,
|
||||||
GiteaPackageOwner: "TAI",
|
GiteaPackageOwner: "TAI",
|
||||||
GiteaWriteUser: "publisher",
|
GiteaWriteUser: "publisher",
|
||||||
GiteaWriteToken: "write-token",
|
GiteaWriteToken: "write-token",
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ assert_env() {
|
|||||||
assert_env 'SSL_MODE=none'
|
assert_env 'SSL_MODE=none'
|
||||||
assert_env 'TAPM_PUBLIC_URL=http://broker.test:8780'
|
assert_env 'TAPM_PUBLIC_URL=http://broker.test:8780'
|
||||||
assert_env 'TAPM_GITEA_URL=http://git.test:8780'
|
assert_env 'TAPM_GITEA_URL=http://git.test:8780'
|
||||||
|
assert_env 'TAPM_GITEA_INTERNAL_URL=http://gitea:3000'
|
||||||
assert_env 'GITEA_PUBLIC_URL=http://git.test:8780/'
|
assert_env 'GITEA_PUBLIC_URL=http://git.test:8780/'
|
||||||
grep -F -- '-f compose.yaml -f compose.http.yaml up -d gitea nginx' \
|
grep -F -- '-f compose.yaml -f compose.http.yaml up -d gitea nginx' \
|
||||||
"$MOCK_DOCKER_LOG" >/dev/null || {
|
"$MOCK_DOCKER_LOG" >/dev/null || {
|
||||||
|
|||||||
Reference in New Issue
Block a user