Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Token Introspection Policy to get client information from "oidc_issuer_endpoint". #755

Merged

Conversation

y-tabata
Copy link
Contributor

@y-tabata y-tabata commented Jun 8, 2018

Since it is troublesome to define the client_id and client_secret twice in the AUTHENTICATION SETTINGS and in the POLICIES of the Admin Portal, this PR adds "use_oidc_issuer_endpoint" property to get client information from oidc_issuer_endpoint.

@y-tabata y-tabata requested a review from a team as a code owner June 8, 2018 06:36
@@ -21,6 +21,11 @@
"description": "Client Secret for the Token Introspection Endpoint",
"type": "string"
},
"use_oidc_issuer_endpoint": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When this is true we don't need ClientID + Secret anymore, right?

I wonder if it makes sense to use dynamic schema like in #741.
Using either https://github.com/mozilla-services/react-jsonschema-form#property-dependencies or https://github.com/mozilla-services/react-jsonschema-form#schema-dependencies could allow us to have two login methods: clientid+secret or automatic using oidc_issuer_endpoint.

@davidor wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When this is true we don't need ClientID + Secret anymore, right?

Yes. We don't need to define client_id and client_secret in the schema.

Copy link
Contributor

@mikz mikz Jun 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is having either client_id+client_secret or use_oidc_issuer_endpoint.

Try following schema:

{
  "type": "object",
  "properties": {
    "auth_type": {
      "type": "string",
      "enum": [
        "oidc_issuer_endpoint",
        "client_id+client_secret"
      ],
      "default": "client_id+client_secret"
    }
  },
  "required": [
    "auth_type"
  ],
  "dependencies": {
    "auth_type": {
      "oneOf": [
        {
          "properties": {
            "auth_type": {
              "enum": [
                "oidc_issuer_endpoint"
              ]
            }
          }
        },
        {
          "properties": {
            "auth_type": {
              "enum": [
                "client_id+client_secret"
              ]
            },
            "client_id": {
              "type": "string"
            },
            "client_secret": {
              "type": "string"
            }
          },
          "required": [
            "client_id",
            "client_secret"
          ]
        }
      ]
    }
  }
}

In https://mozilla-services.github.io/react-jsonschema-form/

That would allow user to choose which auth method to use and then fill the credentials.
It should also be extensible to add more properties in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

function _M:rewrite(context)
if self.use_oidc_issuer_endpoint then
local components = resty_url.parse(context.service.oidc.issuer_endpoint)
set_client(self, components.user, components.password)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be easier to pass the headers into the individual http call instead of initializing new client every time. Then we won't mutate self and initialize new http client on every request.

You can pass headers when making the request: https://github.com/3scale/apicast/blob/154dc5a4087c97ef9c46209ada6fc8d7d944fea6/spec/resty/http_ng_spec.lua#L78

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

@@ -55,7 +66,8 @@ local function introspect_token(self, token)

--- Parameters for the token introspection endpoint.
-- https://tools.ietf.org/html/rfc7662#section-2.1
local res, err = self.http_client.post(self.introspection_url , { token = token, token_type_hint = 'access_token'})
local res, err = self.http_client.post{self.introspection_url , { token = token, token_type_hint = 'access_token'},
headers = {['User-Agent'] = user_agent(), ['Authorization'] = self.credential}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User-Agent does not change, so it can be passed when creating the HTTP Client.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

function _M.new(config)
local self = new(config)
self.config = config or {}
self.auth_type = config.auth_type or {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the default value for auth_type is "client_id+client_secret", right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@y-tabata y-tabata force-pushed the liquid-templating-token-introspection-policy branch 2 times, most recently from 9be11ca to da3a079 Compare June 12, 2018 00:08
@@ -13,13 +13,10 @@
"description": "Introspection Endpoint URL",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When using the OIDC endpoint, this setting is also unnecessary, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mikz Regarding keycloak, the endpoint is http://${host}:${port}/auth/realms/${realm_name}/protocol/openid-connect/token/introspect.
But this is not common to all.
I wonder whether it's good that this is dedicated to keycloak.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this endpoint is discoverable through OIDC.

For example: https://keycloak.3sca.net/auth/realms/oidc-demo/.well-known/openid-configuration.

It should be possible to get it from context.proxy.oauth.config. You can use require('resty.repl').start() to start a REPL and see around the objects available.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

if self.auth_type == "oidc_issuer_endpoint" then
local components = resty_url.parse(context.service.oidc.issuer_endpoint)
self.credential = create_credential(components.user, components.password)
self.introspection_url = context.proxy.oauth.config.openid.token_introspection_endpoint
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably should test how this policy behaves on non OIDC service. I think this would crash.

Copy link
Contributor

@mikz mikz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great change! Thank you so much @y-tabata ! 👍

Left few final comments regarding the schema naming.

"properties": {
"auth_type": {
"describe": "Get the client and the introspection end point from the oidc issuer endpoint",
"enum": ["oidc_issuer_endpoint"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One final nitpick. oidc_issuer_endpoint would imply the value is an endpoint, but in fact it is just a boolean flag. IMO better name would be use_3scale_oidc_issuer_endpoint, use_service_oidc_issuer_endpoint or something along those lines.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

"oneOf": [{
"properties": {
"auth_type": {
"describe": "Get the client and the introspection end point from the oidc issuer endpoint",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be improved a bit.

Use the Client credentials and the OIDC Issuer Endpoint from the OpenID Connect Issuer setting.

Still not perfect, but we can improve that later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

}, {
"properties": {
"auth_type": {
"describe": "Specify the client ID and the client secret",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably should say something like:

Specify the Token Introspection Endpoint, Client ID, and Client Secret.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

@y-tabata y-tabata force-pushed the liquid-templating-token-introspection-policy branch from bc91d90 to 20823bc Compare June 15, 2018 08:24
Copy link
Contributor

@mikz mikz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@mikz mikz merged commit 56ae1fc into 3scale:master Jun 15, 2018
@y-tabata y-tabata deleted the liquid-templating-token-introspection-policy branch June 15, 2018 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants