daml/triggers/service/authentication.md
Andreas Herrmann 199c52fd79
Don't always redirect to /login automatically (#8532)
* Don't always redirect to /login automatically

The redirect mode can be configured to never redirect, always redirect,
or redirect based on the request type (redirect for text/html).

In case of no redirect the auth middleware client will reply with 401
Unauthorized with a custom WWW-Authenticate challenge to login on the
auth middleware.

* Make login to redirect configurable on trigger service

By default the trigger service will redirect for HTML requests and not
redirect for JSON requests. The test suite uses automatic redirect as
the OAuth2 test server works without user interaction.

changelog_begin
changelog_end

* Preserve path and query in authMiddlewareUri

This is necessary if the auth middleware lies behind a reverse proxy
with a path prefix or a similar setup.

* Bump default auth middleware login timeout

One minute was to short for a login cycle that requires manual user
input.

* Set token cookie properties

`path = "/"` is required so that the `/login` endpoint can reliably
override the cookie value for other endoints such as `/cb` or
`/v1/triggers`.

* Test redirectToLogin modes

* Redirect on HTML

https://github.com/digital-asset/daml/pull/8532#discussion_r559368335

* Use pass/reject in onRedirectToLogin

8db2bff9af (r559370308)

* default login timeout 5min

https://github.com/digital-asset/daml/pull/8532#discussion_r559535511

Co-authored-by: Andreas Herrmann <andreas.herrmann@tweag.io>
2021-01-18 14:03:39 +00:00

91 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Design for Trigger Service Authentication/Authorization
## Goals
- Be compatible with an OAuth2 authorization code grant
https://tools.ietf.org/html/rfc6749#section-4.1
- Do not require OAuth2 or any other specific
authentication/authorization protocol from the IAM. In other words,
the communication with the IAM must be pluggable.
- Do not rely on wildcard access for the trigger service, it should
only be able to start triggers on behalf of a party if a user that
controls that party has given consent.
- Support long-running triggers without constant user
interaction. Since auth tokens are often short-lived (e.g., expire
after 1h), this implies some mechanism for token refresh.
## Design
This involves 3 components:
1. The trigger service provided by DA.
2. An auth middleware. DA provides an implementation of this for at
least the OAuth2 authorization code grant but this is completely
pluggable so if the DA-provided middleware does not cover the IAM
infrastructure of a client, they can implement their own.
3. The IAM. This is the entity that signs Ledger API tokens. This is
not provided by DA. The Ledger is configured to trust this entity.
### Auth Middleware API
The auth middleware provides a few endpoints (the names dont matter
all that much, they just need to be fixed once).
1. /auth The trigger service, will contact this endpoint with a set of
claims passing along all cookies in the original request. If
the user has already authenticated and is authorized for those
claims, it will return an access token (an opaque blob to the
trigger service) for at least those claims and a refresh token
(another opaque blob). If not, it will return an unauthorized
status code.
2. /login If /auth returned unauthorized, the trigger service will
redirect users to this.
For HTML requests via HTTP redirect, otherwise via a custom WWW-Authenticate challenge in a 401 resonse.
The parameters will include the requested claims as well as an optional callback URL (note that this is not the OAuth2 callback url but a callback URL on the trigger service). This will start an auth flow,
e.g., an OAuth2 authorization code grant. If the flow succeeds the
auth service will set a cookie with the access and refresh token
and redirect to the callback URL if present or return status code 200.
At this point, a request to
/auth will succeed (based on the cookie). If the flow failed the
auth service will not set a cookie and redirect to the callback URL
with an additional error and optional error_description parameter
or return 403 with error and optional error_description in the response body.
3. /refresh This accepts a refresh token and returns a new access
token and optionally a new refresh token (or fails).
### Auth Middleware Implementation based on OAuth2 Authorization Code Grant
1. /auth checks for the presence of a cookie with the tokens in it.
2. /login starts an OAuth2 authorization code grant flow. After the
redirect URI is called by the authorization server, the middleware
makes a request to get the tokens, sets them in cookies and
redirects back to the callback URI. Upon failure the middleware
forwards the error and error_description to the callback URI.
3. /refresh simply proxies to the refresh endpoint on the
authorization server adding the client id and secret.
Note that the auth middleware does not need to persist any state in
this model. The trigger service does need to persist at least the
refresh token and potentially the access token.
## Related Projects
The design here is very close to existing OAuth2 middlewares/proxies
such as [Vouch](https://github.com/vouch/vouch-proxy) or [OAuth2
Proxy](https://github.com/oauth2-proxy/oauth2-proxy). There are two
main differences:
1. The trigger service extracts the required claims from the original
request. This means that the first request goes to the trigger
service and not to the proxy/middleware. The middleware shouldnt
have to know how to map a request to the set of required claims so
this seems the only workable option.
2. The /auth request takes a custom set of claims. The existing
proxies focus on OIDC and dont support any custom claims.
Nevertheless, the fact that the design is very close to existing
proxies seems like a good thing.