sso: support public MCIAS authorize URL for non-Tailnet browsers

Add [sso].public_url: the browser-facing MCIAS base URL for the SSO
authorize redirect, kept separate from [mcias].server_url (the internal
address used for the server-to-server code exchange). Enables public SSO
without routing internal auth through the edge. Bumps mcdsl to v1.9.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Kyle Isom
2026-06-11 11:06:43 -07:00
parent bed563fd20
commit ee31dff01e
7 changed files with 48 additions and 17 deletions

View File

@@ -65,11 +65,11 @@ func Open(path string) (*sql.DB, error) {
// connection to serialize all access and eliminate busy errors.
database.SetMaxOpenConns(1)
// Ensure permissions are correct even if the file already existed.
if err := os.Chmod(path, 0600); err != nil {
_ = database.Close()
return nil, fmt.Errorf("db: chmod %s: %w", path, err)
}
// Best-effort permissions tightening. This may fail inside rootless
// podman containers where fchmod is denied in the user namespace.
// The database still functions correctly without it.
// See: log/2026-04-03-uid-incident.md
_ = os.Chmod(path, 0600)
return database, nil
}
@@ -168,9 +168,7 @@ func Snapshot(database *sql.DB, destPath string) error {
return fmt.Errorf("db: snapshot: %w", err)
}
if err := os.Chmod(destPath, 0600); err != nil {
return fmt.Errorf("db: chmod snapshot %s: %w", destPath, err)
}
_ = os.Chmod(destPath, 0600) // best-effort; may fail in rootless containers
return nil
}

View File

@@ -39,9 +39,18 @@ const (
// Config holds the SSO client configuration. The values must match the
// SSO client registration in MCIAS config.
type Config struct {
// MciasURL is the base URL of the MCIAS server.
// MciasURL is the base URL of the MCIAS server used for the
// server-to-server authorization-code exchange. This is typically the
// internal/Tailnet address so the exchange does not depend on the public
// edge.
MciasURL string
// PublicURL, when set, is the browser-facing MCIAS base URL used to build
// the authorize redirect. It must be resolvable and reachable by end-user
// browsers (e.g. the public hostname). When empty, MciasURL is used for
// both, which only works when MciasURL is itself browser-reachable.
PublicURL string
// ClientID is the registered SSO client identifier.
ClientID string
@@ -104,9 +113,19 @@ func New(cfg Config) (*Client, error) {
}, nil
}
// AuthorizeURL returns the MCIAS authorize URL with the given state parameter.
// authorizeBase returns the browser-facing MCIAS base URL: PublicURL when
// configured, otherwise MciasURL.
func (c *Client) authorizeBase() string {
if c.cfg.PublicURL != "" {
return c.cfg.PublicURL
}
return c.cfg.MciasURL
}
// AuthorizeURL returns the MCIAS authorize URL (browser-facing) with the
// given state parameter.
func (c *Client) AuthorizeURL(state string) string {
base := strings.TrimRight(c.cfg.MciasURL, "/")
base := strings.TrimRight(c.authorizeBase(), "/")
return base + "/sso/authorize?" + url.Values{
"client_id": {c.cfg.ClientID},
"redirect_uri": {c.cfg.RedirectURI},

2
vendor/modules.txt vendored
View File

@@ -2,7 +2,7 @@
## explicit; go 1.24.0
git.wntrmute.dev/kyle/goutils/certlib/certgen
git.wntrmute.dev/kyle/goutils/lib
# git.wntrmute.dev/mc/mcdsl v1.7.0
# git.wntrmute.dev/mc/mcdsl v1.9.0
## explicit; go 1.25.7
git.wntrmute.dev/mc/mcdsl/auth
git.wntrmute.dev/mc/mcdsl/config