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

Support custom claims in cloudflare_access_identity_provider (OIDC) config #1440

Closed
kasun-bandara opened this issue Feb 9, 2022 · 3 comments · Fixed by #2313
Closed

Support custom claims in cloudflare_access_identity_provider (OIDC) config #1440

kasun-bandara opened this issue Feb 9, 2022 · 3 comments · Fixed by #2313
Labels
kind/enhancement Categorizes issue or PR as related to improving an existing feature. service/access Categorizes issue or PR as related to the Access service.

Comments

@kasun-bandara
Copy link

kasun-bandara commented Feb 9, 2022

Current Terraform and Cloudflare provider version

Terraform v0.14.9

  • provider registry.terraform.io/cloudflare/cloudflare v3.8.0

Description

Feature request for supporting custom claims for cloudflare_access_identity_provider resource with the type OIDC. This is supported by the Cloudflare generic OIDC identity provider and can't be configured using terraform.

Sample identity provider configuration returned by Cloudflare API which contains custom claims.

{
            "id": "xx",
            "type": "oidc",
            "uid": "xx",
            "name": "xx",
            "config": {
                "auth_url": "xx",
                "certs_url": "xx",
                "claims": [
                    "claim1",
                    "claim2"
                ],
                "client_id": "xx",
                "client_secret": "xx",
                "redirect_url": "xx",
                "scopes": [
                    "openid",
                    "email",
                    "profile"
                ],
                "token_url": "xx"
            },
            "version": "xx"
        },

Use cases

"cloudflare_access_identity_provider" should have the ability to accept custom claims supported by any given IDP with OIDC protocol. Those claims are passed down to Cloudflare via Token ID and we should have the flexibility to decide which claims should be included in the JWT token generated by Cloudflare.

The ideal configuration would be as follows,

Potential Terraform configuration

resource "cloudflare_access_identity_provider" "idp" {
  zone_id    = "xxx"
  name       = "xxx"
  type       = "oidc"
  config {
    client_id     = "xxx"
    client_secret = "xxx"
    auth_url      = "xxx"
    token_url     = "xxx"
    certs_url     = "xxx"
    redirect_url  = "xxx"
    claims        = ["claim1","claim2"]
  }
}
...

References

No response

@kasun-bandara kasun-bandara added kind/enhancement Categorizes issue or PR as related to improving an existing feature. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. labels Feb 9, 2022
@kasun-bandara kasun-bandara changed the title Support scopes in cloudflare_access_identity_provider (OIDC) config Support custom claims in cloudflare_access_identity_provider (OIDC) config Feb 9, 2022
@jacobbednarz
Copy link
Member

i'm not sure if this is supported by the Access service itself but it is definitely not supported in cloudflare-go. i would recommend starting with a support ticket to have this included as a feature and then it can be added downstream before here.

@jacobbednarz jacobbednarz added workflow/pending-cloudflare-response Indicates an issue or PR requires a response from the Cloudflare team. workflow/pending-upstream-library Indicates an issue or PR requires changes from an upstream library. service/access Categorizes issue or PR as related to the Access service. labels Feb 14, 2022
@jmuchovej
Copy link

So, this definitely appears to be supported by Access, based on the API docs and the example API configuration. This also seems to to be a single-line addition to cloudflare-go. It appears the the implementation would require adding the following.

type AccessIdentityProviderConfiguration struct {
	APIToken           string   `json:"api_token,omitempty"`
        // ...
+       Scopes             string   `json:"scopes,omitempty"`
}

(Copied from L18-45 in cloudflare-go.) However I'm not sure where else these changes would need to be implemented (e.g., throughout cloudflare-go/access_identity_provider.go there's primarily api.<func> calls (and doesn't seem to have any validation). Then in terraform-.../resource_cloudflare_access_identity_provider.go, it seems that

func convertSchemaToStruct(d *schema.ResourceData) (cloudflare.AccessIdentityProviderConfiguration, error) {
    // ...
        IDPConfig.PKCEEnabled = cloudflare.BoolPtr(d.Get("config.0.pkce_enabled").(bool))
        // I know that `scopes` is supposed to be a list(string), but it's been ages since 
        //   I've used Go, so I'm not sure how this ought to be written.
+       IDPConfig.Scopes = cloudflare.ListPtr(d.Get("config.0.scopes").(string))
    }

    return IDPConfig, nil
}

and

