Extending dex to allow additional claims in the JWTs

瀏覽次數:507 次
跳到第一則未讀訊息

Christopher L. Cousins

未讀,
2016年5月3日 晚上8:22:082016/5/3
收件者:CoreOS Dev

Hello,


I am planning on using dex to authenticate users with credentials stored in LDAP.  In addition to the information returned in oidc.Identity, I need to enrich the JWT with additional claims for the users using information that is also stored in LDAP and I would prefer to collect this information right after the user authenticates using their LDAP credentials.


Since the LDAP searches and other logic I need to use to collect this additional information are of no use to anyone else, and I don't like the idea of maintaining a custom branch of dex (modifying the existing LDAP connector), I was thinking about creating a new 'local-http' connector that would allow me to run a companion application next to every dex-worker instance that would handle all of the connector functionally over an HTTP API on the loopback interface.  In my case, this would be sidecar Kubernetes container in a pod that also contains a (hopefully eventually stock) dex-worker container.


I assume there are other users or potential users of dex that have some legacy systems like I do, and it would be easier for them to maintain a separate application with small HTTP API than adding or maintaining connectors to dex that are not necessarily useful to others.  Is this something that anyone else has expressed interest in?


For this type of a connector to be useful to me, I would still need to be able to then enrich the JWTs with additional claims.  oidc.Identity as returned by Identity() today does not allow/encourage this.  Is there another extension point (real or planned) for connectors that would allow me to pass along additional information?


user.AddToClaims() is another potential extension point I found.  I like that it would work for enriching JWTs for oauth2.GrantTypeRefreshToken requests too, however adding the additional claims to this function would require me to use LDAP credentials other than the users, as they are no longer available at the time of this call.  Does anyone think it would be better to add additional claims here instead of from a connector?


Any other ideas on how best to add additional claims?


Thanks,


Brandon Philips

未讀,
2016年5月3日 晚上9:14:092016/5/3
收件者:coreo...@googlegroups.com、Frode Nordahl
cc'ing in Frode who wrote the original LDAP integration. He may have thoughts.

Brandon

Bobby Rullo

未讀,
2016年5月3日 晚上11:11:452016/5/3
收件者:coreo...@googlegroups.com、Frode Nordahl
Hi Christopher,

I'll try to answer best as I can inline:


I am planning on using dex to authenticate users with credentials stored in LDAP.  In addition to the information returned in oidc.Identity, I need to enrich the JWT with additional claims for the users using information that is also stored in LDAP and I would prefer to collect this information right after the user authenticates using their LDAP credentials.


Sounds reasonable so far. 

Since the LDAP searches and other logic I need to use to collect this additional information are of no use to anyone else, and I don't like the idea of maintaining a custom branch of dex (modifying the existing LDAP connector), I was thinking about creating a new 'local-http' connector that would allow me to run a companion application next to every dex-worker instance that would handle all of the connector functionally over an HTTP API on the loopback interface.  In my case, this would be sidecar Kubernetes container in a pod that also contains a (hopefully eventually stock) dex-worker container.

It's an intriguing idea but sound tricky to do given how connectors currently work. Could you sketch out the API you have in mind? 


I assume there are other users or potential users of dex that have some legacy systems like I do, and it would be easier for them to maintain a separate application with small HTTP API than adding or maintaining connectors to dex that are not necessarily useful to others.  Is this something that anyone else has expressed interest in?

Maintaining a patched dex sounds easier than all this, if your patch is just limited to adding a custom connector, is my opinion.
 


For this type of a connector to be useful to me, I would still need to be able to then enrich the JWTs with additional claims.  oidc.Identity as returned by Identity() today does not allow/encourage this.  Is there another extension point (real or planned) for connectors that would allow me to pass along additional information?

I agree with the limitedness of oidc.Identity. A little background here: originally dex was an internal project and in comprised what is now dex, and what is now go-oidc in one project. When we decided to opensource it, we split it up into dex, the IdP, and go-oidc, the OIDC library. Some stuff made it into go-oidc which, in retrospect, probably is dex-specific.

Identity I think is one of those things. off the top of my head: I would do something like the following: remove dex's dependency on the Identity type, and create one within dex. This might be a big change in terms of LOC, but fairly mechanical (I think). Then add something like "other claims" which could just be a Claims object. Then connectors could populate it with whatever they want. 

(And eventually, remove Identity from go-oidc altogether I think)


user.AddToClaims() is another potential extension point I found.  I like that it would work for enriching JWTs for oauth2.GrantTypeRefreshToken requests too, however adding the additional claims to this function would require me to use LDAP credentials other than the users, as they are no longer available at the time of this call.  Does anyone think it would be better to add additional claims here instead of from a connector?


