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 separates OIDC identity-source initialization from site-access policy updates. Access-only changes skip discovery and do not emit the provider-reload generation, 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 'This release preserves an explicit empty OIDC allowlist on the platform API wire. It avoids the generated setting client omitting an empty value, so a confirmed unrestricted transition durably clears stale restricted identities. Access-only changes continue to skip discovery and provider reload; access expansion remains protected by a single-use MFA confirmation bound to the operator and canonical request digest.\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.38
VERSION_OVERRIDE: v0.4.39
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.38-linux-amd64.tar.xz"
artifact="dist/artifacts/authentication-service-0.4.39-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.38' >/dev/null
evidence/product/authentication-service --version | grep -F '0.4.39' >/dev/null
sha256sum "$artifact" > evidence/authentication-service.tar.xz.sha256
docker run --rm --entrypoint go \
--volume "$PWD:/work:ro" \
Expand Down
3 changes: 3 additions & 0 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ 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.
The empty allowlist must be present as an explicit `value: ""` field in the
platform setting update. Generated client omission rules must not turn the
clear operation into a no-op.

Operator lifecycle messages support `en-US` and `zh-TW`. Tokens, usernames,
groups, identity-provider data, OpenID Connect claims, SAML documents,
Expand Down
12 changes: 8 additions & 4 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 is `v0.4.38`. It retains the existing Ubuntu 26.04,
The current compatibility release is `v0.4.39`. 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 @@ -21,7 +21,7 @@ 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.38` separates OIDC identity-source changes from site-access
Release `v0.4.39` 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, emitting a provider
reload generation, or repeating the five-minute local recovery ceremony.
Expand All @@ -33,6 +33,10 @@ 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.
The unrestricted transition sends an explicit empty allowlist value on the
platform API wire. This prevents the generated client's `omitempty` behavior
from turning a requested clear into an omitted field and retaining stale
restricted identities in the database.

Product-owned imports, executable names, CLI settings, client variables, and
operator messages use PastureStack naming.
Expand All @@ -51,9 +55,9 @@ make build
make package
```

Set `VERSION_OVERRIDE=v0.4.38` for the reviewed identity-security compatibility
Set `VERSION_OVERRIDE=v0.4.39` for the reviewed identity-security compatibility
release. Packaging produces the deterministic, versioned
`authentication-service-0.4.38-linux-amd64.tar.xz` asset. The manually
`authentication-service-0.4.39-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: 6 additions & 2 deletions server/auth_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,8 +483,12 @@ func updateCommonSettings(settings map[string]string) error {
return err
}

setting, err = PlatformClient.Setting.Update(setting, &client.Setting{
Value: value,
// The generated Setting.Value field uses json:",omitempty". A typed
// Setting therefore drops the field when an unrestricted OIDC policy
// intentionally clears the allowlist. Use an explicit wire payload so
// an empty value remains distinguishable from "leave unchanged".
setting, err = PlatformClient.Setting.Update(setting, map[string]interface{}{
"value": value,
})
if err != nil {
log.Errorf("Error updating the setting %v: %v", key, err)
Expand Down
15 changes: 10 additions & 5 deletions server/config_update_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,16 +348,21 @@ func TestPolicyOnlyUpdateClearsStoredAllowlistWithoutDiscovery(t *testing.T) {
return
}
if request.Method == http.MethodPut {
var update struct {
Value string `json:"value"`
}
var update map[string]interface{}
if err := json.NewDecoder(request.Body).Decode(&update); err != nil {
t.Fatal(err)
}
settings[name] = update.Value
rawValue, present := update["value"]
value, stringValue := rawValue.(string)
if !present || !stringValue {
t.Errorf("setting update omitted an explicit string value: %#v", update)
http.Error(response, "missing explicit setting value", http.StatusUnprocessableEntity)
return
}
settings[name] = value
writes = append(writes, name)
_, _ = fmt.Fprintf(response, `{"id":%q,"type":"setting","activeValue":%q,"value":%q,"links":{"self":%q}}`,
name, update.Value, update.Value, platformServer.URL+request.URL.Path)
name, value, value, platformServer.URL+request.URL.Path)
return
}
http.Error(response, "unexpected platform method", http.StatusMethodNotAllowed)
Expand Down