Add a new Stateful type implementing the stateful authentication flow
from Pomerium v0.20 and earlier.
This consists mainly of logic from authenticate/handlers.go prior to
commits 57217af and 539fd51.
One significant change is to set the default IdP ID when an IdP ID is
not provided in the request URL (e.g. when signing in directly at the
authenticate service domain). Otherwise, if session state is stored with
an empty IdP ID, it won't be valid for any route.
Move the Stateless.logAuthenticateEvent() method into the main
stateless.go file.
(This was in events.go temporarily so that Git would track the file
history as a rename from authenticate/events.go.)
Consolidate all logic specific to the stateless authenticate flow into a
a new Stateless type in a new package internal/authenticateflow. This is
in preparation for adding a new Stateful type implementing the older
stateful authenticate flow (from Pomerium v0.20 and previous).
This change is intended as a pure refactoring of existing logic, with no
changes in functionality.
If a request is made to the Pomerium metrics endpoint with an Accept
header requesting the Prometheus protobuf exposition format, some
metrics will be missing from the response.
These missing metrics are obtained by replaying the incoming request to
an OpenCensus metrics exporter. This exporter honors the request for the
protobuf format, however Pomerium expects this response to be in the
text format.
We can avoid this mismatch by explicitly requesting the text format from
the OpenCensus exporter, regardless of the incoming request's Accept
header.
(Note: the Pomerium metrics endpoint always responds with text format
metrics, even if the protobuf format is requested.)
Currently the RunWithRestart() loop may not exit when execFn returns an
error unrelated to its context cancellation. Add an additional check for
this case.
Update the AccessTracker, WebAuthn handlers, and identity manager
refresh loop to perform their session record updates using the
databroker Patch() method.
This should prevent any of these updates from conflicting.
* core/config: refactor file watcher
* add comments
* updates
* only use the polling watcher
* fix test
* fix test
* try to fix test again
* remove batching
* dont rely on file modification timestamp
* remove benchmark
* try fix again
Add a Patch() method to the databroker gRPC service.
Update the storage.Backend interface to include the Patch() method now
that all the storage.Backend implementations include it.
Add a test to exercise the patch method under concurrent usage.
Remove the Redis databroker backend. According to
https://www.pomerium.com/docs/internals/data-storage#redis it has been
discouraged since Pomerium v0.18.
Update the config options validation to return an error if "redis" is
set as the databroker storage backend type.
* core/config: refactor change dispatcher
* update test
* close listener go routine when context is canceled
* use cancel cause
* use context
* add more time
* more time
Currently, if a temporary error occurs while attempting to refresh an
OAuth2 token, the identity manager won't schedule another attempt.
Instead, update the session refresh logic so that it will retry after
temporary errors. Extract the bulk of this logic into a separate method
that returns a boolean indicating whether to schedule another refresh.
Update the unit test to simulate a temporary error during OAuth2 token
refresh.
The databroker identity manager is responsible for refreshing session
records, to account for overall session expiration as well as OAuth2
access token expiration.
Refresh events are scheduled subject to a coolOffDuration (10 seconds,
by default) relative to a lastRefresh timestamp. Currently, any update
to a session record will reset the associated lastRefresh value and
reschedule any pending refresh event for that session. If an update
occurs close before a scheduled refresh event, this will push back the
scheduled refresh event to 10 seconds from that time.
This means that if a session is updated frequently enough (e.g. if there
is a steady stream of requests that cause constant updates via the
AccessTracker), the access token may expire before a refresh ever runs.
To avoid this problem, do not update the lastRefresh time upon every
session record update, but only if it hasn't yet been set. Instead,
update the lastRefresh during the refresh attempt itself.
Add unit tests to exercise these changes. There is a now() function as
part of the manager configuration (to allow unit tests to set a fake
time); update the Manager to use this function throughout.
The current session refresh loop attempts to refresh access tokens when
they are due to expire in less than one minute. However, the code to
perform the refresh relies on a TokenSource from the x/oauth2 package,
which has its own internal 'expiryDelta' threshold, with a default of
10 seconds. As a result, the first four or five attempts to refresh a
particular access token will not actually refresh the token. The refresh
will happen only when the access token is within 10 seconds of expiring.
Instead, before we obtain a new TokenSource, first clear any existing
access token. This causes the TokenSource to consider the token invalid,
triggering a refresh. This should give the refresh loop more control
over when refreshes happen.
Consolidate this logic in a new Refresh() method in the oidc package.
Add unit tests for this new method.
* config: add customization options for logging
* config: validate log fields
* proxy: add support for logging http request headers
* log subset of headers
* add support for logging the http query
* fix test name
* use strings.Cut, add unit tests
* config: add customization options for logging
* config: validate log fields
* proxy: add support for logging http request headers
* log subset of headers
* fix test name
* dont use log.HTTPHeaders for access logs
* canonicalize http/2 headers
Configure Envoy to validate client certificates, using the union of all
relevant client CA bundles (that is, a bundle of the main client CA
setting together with all per-route client CAs). Pass the validation
status from Envoy through to the authorize service, by configuring Envoy
to use the newly-added SetClientCertificateMetadata filter, and by also
adding the relevant metadata namespace to the ExtAuthz configuration.
Remove the existing 'include_peer_certificate' setting from the ExtAuthz
configuration, as the metadata from the Lua filter will include the full
certificate chain (when it validates successfully by Envoy).
Update policy evaluation to consider the validation status from Envoy,
in addition to its own certificate chain validation. (Policy evaluation
cannot rely solely on the Envoy validation status while we still support
the per-route client CA setting.)