func convertStructToSchema(d *schema.ResourceData, options cloudflare.AccessIdentityProviderConfiguration) []interface{} {
    // ...
        "pkce_enabled":         options.PKCEEnabled,
+       "scopes":               options.Scopes,
    }

    return []interface{}{m}
}

I pulled the last two examples from here:

func convertSchemaToStruct(d *schema.ResourceData) (cloudflare.AccessIdentityProviderConfiguration, error) {
IDPConfig := cloudflare.AccessIdentityProviderConfiguration{}
if _, ok := d.GetOk("config"); ok {
if _, ok := d.GetOk("config.0.attributes"); ok {
attrData := make([]string, d.Get("config.0.attributes.#").(int))
for id := range attrData {
attrData[id] = d.Get(fmt.Sprintf("config.0.attributes.%d", id)).(string)
}
IDPConfig.Attributes = attrData
}
IDPConfig.APIToken = d.Get("config.0.api_token").(string)
IDPConfig.AppsDomain = d.Get("config.0.apps_domain").(string)
IDPConfig.AuthURL = d.Get("config.0.auth_url").(string)
IDPConfig.CentrifyAccount = d.Get("config.0.centrify_account").(string)
IDPConfig.CentrifyAppID = d.Get("config.0.centrify_app_id").(string)
IDPConfig.CertsURL = d.Get("config.0.certs_url").(string)
IDPConfig.ClientID = d.Get("config.0.client_id").(string)
IDPConfig.ClientSecret = d.Get("config.0.client_secret").(string)
IDPConfig.DirectoryID = d.Get("config.0.directory_id").(string)
IDPConfig.EmailAttributeName = d.Get("config.0.email_attribute_name").(string)
IDPConfig.IdpPublicCert = d.Get("config.0.idp_public_cert").(string)
IDPConfig.IssuerURL = d.Get("config.0.issuer_url").(string)
IDPConfig.OktaAccount = d.Get("config.0.okta_account").(string)
IDPConfig.OneloginAccount = d.Get("config.0.onelogin_account").(string)
IDPConfig.RedirectURL = d.Get("config.0.redirect_url").(string)
IDPConfig.SignRequest = d.Get("config.0.sign_request").(bool)
IDPConfig.SsoTargetURL = d.Get("config.0.sso_target_url").(string)
IDPConfig.SupportGroups = d.Get("config.0.support_groups").(bool)
IDPConfig.TokenURL = d.Get("config.0.token_url").(string)
IDPConfig.PKCEEnabled = cloudflare.BoolPtr(d.Get("config.0.pkce_enabled").(bool))
}
return IDPConfig, nil
}
func convertStructToSchema(d *schema.ResourceData, options cloudflare.AccessIdentityProviderConfiguration) []interface{} {
if _, ok := d.GetOk("config"); !ok {
return []interface{}{}
}
attributes := make([]string, 0)
for _, value := range options.Attributes {
attributes = append(attributes, value)
}
m := map[string]interface{}{
"api_token": options.APIToken,
"apps_domain": options.AppsDomain,
"attributes": attributes,
"auth_url": options.AuthURL,
"centrify_account": options.CentrifyAccount,
"centrify_app_id": options.CentrifyAppID,
"certs_url": options.CertsURL,
"client_id": options.ClientID,
"client_secret": options.ClientSecret,
"directory_id": options.DirectoryID,
"email_attribute_name": options.EmailAttributeName,
"idp_public_cert": options.IdpPublicCert,
"issuer_url": options.IssuerURL,
"okta_account": options.OktaAccount,
"onelogin_account": options.OneloginAccount,
"redirect_url": options.RedirectURL,
"sign_request": options.SignRequest,
"sso_target_url": options.SsoTargetURL,
"support_groups": options.SupportGroups,
"token_url": options.TokenURL,
"pkce_enabled": options.PKCEEnabled,
}
return []interface{}{m}
}

@jmuchovej
Copy link

jmuchovej commented Mar 21, 2023

This seems to be resolved in cloudflare/cloudflare-go#1237, which seems slated for v0.64.0.

@jacobbednarz jacobbednarz removed workflow/pending-cloudflare-response Indicates an issue or PR requires a response from the Cloudflare team. workflow/pending-upstream-library Indicates an issue or PR requires changes from an upstream library. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. labels Mar 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/enhancement Categorizes issue or PR as related to improving an existing feature. service/access Categorizes issue or PR as related to the Access service.
Projects
None yet
3 participants