diff --git a/main.tf b/main.tf index eb2d6c9..eb6f587 100644 --- a/main.tf +++ b/main.tf @@ -196,7 +196,43 @@ resource "traceable_ip_range_rule" "my_ip_range" { ] environment=[] #all env description="rule created from custom provider" +} + +resource "traceable_notification_rule_blocked_threat_activity" "rule1" { + name = "example_notification_rule3" + environments = [] + channel_id = data.traceable_notification_channels.mychannel.channel_id + threat_types = [] + notification_frequency = "PT1H" +} +resource "traceable_notification_rule_threat_actor_status" "rule1" { + name = "terraform_threat_actor_status" + environments = ["fintech-1"] + channel_id = data.traceable_notification_channels.mychannel.channel_id + actor_states = ["NORMAL"] +} +resource "traceable_notification_rule_actor_severity_change" "rule1" { + name = "terraform_threat_actor_severity2" + environments = ["fintech-1"] + channel_id = data.traceable_notification_channels.mychannel.channel_id + actor_severities = [] + actor_ip_reputation_levels = ["HIGH"] + +} + + +resource "traceable_ip_range_rule" "my_ip_range" { + name = "first_rule" + rule_action = "RULE_ACTION_ALERT" + event_severity = "LOW" + raw_ip_range_data = [ + "1.1.1.1", + "3.3.3.3" + ] + environment=[] #all env + description="rule created from custom provider" +} resource "traceable_notification_rule_blocked_threat_activity" "rule1" { name = "example_notification_rule3" environments = [] @@ -218,4 +254,68 @@ resource "traceable_notification_rule_actor_severity_change" "rule1" { actor_severities = [] actor_ip_reputation_levels = ["HIGH"] -} \ No newline at end of file +} + +resource "traceable_session_identification_request_rule" "example" { + name = "example-session-rule-req-83" + description = "This is an example session identification rule" + environment_names = ["default", "docker"] + service_names = [] + url_match_regexes = ["^/api/.*$", "^/internal/.*$"] + + token_extraction_condition_list { + condition_request_header { + key = "X-Example-Header" + operator = "EQUALS" + value = "example-value" + } + condition_request_header { + key = "X-Example-Cokkie-2" + operator = "EQUALS" + value = "example-value" + } + condition_request_cookie { + key = "X-Example-Cokkie-2" + operator = "EQUALS" + value = "example-value" + } + condition_request_cookie { + key = "X-Example-Cokkie-6" + operator = "EQUALS" + value = "example-value" + } + condition_request_cookie { + key = "X-Example-Cokkie-8" + operator = "EQUALS" + value = "example-value" + } + } + + session_token_details { + token_request_header { + token_key = "Authorization" + operator = "MATCHES_REGEX" + } + } + + obfuscation = true + expiration_type = "JWT" + + token_value_transformation_list { + json_path { + value= "random" + } + regex_capture_group { + value="(test-val)" + } + } +} + + + + + + + + + diff --git a/provider/provider.go b/provider/provider.go index 62a1573..bfb77aa 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -23,19 +23,19 @@ func Provider() *schema.Provider { "traceable_user_attribution_rule_basic_auth": resourceUserAttributionBasicAuthRule(), "traceable_user_attribution_rule_req_header": resourceUserAttributionRequestHeaderRule(), "traceable_user_attribution_rule_jwt_authentication": resourceUserAttributionJwtAuthRule(), - "traceable_user_attribution_rule_response_body": resourceUserAttributionResponseBodyRule(), - "traceable_user_attribution_rule_custom_json": resourceUserAttributionCustomJsonRule(), - "traceable_user_attribution_rule_custom_token": resourceUserAttributionCustomTokenRule(), - // "traceable_notification_channel": resourceNotificationChannelRule(), + "traceable_user_attribution_rule_response_body": resourceUserAttributionResponseBodyRule(), + "traceable_user_attribution_rule_custom_json": resourceUserAttributionCustomJsonRule(), + "traceable_user_attribution_rule_custom_token": resourceUserAttributionCustomTokenRule(), + // "traceable_notification_channel": resourceNotificationChannelRule(), // "traceable_notification_rule_logged_threat_activity": resourceNotificationRuleLoggedThreatActivity(), // "traceable_notification_rule_blocked_threat_activity": resourceNotificationRuleBlockedThreatActivity(), // "traceable_notification_rule_threat_actor_status": resourceNotificationRuleThreatActorStatusChange(), // "traceable_notification_rule_actor_severity_change": resourceNotificationRuleActorSeverityChange(), - "traceable_api_naming_rule": resourceApiNamingRule(), + "traceable_api_naming_rule": resourceApiNamingRule(), // "traceable_api_exclusion_rule": resourceApiExclusionRule(), - "traceable_label_creation_rule": resourceLabelCreationRule(), - "traceable_agent_token": resourceAgentToken(), - + "traceable_label_creation_rule": resourceLabelCreationRule(), + "traceable_agent_token": resourceAgentToken(), + "traceable_session_identification_request_rule": resourceSessionIdentificationRequestRule(), }, DataSourcesMap: map[string]*schema.Resource{ "traceable_notification_channels": dataSourceNotificationChannel(), diff --git a/provider/resource_session_identifier-request.go b/provider/resource_session_identifier-request.go new file mode 100644 index 0000000..01508bf --- /dev/null +++ b/provider/resource_session_identifier-request.go @@ -0,0 +1,933 @@ +package provider + +import ( + "encoding/json" + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceSessionIdentificationRequestRule() *schema.Resource { + return &schema.Resource{ + Create: resourceSessionIdentificationRequestRuleCreate, + Read: resourceSessionIdentificationRequestRuleRead, + Update: resourceSessionIdentificationRequestRuleUpdate, + Delete: resourceSessionIdentificationRequestRuleDelete, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Description: "The name of the Session Identification Rule", + Required: true, + }, + "description": { + Type: schema.TypeString, + Description: "The description of the Session Identification Rule", + Optional: true, + }, + "environment_names": { + Type: schema.TypeList, + Description: "List of environment names", + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "service_names": { + Type: schema.TypeList, + Description: "List of service names", + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "url_match_regexes": { + Type: schema.TypeList, + Description: "List of URL match regexes", + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "token_extraction_condition_list": { + Type: schema.TypeSet, + Description: "Conditions to satisfy for extracting Session Token", + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "condition_request_header": { + Type: schema.TypeSet, + Description: "Attribute type request header", + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Description: "request header key", + Required: true, + }, + "operator": { + Type: schema.TypeString, + Description: "match operator", + Required: true, + }, + "value": { + Type: schema.TypeString, + Description: "request header value", + Required: true, + }, + }, + }, + DiffSuppressFunc: suppressConditionListDiff, + }, + "condition_request_cookie": { + Type: schema.TypeSet, + Description: "Attribute type request cookie", + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Description: "request cookie key", + Required: true, + }, + "operator": { + Type: schema.TypeString, + Description: "match operator", + Required: true, + }, + "value": { + Type: schema.TypeString, + Description: "request cookie value", + Required: true, + }, + }, + }, + DiffSuppressFunc: suppressConditionListDiff, + }, + "condition_request_query_param": { + Type: schema.TypeSet, + Description: "Attribute type request query param", + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Description: "request query param key", + Required: true, + }, + "operator": { + Type: schema.TypeString, + Description: "match operator", + Required: true, + }, + "value": { + Type: schema.TypeString, + Description: "request query param value", + Required: true, + }, + }, + }, + DiffSuppressFunc: suppressConditionListDiff, + }, + }, + }, + }, + "session_token_details": { + Type: schema.TypeList, + Description: "Details of the session token of type request", + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "token_request_header": { + Type: schema.TypeSet, + Description: "request header for token", + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "token_key": { + Type: schema.TypeString, + Description: "Test header key", + Required: true, + }, + "operator": { + Type: schema.TypeString, + Description: "match operator", + Required: true, + }, + }, + }, + DiffSuppressFunc: suppressSessionTokenDetailsDiff, + }, + "token_request_cookie": { + Type: schema.TypeSet, + Description: "request cookie for token", + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "token_key": { + Type: schema.TypeString, + Description: "Test cookie key", + Required: true, + }, + "operator": { + Type: schema.TypeString, + Description: "match operator", + Required: true, + }, + }, + }, + DiffSuppressFunc: suppressSessionTokenDetailsDiff, + }, + "token_request_query_param": { + Type: schema.TypeSet, + Description: "request query param for token", + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "token_key": { + Type: schema.TypeString, + Description: "Test query param key", + Required: true, + }, + "operator": { + Type: schema.TypeString, + Description: "match operator", + Required: true, + }, + }, + }, + DiffSuppressFunc: suppressSessionTokenDetailsDiff, + }, + "token_request_body": { + Type: schema.TypeBool, + Description: "request body for token", + Optional: true, + DiffSuppressFunc: suppressSessionTokenDetailsDiff, + }, + }, + }, + }, + "obfuscation": { + Type: schema.TypeBool, + Description: "If the obfuscation strategy of HASH to be used", + Required: true, + }, + "expiration_type": { + Type: schema.TypeString, + Description: "expiration is jwt based or not applicable", + Optional: true, + }, + "token_value_transformation_list": { + Type: schema.TypeSet, + Description: "List of value transformations for the session token", + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "json_path": { + Type: schema.TypeSet, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "value": { + Type: schema.TypeString, + Description: "The json path value for transformation", + Required: true, + }, + }, + }, + Optional: true, + DiffSuppressFunc: suppressValueTransformationListDiff, + }, + "regex_capture_group": { + Type: schema.TypeSet, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "value": { + Type: schema.TypeString, + Description: "The regex capture group value for transformation", + Required: true, + }, + }, + }, + Optional: true, + DiffSuppressFunc: suppressValueTransformationListDiff, + }, + "jwt_payload_claim": { + Type: schema.TypeSet, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "value": { + Type: schema.TypeString, + Description: "The jwt payload claim value for transformation", + Required: true, + }, + }, + }, + Optional: true, + DiffSuppressFunc: suppressValueTransformationListDiff, + }, + "base64": { + Type: schema.TypeSet, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "value": { + Type: schema.TypeBool, + Description: "Whether the base64 value transformation is used", + Required: true, + }, + }, + }, + Optional: true, + DiffSuppressFunc: suppressValueTransformationListDiff, + }, + }, + }, + }, + }, + } +} + +func suppressConditionListDiff(k, old, new string, d *schema.ResourceData) bool { + return suppressListDiff(old, new) +} + +func suppressSessionTokenDetailsDiff(k, old, new string, d *schema.ResourceData) bool { + return suppressListDiff(old, new) +} + +func suppressValueTransformationListDiff(k, old, new string, d *schema.ResourceData) bool { + return suppressListDiff(old, new) +} + +func suppressListDiff(old, new string) bool { + oldList := strings.FieldsFunc(old, func(r rune) bool { return r == ',' || r == '[' || r == ']' || r == '{' || r == '}' || r == '"' }) + newList := strings.FieldsFunc(new, func(r rune) bool { return r == ',' || r == '[' || r == ']' || r == '{' || r == '}' || r == '"' }) + if len(oldList) != len(newList) { + return false + } + oldMap := make(map[string]bool) + for _, v := range oldList { + oldMap[v] = true + } + for _, v := range newList { + if !oldMap[v] { + return false + } + } + return true +} + +func resourceSessionIdentificationRequestRuleCreate(d *schema.ResourceData, meta interface{}) error { + name := d.Get("name").(string) + + descriptionStr := "" + if v, ok := d.GetOk("description"); ok { + descriptionStr = fmt.Sprintf(`description: "%s",`, v.(string)) + } + + scopeStr := "" + envNames := d.Get("environment_names").([]interface{}) + serviceNames := d.Get("service_names").([]interface{}) + urlMatchRegexes := d.Get("url_match_regexes").([]interface{}) + + envNamesStr := buildStringArray(interfaceSliceToStringSlice(envNames)) + serviceNamesStr := buildStringArray(interfaceSliceToStringSlice(serviceNames)) + urlMatchRegexesStr := buildStringArray(interfaceSliceToStringSlice(urlMatchRegexes)) + + if len(envNames) > 0 { + scopeStr = fmt.Sprintf(`scope: { + environmentNames: %s`, envNamesStr) + if len(serviceNames) > 0 { + scopeStr += fmt.Sprintf(`, serviceNames: %s`, serviceNamesStr) + } + if len(urlMatchRegexes) > 0 { + scopeStr += fmt.Sprintf(`, urlMatchRegexes: %s`, urlMatchRegexesStr) + } + scopeStr += "}," + } else if len(serviceNames) > 0 && (len(serviceNames) != 1 || serviceNames[0] != "") { + scopeStr = fmt.Sprintf(`scope: { + serviceNames: %s + },`, serviceNamesStr) + } + + conditionListStr := "" + if v, ok := d.GetOk("token_extraction_condition_list"); ok { + conditions := v.(*schema.Set).List() + if len(conditions) > 0 { + conditionListStr = `predicate: { predicateType: LOGICAL, logicalPredicate: { operator: AND, children: [` + + for _, condition := range conditions { + conditionMap := condition.(map[string]interface{}) + + if v, ok := conditionMap["condition_request_header"]; ok { + conditionListStr += buildConditionList("HEADER", v.(*schema.Set).List()) + } + if v, ok := conditionMap["condition_request_cookie"]; ok { + conditionListStr += buildConditionList("COOKIE", v.(*schema.Set).List()) + } + if v, ok := conditionMap["condition_request_query_param"]; ok { + conditionListStr += buildConditionList("QUERY_PARAMETER", v.(*schema.Set).List()) + } + } + + conditionListStr += `]}},` + } + } + + // the trailing comma is removed if no conditions are present + if conditionListStr == `predicate: { predicateType: LOGICAL, logicalPredicate: { operator: AND, children: []}}, ` { + conditionListStr = "" + } + + expirationTypeStr := "" + if v, ok := d.GetOk("expiration_type"); ok { + expirationTypeStr = fmt.Sprintf(`expirationType: %s,`, v.(string)) + } + + obfuscationStr := "" + if v, ok := d.GetOk("obfuscation"); ok { + if v.(bool) { + obfuscationStr = `obfuscationStrategy: HASH,` + } + } + + requestAttributeKeyLocationStr := "" + tokenMatchConditionStr := "" + if v, ok := d.GetOk("session_token_details"); ok { + sessionTokenDetails := v.([]interface{})[0].(map[string]interface{}) + + if tokenRequestHeader, ok := sessionTokenDetails["token_request_header"]; ok { + if len(tokenRequestHeader.(*schema.Set).List()) > 0 { + requestAttributeKeyLocationStr = "HEADER" + tokenRequestHeaderList := tokenRequestHeader.(*schema.Set).List() + tokenKey := tokenRequestHeaderList[0].(map[string]interface{})["token_key"].(string) + operator := tokenRequestHeaderList[0].(map[string]interface{})["operator"].(string) + tokenMatchConditionStr = fmt.Sprintf(`matchCondition: { matchOperator: %s, stringValue: "%s" },`, operator, tokenKey) + } + } else if tokenRequestCookie, ok := sessionTokenDetails["token_request_cookie"]; ok { + if len(tokenRequestCookie.(*schema.Set).List()) > 0 { + requestAttributeKeyLocationStr = "COOKIE" + tokenRequestCookieList := tokenRequestCookie.(*schema.Set).List() + tokenKey := tokenRequestCookieList[0].(map[string]interface{})["token_key"].(string) + operator := tokenRequestCookieList[0].(map[string]interface{})["operator"].(string) + tokenMatchConditionStr = fmt.Sprintf(`matchCondition: { matchOperator: %s, stringValue: "%s" },`, operator, tokenKey) + } + } else if tokenRequestQueryParam, ok := sessionTokenDetails["token_request_query_param"]; ok { + if len(tokenRequestQueryParam.(*schema.Set).List()) > 0 { + requestAttributeKeyLocationStr = "QUERY_PARAMETER" + tokenRequestQueryParamList := tokenRequestQueryParam.(*schema.Set).List() + tokenKey := tokenRequestQueryParamList[0].(map[string]interface{})["token_key"].(string) + operator := tokenRequestQueryParamList[0].(map[string]interface{})["operator"].(string) + tokenMatchConditionStr = fmt.Sprintf(`matchCondition: { matchOperator: %s, stringValue: "%s" },`, operator, tokenKey) + } + } else if tokenRequestBody, ok := sessionTokenDetails["token_request_body"].(bool); ok && tokenRequestBody { + requestAttributeKeyLocationStr = "BODY" + } + } + + valueProjectionsStr := "" + if v, ok := d.GetOk("token_value_transformation_list"); ok { + valueTransformations := v.(*schema.Set).List() + var valueProjections []string + for _, transformation := range valueTransformations { + transformationMap := transformation.(map[string]interface{}) + if jsonPathSet, ok := transformationMap["json_path"].(*schema.Set); ok { + for _, jsonPath := range jsonPathSet.List() { + jsonPathMap := jsonPath.(map[string]interface{}) + value := jsonPathMap["value"].(string) + valueProjections = append(valueProjections, fmt.Sprintf(`{ + valueProjectionType: JSON_PATH, + jsonPathProjection: { path: "%s" } + }`, value)) + } + } + if regexCaptureGroupSet, ok := transformationMap["regex_capture_group"].(*schema.Set); ok { + for _, regexCaptureGroup := range regexCaptureGroupSet.List() { + regexCaptureGroupMap := regexCaptureGroup.(map[string]interface{}) + value := regexCaptureGroupMap["value"].(string) + valueProjections = append(valueProjections, fmt.Sprintf(`{ + valueProjectionType: REGEX_CAPTURE_GROUP, + regexCaptureGroupProjection: { regexCaptureGroup: "%s" } + }`, value)) + } + } + if jwtPayloadClaimSet, ok := transformationMap["jwt_payload_claim"].(*schema.Set); ok { + for _, jwtPayloadClaim := range jwtPayloadClaimSet.List() { + jwtPayloadClaimMap := jwtPayloadClaim.(map[string]interface{}) + value := jwtPayloadClaimMap["value"].(string) + valueProjections = append(valueProjections, fmt.Sprintf(`{ + valueProjectionType: JWT_PAYLOAD_CLAIM, + jwtPayloadClaimProjection: { claim: "%s" } + }`, value)) + } + } + if base64Set, ok := transformationMap["base64"].(*schema.Set); ok { + for _, base64 := range base64Set.List() { + base64Map := base64.(map[string]interface{}) + value := base64Map["value"].(bool) + valueProjections = append(valueProjections, fmt.Sprintf(`{ + valueProjectionType: BASE64, + base64: %t + }`, value)) + } + } + } + if len(valueProjections) > 0 { + valueProjectionsStr = fmt.Sprintf("valueProjections: [%s]", strings.Join(valueProjections, ", ")) + } + } + + query := fmt.Sprintf(`mutation { + createSessionIdentificationRuleV2( + create: { + name: "%s" + %s + %s + sessionTokenRules: [ + { + %s + tokenType: REQUEST + requestSessionTokenDetails: { + requestAttributeKeyLocation: %s + %s + } + sessionTokenValueRule: { + %s + projectionRoot: { + projectionType: ATTRIBUTE + attributeProjection: { + %s + %s + } + } + } + } + ] + } + ) { + id + } + } + `, name, descriptionStr, scopeStr, conditionListStr, requestAttributeKeyLocationStr, expirationTypeStr, obfuscationStr, tokenMatchConditionStr, valueProjectionsStr) + + var response map[string]interface{} + responseStr, err := executeQuery(query, meta) + err = json.Unmarshal([]byte(responseStr), &response) + if err != nil { + return fmt.Errorf("Error while executing GraphQL query: %s", err) + + } + + log.Printf("GraphQL response: %s", responseStr) + + if response["data"] != nil && response["data"].(map[string]interface{})["createSessionIdentificationRuleV2"] != nil { + id := response["data"].(map[string]interface{})["createSessionIdentificationRuleV2"].(map[string]interface{})["id"].(string) + d.SetId(id) + } else { + return fmt.Errorf("could not create Session Identification request rule, no ID returned") + } + + return nil +} + +func buildStringArray(input []string) string { + if len(input) == 0 { + return "[]" + } + output := "[" + for _, v := range input { + output += fmt.Sprintf(`"%s",`, v) + } + output = output[:len(output)-1] // Remove trailing comma + output += "]" + return output +} + +func interfaceSliceToStringSlice(input []interface{}) []string { + var output []string + for _, v := range input { + output = append(output, v.(string)) + } + return output +} + +func buildConditionList(attributeType string, conditions []interface{}) string { + conditionStr := "" + for _, condition := range conditions { + conditionMap := condition.(map[string]interface{}) + key := conditionMap["key"].(string) + operator := conditionMap["operator"].(string) + value := conditionMap["value"].(string) + conditionStr += fmt.Sprintf(`{ + predicateType: ATTRIBUTE, + attributePredicate: { + attributeProjection: { + matchCondition: { + matchOperator: %s, + stringValue: "%s" + } + }, + matchCondition: { + matchOperator: %s, + stringValue: "%s" + }, + attributeKeyLocationType: REQUEST, + requestAttributeKeyLocation: %s + } + },`, operator, key, operator, value, attributeType) + } + // Remove trailing comma + if len(conditionStr) > 0 { + conditionStr = conditionStr[:len(conditionStr)-1] + } + return conditionStr +} + +func resourceSessionIdentificationRequestRuleRead(d *schema.ResourceData, meta interface{}) error { + readQuery := `{sessionIdentificationRulesV2{count results{id scope{environmentNames serviceNames urlMatchRegexes}description name sessionTokenRules{predicate{attributePredicate{attributeKeyLocationType attributeProjection{matchCondition{matchOperator stringValue}valueProjections{jsonPathProjection{path}jwtPayloadClaimProjection{claim}regexCaptureGroupProjection{regexCaptureGroup}valueProjectionType}}matchCondition{matchOperator stringValue}requestAttributeKeyLocation responseAttributeKeyLocation}customProjection{customJson}logicalPredicate{children{attributePredicate{attributeKeyLocationType attributeProjection{matchCondition{matchOperator stringValue}valueProjections{jsonPathProjection{path}jwtPayloadClaimProjection{claim}regexCaptureGroupProjection{regexCaptureGroup}valueProjectionType}}matchCondition{matchOperator stringValue}requestAttributeKeyLocation responseAttributeKeyLocation}predicateType}operator}predicateType}requestSessionTokenDetails{requestAttributeKeyLocation expirationType}responseSessionTokenDetails{attributeExpiration{expirationFormat projectionRoot{attributeProjection{matchCondition{matchOperator stringValue}valueProjections{jsonPathProjection{path}jwtPayloadClaimProjection{claim}regexCaptureGroupProjection{regexCaptureGroup}valueProjectionType}}customProjection{customJson}projectionType}responseAttributeKeyLocation}expirationType responseAttributeKeyLocation}sessionTokenValueRule{obfuscationStrategy projectionRoot{attributeProjection{matchCondition{matchOperator stringValue}valueProjections{jsonPathProjection{path}jwtPayloadClaimProjection{claim}regexCaptureGroupProjection{regexCaptureGroup}valueProjectionType}}customProjection{customJson}projectionType}}tokenType}status{disabled}}total}}` + + var response map[string]interface{} + responseStr, err := executeQuery(readQuery, meta) + if err != nil { + return fmt.Errorf("Error: %s", err) + } + log.Printf("This is the GraphQL query: %s", readQuery) + log.Printf("This is the GraphQL response: %s", responseStr) + err = json.Unmarshal([]byte(responseStr), &response) + if err != nil { + return fmt.Errorf("Error: %s", err) + } + + id := d.Id() + ruleDetails := getRuleDetailsFromRulesListUsingIdName(response, "sessionIdentificationRulesV2", id, "id", "name") + if len(ruleDetails) == 0 { + d.SetId("") + return nil + } + log.Printf("Session Identification Rule: %s", ruleDetails) + + d.Set("name", ruleDetails["name"]) + d.Set("description", ruleDetails["description"]) + + scope := ruleDetails["scope"].(map[string]interface{}) + if environmentNames, ok := scope["environmentNames"]; ok { + d.Set("environment_names", environmentNames) + } + if serviceNames, ok := scope["serviceNames"]; ok { + d.Set("service_names", serviceNames) + } + if urlMatchRegexes, ok := scope["urlMatchRegexes"]; ok { + d.Set("url_match_regexes", urlMatchRegexes) + } + + sessionTokenRules := ruleDetails["sessionTokenRules"].([]interface{}) + if len(sessionTokenRules) > 0 { + sessionTokenRule := sessionTokenRules[0].(map[string]interface{}) + if requestSessionTokenDetails, ok := sessionTokenRule["requestSessionTokenDetails"].(map[string]interface{}); ok { + var tokenDetails map[string]interface{} + if requestAttributeKeyLocation, ok := requestSessionTokenDetails["requestAttributeKeyLocation"].(string); ok { + switch requestAttributeKeyLocation { + case "HEADER": + if v, ok := requestSessionTokenDetails["token_request_header"]; ok { + tokenDetails = v.([]interface{})[0].(map[string]interface{}) + } + case "COOKIE": + if v, ok := requestSessionTokenDetails["token_request_cookie"]; ok { + tokenDetails = v.([]interface{})[0].(map[string]interface{}) + } + case "QUERY_PARAMETER": + if v, ok := requestSessionTokenDetails["token_request_query_param"]; ok { + tokenDetails = v.([]interface{})[0].(map[string]interface{}) + } + } + } + if tokenDetails != nil { + d.Set("session_token_details", []interface{}{ + map[string]interface{}{ + "token_key": tokenDetails["token_key"], + "operator": tokenDetails["operator"], + }, + }) + } + } else { + d.Set("name", "") + d.Set("description", "") + d.Set("session_token_details", "") + } + + if sessionTokenValueRule, ok := sessionTokenRule["sessionTokenValueRule"].(map[string]interface{}); ok { + obfuscationStrategy := sessionTokenValueRule["obfuscationStrategy"].(string) + if obfuscationStrategy == "HASH" { + d.Set("obfuscation", true) + } else { + d.Set("obfuscation", false) + } + + if projectionRoot, ok := sessionTokenValueRule["projectionRoot"].(map[string]interface{}); ok { + if attributeProjection, ok := projectionRoot["attributeProjection"].(map[string]interface{}); ok { + if valueProjections, ok := attributeProjection["valueProjections"].([]interface{}); ok { + d.Set("token_value_transformation_list", valueProjections) + } else { + // If valueProjections is not present or empty, clear the token_value_transformation_list + d.Set("token_value_transformation_list", nil) + } + } else { + // If attributeProjection is not present, clear the token_value_transformation_list + d.Set("token_value_transformation_list", nil) + } + } else { + // If projectionRoot is not present, clear the token_value_transformation_list + d.Set("token_value_transformation_list", nil) + } + } + } + + return nil +} + +func resourceSessionIdentificationRequestRuleUpdate(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + name := d.Get("name").(string) + + descriptionStr := "" + if v, ok := d.GetOk("description"); ok { + descriptionStr = fmt.Sprintf(`description: "%s",`, v.(string)) + } + + scopeStr := "" + envNames := d.Get("environment_names").([]interface{}) + serviceNames := d.Get("service_names").([]interface{}) + urlMatchRegexes := d.Get("url_match_regexes").([]interface{}) + + envNamesStr := buildStringArray(interfaceSliceToStringSlice(envNames)) + serviceNamesStr := buildStringArray(interfaceSliceToStringSlice(serviceNames)) + urlMatchRegexesStr := buildStringArray(interfaceSliceToStringSlice(urlMatchRegexes)) + + if len(envNames) > 0 && (len(envNames) != 1 || envNames[0] != "") { + scopeStr = fmt.Sprintf(`scope: { + environmentNames: %s`, envNamesStr) + if len(serviceNames) > 0 { + scopeStr += fmt.Sprintf(`, serviceNames: %s`, serviceNamesStr) + } + if len(urlMatchRegexes) > 0 { + scopeStr += fmt.Sprintf(`, urlMatchRegexes: %s`, urlMatchRegexesStr) + } + scopeStr += "}," + } else if len(serviceNames) > 0 && (len(serviceNames) != 1 || serviceNames[0] != "") { + scopeStr = fmt.Sprintf(`scope: { + serviceNames: %s + },`, serviceNamesStr) + } + + conditionListStr := "" + if v, ok := d.GetOk("token_extraction_condition_list"); ok { + conditions := v.(*schema.Set).List() + if len(conditions) > 0 { + conditionListStr = `predicate: { predicateType: LOGICAL, logicalPredicate: { operator: AND, children: [` + + for _, condition := range conditions { + conditionMap := condition.(map[string]interface{}) + + if v, ok := conditionMap["condition_request_header"]; ok { + conditionListStr += buildConditionList("HEADER", v.(*schema.Set).List()) + } + if v, ok := conditionMap["condition_request_cookie"]; ok { + conditionListStr += buildConditionList("COOKIE", v.(*schema.Set).List()) + } + if v, ok := conditionMap["condition_request_query_param"]; ok { + conditionListStr += buildConditionList("QUERY_PARAMETER", v.(*schema.Set).List()) + } + } + + conditionListStr += `]}},` + } + } + + if conditionListStr == `predicate: { predicateType: LOGICAL, logicalPredicate: { operator: AND, children: []}},` { + conditionListStr = "" + } + + expirationTypeStr := "" + if v, ok := d.GetOk("expiration_type"); ok { + expirationTypeStr = fmt.Sprintf(`expirationType: %s,`, v.(string)) + } + + obfuscationStr := "" + if v, ok := d.GetOk("obfuscation"); ok { + if v.(bool) { + obfuscationStr = `obfuscationStrategy: HASH,` + } + } + + requestAttributeKeyLocationStr := "" + tokenMatchConditionStr := "" + if v, ok := d.GetOk("session_token_details"); ok { + sessionTokenDetails := v.([]interface{})[0].(map[string]interface{}) + + if tokenRequestHeader, ok := sessionTokenDetails["token_request_header"]; ok { + if len(tokenRequestHeader.(*schema.Set).List()) > 0 { + requestAttributeKeyLocationStr = "HEADER" + tokenRequestHeaderList := tokenRequestHeader.(*schema.Set).List() + tokenKey := tokenRequestHeaderList[0].(map[string]interface{})["token_key"].(string) + operator := tokenRequestHeaderList[0].(map[string]interface{})["operator"].(string) + tokenMatchConditionStr = fmt.Sprintf(`matchCondition: { matchOperator: %s, stringValue: "%s" },`, operator, tokenKey) + } + } else if tokenRequestCookie, ok := sessionTokenDetails["token_request_cookie"]; ok { + if len(tokenRequestCookie.(*schema.Set).List()) > 0 { + requestAttributeKeyLocationStr = "COOKIE" + tokenRequestCookieList := tokenRequestCookie.(*schema.Set).List() + tokenKey := tokenRequestCookieList[0].(map[string]interface{})["token_key"].(string) + operator := tokenRequestCookieList[0].(map[string]interface{})["operator"].(string) + tokenMatchConditionStr = fmt.Sprintf(`matchCondition: { matchOperator: %s, stringValue: "%s" },`, operator, tokenKey) + } + } else if tokenRequestQueryParam, ok := sessionTokenDetails["token_request_query_param"]; ok { + if len(tokenRequestQueryParam.(*schema.Set).List()) > 0 { + requestAttributeKeyLocationStr = "QUERY_PARAMETER" + tokenRequestQueryParamList := tokenRequestQueryParam.(*schema.Set).List() + tokenKey := tokenRequestQueryParamList[0].(map[string]interface{})["token_key"].(string) + operator := tokenRequestQueryParamList[0].(map[string]interface{})["operator"].(string) + tokenMatchConditionStr = fmt.Sprintf(`matchCondition: { matchOperator: %s, stringValue: "%s" },`, operator, tokenKey) + } + } else if tokenRequestBody, ok := sessionTokenDetails["token_request_body"].(bool); ok && tokenRequestBody { + requestAttributeKeyLocationStr = "BODY" + } + } + + valueProjectionsStr := "" + if v, ok := d.GetOk("token_value_transformation_list"); ok { + valueTransformations := v.(*schema.Set).List() + var valueProjections []string + for _, transformation := range valueTransformations { + transformationMap := transformation.(map[string]interface{}) + if jsonPathSet, ok := transformationMap["json_path"].(*schema.Set); ok { + for _, jsonPath := range jsonPathSet.List() { + jsonPathMap := jsonPath.(map[string]interface{}) + value := jsonPathMap["value"].(string) + valueProjections = append(valueProjections, fmt.Sprintf(`{ + valueProjectionType: JSON_PATH, + jsonPathProjection: { path: "%s" } + }`, value)) + } + } + if regexCaptureGroupSet, ok := transformationMap["regex_capture_group"].(*schema.Set); ok { + for _, regexCaptureGroup := range regexCaptureGroupSet.List() { + regexCaptureGroupMap := regexCaptureGroup.(map[string]interface{}) + value := regexCaptureGroupMap["value"].(string) + valueProjections = append(valueProjections, fmt.Sprintf(`{ + valueProjectionType: REGEX_CAPTURE_GROUP, + regexCaptureGroupProjection: { regexCaptureGroup: "%s" } + }`, value)) + } + } + if jwtPayloadClaimSet, ok := transformationMap["jwt_payload_claim"].(*schema.Set); ok { + for _, jwtPayloadClaim := range jwtPayloadClaimSet.List() { + jwtPayloadClaimMap := jwtPayloadClaim.(map[string]interface{}) + value := jwtPayloadClaimMap["value"].(string) + valueProjections = append(valueProjections, fmt.Sprintf(`{ + valueProjectionType: JWT_PAYLOAD_CLAIM, + jwtPayloadClaimProjection: { claim: "%s" } + }`, value)) + } + } + if base64Set, ok := transformationMap["base64"].(*schema.Set); ok { + for _, base64 := range base64Set.List() { + base64Map := base64.(map[string]interface{}) + value := base64Map["value"].(bool) + valueProjections = append(valueProjections, fmt.Sprintf(`{ + valueProjectionType: BASE64, + base64: %t + }`, value)) + } + } + } + if len(valueProjections) > 0 { + valueProjectionsStr = fmt.Sprintf("valueProjections: [%s]", strings.Join(valueProjections, ", ")) + } else { + valueProjectionsStr = "valueProjections: []" + } + } + + query := fmt.Sprintf(`mutation { + updateSessionIdentificationRuleV2( + update: { + id: "%s" + name: "%s" + %s + %s + sessionTokenRules: [ + { + %s + tokenType: REQUEST + requestSessionTokenDetails: { + requestAttributeKeyLocation: %s + %s + } + sessionTokenValueRule: { + %s + projectionRoot: { + projectionType: ATTRIBUTE + attributeProjection: { + %s + %s + } + } + } + } + ] + } + ) { + id + } + } + `, id, name, descriptionStr, scopeStr, conditionListStr, requestAttributeKeyLocationStr, expirationTypeStr, obfuscationStr, tokenMatchConditionStr, valueProjectionsStr) + + var response map[string]interface{} + responseStr, err := executeQuery(query, meta) + if err != nil { + return fmt.Errorf("Error while executing GraphQL query: %s", err) + } + err = json.Unmarshal([]byte(responseStr), &response) + if err != nil { + return fmt.Errorf("Error while unmarshalling GraphQL response: %s", err) + } + + log.Printf("GraphQL response: %s", responseStr) + + if response["data"] != nil && response["data"].(map[string]interface{})["updateSessionIdentificationRuleV2"] != nil { + d.SetId(id) + } else { + return fmt.Errorf("could not update Session Identification request rule, no ID returned") + } + + return nil +} + +func resourceSessionIdentificationRequestRuleDelete(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + + query := fmt.Sprintf(`mutation { + deleteSessionIdentificationRuleV2( + delete: { id: "%s" } + ) { + success + } + } + `, id) + + var response map[string]interface{} + responseStr, err := executeQuery(query, meta) + if err != nil { + return fmt.Errorf("Error while executing GraphQL query: %s", err) + } + err = json.Unmarshal([]byte(responseStr), &response) + if err != nil { + return fmt.Errorf("Error while unmarshalling GraphQL response: %s", err) + } + + log.Printf("GraphQL response: %s", responseStr) + + success, ok := response["data"].(map[string]interface{})["deleteSessionIdentificationRuleV2"].(map[string]interface{})["success"].(bool) + if !ok || !success { + return fmt.Errorf("failed to delete Session Identification request rule") + } + + d.SetId("") + return nil +} diff --git a/terraform-registry-manifest.json b/terraform-registry-manifest.json deleted file mode 100644 index a8d9d6e..0000000 --- a/terraform-registry-manifest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 1, - "metadata": { - "protocol_versions": ["6.0"] - } - } - \ No newline at end of file