Skip to content

Commit

Permalink
AUTH-6146: Add Hybrid and Implicit support to Access OIDC SaaS Apps
Browse files Browse the repository at this point in the history
  • Loading branch information
ajholland committed Jun 7, 2024
1 parent dced1f5 commit 87df4a2
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .changelog/3324.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/cloudflare_access_application: Add Hybrid and Implicit flow support to OIDC SaaS Apps
```
Original file line number Diff line number Diff line change
Expand Up @@ -542,8 +542,9 @@ func TestAccCloudflareAccessApplication_WithOIDCSaas(t *testing.T) {
resource.TestCheckResourceAttr(name, "saas_app.0.auth_type", "oidc"),
resource.TestCheckResourceAttr(name, "saas_app.0.redirect_uris.#", "1"),
resource.TestCheckResourceAttr(name, "saas_app.0.redirect_uris.0", "https://saas-app.example/sso/oauth2/callback"),
resource.TestCheckResourceAttr(name, "saas_app.0.grant_types.#", "1"),
resource.TestCheckResourceAttr(name, "saas_app.0.grant_types.#", "2"),
resource.TestCheckResourceAttr(name, "saas_app.0.grant_types.0", "authorization_code"),
resource.TestCheckResourceAttr(name, "saas_app.0.grant_types.1", "hybrid"),
resource.TestCheckResourceAttr(name, "saas_app.0.scopes.#", "4"),
resource.TestCheckResourceAttr(name, "saas_app.0.scopes.0", "email"),
resource.TestCheckResourceAttr(name, "saas_app.0.scopes.1", "groups"),
Expand All @@ -558,6 +559,9 @@ func TestAccCloudflareAccessApplication_WithOIDCSaas(t *testing.T) {
resource.TestCheckResourceAttr(name, "saas_app.0.custom_claim.0.scope", "profile"),
resource.TestCheckResourceAttr(name, "saas_app.0.custom_claim.0.required", "true"),
resource.TestCheckResourceAttr(name, "saas_app.0.custom_claim.0.source.0.name", "rank"),
resource.TestCheckResourceAttr(name, "saas_app.0.hybrid_and_implicit_options.#", "1"),
resource.TestCheckResourceAttr(name, "saas_app.0.hybrid_and_implicit_options.0.return_access_token_from_authorization_endpoint", "true"),
resource.TestCheckResourceAttr(name, "saas_app.0.hybrid_and_implicit_options.0.return_id_token_from_authorization_endpoint", "true"),
resource.TestCheckResourceAttrSet(name, "saas_app.0.client_secret"),
resource.TestCheckResourceAttrSet(name, "saas_app.0.public_key"),
),
Expand All @@ -581,8 +585,9 @@ func TestAccCloudflareAccessApplication_WithOIDCSaas_Import(t *testing.T) {
resource.TestCheckResourceAttr(name, "saas_app.0.auth_type", "oidc"),
resource.TestCheckResourceAttr(name, "saas_app.0.redirect_uris.#", "1"),
resource.TestCheckResourceAttr(name, "saas_app.0.redirect_uris.0", "https://saas-app.example/sso/oauth2/callback"),
resource.TestCheckResourceAttr(name, "saas_app.0.grant_types.#", "1"),
resource.TestCheckResourceAttr(name, "saas_app.0.grant_types.#", "2"),
resource.TestCheckResourceAttr(name, "saas_app.0.grant_types.0", "authorization_code"),
resource.TestCheckResourceAttr(name, "saas_app.0.grant_types.1", "hybrid"),
resource.TestCheckResourceAttr(name, "saas_app.0.scopes.#", "4"),
resource.TestCheckResourceAttr(name, "saas_app.0.scopes.0", "email"),
resource.TestCheckResourceAttr(name, "saas_app.0.scopes.1", "groups"),
Expand All @@ -598,6 +603,9 @@ func TestAccCloudflareAccessApplication_WithOIDCSaas_Import(t *testing.T) {
resource.TestCheckResourceAttr(name, "saas_app.0.custom_claim.0.scope", "profile"),
resource.TestCheckResourceAttr(name, "saas_app.0.custom_claim.0.required", "true"),
resource.TestCheckResourceAttr(name, "saas_app.0.custom_claim.0.source.0.name", "rank"),
resource.TestCheckResourceAttr(name, "saas_app.0.hybrid_and_implicit_options.#", "1"),
resource.TestCheckResourceAttr(name, "saas_app.0.hybrid_and_implicit_options.0.return_access_token_from_authorization_endpoint", "true"),
resource.TestCheckResourceAttr(name, "saas_app.0.hybrid_and_implicit_options.0.return_id_token_from_authorization_endpoint", "true"),
)

resource.Test(t, resource.TestCase{
Expand Down Expand Up @@ -1133,7 +1141,7 @@ resource "cloudflare_access_application" "%[1]s" {
saas_app {
auth_type = "oidc"
redirect_uris = ["https://saas-app.example/sso/oauth2/callback"]
grant_types = ["authorization_code"]
grant_types = ["authorization_code", "hybrid"]
scopes = ["openid", "email", "profile", "groups"]
app_launcher_url = "https://saas-app.example/sso/login"
group_filter_regex = ".*"
Expand All @@ -1149,6 +1157,11 @@ resource "cloudflare_access_application" "%[1]s" {
name = "rank"
}
}
hybrid_and_implicit_options {
return_id_token_from_authorization_endpoint = true
return_access_token_from_authorization_endpoint = true
}
}
auto_redirect_to_identity = false
}
Expand Down
43 changes: 43 additions & 0 deletions internal/sdkv2provider/schema_cloudflare_access_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,26 @@ func resourceCloudflareAccessApplicationSchema() map[string]*schema.Schema {
},
},
},
"hybrid_and_implicit_options": {
Type: schema.TypeList,
Optional: true,
Description: "Hybrid and Implicit Flow options",
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"return_access_token_from_authorization_endpoint": {
Type: schema.TypeBool,
Optional: true,
Description: "If true, the authorization endpoint will return an access token",
},
"return_id_token_from_authorization_endpoint": {
Type: schema.TypeBool,
Optional: true,
Description: "If true, the authorization endpoint will return an id token",
},
},
},
},

// SAML options
"sp_entity_id": {
Expand Down Expand Up @@ -867,6 +887,13 @@ func convertSaasSchemaToStruct(d *schema.ResourceData) *cloudflare.SaasApplicati
claimsAsMap := customClaims.(map[string]interface{})
SaasConfig.CustomClaims = append(SaasConfig.CustomClaims, convertOIDCClaimSchemaToStruct(claimsAsMap))
}

if _, ok := d.GetOk("saas_app.0.hybrid_and_implicit_options"); ok {
SaasConfig.HybridAndImplicitOptions = &cloudflare.AccessApplicationHybridAndImplicitOptions{
ReturnAccessTokenFromAuthorizationEndpoint: cloudflare.BoolPtr(d.Get("saas_app.0.hybrid_and_implicit_options.0.return_access_token_from_authorization_endpoint").(bool)),
ReturnIDTokenFromAuthorizationEndpoint: cloudflare.BoolPtr(d.Get("saas_app.0.hybrid_and_implicit_options.0.return_id_token_from_authorization_endpoint").(bool)),
}
}
} else {
SaasConfig.SPEntityID = d.Get("saas_app.0.sp_entity_id").(string)
SaasConfig.ConsumerServiceUrl = d.Get("saas_app.0.consumer_service_url").(string)
Expand Down Expand Up @@ -1106,6 +1133,18 @@ func convertOIDCClaimStructToSchema(attr cloudflare.OIDCClaimConfig) map[string]
return m
}

func convertHybridAndImplicitOptionsStructToSchema(hybridAndImplicitOptions *cloudflare.AccessApplicationHybridAndImplicitOptions) []interface{} {
if hybridAndImplicitOptions == nil {
return []interface{}{}
}

m := map[string]interface{}{
"return_access_token_from_authorization_endpoint": hybridAndImplicitOptions.ReturnAccessTokenFromAuthorizationEndpoint,
"return_id_token_from_authorization_endpoint": hybridAndImplicitOptions.ReturnIDTokenFromAuthorizationEndpoint,
}
return []interface{}{m}
}

func convertSaasStructToSchema(d *schema.ResourceData, app *cloudflare.SaasApplication) []interface{} {
if app == nil {
return []interface{}{}
Expand Down Expand Up @@ -1135,6 +1174,10 @@ func convertSaasStructToSchema(d *schema.ResourceData, app *cloudflare.SaasAppli
m["custom_claim"] = customClaims
}

if app.HybridAndImplicitOptions != nil {
m["hybrid_and_implicit_options"] = convertHybridAndImplicitOptionsStructToSchema(app.HybridAndImplicitOptions)
}

// client secret is only returned on create, if it is present in the state, preserve it
if client_secret, ok := d.GetOk("saas_app.0.client_secret"); ok {
m["client_secret"] = client_secret.(string)
Expand Down

0 comments on commit 87df4a2

Please sign in to comment.