Dex: Connector middleware

Created on 21 Jan 2020  路  11Comments  路  Source: dexidp/dex

Right now connectors implement certain types of behavior that could be reused. The most common example is filtering groups.

Consider creating a common middleware layer for connectors instead of implementing these features (and configuration for them) separately for each connector.

areconnector kinenhancement

Most helpful comment

OK, so my assumption here is that the middleware layer will be passed the identity returned by a successful invocation of a Connector, and will return an (Identity, error) pair. Additionally, multiple middleware components can be stacked, in which case the identity output of one will be passed into the identity input of the next in the stack.

In addition, it looks like the Identity struct will need to be extended to enable custom claims, since middleware that adds custom claims is something people are likely to be interested in (in addition to being able to mutate group names and things). I know we are.

All 11 comments

The most common example is filtering groups.

馃挴 It would be great to refactor that at least. If it fits a more generic pattern (as you described) all the better for it. 馃憤

related → #1790

+1 for this kind of pattern.

Maybe there is something to do/learn from ory oathkeeper: https://www.ory.sh/oathkeeper/docs/pipeline/mutator

(by the way... this kind of feature is awesome and we dream about it @renault :) : https://www.ory.sh/oathkeeper/docs/pipeline/mutator#hydrator)

We're going to want something like this too. If anyone has any suggestions about what designs they might prefer, I might have some time to work on this.

OK, so my assumption here is that the middleware layer will be passed the identity returned by a successful invocation of a Connector, and will return an (Identity, error) pair. Additionally, multiple middleware components can be stacked, in which case the identity output of one will be passed into the identity input of the next in the stack.

In addition, it looks like the Identity struct will need to be extended to enable custom claims, since middleware that adds custom claims is something people are likely to be interested in (in addition to being able to mutate group names and things). I know we are.

I'm fully agree with that.

As a use case : we operate an homemade extensions on Keycloak 馃様 in order to retrieve custom claims in order to enrich the user identity. This extension is a simple http call. I easily imagine a Dex "connector" that can do the same.

This kind of feature is for us very precious.

It would be very interesting to issue an HTTP request from dex and let OPA do the authorization for which claims to include, maybe even handover additional infos like HTTP request headers

馃挱 Just sharing a thought here: It could end up nicely if Dex embedded OPA, exposing an interface similar to what gatekeeper does.

A sketchy adaptation of that model to Dex would look like this:

  1. There are _contraints_, like
constraints:
  - kind: allowedGroups
    match:
    - connector: ldap # some connector ID
    parameters:
      groups:
       - ops
       - admin
  1. and there's _constraint templates_, like
spec:
  crd:
    spec:
      names:
        kind: allowedGroups
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          properties:
            groups:
              type: array
              items: string
  targets:
    - rego: |
        package allowedgroups

        violation[{"msg": msg, "details": {"existing_groups": existing}}] {
          existing := {group | input.review.identity.groups[_]}
          allowed := {group | group := input.parameters.groups[_]}
          overlap := allowed | provided # set intersection
          count(overlap) == 0
          msg := sprintf("must be in one of the allowed groups: %v", [allowed])
        }

The most common constraint templates would be shipped with Dex, but it would also allow creating your own ones, and using them. The constraints would live in the config file, the constraint templates maybe in some other place.

The sketch doesn't include how you'd have the constraints eventually _alter_ the groups, or other claims, of a user, but that's something that could surely be done; but may have to be discussed, too.

This scheme has proven useful for gatekeeper, I believe, as it allows most usecases to be done from configuration without messing with Rego and OPA, but leaves an escape hatch for everyone who has special needs.

Furthermore, Rego policies can do HTTP requests, so this could be an extension point for using another system.

More information about the constraint framework can be found in https://github.com/open-policy-agent/frameworks/tree/master/constraint.

That sounds really interesting.

As far as I can tell, this is mostly useful for policy enforcement. As you also pointed out, it could alter groups and other claims, but I wonder if we should take a more generic approach and make OPA/rego an implementation detail providing policy enforcement.

@sagikazarmark Yeah it would also make for a decent middleware piece, sure. 馃槂

I note that this PR adds a CustomClaims to connector.Identity.

I think that changing connector.Identity in this way is a pre-requisite for external connectors (#1907) as well. If the connectors can't provide custom claims from upstream IDPs, then there will be less information for the middleware to work with.

Was this page helpful?
0 / 5 - 0 ratings