I'm afraid you've lost me here :) What do you mean by  "at the time of this call" - where exactly do you mean? In CodeToken or RefreshToken you mean?

Christopher L. Cousins

未讀,
2016年5月4日 下午3:14:342016/5/4
收件者:CoreOS Dev、frode....@gmail.com
Hello Bobby,

On Tuesday, May 3, 2016 at 8:11:45 PM UTC-7, Bobby Rullo wrote:

[...]
 

Since the LDAP searches and other logic I need to use to collect this additional information are of no use to anyone else, and I don't like the idea of maintaining a custom branch of dex (modifying the existing LDAP connector), I was thinking about creating a new 'local-http' connector that would allow me to run a companion application next to every dex-worker instance that would handle all of the connector functionally over an HTTP API on the loopback interface.  In my case, this would be sidecar Kubernetes container in a pod that also contains a (hopefully eventually stock) dex-worker container.

It's an intriguing idea but sound tricky to do given how connectors currently work. Could you sketch out the API you have in mind? 

I thinking of something similar to the following.

POST /auth

{

  id: string,

  password: string

}


200 OK

{

  id: string,

  email: string,

  name: string,

  claims: {

    claim1: string,

    claim2: [string1, string2, ...]

  }

}

401 by default 

My expectation is the 'local_http' connector would only allow the port and a timeout to be configured and not the hostname to prevent/discourage users from making requests over the network.


dex could then be extended by others without the need to patch dex using a simple adapter application that implements the '/auth' endpoint. The adapter application could be written in any language too, enabling easier integration by groups with legacy libraries not written in Go.


 


I assume there are other users or potential users of dex that have some legacy systems like I do, and it would be easier for them to maintain a separate application with small HTTP API than adding or maintaining connectors to dex that are not necessarily useful to others.  Is this something that anyone else has expressed interest in?

Maintaining a patched dex sounds easier than all this, if your patch is just limited to adding a custom connector, is my opinion.

I agree that it would be easier initially, but not in the medium to long term.  To take advantage of new dex features and capabilities, I would prefer to bump the version number in my k8s deployment spec files over merging the latest changes to a private branch.



For this type of a connector to be useful to me, I would still need to be able to then enrich the JWTs with additional claims.  oidc.Identity as returned by Identity() today does not allow/encourage this.  Is there another extension point (real or planned) for connectors that would allow me to pass along additional information?

I agree with the limitedness of oidc.Identity. A little background here: originally dex was an internal project and in comprised what is now dex, and what is now go-oidc in one project. When we decided to opensource it, we split it up into dex, the IdP, and go-oidc, the OIDC library. Some stuff made it into go-oidc which, in retrospect, probably is dex-specific.

Identity I think is one of those things. off the top of my head: I would do something like the following: remove dex's dependency on the Identity type, and create one within dex. This might be a big change in terms of LOC, but fairly mechanical (I think). Then add something like "other claims" which could just be a Claims object. Then connectors could populate it with whatever they want. 

(And eventually, remove Identity from go-oidc altogether I think)

ok.  I think this would work for oauth2.GrantTypeAuthCode requests, but is not enough for oauth2.GrantTypeRefreshToken requests.  For oauth2.GrantTypeRefreshToken requests to maintain the additional claims, they would need to be persisted along with the refresh token (to keep the same lifecycle) or...


user.AddToClaims() is another potential extension point I found.  I like that it would work for enriching JWTs for oauth2.GrantTypeRefreshToken requests too, however adding the additional claims to this function would require me to use LDAP credentials other than the users, as they are no longer available at the time of this call.  Does anyone think it would be better to add additional claims here instead of from a connector?


I'm afraid you've lost me here :) What do you mean by  "at the time of this call" - where exactly do you mean? In CodeToken or RefreshToken you mean?



For an oauth2.GrantTypeRefreshToken request, any additional claims added by the connector for the original oauth2.GrantTypeAuthCode request will be lost unless they are either persisted to the db or if another LDAP search is performed.  user.AddToClaims() is called for both request types, so I see it as another possible extension point for adding additional claims, but right now my I would prefer to persist them with the refresh token.  Does that make sense?

Frode Nordahl

未讀,
2016年5月4日 下午5:06:052016/5/4
收件者:Christopher L. Cousins、coreo...@googlegroups.com、Brandon Philips
(Sorry for duplicates, had to join the group to be able to send to it.)

> On 4. mai 2016, at 03.13, Brandon Philips <brandon...@coreos.com> wrote:
>
> cc'ing in Frode who wrote the original LDAP integration. He may have thoughts.
>
> Brandon

Thx!

