Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ jobs:

{
printf '# PastureStack Authentication Service %s\n\n' "$RELEASE_TAG"
printf 'This release provides provider-neutral OpenID Connect authorization-code authentication, a short-lived signed identity proof for explicit account linking or reassignment, transactional provider switching, and local-administrator recovery without username or email guessing.\n\n'
printf 'This release separates OIDC identity-source initialization from site-access policy updates. Access-only changes skip discovery, unrestricted mode clears the allowlist, restricted and required policies accept only deduplicated OIDC users and groups, and access expansion requires a single-use MFA confirmation bound to the operator and canonical request digest. Initial enablement and identity-source changes retain the fresh local-recovery gate.\n\n'
printf '## Immutable coordinates\n\n'
printf -- '- Source commit: `%s`\n' "$SOURCE_SHA"
printf -- '- Artifact SHA-256: `%s`\n\n' "$artifact_sha"
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/security-release-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
env:
DAPPER_IMAGE: pasturestack/authentication-service-dapper:${{ github.sha }}
TRIVY_IMAGE: aquasec/trivy:0.73.0@sha256:7cced7cae583819fc7806d4cbc0dbbc7cad18b99f7d3e235192e6da8c091045c
VERSION_OVERRIDE: v0.4.36
VERSION_OVERRIDE: v0.4.37
steps:
- name: Check out candidate
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down Expand Up @@ -70,7 +70,7 @@ jobs:
}

run_ci
artifact="dist/artifacts/authentication-service-0.4.36-linux-amd64.tar.xz"
artifact="dist/artifacts/authentication-service-0.4.37-linux-amd64.tar.xz"
test -s "$artifact"
cp "$artifact" /tmp/authentication-service-first.tar.xz
rm -rf bin dist
Expand All @@ -81,7 +81,7 @@ jobs:
tar -xJf "$artifact" -C evidence/product
test -x evidence/product/authentication-service
test "$(find evidence/product -maxdepth 1 -type f | wc -l)" -eq 1
evidence/product/authentication-service --version | grep -F '0.4.36' >/dev/null
evidence/product/authentication-service --version | grep -F '0.4.37' >/dev/null
sha256sum "$artifact" > evidence/authentication-service.tar.xz.sha256
docker run --rm --entrypoint go \
--volume "$PWD:/work:ro" \
Expand Down
16 changes: 16 additions & 0 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@ the active authentication method changes. Existing local authentication
remains the recovery path until a second, fresh authorization-code exchange
creates a normal platform session.

## OIDC site-access policy updates

OIDC provider initialization and site-access authorization are independent
transactions. Updating only `accessMode` or `allowedIdentities` on an already
enabled, unchanged OIDC provider must not repeat discovery, key retrieval, or
provider initialization. Initial enablement, changing provider type, or
changing the OIDC identity source still requires a fresh local-recovery check
and successful provider initialization.

Expanding access requires a one-time Engine MFA security confirmation bound to
the authenticated operator, purpose `oidcAccessPolicyUpdate`, and the canonical
SHA-256 request digest. Reducing access does not require step-up confirmation.
Unrestricted mode persists a non-null empty allowlist. Restricted and required
mode entries are canonicalized and deduplicated by `externalIdType` plus
`externalId`; only `oidc_user` and `oidc_group` are accepted.

Operator lifecycle messages support `en-US` and `zh-TW`. Tokens, usernames,
groups, identity-provider data, OpenID Connect claims, SAML documents,
database settings, HTTP payloads, and protocol errors are not translated.
Expand Down
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ PastureStack is an independent community effort to preserve, audit, and moderniz

## Project status

The current compatibility release retains the existing Ubuntu 26.04,
The current compatibility release is `v0.4.37`. It retains the existing Ubuntu 26.04,
Go 1.27.0, JWT, cookie, TLS, LDAP, GitHub, Shibboleth,
dependency, and build maintenance. It adds a provider-neutral OpenID Connect
authorization-code client with discovery, PKCE S256, nonce validation,
Expand All @@ -20,6 +20,19 @@ Successful staged sign-in also produces a short-lived, audience-bound,
single-use signed identity proof. The control platform uses that proof for an
explicit account-link or reassignment decision; profile fields are never
trusted as implicit account-matching keys.

Release `v0.4.37` separates OIDC identity-source changes from site-access
policy changes. An already-enabled provider can change access mode and its
OIDC user/group allowlist without repeating discovery or the five-minute local
recovery ceremony. Initial enablement, provider switches, and changes to the
discovery URL, client credentials, custom CA, scopes, PKCE, or identity claims
still require fresh local recovery and provider validation. Access expansion
requires a single-use MFA confirmation bound to the authenticated operator and
the canonical request digest. Unrestricted mode always persists an explicit
empty allowlist; restricted and required modes accept and deduplicate only
`oidc_user` and `oidc_group` identities. Stable error codes distinguish local
recovery, MFA confirmation, and invalid access-policy failures.

