Skip to content

Commit

Permalink
Add DEP 2876
Browse files Browse the repository at this point in the history
Signed-off-by: Andy Lo-A-Foe <andy.loafoe@gmail.com>
  • Loading branch information
loafoe committed May 17, 2023
1 parent 6b3ed9a commit 985f7b1
Showing 1 changed file with 120 additions and 0 deletions.
120 changes: 120 additions & 0 deletions docs/enhancements/extend-payload-2023-05-17-#2876.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Dex Enhancement Proposal (DEP) 2876 - 2023-05-17 - Extend payload

## Table of Contents

- [Summary](#summary)
- [Motivation](#motivation)
- [Goals/Pain](#goals)
- [Non-Goals](#non-goals)
- [Proposal](#proposal)
- [User Experience](#user-experience)
- [Implementation Details/Notes/Constraints](#implementation-detailsnotesconstraints)
- [Risks and Mitigations](#risks-and-mitigations)
- [Alternatives](#alternatives)
- [Future Improvements](#future-improvements)

## Summary

Dex has very rigid claims support. Adding additional claims via a connector requires forking the code and making changes to various internal structures. There are a number of proposals where this discussed, namely #1635 .
The scope of these is fairly large and we are exploring a possible solution that limits itself to just
mutating of the claims.

## Context

- #1636

## Motivation

### Goals

The working goals of this proposal are:

- Minimal changes to Dex core source
- Provide an optional Go Interface specification connectors can implement to support extending token payload
- Limit the interface to a sing method which allows mutating all claims before Dex core signs and delivers it

### Non-goals

- We will not explore dynamic loading. This is a future topic.

## Proposal

### User Experience

The implementation is fully backwards compatible. Users not requiring this
feature won't have to change anything in their Dex deployment.

We expect that connectors will expose additional configuration options to allow for customizations
of the payload extender functionality. Examples are toggles to include/exclude certain IDP claims

### Implementation Details/Notes/Constraints

We propose adding a new PayloadExtender interface which connectors can choose to implement:

```golang
// PayloadExtender allows connectors to enhance the payload before signing
type PayloadExtender interface {
ExtendPayload(scopes []string, payload []byte, connectorData []byte) ([]byte, error)
}
```

The `ExtendPayload` method will be called just before the `JWT` is signed by Dex core.

By implementing this interface connectors get a chance to mutate the `id_token` payload
before signature creation. The `scopes` may be used to perform conditional mutation.
The `payload` is passed as a byte array as well as the `connectorData` associated with the authorization request. This allows the connector to pass session specific context via `connectorData`.
The resulting mutated structure is returned including an `error` condition.

> A separate DEP will be created to propopse `Dynamic Scopes support` so payload extending can be application driven.
### Working example

A working example of this interface implementation could look like this:

```golang
func (c *hsdpConnector) ExtendPayload(scopes []string, payload []byte, cdata []byte) ([]byte, error) {
var cd connectorData
var originalClaims map[string]interface{}

c.logger.Info("ExtendPayload called")

if err := json.Unmarshal(cdata, &cd); err != nil {
return payload, err
}
if err := json.Unmarshal(payload, &originalClaims); err != nil {
return payload, err
}

// Experimental teams
var teams []string
teams = append(teams, cd.Introspect.Organizations.ManagingOrganization)
originalClaims["teams"] = teams

extendedPayload, err := json.Marshal(originalClaims)
if err != nil {
return payload, err
}
return extendedPayload, nil
}
```

This results in a `teams` claim being available in the id_token.

### Risks and Mitigations

Since the claims are mutated / extended from the upstream IDP, any consuming application should
be aware of active payload extending of the connector. Care should be taken by the extender not to
break or remove standard claims. All ExtendPayload implementation should include tests to cover
all common scenarios.

Any connector not implementing the `ExtendPayload` interface should function as before.

### Alternatives

- We looked at KeyCloak to support this but Dex is way lighter in deployment and maintenance.
- Commercial IDP offerings have similar filtering/mutating capabilities but have a lock-in disadvantage.

## Future Improvements

- An DEP will be submitted to support `Dynamic scopes support`
- We want to explore implementing a generic pluggable filtering mechanism which is connector agnostic

0 comments on commit 985f7b1

Please sign in to comment.