> On Tue, May 3, 2016 at 5:22 PM Christopher L. Cousins <clc....@gmail.com> wrote:
> Hello,
>
> I am planning on using dex to authenticate users with credentials stored in LDAP. In addition to the information returned in oidc.Identity, I need to enrich the JWT with additional claims for the users using information that is also stored in LDAP and I would prefer to collect this information right after the user authenticates using their LDAP credentials.

This is something I would like to see as well. At the time of writing the original LDAP connector code implementing this was out of scope. If someone can point me in the direction of how to return a richer dataset to Dex at time of call to Identity that would be most helpfull.


> Since the LDAP searches and other logic I need to use to collect this additional information are of no use to anyone else, and I don't like the idea of maintaining a custom branch of dex (modifying the existing LDAP connector), I was thinking about creating a new 'local-http' connector that would allow me to run a companion application next to every dex-worker instance that would handle all of the connector functionally over an HTTP API on the loopback interface. In my case, this would be sidecar Kubernetes container in a pod that also contains a (hopefully eventually stock) dex-worker container.


Adding additional claims to the JWT with data from LDAP is most definitely something other users will have use for. Could you describe your use case and I can try to come up with a generic and configurable way to handle it in the LDAP connector.

[ snip ]

--
Frode Nordahl



Christopher L. Cousins

未讀,
2016年5月5日 晚上8:27:492016/5/5
收件者:CoreOS Dev、clc....@gmail.com、brandon...@coreos.com
Hello Frode,

[...]

 
> I am planning on using dex to authenticate users with credentials stored in LDAP.  In addition to the information returned in oidc.Identity, I need to enrich the JWT with additional claims for the users using information that is also stored in LDAP and I would prefer to collect this information right after the user authenticates using their LDAP credentials.

This is something I would like to see as well. At the time of writing the original LDAP connector code implementing this was out of scope. If someone can point me in the direction of how to return a richer dataset to Dex at time of call to Identity that would be most helpfull.

Bobby Rullo mentioned in a previous post that replacing oidc.Identity type with a dex specific type was a possibility.  I don't think this by itself is a enough though, as the additional claims would be lost after a oauth2.GrantTypeRefreshToken request, but it would work great for oauth2.GrantTypeAuthCode requests.  I plan to spend some time tomorrow looking to see if the type needs to be fully replaced or just wrapped with a dex specific type for the IdentityProvider interface.


> Since the LDAP searches and other logic I need to use to collect this additional information are of no use to anyone else, and I don't like the idea of maintaining a custom branch of dex (modifying the existing LDAP connector), I was thinking about creating a new 'local-http' connector that would allow me to run a companion application next to every dex-worker instance that would handle all of the connector functionally over an HTTP API on the loopback interface.  In my case, this would be sidecar Kubernetes container in a pod that also contains a (hopefully eventually stock) dex-worker container.


Adding additional claims to the JWT with data from LDAP is most definitely something other users will have use for. Could you describe your use case and I can try to come up with a generic and configurable way to handle it in the LDAP connector.


My source LDAP system(s) have a history to them, which basically means there is some duplicate data and unclean data.  I'm not sure a something like issue 432 would quite solve it, but the need is very similar.  Basically after finding the user (or users that are really one user), I need to search multiple DNs looking for groupOfNames the user is a member of, then filter that list down to only the groups needed by systems that will use OIDC for authentication.

Christopher L. Cousins

未讀,
2016年5月5日 晚上8:39:482016/5/5
收件者:CoreOS Dev、frode....@gmail.com
Hello Bobby,

For this type of a connector to be useful to me, I would still need to be able to then enrich the JWTs with additional claims.  oidc.Identity as returned by Identity() today does not allow/encourage this.  Is there another extension point (real or planned) for connectors that would allow me to pass along additional information?

I agree with the limitedness of oidc.Identity. A little background here: originally dex was an internal project and in comprised what is now dex, and what is now go-oidc in one project. When we decided to opensource it, we split it up into dex, the IdP, and go-oidc, the OIDC library. Some stuff made it into go-oidc which, in retrospect, probably is dex-specific.

Identity I think is one of those things. off the top of my head: I would do something like the following: remove dex's dependency on the Identity type, and create one within dex. This might be a big change in terms of LOC, but fairly mechanical (I think). Then add something like "other claims" which could just be a Claims object. Then connectors could populate it with whatever they want.

Rather than creating a type specific to dex, is there any reason to not modify the existing oidc.Identity type to support additional claims?  For my specific needs, the changes I'm interested in for the type are not really dex specific, but are specific to oidc.

Frode Nordahl

未讀,
2016年5月15日 下午3:32:372016/5/15
收件者:Christopher L. Cousins、CoreOS Dev

I’m in the process of preparing a patch to extend the go-oidc Identity with all the standard claims as well as a way to handle additional claims.

--
Frode Nordahl



回覆所有人
回覆作者
轉寄
0 則新訊息