Product-owned imports, executable names, CLI settings, client variables, and
operator messages use PastureStack naming.

Expand All @@ -37,9 +50,9 @@ make build
make package
```

Set `VERSION_OVERRIDE=v0.4.36` for the reviewed identity-security compatibility
Set `VERSION_OVERRIDE=v0.4.37` for the reviewed identity-security compatibility
release. Packaging produces the deterministic, versioned
`authentication-service-0.4.36-linux-amd64.tar.xz` asset. The manually
`authentication-service-0.4.37-linux-amd64.tar.xz` asset. The manually
dispatched release workflow runs the full test and validation suite twice,
requires byte-identical packages, verifies a fixed and attested security
scanner, publishes CycloneDX SBOMs and scan evidence, and publishes the
Expand Down
8 changes: 8 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ administrator testing before activation.
replay-protected by the control platform. It carries the exact provider and
immutable external identifier used for an explicit account-link decision;
usernames and email addresses are display data, not matching keys.
- Expanding OIDC site access requires a single-use MFA confirmation bound to
the authenticated operator, the fixed policy-update purpose, and a canonical
SHA-256 request digest. The confirmation value is detached before provider
normalization or persistence and is never written to settings or logs.
- Unrestricted OIDC access always clears the stored identity allowlist. Other
access modes accept only canonical `oidc_user` and `oidc_group` principals;
duplicate or delimiter-injecting entries are rejected or deduplicated before
storage.
- Do not commit keys, credentials, tokens, encrypted production settings, identity data, or live assertions.

## Dependency and build evidence
Expand Down
17 changes: 9 additions & 8 deletions model/auth_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import "github.com/rancher/go-rancher/v2"
// AuthConfig structure contains the AuthConfig definition
type AuthConfig struct {
client.Resource
Provider string `json:"provider"`
Enabled bool `json:"enabled"`
AccessMode string `json:"accessMode"`
AllowedIdentities []client.Identity `json:"allowedIdentities"`
GithubConfig GithubConfig `json:"githubConfig"`
ShibbolethConfig ShibbolethConfig `json:"shibbolethConfig"`
LdapConfig LdapConfig `json:"ldapConfig"`
OIDCConfig OIDCConfig `json:"oidcConfig"`
Provider string `json:"provider"`
Enabled bool `json:"enabled"`
AccessMode string `json:"accessMode"`
AllowedIdentities []client.Identity `json:"allowedIdentities"`
GithubConfig GithubConfig `json:"githubConfig"`
ShibbolethConfig ShibbolethConfig `json:"shibbolethConfig"`
LdapConfig LdapConfig `json:"ldapConfig"`
OIDCConfig OIDCConfig `json:"oidcConfig"`
SecurityConfirmation string `json:"securityConfirmation,omitempty"`
}

type TestAuthConfig struct {
Expand Down
6 changes: 4 additions & 2 deletions model/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import "github.com/rancher/go-rancher/client"
// AuthServiceError structure contains the error resource definition
type AuthServiceError struct {
client.Resource
Status string `json:"status"`
Message string `json:"message"`
Status string `json:"status"`
Code string `json:"code,omitempty"`
Message string `json:"message"`
RequestDigest string `json:"requestDigest,omitempty"`
}
6 changes: 6 additions & 0 deletions providers/oidc/oidc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ func normalizeConfig(config *model.OIDCConfig) {
}
}

// NormalizeConfig applies the same canonical defaults used by the live OIDC
// client without performing discovery or making a network request.
func NormalizeConfig(config *model.OIDCConfig) {
normalizeConfig(config)
}

func validateConfig(config *model.OIDCConfig) error {
if config.WellKnownURL == "" {
return fmt.Errorf("OIDC discovery URL is required")
Expand Down
7 changes: 6 additions & 1 deletion providers/oidc/oidc_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,12 @@ func (p *Provider) GetConfig() model.AuthConfig {
}

func (p *Provider) GetSettings() map[string]string {
config := p.client.config
return SettingsForConfig(*p.client.config)
}

// SettingsForConfig serializes OIDC settings without initializing the
// provider. It is used for display-only updates that must not repeat discovery.
func SettingsForConfig(config model.OIDCConfig) map[string]string {
settings := map[string]string{
displayNameSetting: config.DisplayName,
wellKnownURLSetting: config.WellKnownURL,
Expand Down
Loading