Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Overview and first steps for building an Open Authorization API connector
oaaclientStrategies for extracting authorization, identity, and resource metadata
{
"resource_type": "Cluster",
"description": "release staging cluster",
"sub_resources": [],
"tags": [
{
"key": "environment",
"value": "development"
}
]
}- orgs/{org_name} - Get Organization information
- orgs/{org_name}/members - List members for an organization
- orgs/{org_name}/teams - List teams for an organization
- orgs/{org_name}/teams/{team}/members - List members for a given team
- orgs/{org_name}/repos - List organization repositories
- repos/{org_name}/{repo}/teams - List Team permissions for repository
- repos/{org_name}/{repo}/collaborators?affiliation=direct - List team members with direct permissionscustom_app.add_custom_permission("owner", [OAAPermission.DataRead, OAAPermission.DataWrite])
jane = custom_app.add_local_user("jane", identities="[email protected]")
resource1 = custom_app.add_resource(name="customers", resource_type="database")
jane.add_permission(permission="owner", resources=[customers]){
"applications": [
{
"name": "Support Portal",
"application_type": "support_portal",
"description": "Our customer support portal",
"local_users": [
{
"name": "bob",
"identities": [
"[email protected]"
],
"groups": [
"admins"
],
"is_active": true,
"last_login_at": "2022-03-21T18:56:38Z"
},
{
"name": "sue",
"identities": [
"[email protected]"
] }
],
"local_groups": [
{
"name": "admins"
}
]
}
],
"permissions": [
{
"name": "admin",
"permission_type": [
"DataWrite",
"DataRead",
"DataDelete",
"MetadataWrite",
"MetadataRead"
]
},
{
"name": "login",
"permission_type": [
"DataRead",
"MetadataRead"
]
}
],
"identity_to_permissions": [
{
"identity": "bob",
"identity_type": "local_user",
"application_permissions": [
{
"application": "Support Portal",
"permission": "login"
}
]
},
{
"identity": "sue",
"identity_type": "local_user",
"application_permissions": [
{
"application": "Support Portal",
"permission": "login"
}
]
},
{
"identity": "admins",
"identity_type": "local_group",
"application_permissions": [
{
"application": "Support Portal",
"permission": "admin"
}
]
}
]
}from oaaclient.client import OAAClient
from oaaclient.templates import CustomApplication, OAAPermission
# creates a connection class to communicate with Veza
veza_con = OAAClient(url=veza_url, token=veza_api_key)
# creates a new Custom Application model
custom_app = CustomApplication(name="Sample App", application_type="sample"){
"warnings": [
{
"message": "Cannot find identity by names (values: [email protected])"
}
]
}...
"local_groups": [
{
"name": "LGroup1",
"identities": [
"[email protected]"
],
"tags": [
{
"key": "NewTag2Key",
"value": "NewTag2Value"
}
],
"operation": "add_tag"
}
]
...id value becomes the key for referencing local users, groups and roles in the identity_to_permissions section of the payload and for referencing group memberships.API calls for managing and updating custom data sources
Open Authorization API usage examples
Modifying custom providers using a partial OAA payload





sequence_number, not upload order.operationPOST /api/v1/providers/custom/{id}/datasources/{data_source_id}:partsPAYLOAD_FILE="large_payload.json"
CHUNK_SIZE=10485760 # 10 MB per chunk
# 1. Start the upload session
RESPONSE=$(curl -s -X POST "https://$VEZA_URL/api/v1/providers/custom/$PROVIDER_ID/datasources/$DATASOURCE_ID:parts" \
-H "authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"operation":"start"}')
UPLOAD_ID=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['upload_id'])")
# 2. Split into raw chunks and upload each
SEQUENCE=0
split -b $CHUNK_SIZE "$PAYLOAD_FILE" /tmp/oaa_chunk_
for CHUNK_FILE in $(ls /tmp/oaa_chunk_* | sort); do
SEQUENCE=$((SEQUENCE + 1))
ENCODED=$(base64 -w 0 < "$CHUNK_FILE") # use -b 0 on macOS
curl -s -X POST "https://$VEZA_URL/api/v1/providers/custom/$PROVIDER_ID/datasources/$DATASOURCE_ID:parts" \
-H "authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"operation\": \"upload\",
\"upload_id\": \"$UPLOAD_ID\",
\"sequence_number\": $SEQUENCE,
\"data\": \"$ENCODED\"
}"
done
# 3. Finalize the upload
curl -s -X POST "https://$VEZA_URL/api/v1/providers/custom/$PROVIDER_ID/datasources/$DATASOURCE_ID:parts" \
-H "authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"operation\": \"complete\",
\"upload_id\": \"$UPLOAD_ID\",
\"sequence_count\": $SEQUENCE
}"
rm /tmp/oaa_chunk_*from oaaclient.client import OAAClient
client = OAAClient(url=veza_url, token=veza_api_key)
client.enable_multipart = True
# Push as usual - the SDK automatically chunks large payloads
client.push_application(provider_name, data_source_name, application_object=app) "resources": [
{
"name": "resource1",
"resource_type": "type1",
"tags": [
{
"key": "keyDelta1",
"value": "valDelta1"
}
],
"operation": "add_tag"
},
{
"name": "resource1",
"resource_type": "type1",
"operation": "modify"
}
]{
"incremental_change": true,
"applications": [
{
"name": "Controller1",
"application_type": "WebServer",
"description": "The base web server",
"local_users": [
{
"name": "LUser1",
"identities": [
"[email protected]"
],
"operation": "delete"
},
{
"name": "LUser1",
"identities": [
"[email protected]"
],
"operation": "add"
}
],
"local_groups": [
{
"name": "LGroup1",
"identities": [
"[email protected]"
],
"tags": [
{
"key": "groupTag2Key",
"value": "groupTag2Value"
}
],
"operation": "add_tag"
}
],
"local_roles": [
{
"name": "LRole2",
"permissions": [
"FULL"
],
"operation": "delete"
}
],
"resources": [
{
"name": "resource1",
"sub_resources": [
{
"name": "sub1b",
"operation": "delete"
}
],
"operation": "modify"
}
]
}
],
"permissions": [
{
"name": "Just Access",
"operation": "modify"
},
{
"name": "NonData",
"PermissionType": [
"NonData"
],
"operation": "add"
},
{
"name": "READ",
"permission_type": [
"DataRead"
],
"operation": "delete"
},
{
"name": "READ",
"permission_type": [
"DataRead"
],
"operation": "add"
}
],
"identity_to_permissions": [
{
"identity": "[email protected]",
"identity_type": "IDP",
"role_assignments": [
{
"application": "Controller1",
"role": "LRole1",
"apply_to_application": true,
"operation": "delete"
},
{
"application": "Controller1",
"role": "LRole2",
"resources": [
"resource1",
"resource1.sub1a.sub2b"
],
"operation": "add"
}
]
},
{
"identity": "[email protected]",
"identity_type": "IDP",
"role_assignments": [
{
"application": "Controller1",
"role": "LRole1",
"resources": [
"resource1.sub1b",
"resource1.sub1c"
],
"operation": "delete_resource"
},
{
"application": "Controller1",
"role": "LRole1",
"resources": [
"resource1.sub1a"
],
"operation": "add_resource"
}
],
"application_permissions": [
{
"application": "WebServer2",
"permission": "Just Access",
"operation": "delete"
}
]
}
]
}Strategies and best practices for OAA connector development
Applying additional metadata to OAA entities
Building blocks for your custom OAA integration
{
"external_id": "[email protected]",
"owner_type": "OktaUser",
"primary": true
} "local_roles": [
{
"name": "User Admin",
"permissions": [
"view_all",
"manage_users"
],
"owners": [
{
"external_id": "[email protected]",
"owner_type": "OktaUser",
"primary": true
}
]
}
]POST /api/v1/providers/custom/{id}/datasources/{data_source_id}:parts{
"csv_data": "abc123="
}CSV_PAYLOAD=$(cat my_app_data.csv | base64)
curl --location https://example.vezacloud.com/api/v1/providers/custom/40bdd318-d320-4574-be90-ca556d59889a/datasources/9bc29dc6-8cd0-4926-992e-7d720305ae2f:push_csv \
--request POST \
--header "Content-Type: application/json" \
--header "Authorization: Bearer $VEZA_API_KEY" \
--data "{\"csv_data\": \"${CSV_PAYLOAD}\"}"cat app_payload.json | gzip | base64 -o json_data.b64payload = {"id": provider_id,
"data_source_id": data_source_id,
"json_data": json.dumps(template_contents)
}curl -X POST '{{VezaURL}}/api/v1/providers/custom/962d5eff-285c-4b08-a54e-400eead1e680:icon' \
-H "authorization: Bearer $API_KEY" \
-d '{"icon_base64": "PHN2ZyBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciICB2aWV3Qm94PSIwIDAgNjQgNjQiIHdpZHRoPSIzMnB4IiBoZWlnaHQ9IjMycHgiPjxwYXRoIGQ9Ik0zMiA2QzE3LjY0MSA2IDYgMTcuNjQxIDYgMzJjMCAxMi4yNzcgOC41MTIgMjIuNTYgMTkuOTU1IDI1LjI4Ni0uNTkyLS4xNDEtMS4xNzktLjI5OS0xLjc1NS0uNDc5VjUwLjg1YzAgMC0uOTc1LjMyNS0yLjI3NS4zMjUtMy42MzcgMC01LjE0OC0zLjI0NS01LjUyNS00Ljg3NS0uMjI5LS45OTMtLjgyNy0xLjkzNC0xLjQ2OS0yLjUwOS0uNzY3LS42ODQtMS4xMjYtLjY4Ni0xLjEzMS0uOTItLjAxLS40OTEuNjU4LS40NzEuOTc1LS40NzEgMS42MjUgMCAyLjg1NyAxLjcyOSAzLjQyOSAyLjYyMyAxLjQxNyAyLjIwNyAyLjkzOCAyLjU3NyAzLjcyMSAyLjU3Ny45NzUgMCAxLjgxNy0uMTQ2IDIuMzk3LS40MjYuMjY4LTEuODg4IDEuMTA4LTMuNTcgMi40NzgtNC43NzQtNi4wOTctMS4yMTktMTAuNC00LjcxNi0xMC40LTEwLjQgMC0yLjkyOCAxLjE3NS01LjYxOSAzLjEzMy03Ljc5MkMxOS4zMzMgMjMuNjQxIDE5IDIyLjQ5NCAxOSAyMC42MjVjMC0xLjIzNS4wODYtMi43NTEuNjUtNC4yMjUgMCAwIDMuNzA4LjAyNiA3LjIwNSAzLjMzOEMyOC40NjkgMTkuMjY4IDMwLjE5NiAxOSAzMiAxOXMzLjUzMS4yNjggNS4xNDUuNzM4YzMuNDk3LTMuMzEyIDcuMjA1LTMuMzM4IDcuMjA1LTMuMzM4LjU2NyAxLjQ3NC42NSAyLjk5LjY1IDQuMjI1IDAgMi4wMTUtLjI2OCAzLjE5LS40MzIgMy42OTdDNDYuNDY2IDI2LjQ3NSA0Ny42IDI5LjEyNCA0Ny42IDMyYzAgNS42ODQtNC4zMDMgOS4xODEtMTAuNCAxMC40IDEuNjI4IDEuNDMgMi42IDMuNTEzIDIuNiA1Ljg1djguNTU3Yy0uNTc2LjE4MS0xLjE2Mi4zMzgtMS43NTUuNDc5QzQ5LjQ4OCA1NC41NiA1OCA0NC4yNzcgNTggMzIgNTggMTcuNjQxIDQ2LjM1OSA2IDMyIDZ6TTMzLjgxMyA1Ny45M0MzMy4yMTQgNTcuOTcyIDMyLjYxIDU4IDMyIDU4IDMyLjYxIDU4IDMzLjIxMyA1Ny45NzEgMzMuODEzIDU3Ljkzek0zNy43ODYgNTcuMzQ2Yy0xLjE2NC4yNjUtMi4zNTcuNDUxLTMuNTc1LjU1NEMzNS40MjkgNTcuNzk3IDM2LjYyMiA1Ny42MSAzNy43ODYgNTcuMzQ2ek0zMiA1OGMtLjYxIDAtMS4yMTQtLjAyOC0xLjgxMy0uMDdDMzAuNzg3IDU3Ljk3MSAzMS4zOSA1OCAzMiA1OHpNMjkuNzg4IDU3LjljLTEuMjE3LS4xMDMtMi40MTEtLjI4OS0zLjU3NC0uNTU0QzI3LjM3OCA1Ny42MSAyOC41NzEgNTcuNzk3IDI5Ljc4OCA1Ny45eiIvPjwvc3ZnPg=="}'from oaaclient.client import OAAClient
from oaaclient.templates import CustomApplication, OAAPermission
# creates a connection class to communicate with Veza
veza_con = OAAClient(url=veza_url, token=veza_api_key)
# creates a new Custom Application model
custom_app = CustomApplication(name="Sample App", application_type="sample")# define a permission
custom_app.add_custom_permission("owner", [OAAPermission.DataRead, OAAPermission.DataWrite])
# create a local user
jsmith = custom_app.add_local_user(unique_id="jsmith", name="Jane Smith", identities=["[email protected]"])
# create a resource
resource1 = custom_app.add_resource(name="Resource 1", resource_type="Thing")
# assign a user to a resource
jsmith.add_permission(permission="owner", resources=[resource1])veza_con.push_application(provider, data_source_name, application_object=custom_app) try:
response = veza_con.push_application(provider_name=provider_name,
data_source_name=data_source_name,
application_object=custom_app,
)
if response.get("warnings"):
print("Push succeeded with warnings:")
for w in response["warnings"]:
print(w)
except OAAClientError as e:
print(f"Error: {e.error}: {e.message} ({e.status_code})", file=sys.stderr)
if hasattr(e, "details"):
for d in e.details:
print(d, file=sys.stderr)using Veza.OAA;
using Veza.OAA.Application;
using Veza.OAA.Base;
// inside namespace/class
OAAClient oaaClient = new(api_key: <your_api_key>, url: <veza_tenant_url>);
CustomApplication customApp = new(name: "sample app",
applicationType: "sample", description: "This is a sample application"); // add custom permissions
customApp.AddCustomPermission(name: "Admin", permissions: new List<Permission>
{
Permission.DataRead,
Permission.DataWrite,
Permission.MetadataRead,
Permission.MetadataWrite,
Permission.NonData
},
applyToSubResources: true
);
// define custom user properties
customApp.DefinedProperties[typeof(User)].DefineProperty("is_guest", typeof(bool));
// add user
User user = customApp.AddUser(name: "bob");
user.AddIdentity("[email protected]");
user.IsActive = true;
user.CreatedAt = "2001-01-01T00:00:00.000Z".FromRFC3339();
user.DeactivatedAt = "2003-03-01T00:00:00.000Z".FromRFC3339();
user.LastLoginAt = "2002-02-01T00:00:00.000Z".FromRFC3339();
user.PasswordLastChangedAt = "2004-04-01T00:00:00.000Z".FromRFC3339();
user.SetProperty(name: "is_guest", value: false);
// define group properties
customApp.DefinedProperties[typeof(Group)].DefineProperty("group_id", typeof(int));
// add group
Group group1 = customApp.AddGroup("group1");
group1.CreatedAt = "2001-01-01T00:00:00.000Z".FromRFC3339();
group1.SetProperty(name: "group_id", 1);
customApp.Users["bob"].AddGroup("group1");
Group group2 = customApp.AddGroup("group2");
group2.AddGroup("group1");
// idp identities
customApp.AddIdPIdentity("[email protected]");
// define role properties
customApp.DefinedProperties[typeof(Role)].DefineProperty("custom", typeof(bool));
// add roles
Role role1 = customApp.AddRole(name: "role1", permissions: new List<string> { "all", "Admin", "Manage_Thing" });
role1.SetProperty(name: "custom", value: false);
// define resource properties
customApp.DefineResourceProperty("private", typeof(bool), "thing");
// add resources
Resource thing1 = customApp.AddResource(name: "thing1", resourceType: "thing", description: "thing1");
thing1.SetProperty(name: "private", false);
thing1.AddTag(name: "tag1", value: "This is a value @,-_.");
Resource cog1 = thing1.AddSubResource(name: "cog1", resourceType: "cog");
cog1.AddConnection(id: "[email protected]", nodeType: "GoogleCloudServiceAccount");
// authorizations
customApp.Users["bob"].AddRole(name: "role1", applyToApplication: true);
customApp.Groups["group2"].AddRole(name: "role1", resources: new List<Resource> { thing1 });
customApp.IdPIdentities["[email protected]"].AddRole(name: "role1", applyToApplication: true);
return customApp; await oaaClient.CreateProvider(provider_name: "sample app", custom_template: "application");
await oaaClient.PushApplication(provider_name: "sample app", data_source_name: "sample app 1", customApp);Template for setting custom property values on existing entities in the Veza authorization graph
app = CustomApplication(name="Demo", application_type="Demo")
# Define a new local user string property `email`
app.property_definitions.define_local_user_property("email", OAAPropertyType.STRING)
local_user = app.add_local_user(name="name", unique_id="user_id")
# set the property by name
local_user.set_property("email", "[email protected]") "custom_property_definition": {
"applications": [
{
"application_type": "GitLab",
"application_properties": {},
"local_user_properties": {
"id": "NUMBER",
"bot": "BOOLEAN",
"is_licensed": "BOOLEAN",
"state": "STRING"
},
"local_group_properties": {},
"local_role_properties": {},
"role_assignment_properties": {
"assigned_at": "TIMESTAMP",
"expires_at": "TIMESTAMP"
},
"local_access_creds_properties": {
"scope": "STRING",
"rotation_period_days": "NUMBER"
},
"resources": [
{
"resource_type": "project",
"properties": {
"id": "NUMBER",
"visibility": "STRING"
}
}
]
}
]
}{
"name": "support-bot",
"identities": ["[email protected]"],
"groups": null,
"is_active": true,
"created_at": "2022-01-25T18:55:19.146Z",
"last_login_at": null,
"deactivated_at": null,
"password_last_changed_at": null,
"tags": [],
"custom_properties": {
"id": 7,
"is_licensed": false,
"state": "active",
"bot": true
}
}{
"custom_property_definition": {
"domain_properties": null,
"group_properties": {
"group_lead": "STRING"
},
"user_properties": {
"birthday": "TIMESTAMP",
"description": "STRING",
"last_login": "TIMESTAMP",
"is_licensed": "BOOLEAN",
"region": "STRING"
}
},
"name": "My IdP",
"id": "custom_idp",
"domains": [
{
"name": "domain.biz"
}
],
"users": [
{
"name": "Colby Smith",
"custom_properties": {
"is_licensed": false,
"region": "US-West"
}
}
]
}json_datajq -Rs .payload.json{
"enriched_entity_property_definitions": [
{
"entity_type": "AwsIamRole",
"enriched_properties": {
"my_company_id": "STRING",
"company_purpose": "STRING",
"is_compliance_validated": "BOOLEAN"
}
},
{
"entity_type": "AwsIamUser",
"enriched_properties": {
"company_purpose": "STRING"
}
}
],
"enriched_entities": [
{
"type": "AwsIamRole",
"id": "arn:aws:iam::339083562601:role/Administrator",
"data_source_id": "339083562601:awsiam",
"properties": {
"my_company_id": "DCFB16CD-A044-4787-9165-1C926221F887",
"company_purpose": "Built in Admin role",
"is_compliance_validated": true
}
},
{
"type": "AwsIamRole",
"id": "arn:aws:iam::650251689811:role/andrew_s3_all",
"data_source_id": "339083562601:awsiam",
"properties": {
"my_company_id": "A3F40BAC-1871-4EFC-A0EE-CD77E3F513C27",
"company_purpose": "Some role for Andrew",
"is_compliance_validated": false
}
},
{
"type": "AwsIamUser",
"id": "arn:aws:iam::339083562601:user/andrew",
"data_source_id": "339083562601:awsiam",
"properties": {
"company_purpose": "Engineering service account"
}
}
]
}curl -X POST "https://{VEZA_URL}/api/v1/providers/custom" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data '{"name":"My Enrichment Provider","custom_template":"entity_enrichment"}'"enriched_entity_property_definitions": [
{
"entity_type": "AwsIamRole",
"enriched_properties": {
"my_company_id": "STRING",
"is_compliance_validated": "BOOLEAN"
}
}
]"enriched_entities": [
{
"type": "AwsIamRole",
"id": "arn:aws:iam::339083562601:role/Administrator",
"data_source_id": "339083562601:awsiam",
"properties": {
"my_company_id": "DCFB16CD-A044-4787-9165-1C926221F887",
"is_compliance_validated": true
}
}
]curl -X POST "https://{VEZA_URL}/api/v1/providers/custom" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data '{"name":"Enrichment Provider","custom_template":"entity_enrichment"}'curl -X POST "https://{VEZA_URL}/api/v1/providers/custom/{PROVIDER_ID}/datasources" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data '{"name":"Enrichment Data Source"}'curl -X POST "https://{VEZA_URL}/api/v1/providers/custom/{PROVIDER_ID}/datasources/{DATASOURCE_ID}:push" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data "{\"json_data\": $(jq -Rs . payload.json)}"Veza API key for authentication. Generate keys in Administration > API Keys.
For external OAA, how to manage lifecycle management requests
OK
Default error response
Retrieve all custom (OAA) providers configured in the tenant. Custom providers represent integrations built using the Open Authorization API (OAA), including both Veza-managed connectors and customer-built integrations. Use the filter parameter to narrow results by name, state, or custom_template (e.g., filter=name eq "My App"). Set page_size to control results per page (default varies), and use page_token from the response to retrieve subsequent pages.
Veza API key for authentication. Generate keys in Administration > API Keys.
The maximum number of results to be returned. Fewer results may be returned even when more pages exist.
The token specifying the specific page of results to retrieve.
OK
Paginated list of custom (OAA) providers.
Token to retrieve the next page of results. Empty when no more pages exist.
If true, additional pages of results are available.
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
The maximum number of results to be returned. Fewer results may be returned even when more pages exist.
The token specifying the specific page of results to retrieve.
OK
The pagination token to retrieve the next page of results.
If true, more results are available.
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response
Veza API key for authentication. Generate keys in Administration > API Keys.
OK
Default error response

OK
{
"value": {
"id": "text",
"external_id": "text",
"name": "text",
"custom_template": "text",
"custom_templates": [
"text"
],
"state": 1,
"application_types": [
"text"
],
"idp_types": [
"text"
],
"file_system_types": [
"text"
],
"hris_types": [
"text"
],
"principal_types": [
"text"
],
"schema_definition_json": "text",
"provisioning": true,
"push_type": 1,
"rbac_id": "text",
"internal_app_name": "text",
"configuration_json": "text",
"data_plane_id": "text",
"lifecycle_management_state": 1,
"team_id": "text",
"csv_mapping_configuration": {
"template_type": "text",
"column_mappings": [
{
"column_name": "text",
"destination_type": "text",
"destination_property": "text",
"custom_property": {
"name": "text",
"type": 1,
"lcm_unique_identifier": true
},
"as_list": true,
"template": "text",
"property_type": 1,
"is_required": true
}
],
"application": {
"application_name": "text",
"application_type": "text",
"identity": [
"text"
],
"resource_type": "text"
},
"advanced": {
"list_delimiter": "text"
},
"idp": {
"idp_type": "text",
"domain": "text"
},
"hris": {
"hris_name": "text",
"hris_type": "text",
"hris_url": "text",
"hris_identity_mapping": {
"mappings": [
{
"destination_datasource_type": "text",
"destination_datasource_oaa_app_type": "text",
"type": 1,
"mode": 1,
"transformations": [
1
],
"custom_value": "text",
"property_matchers": [
{
"source_property": 1,
"destination_property": 1,
"custom_source_property": "text",
"custom_destination_property": "text"
}
],
"id_matchers": [
{
"source_id": "text",
"destination_id": "text"
}
],
"destination_datasources": [
{
"type": "text",
"oaa_app_type": "text"
}
]
}
],
"use_email": true
},
"hris_provisioning_source": true
}
},
"secret_references": [
{
"id": "text",
"secret_id": "text",
"vault_id": "text",
"vault": {
"id": "text",
"name": "text",
"vault_provider": "text",
"insight_point_id": "text",
"deleted": true
}
}
],
"external_lifecycle_management_type": 1
}
}{
"values": [
{
"id": "text",
"external_id": "text",
"name": "text",
"custom_template": "text",
"custom_templates": [
"text"
],
"state": 1,
"application_types": [
"text"
],
"idp_types": [
"text"
],
"file_system_types": [
"text"
],
"hris_types": [
"text"
],
"principal_types": [
"text"
],
"schema_definition_json": "text",
"provisioning": true,
"push_type": 1,
"rbac_id": "text",
"internal_app_name": "text",
"configuration_json": "text",
"data_plane_id": "text",
"lifecycle_management_state": 1,
"team_id": "text",
"csv_mapping_configuration": {
"template_type": "text",
"column_mappings": [
{
"column_name": "text",
"destination_type": "text",
"destination_property": "text",
"custom_property": {
"name": "text",
"type": 1,
"lcm_unique_identifier": true
},
"as_list": true,
"template": "text",
"property_type": 1,
"is_required": true
}
],
"application": {
"application_name": "text",
"application_type": "text",
"identity": [
"text"
],
"resource_type": "text"
},
"advanced": {
"list_delimiter": "text"
},
"idp": {
"idp_type": "text",
"domain": "text"
},
"hris": {
"hris_name": "text",
"hris_type": "text",
"hris_url": "text",
"hris_identity_mapping": {
"mappings": [
{
"destination_datasource_type": "text",
"destination_datasource_oaa_app_type": "text",
"type": 1,
"mode": 1,
"transformations": [
1
],
"custom_value": "text",
"property_matchers": [
{
"source_property": 1,
"destination_property": 1,
"custom_source_property": "text",
"custom_destination_property": "text"
}
],
"id_matchers": [
{
"source_id": "text",
"destination_id": "text"
}
],
"destination_datasources": [
{
"type": "text",
"oaa_app_type": "text"
}
]
}
],
"use_email": true
},
"hris_provisioning_source": true
}
},
"secret_references": [
{
"id": "text",
"secret_id": "text",
"vault_id": "text",
"vault": {
"id": "text",
"name": "text",
"vault_provider": "text",
"insight_point_id": "text",
"deleted": true
}
}
],
"external_lifecycle_management_type": 1
}
],
"next_page_token": "text",
"has_more": true
}{
"values": [
{}
],
"next_page_token": "text",
"has_more": true
}{
"value": {
"id": "text",
"name": "text"
}
}{
"warnings": [
{
"message": "text"
}
]
}{
"warnings": [
{
"message": "text"
}
]
}{
"warnings": [
{
"message": "text"
}
]
}{
"warnings": [
{
"message": "text"
}
]
}{}POST /api/v1/providers/custom HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 1328
{
"name": "text",
"custom_template": "text",
"provisioning": true,
"push_type": 1,
"internal_app_name": "text",
"configuration_json": "text",
"data_plane_id": "text",
"custom_templates": [
"text"
],
"csv_mapping_configuration": {
"template_type": "text",
"column_mappings": [
{
"column_name": "text",
"destination_type": "text",
"destination_property": "text",
"custom_property": {
"name": "text",
"type": 1,
"lcm_unique_identifier": true
},
"as_list": true,
"template": "text",
"property_type": 1,
"is_required": true
}
],
"application": {
"application_name": "text",
"application_type": "text",
"identity": [
"text"
],
"resource_type": "text"
},
"advanced": {
"list_delimiter": "text"
},
"idp": {
"idp_type": "text",
"domain": "text"
},
"hris": {
"hris_name": "text",
"hris_type": "text",
"hris_url": "text",
"hris_identity_mapping": {
"mappings": [
{
"destination_datasource_type": "text",
"destination_datasource_oaa_app_type": "text",
"type": 1,
"mode": 1,
"transformations": [
1
],
"custom_value": "text",
"property_matchers": [
{
"source_property": 1,
"destination_property": 1,
"custom_source_property": "text",
"custom_destination_property": "text"
}
],
"id_matchers": [
{
"source_id": "text",
"destination_id": "text"
}
],
"destination_datasources": [
{
"type": "text",
"oaa_app_type": "text"
}
]
}
],
"use_email": true
},
"hris_provisioning_source": true
}
},
"secret_references": [
{
"secret_id": "text",
"vault_id": "text"
}
],
"external_lifecycle_management_type": 1
}GET /api/v1/providers/custom HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
GET /api/v1/providers/custom/{id} HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"value": {
"id": "text",
"external_id": "text",
"name": "text",
"custom_template": "text",
"custom_templates": [
"text"
],
"state": 1,
"application_types": [
"text"
],
"idp_types": [
"text"
],
"file_system_types": [
"text"
],
"hris_types": [
"text"
],
"principal_types": [
"text"
],
"schema_definition_json": "text",
"provisioning": true,
"push_type": 1,
"rbac_id": "text",
"internal_app_name": "text",
"configuration_json": "text",
"data_plane_id": "text",
"lifecycle_management_state": 1,
"team_id": "text",
"csv_mapping_configuration": {
"template_type": "text",
"column_mappings": [
{
"column_name": "text",
"destination_type": "text",
"destination_property": "text",
"custom_property": {
"name": "text",
"type": 1,
"lcm_unique_identifier": true
},
"as_list": true,
"template": "text",
"property_type": 1,
"is_required": true
}
],
"application": {
"application_name": "text",
"application_type": "text",
"identity": [
"text"
],
"resource_type": "text"
},
"advanced": {
"list_delimiter": "text"
},
"idp": {
"idp_type": "text",
"domain": "text"
},
"hris": {
"hris_name": "text",
"hris_type": "text",
"hris_url": "text",
"hris_identity_mapping": {
"mappings": [
{
"destination_datasource_type": "text",
"destination_datasource_oaa_app_type": "text",
"type": 1,
"mode": 1,
"transformations": [
1
],
"custom_value": "text",
"property_matchers": [
{
"source_property": 1,
"destination_property": 1,
"custom_source_property": "text",
"custom_destination_property": "text"
}
],
"id_matchers": [
{
"source_id": "text",
"destination_id": "text"
}
],
"destination_datasources": [
{
"type": "text",
"oaa_app_type": "text"
}
]
}
],
"use_email": true
},
"hris_provisioning_source": true
}
},
"secret_references": [
{
"id": "text",
"secret_id": "text",
"vault_id": "text",
"vault": {
"id": "text",
"name": "text",
"vault_provider": "text",
"insight_point_id": "text",
"deleted": true
}
}
],
"external_lifecycle_management_type": 1
}
}DELETE /api/v1/providers/custom/{id} HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{}GET /api/v1/providers/custom/{id}/datasources HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
POST /api/v1/providers/custom/{id}/datasources HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 52
{
"id": "text",
"name": "text",
"custom_template": "text"
}GET /api/v1/providers/custom/{id}/datasources/{data_source_id} HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"value": {}
}DELETE /api/v1/providers/custom/{id}/datasources/{data_source_id} HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{}POST /api/v1/providers/custom/{id}/datasources/{data_source_id}:push HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 98
{
"id": "text",
"data_source_id": "text",
"json_data": "text",
"compression_type": 1,
"priority_push": true
}POST /api/v1/providers/custom/{id}/datasources/{data_source_id}:push_csv HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 125
{
"id": "text",
"data_source_id": "text",
"csv_data": "text",
"name": "text",
"type": "text",
"compression_type": 1,
"priority_push": true
}POST /api/v1/providers/custom/{id}/datasources/{data_source_id}:push HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 98
{
"id": "text",
"data_source_id": "text",
"json_data": "text",
"compression_type": 1,
"priority_push": true
}POST /api/v1/providers/custom/{id}/datasources/{data_source_id}:push_csv HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 125
{
"id": "text",
"data_source_id": "text",
"csv_data": "text",
"name": "text",
"type": "text",
"compression_type": 1,
"priority_push": true
}POST /api/v1/providers/custom/{id}:icon HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 34
{
"id": "text",
"icon_base64": "text"
}GET /api/v1/providers/custom/{id}:icon HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"mime_type": "text",
"icon_base64": "text"
}GET /api/v1/providers/custom:icon HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"mime_type": "text",
"icon_base64": "text",
"provider_id": "text"
}DELETE /api/v1/providers/custom/{id}:icon HTTP/1.1
Host: your-tenant.vezacloud.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{}self.app.add_local_role("Write", ["Pull", "Fork", "Push", "Merge"])self.app.add_custom_permission("limited_user", permissions=[OAAPermission.DataRead, OAAPermission.MetadataRead])
self.app.add_local_role("Responder", unique_id="limited_user", permissions=["limited_user"])VEZA_URL__init__(data=None, **kwargs) → Nonelog_arg_error(log: object, arg: str = None, env: str = None) → Noneload_json_from_file(json_path: str) → dictencode_icon_file(icon_path: str) → strexists_in_query_array(value_to_find, input_array) → boolbuild_report(veza_con, report_definition: dict) → dicttruncate_string(source_str: str, length: int = 256) → strcurl -X GET "https://$VEZA_URL/api/v1/providers/custom" \
-H "authorization: Bearer $API_KEY"curl -X POST "https://$VEZA_URL/api/v1/providers/custom" \
-H "authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"GitHub","custom_template":"application"}'curl -X POST "https://$VEZA_URL/api/v1/providers/custom" \
-H "authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Internal Portal",
"custom_template": "application",
"external_lifecycle_management_type": "SCIM"
}'curl -X POST "https://$VEZA_URL/api/v1/providers/custom" \
-H "authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Legacy Access System",
"custom_template": "application",
"external_lifecycle_management_type": "SEND_REST_PAYLOAD"
}'curl -X POST "https://$VEZA_URL/api/v1/providers/custom" \
-H "authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Corporate LDAP","custom_template":"identity_provider"}'curl -X POST "https://$VEZA_URL/api/v1/providers/custom" \
-H "authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Workday",
"custom_template": "hris",
"provisioning": true
}'{
"value": {
"id": "a6ef8d8d-d17b-4491-a67a-635ad70f1ba9",
"name": "GitHub",
"custom_template": "application",
"state": "ENABLED",
"application_types": [],
"resource_types": [],
"idp_types": [],
"schema_definition_json": "e30="
}
}from oaaclient.client import OAAClient
client = OAAClient(url=veza_url, token=veza_api_key)
# Basic application provider
provider = client.create_provider(name="GitHub", custom_template="application")
# Application with SCIM lifecycle management
provider = client.create_provider(
name="Internal Portal", custom_template="application",
options={"external_lifecycle_management_type": "SCIM"}
)
# HRIS as system of record
provider = client.create_provider(
name="Acme HR", custom_template="hris",
options={"provisioning": True}
)curl -X POST "https://${VEZA_URL}/api/v1/providers/custom/${PROVIDER_ID}/datasources" \
-H 'accept: application/json' \
-H 'authorization: Bearer '${API_KEY} \
-d '{"id": "<PROVIDER ID>", "name":"DemoApp - Documentation Datasource"}'{
"value": {
"id": "1bd31da0-64ee-4dfe-82c9-cb9f0f2fc369",
"name": "DemoApp - Documentation Datasource"
}
}{
"id": "532f6fe3-189f-4576-afdf-8913088961e4",
"compression_type": "none",
"data_source_id": "b6a32af6-b854-47e1-8325-e5984f78bb4d",
"json_data": "{\"name\":\"CustomApp\",\"application_type\"...}"
}curl -X POST "https://$VEZA_URL/api/v1/providers/custom/$PROVIDER_ID/datasources/$DATASOURCE_ID:push" \
-H 'accept: application/json' \
-H 'authorization: Bearer '$API_KEY \
--compressed --data-binary @body.jsoncurl -X GET "https://$VEZA_URL/api/v1/providers/custom" \
-H 'accept: application/json' \
-H 'authorization: Bearer '$API_KEYcurl -X GET "https://$VEZA_URL/api/v1/providers/custom/$PROVIDER_ID" \
-H 'accept: application/json' \
-H 'authorization: Bearer '$API_KEYcurl -X POST "https://$VEZA_URL/api/v1/providers/custom/$PROVIDER_ID/datasources/$DATASOURCE_ID:push" \
-H 'accept: application/json' \
-H 'authorization: Bearer '$API_KEY \
--compressed --data-binary @payload.jsonexport OAA_TOKEN="xxxxxxx"
export VEZA_URL="https://myveza.vezacloud.com"
./sample-app.pydiscover() function to collect Users, Groups, Roles, and any resources for the application. As the entities are discovered, add them to the CustomApplication object using the appropriate SDK operations.#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import logging
import os
import sys
import requests
from requests.exceptions import HTTPError, RequestException
from oaaclient.client import OAAClient, OAAClientError
from oaaclient.templates import CustomApplication, OAAPermission, OAAPropertyType, LocalUser
import oaaclient.utils as oaautils
"""
Logging in connectors is very important. Establishing a local logging function here
allows the connector log even if its imported into another block of code
"""
logging.basicConfig(
format='%(asctime)s %(levelname)s: %(message)s', level=logging.INFO)
log = logging.getLogger(__name__)
"""
The main logic for connecting to the destination application.
Authorization data collection and OAA template population should be structured into a class.
The class can store the authentication tokens making connections through an API or SDK easier.
The class should also instantiate the OAA CustomApplication or CustomIdP class
to manage populating all the identity, resource and authorization data.
"""
class OAAConnector():
APP_TYPE="SampleApp"
def __init__(self, auth_token: str) -> None:
self.auth_token = auth_token
# Set the application name and type. The type will generally be the vendor or product.
# The App Name can be the same, or contain additional context like the instance name.
app_name = "My App - West"
self.app = CustomApplication(app_name, application_type=self.APP_TYPE)
# declaring custom properties as part of the `__init__` keeps them together
self.app.property_definitions.define_local_user_property("email", OAAPropertyType.STRING)
self.app.property_definitions.define_local_user_property("has_mfa", OAAPropertyType.BOOLEAN)
"""
A `discover` method that starts the discovery cycle.
The discovery cycle should be invoked separately from the init.
More complex connectors may have additional setup steps between init and discovery
"""
def discover(self) -> None:
"""Discovery method"""
log.info(
"Start App discovery") # Start and stop log messages provide progress as discovery proceeds
self._discover_users()
self._discover_roles()
log.info("Finished App discovery")
return
"""
Smaller functions to perform portions of the discovery like users, groups, roles
should be private `_` functions to imply that they should not be run alone,
unless care is taken to ensure no dependencies.
For example, discovery of roles may assume that users are already discovered.
"""
def _discover_users(self) -> None:
log.info("Start user discovery")
# perform user discovery, for example process each user returned from an API call
for user in self._api_get("/Users"):
local_user = self.app.add_local_user(id=user["id"], name=user["name"])
local_user.is_active = user["active"]
local_user.set_property("has_mfa", user["mfa_enabled"])
log.info("Finished user discovery")
return
def _discover_roles(self) -> None:
log.info("Start role discovery")
# perform user discovery
log.info("Finished role discovery")
return
"""
Any required methods to interface with the application should be defined
as part of the class. Not all connectors need these methods, as they may use
other SDKs to interface with the application.
"""
def _api_get(self, path: str) -> dict:
# implement logic to make API call, process results, handle errors, retries ect.
# Could be done with a vendor SDK, SQL, or any method supported by the application
return {}
"""
A run function that is separate from `main` makes it easy to import the connector
into another piece of Python code. This may be useful to call the connector from
code that retrieves secrets or manages the job in other ways.
All necessary parameters should be taken in through the `run` function
"""
def run(veza_url: str, veza_api_key: str, app_key: str, **config_args) -> None:
# Process any configuration arguments
if config_args.get("debug"):
log.setLevel(logging.DEBUG)
logging.getLogger("urllib3").setLevel(logging.INFO)
log.info("Enabling debug logging")
else:
log.setLevel(logging.INFO)
save_json = config_args.get("save_json", False)
if not isinstance(save_json, bool):
raise TypeError("save_json argument must be boolean")
# Connect to the Veza instance before discovery to validate that the credentials are valid
try:
conn = OAAClient(url = veza_url, api_key = veza_api_key)
except OAAClientError as error:
log.error(f"Unable to connect to Veza {veza_url}")
log.error(error.message)
# run function should raise any exception so that they can be handled by the parent code, never exit
raise error
# Initialize the connector class and run discovery
try:
app = OAAConnector(auth_token=app_key)
app.discover()
except RequestException as e:
# process possible exceptions from the app discovery
log.error("Error during discovery")
log.error(f"{e} - {e.response.status_code} {e.response.text}")
raise e
# After discovery is complete, set up the Provider and Data Source to push the data to
# Provider name should be consistent with the vendor and application
provider_name = "My App"
provider = conn.get_provider(provider_name)
if provider:
log.info("found existing provider")
else:
log.info(f"creating provider {provider_name}")
provider = conn.create_provider(provider_name, "application", base64_icon=APP_SVG_B64)
log.info(f"provider: {provider['name']} ({provider['id']})")
# Data Source name should be unique to the instance of the app that is discovered but consistent.
# For example the hostname of the application or deployment name. Do not use something that will change.
data_source_name = f"App - {app.unique_identifier}"
try:
log.info("uploading application data")
response = conn.push_application(provider_name,
data_source_name = data_source_name,
application_object = app.app,
save_json = save_json
)
# An OAA Push can succeed with warnings, you can log out the warnings
if response.get("warnings", None):
log.warning("Push succeeded with warnings:")
for e in response["warnings"]:
log.warning(e)
log.info("success")
except OAAClientError as error:
# if there is an issue with the OAA payload the error details should contain useful information to help resolve the problem
log.error(f"{error.error}: {error.message} ({error.status_code})")
if hasattr(error, "details"):
for detail in error.details:
log.error(detail)
raise error
return
"""
Setting an application icon helps visually identify the app in the Veza UI.
A Base64 encoding of an SVG or PNG in the app code is an option.
You can also import an icon from a file with `oaaclient.utils.encode_icon_file`.
"""
APP_SVG_B64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/Pg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFRE
IFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4NCjxzdmcgd2lkdGg9IjQwMCIgaGVpZ2h0
PSI0MDAiIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KICA8cGF0aCBmaWxsPSJyZWQiIHN0cm9r
ZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIyLjUiIGQ9Ik0xNjggMTY4SDMyVjMyaDEzNnoiLz4NCjwvc3ZnPg0K
"""
"""
The main entry point should only deal with processing parameters and invoking
the run function. No OAA or application discovery should happen during the main
function. All required parameters should be configurable through the OS
environment. It should be possible to run the connector from the command line
with no arguments.
"""
def main():
"""
process command line and OS environment variables, then call `run`
"""
parser = argparse.ArgumentParser(description = "OAA Connector")
# using the `default=os.getenv()` pattern makes it easier to get parameters from command line or OS environment
parser.add_argument("--veza-url", default=os.getenv("VEZA_URL"), help="the URL of the Veza instance")
parser.add_argument("--debug", action="store_true", help="Set the log level to debug")
parser.add_argument("--save-json", action="store_true", help="Save OAA JSON payload to file")
args = parser.parse_args()
# Secrets should only be passed in through ENV
veza_api_key = os.getenv("VEZA_API_KEY")
veza_url = args.veza_url
save_json = args.save_json
if not veza_api_key:
oaautils.log_arg_error(log, None, "VEZA_API_KEY")
if not veza_url:
oaautils.log_arg_error(log, "--veza-url", "VEZA_URL")
# ensure required variables are provided
if None in [veza_api_key, veza_url]:
log.error(f"missing one or more required parameters")
sys.exit(1)
try:
run( veza_url=veza_url, veza_api_key=veza_api_key, save_json=save_json, debug=args.debug)
except (OAAClientError, RequestException):
log.error("Exiting with error")
sys.exit(1)
if __name__ == "__main__":
# replace the log with the root logger if running as main
log = logging.getLogger()
logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=logging.INFO)
main()#!env python3
"""
Copyright 2022 Veza Technologies Inc.
Use of this source code is governed by the MIT
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
Example of using the `CustomApplication` class to model a typical application where users and groups are assigned
permissions to the application or resources.
If you want to run the code you will need to export environment variables for the Veza URL, user and API keys.
```
export OAA_TOKEN="xxxxxxx"
export VEZA_URL="https://myveza.vezacloud.com"
./sample-app.py
```
"""
from oaaclient.client import OAAClient, OAAClientError
from oaaclient.templates import CustomApplication, OAAPermission
import os
import sys
def main():
# OAA requires an API token, which you can generate from your Veza user profile
# Export the API token, and Veza URL as environment variables
# Making them available to your connector in this way keeps credentials out of the source code
veza_api_key = os.getenv('VEZA_API_KEY')
veza_url = os.getenv('VEZA_URL')
if None in (veza_url, veza_api_key):
print("Unable to local all environment variables")
sys.exit(1)
# Instantiates a client connection. The client will confirm the credentials and Veza URL are valid
# Checking this early helps prevents connection failures in the final stage
veza_con = OAAClient(url=veza_url, api_key=veza_api_key)
# Create an instance of the OAA CustomApplication class, modeling the application name and type
# `name` will be displayed in the Veza UI
# `application_type` should be a short key reflecting the source application authorization is being modeled for
# You can use the same type for multiple applications
custom_app = CustomApplication(name="Sample App", application_type="sample")
# In the OAA payload, each permission native to the custom app is mapped to the Veza effective permission (data/nondata C/R/U/D).
# Permissions must be defined before they can be referenced, as they are discovered or ahead of time.
# For each custom application permission, bind them to the Veza permissions using the `OAAPermission` enum:
custom_app.add_custom_permission("admin", [OAAPermission.DataRead, OAAPermission.DataWrite])
custom_app.add_custom_permission("operator", [OAAPermission.DataRead])
# Create resources and sub-resource to model the entities in the application
# To Veza, an application can be a single entity or can contain resources and sub-resources
# Utilizing resources enables tracking of authorizations to specific components of the system being modeled
# Setting a `resource_type` can help group entities of the same type for reporting/queries
entity1 = custom_app.add_resource(name="Entity1", resource_type="thing",
entity2 = custom_app.add_resource(name="Entity2", resource_type="thing",
other = custom_app.add_resource(name="Other", resource_type="other", description
# Sub-resources can be added to any resource (including other sub-resources)
child1 = entity1.add_sub_resource(name="Child 1", resource_type="child",
child1.add_sub_resource(name="Grandchild 1", resource_type="grandchild", description=
# Any users and groups local to the application can be defined.
# IdP users can be mapped directly without defining them in the OAA application (see below)
custom_app.add_local_user("bob")
# A local user can be associated with an IdP user by adding an identity to the user:
custom_app.local_users["bob"].add_identity("[email protected]")
# Identities, groups and roles can be assigned to local users at creation or after (groups and roles must exist):
jane = custom_app.add_local_user("jane", identities="[email protected]")
# when adding a user the new user is returned and can updated if needed, there are multiple built in properties that can be set for a user
jane.is_active = False
jane.created_at = "2022-01-26T20:48:12.460Z"
# Define a local group and add a user to it
custom_app.add_local_group("admins")
custom_app.local_users["jane"].add_group("admins")
# adding local users and groups requires that the name not already exist
if "yan" not in custom_app.local_users:
custom_app.add_local_user("yan")
# For each Identity (user, group, IdP) assign permissions to the application or resource.
# The identities (users, groups) permissions and resources must already be defined
# To add a permission directly to the application use `apply_to_application=True`
custom_app.local_users["bob"].add_permission(permission="operator", apply_to_application=True
custom_app.local_groups["admins"].add_permission(permission="admin", apply_to_application=True
# You can describe specific permissions to individual resources or sub-resources:
custom_app.local_users["yan"].add_permission(permission="operator", resources=[entity1
# Authorization can also be created directly for an IdP identity
custom_app.add_idp_identity("[email protected]")
# resources can also be referenced by name from the application model
custom_app.idp_identities["[email protected]"].add_permission(permission="admin", resources=[
# Once all authorizations have been mapped, the final step is to publish the app to Veza
# Connect to the API to Push to Veza, define the provider and create if necessary:
provider_name = "Sample"
provider = veza_con.get_provider(provider_name)
if provider:
print("-- Found existing provider")
else:
print(f"++ Creating Provider {provider_name}")
provider = veza_con.create_provider(provider_name, "application")
print(f"-- Provider: {provider['name']} ({provider['id'
# Push the metadata payload:
try:
response = veza_con.push_application(provider_name,
data_source_name=f"{custom_app.name} ({custom_app.application_type})",
application_object=custom_app,
save_json=False
)
if response.get("warnings", None):
# Veza may return warnings on a successful uploads. These are informational warnings that did not stop the processing
# of the OAA data but may be important. Specifically identities that cannot be resolved will be returned here.
print("-- Push succeeded with warnings:")
for e in response["warnings"]:
print(f" - {e}")
except OAAClientError as e:
print(f"-- Error: {e.error}: {e.message} ({e.
if hasattr(e, "details"):
for d in e.details:
print(f" -- {d}", file=sys.stderr)
return
if __name__ == '__main__':
main()
#!env python3
"""
Copyright 2022 Veza Technologies Inc.
Use of this source code is governed by the MIT
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
Example of using the `CustomIdPProvider` class to model an identity provider as a source of users.
If you want to run the code you will need to export environment variables for the Veza URL, user and API keys.
```
export VEZA_API_KEY="xxxxxxx"
export VEZA_URL="https://myveza.vezacloud.com"
./sample-idp.py
```
Since the example includes fake AWS ARNs that Veza will not have discovered the expected output will
contain warning like "Cannot find IAM role by names ..."
"""
from oaaclient.client import OAAClient, OAAClientError
from oaaclient.templates import CustomIdPProvider, OAAPropertyType
import os
import sys
def main():
# OAA requires a Veza API key, which you can generate from Administration > API Keys
# Export the API key, and Veza URL as environment variables
# Making them available to your connector in this way keeps credentials out of the source code
veza_api_key = os.getenv("VEZA_API_KEY")
veza_url = os.getenv("VEZA_URL")
if not veza_api_key or not veza_url:
print("Unable to load VEZA_API_KEY and VEZA_URL from OS")
sys.exit(1)
# Instantiates a client connection. The client will confirm the credentials and Veza URL are valid
# Checking this early helps prevents connection failures in the final stage
veza_con = OAAClient(url=veza_url, api_key=veza_api_key)
# create a CustomIdPProvider to represent your IdP. This can be named generically or specific to the environment if you have
# multiple namespaces to model. idp_type will typically be the technology/vendor for the provider.
idp = CustomIdPProvider("My IdP", domain="example.com", idp_type="custom_idp
# add users to the idp, properties for users can be set during creation or updated after
idp.add_user("mrichardson", full_name="Michelle Richardson", email="[email protected]
evargas_user = idp.add_user("evargas")
evargas_user.full_name = "Elizabeth Vargas"
evargas_user.email = "[email protected]"
# users and groups can have optional identity property. The identity serves as the unique reference identifier across
# Veza. If omitted CustomIdPProvider will automatically populate the identity with the name
idp.add_user("willis", email="[email protected]", identity="cwilliams
# OAA can support custom properties for users to track additional metadata unique to the environment
# to use custom properties the property must first be defined and given a type, then can be set for the individual entity
idp.property_definitions.define_user_property("region", OAAPropertyType.STRING)
idp.property_definitions.define_user_property("is_contractor", OAAPropertyType.BOOLEAN)
idp.users['willis'].set_property("region", "NorthAmerica")
idp.users['willis'].set_property("is_contractor", True)
# Create Groups
idp.add_group("developers")
idp.add_group("sec-ops")
idp.add_group("everyone", full_name="All Company Employees")
# users can be added to groups using the add_group function, users can be added to multiple groups in a single call
for username in idp.users:
idp.users[username].add_groups(["everyone"])
evargas_user.add_groups(["developers", "sec-ops"])
idp.users["mrichardson"].add_groups(["developers"])
# Veza CustomIdP supports tracking the AWS Roles a user can assume. For users who can assume roles Veza can calculate
# their effective permissions to AWS resources based on the role(s)
# roles are added by ARN
idp.users["mrichardson"].add_assumed_role_arns(["arn:aws:iam::123456789012:role/role001", "arn:aws:iam::123456789012:role/role002"])
# After adding users and groups, the IdP information is pushed to Veza using the OAA API
provider_name = "Sample-IdP"
provider = veza_con.get_provider(provider_name)
if provider:
print("-- Found existing provider")
else:
print(f"++ Creating Provider {provider_name}")
provider = veza_con.create_provider(provider_name, "identity_provider")
print(f"-- Provider: {provider['name']} ({provider['id'
# Push the metadata payload:
try:
response = veza_con.push_application(provider_name,
data_source_name=f"{idp.name} ({idp.idp_type})",
application_object=idp,
save_json=True
)
if response.get("warnings", None):
# Veza may return warnings on a successful uploads. These are informational warnings that did not stop the processing
# of the OAA data but may be important, for example: AWS role ARNs assigned to users that Veza has not discovered
print("-- Push succeeded with warnings:")
for e in response["warnings"]:
print(f" - {e}")
except OAAClientError as e:
print(f"-- Error: {e.error}: {e.message} ({e.
if hasattr(e, "details"):
for d in e.details:
print(f" -- {d}", file=sys.stderr)
if __name__ == '__main__':
main()
#!env python3
"""Example of using `oaaclient` to import users from a CSV file.
Reads user properties from the input file, populates an OAA payload,
and creates a new OAA identity provider containing the imported users.
Expected CSV headers are `identity,name,full_name,is_active,is_guest,manager_id`
Can be updated to match custom column headings or apply custom properties.
Example:
```
export VEZA_URL=<Veza URL>
export VEZA_API_KEY=<Veza API key>
./idp-importer-csv.py --provider MyIdpProvider --datasource MyDatasource ./my-users.csv
```
Copyright 2022 Veza Technologies Inc.
Use of this source code is governed by the MIT
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
"""
from oaaclient.client import OAAClient, OAAClientError
from oaaclient.templates import CustomIdPProvider
import click
import csv
import logging
import os
import sys
logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=logging.INFO)
log = logging.getLogger()
def load_users(idp: CustomIdPProvider, source: str) -> None:
"""Populate the idp with user from the source csv file"""
log.info(f"Loading users from {source}")
with open(source) as f:
for r in csv.DictReader(f):
# get the identity, name, full_name and email
try:
identity = r["identity"]
name = r["name"]
full_name = r["full_name"]
email = r["email"]
except KeyError as e:
log.error(f"Incorrect CSV column headers, missing column {e}")
sys.exit(1)
# create a new IDP user
new_user = idp.add_user(name=name, full_name=full_name, email=email, identity=identity)
# set the user to active and guest or not, look for strings like true/false or yes/no
if r.get("active"):
active_string = r["active"].lower()
if active_string in ["true", "yes"]:
new_user.is_active = True
elif active_string in ["false", "no"]:
new_user.is_active = False
if r.get("is_guest"):
guest_string = r["is_guest"].lower()
if guest_string in ["true", "yes"]:
new_user.is_guest = True
elif guest_string in ["false", "no"]:
new_user.is_guest = False
# if the manager id column is filled in, set the new users manager
if r.get("manager_id"):
new_user.manager_id = r.get("manager_id")
return
@click.command()
@click.option("--provider", required=True)
@click.option("--datasource", required=True)
@click.option("--save-json", is_flag=True)
@click.argument("file", required=True)
def main(provider, datasource, save_json, file):
# load the Veza URL and API key from the environment
veza_url = os.getenv("VEZA_URL")
veza_api_key = os.getenv("VEZA_API_KEY")
if not (veza_url or veza_api_key):
log.error("Must set VEZA_URL and VEZA_API_KEY")
sys.exit(1)
try:
log.info("Testing Veza credentials")
veza_con = OAAClient(url=veza_url, api_key=veza_api_key)
except OAAClientError as e:
log.error("Unable to connect to Veza API")
log.error(e)
sys.exit(1)
# create a new provider if the provider doesn't already exist
if not veza_con.get_provider(provider):
log.info(f"Creating new provider {provider}")
veza_con.create_provider(provider, "identity_provider")
# Configure the Custom IdP
idp = CustomIdPProvider("Custom IdP", idp_type="custom_idp", domain="example.com", description=None)
# load the user from
load_users(idp, file)
try:
# push the IdP to Veza, log and errors or warnings
log.info("Sending to Veza")
response = veza_con.push_application(provider, datasource, idp, save_json=save_json)
if response.get("warnings", None):
log.warning("Push succeeded with warnings")
for w in response['warnings']:
log.warning(w)
log.info("Success")
except OAAClientError as e:
log.error(f"Error during push {e.message} {e.status_code}")
if e.details:
log.error(e.details)
sys.exit(1)
return
if __name__ == "__main__":
main()
Template for modeling a lightweight identity source with users, groups, and tenants
access_billable flags whether the user counts toward the organization's Atlassian license seat count.curl -X POST "https://{VEZA_URL}/api/v1/providers/custom" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data '{"name":"ExampleCorp","custom_templates":["principal","application"]}'curl -X POST "https://{VEZA_URL}/api/v1/providers/custom/{PROVIDER_ID}/datasources" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data '{"name":"Principal Data Source","custom_template":"principal"}'{
"custom_property_definition": {
"tenant_properties": {
"region": "STRING"
},
"user_properties": {
"department": "STRING",
"mfa_enabled": "BOOLEAN"
},
"group_properties": {
"is_security_group": "BOOLEAN"
}
},
"name": "Example Corp",
"principal_type": "corporate_directory",
"tenant": {
"name": "Example Corp",
"id": "tenant-001",
"tenant_unique_id": "tenant-001",
"tags": [
{
"key": "environment",
"value": "production"
}
],
"custom_properties": {
"region": "us-west-2"
}
},
"users": [
{
"name": "Alice Johnson",
"id": "alice01",
"email": "[email protected]",
"user_unique_id": "alice01",
"display_name": "Alice Johnson",
"is_active": true,
"created_date": "2024-01-15T09:00:00.000Z",
"last_login": "2025-02-20T14:30:00.000Z",
"identities": [
"[email protected]"
],
"groups": [
{
"id": "grp-engineering"
}
],
"custom_properties": {
"department": "Engineering",
"mfa_enabled": true
}
},
{
"name": "Bob Smith",
"id": "bob02",
"email": "[email protected]",
"user_unique_id": "bob02",
"is_active": true,
"identities": [
"[email protected]"
],
"groups": [
{
"id": "grp-engineering"
},
{
"id": "grp-admins"
}
],
"custom_properties": {
"department": "Engineering"
}
}
],
"groups": [
{
"name": "Engineering",
"id": "grp-engineering",
"group_unique_id": "grp-engineering",
"group_type": "Department",
"identities": [
"[email protected]"
],
"custom_properties": {
"is_security_group": false
}
},
{
"name": "Admins",
"id": "grp-admins",
"group_unique_id": "grp-admins",
"group_type": "Security",
"custom_properties": {
"is_security_group": true
}
},
{
"name": "Platform Team",
"id": "grp-platform",
"group_unique_id": "grp-platform",
"group_type": "Team",
"parent_group": {
"id": "grp-engineering"
}
}
]
}{
"custom_property_definition": {
"user_properties": {
"account_type": "STRING",
"account_status": "STRING",
"access_billable": "BOOLEAN",
"product_access": "STRING_LIST",
"user_type": "STRING"
},
"group_properties": {
"description": "STRING"
}
},
"name": "Atlassian Cloud Admin",
"principal_type": "Atlassian Cloud Admin",
"tenant": {
"name": "acme-corp",
"id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"tenant_unique_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
},
"users": [
{
"name": "Jane Doe",
"id": "5b10ac8d82e05b22cc7d4ef5",
"email": "[email protected]",
"user_unique_id": "5b10ac8d82e05b22cc7d4ef5",
"is_active": true,
"identities": [
"[email protected]"
],
"groups": [
{
"id": "jira-software-users"
},
{
"id": "confluence-users"
}
],
"custom_properties": {
"account_type": "atlassian",
"account_status": "active",
"access_billable": true,
"product_access": ["jira-software", "confluence"],
"user_type": "managed"
}
},
{
"name": "[email protected]",
"id": "7c20bd9e93f16c33dd8e5fg6",
"email": "[email protected]",
"user_unique_id": "7c20bd9e93f16c33dd8e5fg6",
"is_active": true,
"identities": [
"[email protected]"
],
"groups": [
{
"id": "jira-software-users"
}
],
"custom_properties": {
"account_type": "atlassian",
"account_status": "active",
"access_billable": true,
"product_access": ["jira-software"],
"user_type": "external"
}
}
],
"groups": [
{
"name": "jira-software-users",
"id": "jira-software-users",
"group_unique_id": "jira-software-users",
"group_type": "product-access",
"custom_properties": {
"description": "Users with access to Jira Software"
}
},
{
"name": "confluence-users",
"id": "confluence-users",
"group_unique_id": "confluence-users",
"group_type": "product-access",
"custom_properties": {
"description": "Users with access to Confluence"
}
},
{
"name": "org-admins",
"id": "org-admins",
"group_unique_id": "org-admins",
"group_type": "admin",
"custom_properties": {
"description": "Organization administrators"
}
}
]
}"tenant": {
"name": "Example Corp",
"id": "tenant-001",
"tenant_unique_id": "tenant-001",
"tags": [],
"custom_properties": {}
}"users": [
{
"name": "Alice Johnson",
"id": "alice01",
"email": "[email protected]",
"user_unique_id": "alice01",
"display_name": "Alice Johnson",
"is_active": true,
"created_date": "2024-01-15T09:00:00.000Z",
"last_login": "2025-02-20T14:30:00.000Z",
"identities": ["[email protected]"],
"groups": [{"id": "grp-engineering"}],
"tags": [],
"custom_properties": {}
}
]"groups": [
{
"name": "Engineering",
"id": "grp-engineering",
"group_unique_id": "grp-engineering",
"group_type": "Department",
"identities": ["[email protected]"],
"tags": [],
"custom_properties": {}
},
{
"name": "Platform Team",
"id": "grp-platform",
"group_type": "Team",
"parent_group": {
"id": "grp-engineering"
}
}
]"custom_property_definition": {
"tenant_properties": {
"region": "STRING"
},
"user_properties": {
"department": "STRING",
"mfa_enabled": "BOOLEAN"
},
"group_properties": {
"is_security_group": "BOOLEAN"
}
}curl -X POST "https://{VEZA_URL}/api/v1/providers/custom" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data '{"name":"ExampleCorp","custom_templates":["principal","application"]}'curl -X POST "https://{VEZA_URL}/api/v1/providers/custom/{PROVIDER_ID}/datasources" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data '{"name":"Principal Data Source","custom_template":"principal"}'curl -X POST "https://{VEZA_URL}/api/v1/providers/custom/{PROVIDER_ID}/datasources/{DATASOURCE_ID}:push" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data "{\"json_data\": $(jq -Rs . payload.json)}"using RestSharp;
using RestSharp.Authenticators;
using Veza.OAA;
using Veza.OAA.Application;
using Veza.OAA.Client;
using NLog;
namespace Example.Integrations
{
/// <summary>
/// Example application group object
/// </summary>
public class AppGroup {
public string Name { get; set; }
public string Type { get; set; }
public string CreatedAt { get; set; }
public List<string> Users { get; set; }
}
/// <summary>
/// Example application resource object
/// </summary>
public class AppResource {
public string Name { get; set; }
public int SiteId { get; set; }
public string ResourceType { get; set; }
}
/// <summary>
/// Example application role object
/// </summary>
public class AppRole {
public string Name { get; set; }
public int SystemId { get; set; }
public string CreatedAt { get; set; }
public List<string> Users { get; set; }
public List<string> Resources { get; set; }
}
public class ExampleApp
{
// Optional NLog logger; can be replaced with any standard logging interface
private static Logger logger = LogManager.GetCurrentClassLogger();
// The base64-encoded logo for the application (displayed on the Veza UI)
public string LogoBase64;
// The name of the provider for the application
public string ProviderName;
// The custom application object for the example application
// This object is used to build the application payload for Veza
public CustomApplication CustomApp { get; set; }
// The example application client for the example application API (not shown in this example)
private ExampleAppClient AppClient { get; set; }
# region "Construction"
public ExampleApp()
{
// Instantiate the example application
CustomApp = new CustomApplication(
name: "Example Application 1",
applicationType: "Example App",
description: "Example application for Veza integration"
);
// Define an "uncategorized" permission for the example application
// This can be used to group permissions that do not fit into another category,
// or if the application API does not provide permission information
CustomApp.AddCustomPermission(
name: "Uncategorized",
permissions: new List<Permission> { Permission.Uncategorized }
);
// define custom properties for the example application
DefineCustomProperties();
// Set the application icon for the Veza UI
// This should be a base64-encoded SVG or PNG image
LogoBase64 = "abc123...def987654"
}
/// <summary>
/// Define custom properties for the example application.
/// This method is called by the constructor to define any custom properties
/// that the example application entities may have.
/// </summary>
private void DefineCustomProperties()
{
CustomApp.DefinedProperties[typeof(User)].
DefineProperty("locked_out", typeof(bool);
CustomApp.DefinedProperties[typeof(Group)].
DefineProperty("type", typeof(string));
CustomApp.DefinedProperties[typeof(Role)].
DefineProperty("system_id", typeof(int));
CustomApp.DefineResourceProperty("site_id", typeof(int)), "widget");
}
# endregion
# region "Discovery"
// Individual methods for discovering users, groups, roles, and resources.
// Should be scoped as private to ensure that they are called only by the Discover method
// and not directly by the client application.
/// <summary>
/// Discover users for the example application.
/// This method is called by the Discover method to discover users for the example application.
/// </summary>
private void DiscoverUsers()
{
Logger.Info("Discovering users for the example application");
// Get users from the example application client.
// In this example, the GetUsers method returns a list of dictionaries of user data.
List<Dictionary<string, string>> users = AppClient.GetUsers();
// Iterate over the users response and add them to the application payload
foreach (Dictionary<string, string> u in users)
{
// Create a new user object and add it to the application payload
User user = CustomApp.AddUser(name: u["username"]);
user.AddIdentity(u["email"]);
user.IsActive = u["active"];
user.CreatedAt = u["created_at"];
}
Logger.Info("User discovery complete");
}
/// <summary>
/// Discover groups for the example application.
/// This method is called by the Discover method to discover groups for the example application.
/// </summary>
private void DiscoverGroups()
{
Logger.Info("Discovering groups for the example application");
// Get groups from the example application client
// in this example, the GetGroups method returns a list of AppGroup objects
List<AppGroup> groups = AppClient.GetGroups();
// Iterate over the groups response and add them to the application payload
foreach (AppGroup g in groups)
{
// Create a new group object and add it to the application payload
Group group = CustomApp.AddGroup(name: g.Name);
group.CreatedAt = g.CreatedAt;
group.SetProperty(name: "type", value: g.Type);
// Iterate users in the group and add them to the group
foreach (string user in g.Users)
{
CustomApp.Users[user].AddGroup(g.Name);
}
}
Logger.Info("Group discovery complete");
}
/// <summary>
/// Discover resources for the example application.
/// This method is called by the Discover method to discover resources for the example application.
/// </summary>
private void DiscoverResources()
{
Logger.Info("Discovering resources for the example application");
// Get resources from the example application
// In this example, the GetResources method returns a list of AppResource objects
List<AppResource> resources = AppClient.GetResources();
foreach (AppResource r in resources)
{
// Create a resource object and add it to the application payload
Resource resource = CustomApp.AddResource(name: r.Name, resourceType: r.ResourceType);
// Set the `site_id` property for the resource if the resource is a "widget"
// Cstom resource properties are defined per-resource type, so non-"widget" resources will not have this property
if (r.ResourceType == "widget")
{
resource.SetProperty(name: "site_id", value: r.SiteId);
}
}
Logger.Info("Resource discovery complete");
}
/// <summary>
/// Discover roles for the example application.
/// This method is called by the Discover method to discover roles for the example application.
/// </summary>
private void DiscoverRoles()
{
Logger.Info("Discovering roles for the example application");
// get roles from the example application
// in this example, the GetRoles method returns a list of AppRole objects
List<AppRole> roles = AppClient.GetRoles();
foreach (Role role in roles)
{
// create a new role object and add it to the application payload
Role role = CustomApp.AddRole(name: role.Name);
role.CreatedAt = role.CreatedAt;
role.SetProperty(name: "system_id", value: role.SystemId);
// iterate users in the role and add them to the role
// set the applyToApplication flag to true to apply the role to the entire application
foreach (string user in role.Users)
{
CustomApp.Users[user].AddRole(name: role.Name, applyToApplication: true);
}
Application.AddRole(role);
}
Logger.Info("Role discovery complete");
}
# endregion
# region "Execution"
/// <summary>
/// Discover the example application.
/// This method is called by the Run method to discover the example application.
/// It serves as a place to instantiate a client for the example application API
/// and then call each of the discovery methods required to build the application payload.
/// </summary>
/// <param name="exampleApiKey">The API key for the example application API</param>
/// <param name="exampleUrl">The URL for the example application API</param>
/// <returns></returns>
public void Discover(string exampleApiKey, string exampleUrl)
{
// instantiate an API client for the example application
AppClient = new ExampleAppClient(exampleApiKey, exampleUrl);
Logger.Info("Beginning example application discovery");
// discover the example application components
DiscoverUsers();
DiscoverGroups();
DiscoverResources();
DiscoverRoles();
Logger.Info("Example application discovery complete");
}
/// <summary>
/// Handle integration execution.
/// This is separated from the Main method to more easily adapt to changes
/// to application execution (e.g. from Command Prompt, as part of another application, etc.)
/// </summary>
/// <param name="exampleApiKey">The API key for the Example application API</param>
/// <param name="exampleUrl">The URL for the Example application API</param>
/// <param name="vezaApiKey">The API key for the Veza tenant</param>
/// <param name="vezaUrl">The URL for the Veza tenant</param>
/// <returns></returns>
public async Task Run(
string exampleApiKey,
string exampleUrl,
string vezaApiKey,
string vezaUrl
)
{
Logger.Info("Starting example application discovery");
// Instantiate a connection to the Veza API.
// The client will attempt to reach the Veza API and throw an exception if it fails.
// This is to ensure that the Veza API is reachable before attempting to discover and push data.
try
{
OAAClient oaaClient = new(vezaApiKey, vezaUrl);
}
catch (ClientException e)
{
Logger.Error("Failed to connect to Veza API: {0}", e.Message);
return;
}
// Discover the example application
Discover(exampleApiKey, exampleUrl);
// Get or create the Veza provider for the payload
Logger.Debug("Checking Veza for an existing provider for the example application");
Sdk.Client.ApiClient.VezaApiResponse providerResponse = await oaaClient.GetProvider(ProviderName);
// Create the provider if none exists
if (providerResponse is null)
{
Logger.Info("No Veza provider exists; creating provider");
await oaaClient.CreateProvider(ProviderName, "application", base64_icon: LogoBase64);
}
// Push OAA payload to Veza
Logger.Info("Pushing example application metadata to Veza");
RestResponse<Sdk.Client.ApiClient.VezaApiResponse> pushResponse = await oaaClient.PushApplication(ProviderName, Environment.MachineName, CustomApp, save_json: true);
if (pushResponse.IsSuccessful)
{
Logger.Info("Example application discovery complete");
} else
{
Logger.Error($"Push response code: {pushResponse.StatusCode}");
Logger.Error($"Push response content: {pushResponse.Content}");
}
}
# endregion
}
}Template for pushing IdP domain, user, and group metadata
Custom Identity Provider definitionIdP DomainIdP UsersIdP GroupsIdP AppsIdentity Mapping ConfigurationOAA Template for Human Resources Information Systems
{
"name": "HRIS Example",
"hris_type": "HR Platform",
"custom_property_definition": {
"system_properties": {},
"employee_properties": {
"job_level": "STRING"
},
"group_properties": {}
},
"system": {
"id": "7D8A21AE-6650-4357-842B-3FCEC8F29195",
"name": "HRIS Example",
"url": "https://hris.example.com",
},
"employees": [
{
"id": "123456",
"name": "jdoe",
"employee_number": "E123456",
"first_name": "John",
"last_name": "Doe",
"canonical_name": "Doe, John",
"email": "[email protected]",
"home_location": "Anytown, CA",
"work_location": "San Francisco, CA",
"employment_status": "HIRED",
"start_date": "2022-05-22T00:00:00Z",
"job_title": "Software Developer",
"employment_types": [
"FULL_TIME"
],
"custom_properties": {
"job_level": "L3"
},
"is_active": true,
"groups": [
{
"id": "all_employees"
}
],
"managers": [
{
"id": "987654"
}
],
"department": {
"id": "engineering"
}
},
{
"id": "987654",
"name": "jane.doe",
"employee_number": "E987654",
"first_name": "Jane",
"last_name": "Doe",
"canonical_name": "Doe, Jane",
"email": "[email protected]",
"home_location": "Anytown, CA",
"work_location": "San Francisco, CA",
"employment_status": "HIRED",
"start_date": "2021-03-13T00:00:00Z",
"job_title": "Software Developer",
"employment_types": [
"FULL_TIME"
],
"custom_properties": {
"job_level": "M2"
},
"is_active": true,
"groups": [
{
"id": "all_employees"
}
],
"department": {
"id": "engineering"
}
}
],
"groups": [
{
"id": "all_employees",
"name": "All Employees",
"group_type": "Employee Group"
},
{
"id": "engineering",
"name": "Engineering",
"group_type": "Department"
}
]
}{
"name": "BambooHR",
"hris_type": "BambooHR",
"custom_property_definition": {
"employee_properties": {
"division": "STRING",
"office_extension": "STRING"
},
"group_properties": {
"headquarters_location": "STRING"
}
},
"system": {
"name": "BambooHR",
"id": "BambooHR",
"url": "https://vezai.bamboohr.com",
"idp_providers": ["okta"]
},
"employees": [
{
"name": "Charlotte Abbott",
"id": "1",
"custom_properties": {
"division": "North America",
"office_extension": "1234"
},
"employee_number": "1",
"email": "[email protected]",
"work_location": "Lindon, Utah",
"job_title": "Sr. HR Administrator"
},
{
"name": "Cheryl Barnet",
"id": "10",
"custom_properties": {
"division": "North America",
"office_extension": "5678"
},
"employee_number": "10",
"email": "[email protected]",
"work_location": "Lindon, Utah",
"job_title": "VP of Customer Success"
}
],
"groups": [
{
"name": "North America-Human Resources",
"id": "North America-Human Resources",
"group_type": "Department",
"custom_properties": {
"headquarters_location": "Lindon, Utah"
}
}
]
}report_builder_entrypoint() → Nonemain()__init__(
error: 'str',
message: 'str',
status_code: 'int' = None,
details: 'list' = None
) → None__init__(*args, **kwargs)__init__(
error: 'str',
message: 'str',
status_code: 'int' = None,
details: 'list' = None
) → None__init__(
url: 'str' = None,
api_key: 'str' = None,
username: 'str' = None,
token: 'str' = None
)add_query_report(report_id: 'str', query_id: 'str') → dictapi_delete(api_path: 'str', params: 'dict' = None) → dictapi_get(api_path: 'str', params: 'dict' = None) → list | dictapi_patch(api_path: 'str', data: 'dict', params: 'dict' = None) → dictapi_post(api_path: 'str', data: 'dict', params: 'dict' = None) → list | dictapi_put(api_path: 'str', data: 'dict', params: 'dict' = None) → list | dictcreate_data_source(
name: 'str',
provider_id: 'str',
options: 'dict | None' = None
) → dictcreate_datasource(name, provider_id)create_provider(
name: 'str',
custom_template: 'str',
base64_icon: 'str' = '',
options: 'dict | None' = None
) → dictcreate_query(query: 'dict') → dictcreate_report(report: 'dict') → dictdelete_data_source(data_source_id: 'str', provider_id: 'str') → dictdelete_provider(provider_id: 'str') → dictdelete_query(id: 'str', force: 'bool' = False) → dictdelete_report(id: 'str') → dictget_data_source(name: 'str', provider_id: 'str') → dictget_data_sources(provider_id: 'str') → list[dict]get_provider(name: 'str') → dictget_provider_by_id(provider_id: 'str') → dictget_provider_list() → list[dict]get_queries(include_inactive_queries: 'bool' = True) → list[dict]get_query_by_id(id: 'str') → dictget_report_by_id(id: 'str', include_inactive_queries: 'bool' = True) → dictget_reports(
include_inactive_reports: 'bool' = True,
include_inactive_queries: 'bool' = True
) → list[dict]push_application(
provider_name: 'str',
data_source_name: 'str',
application_object: 'CustomApplication | CustomIdPProvider',
save_json: 'bool' = False,
create_provider: 'bool' = False,
options: 'dict | None' = None
) → dictpush_metadata(
provider_name: 'str',
data_source_name: 'str',
metadata: 'dict',
save_json: 'bool' = False,
options: 'dict | None' = None
) → dictupdate_provider_icon(provider_id: 'str', base64_icon: 'str') → Noneupdate_report(report_id: 'str', report: 'dict') → dictupdate_user_agent(extra: 'str' = '') → None__init__(backoff_max=30, **kwargs) → None{
"name": "My IdP",
"idp_type": "custom_idp",
"domains": [
{
"name": "example.com",
"tags": [],
}
],
"users": [
{
"name": "m_richardson",
"email": "[email protected]",
"identity": "m_richardson",
"full_name": "Michelle Richardson",
"department": null,
"is_active": true,
"is_guest": false,
"groups": [
{
"identity": "everyone"
},
{
"identity": "developers"
}
],
"assumed_role_arns": [
{
"identity": "arn:aws:iam::123456789012:role/role001"
},
{
"identity": "arn:aws:iam::123456789012:role/role002"
}
],
"tags": [],
},
{
"name": "evargas",
"email": "[email protected]",
"identity": "evargas",
"full_name": "Elizabeth Vargas",
"department": null,
"is_active": true,
"is_guest": false,
"groups": [
{
"identity": "everyone"
},
{
"identity": "developers"
},
{
"identity": "sec-ops"
}
],
"assumed_role_arns": [],
"tags": [],
},
{
"name": "willis",
"email": "[email protected]",
"identity": "c_williams",
"full_name": null,
"department": null,
"is_active": true,
"is_guest": false,
"groups": [
{
"identity": "everyone"
}
],
"assumed_role_arns": [],
"tags": []
}
],
"groups": [
{
"name": "developers",
"identity": "developers",
"full_name": null,
"is_security_group": null,
"tags": []
},
{
"name": "sec-ops",
"identity": "sec-ops",
"full_name": null,
"is_security_group": null,
"tags": []
},
{
"name": "everyone",
"identity": "everyone",
"full_name": "All Company Employees",
"is_security_group": null,
"tags": []
}
],
"identity_mapping_configuration": {
"mappings": [
{
"destination_datasource_type": "GITHUB_USERS",
"property_matchers": [
{
"source_property": "EMAIL",
"destination_property": "UNIQUE_ID"
}
]
},
{
"destination_datasource_type": "SQL_SERVER",
"property_matchers": [
{
"source_property": "EMAIL",
"destination_property": "EMAIL"
}
],
"transformations": [
"IGNORE_DOMAIN"
]
}
]
}
}Template for modeling secret storage systems with vaults, entries, and permissions
{
"name": "Custom User",
"assumed_role_arns": {
"identity": [
"arn:aws:iam::123456789012:role/S3Access"
]
},
}{
"name": "Custom User",
"identity": "00001",
"source_identity": {
"identity": "[email protected]",
"provider_type": "okta"
}
}{
"name": "Custom User",
"identity": "000011",
"entities_owned": [
{
"node_type": "S3Bucket",
"id": "arn:aws:s3:::amazon-connect-53f87966654d"
}
]
}{
"name": "Custom User",
"identity": "000013",
"manager_id": "000011"
}"tags": [
{
"key": "Tag1key",
"value": "optional_Tag1Val"
}
]{
"name": "willis",
"email": "[email protected]",
"identity": "000001",
"full_name": "Charles Willis",
"department": "Sales",
"is_active": true,
"is_guest": false,
"groups": [
{
"identity": "everyone"
}
],
"assumed_role_arns": {
"identity": [
"arn:aws:iam::123456789012:role/S3Access"
]
},
"source_identity": {
"identity": "[email protected]",
"provider_type": "okta"
},
"tags": [],
"custom_properties": {},
"manager_id": "string",
"entities_owned": {
"node_type": "S3Bucket",
"id": "arn:aws:s3:::amazon-connect-53f87966654d"
}
}"groups": [
{
"name": "developers",
"identity": "developers",
"full_name": null,
"is_security_group": null,
"assumed_role_arns": {
"identity": ["arn:aws:iam::123456789012:role/S3Access"]
},
"tags": [],
"groups": [
{ "group_1_identity": "parent" },
{ "group_2_identity": "parent" }
],
"custom_properties": {}
}
] "apps": [
{
"id": "app1",
"name": "Application 1",
"description": "This is a sample application",
"assumed_role_arns": [
{
"identity": "arn:aws:iam::1234567890:role/DevAppRole"
}
],
"custom_properties": {
"owner_org": "engineering"
},
"tags": []
}
] {
"name": "willis",
"email": "[email protected]",
"identity": "cwilliams",
"groups": [
{
"identity": "everyone"
}
],
"custom_properties": {
"region": "NorthAmerica",
"is_contractor": true
},
"app_assignments": [
{
"id": "assignment1",
"name": "Assignment",
"app_id": "app1",
"custom_properties": {
"assigned_on": "2024-12-05T12:42:25+00:00"
}
}
]
}curl -X POST 'https://<veza_url>/api/v1/providers/custom' \
-H 'authorization: Bearer '<access_token> \
--data-binary '{"name":"SimpleIdP","custom_template":"identity_provider"}'{
"value": {
"id": "532f6fe3-189f-4576-afdf-8913088961e4",
"name": "Simple IdP",
"custom_template": "identity_provider",
"state": "ENABLED",
"application_types": [],
"resource_types": [],
"idp_types": []
}
}curl -X POST 'https://<veza_url>/api/v1/providers/custom/532f6fe3-189f-4576-afdf-8913088961e4/datasources' \
-H 'authorization: Bearer '<access_token> \
--data-binary '{"id":"532f6fe3-189f-4576-afdf-8913088961e4", "name":"SimpleDataSource"}'{"value":{"id":"b6a32af6-b854-47e1-8325-e5984f78bb4d","name":"SimpleDataSource"}}curl -X POST 'https://<veza_url>/api/v1/providers/custom/532f6fe3-189f-4576-afdf-8913088961e4/datasources/b6a32af6-b854-47e1-8325-e5984f78bb4d:push' \
-H 'authorization: Bearer '<access_token> \
--compressed --data-binary @payload.json{
"id": "532f6fe3-189f-4576-afdf-8913088961e4",
"data_source_id": "b6a32af6-b854-47e1-8325-e5984f78bb4d",
"json_data": "{\n\"name\":\"CustomIdentityProvider\",\n\"idp_type\": ... "
}{
"identity_mapping_configuration": {
"mappings": [
{
"destination_datasource_type": "OKTA",
"property_matchers": [
{
"source_property": "EMAIL",
"destination_property": "EMAIL"
}
],
"transformations": [
"IGNORE_SPECIAL"
]
},
{
"destination_datasource_type": "AZURE_AD",
"property_matchers": [
{
"source_property": "EMAIL",
"destination_property": "EMAIL"
}
],
"transformations": [
"IGNORE_DOMAIN"
]
},
{
"destination_datasource_type": "GITHUB_USERS",
"property_matchers": [
{
"source_property": "EMAIL",
"destination_property": "UNIQUE_ID"
}
]
}
]
}
}{
"incremental_change": true,
"identity_mapping_configuration": {
"operation": "modify",
"mappings": [
{
"destination_datasource_type": "GITHUB_USERS",
"property_matchers": [
{
"source_property": "EMAIL",
"destination_property": "UNIQUE_ID"
}
]
},
{
"destination_datasource_type": "SQL_SERVER",
"property_matchers": [
{
"source_property": "EMAIL",
"destination_property": "EMAIL"
}
],
"transformations": [
"IGNORE_DOMAIN"
]
}
]
}
}curl --location 'https://<veza_url>/api/v1/providers/custom/816d6e51-6d6a-4279-ba41-2e7c732be880/datasources/716026b5-4b84-4b2f-a805-b41a6ec69cf3:push' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <API_KEY>' \
--data '{
"id": "816d6e51-6d6a-4279-ba41-2e7c732be880",
"data_source_id": "716026b5-4b84-4b2f-a805-b41a6ec69cf3",
"json_data": "{\"incremental_change\":true,\"identity_mapping_configuration\":{\"operation\":\"modify\",\"mappings\":[{\"destination_datasource_type\":\"GITHUB_USERS\",\"property_matchers\":[{\"source_property\":\"EMAIL\",\"destination_property\":\"UNIQUE_ID\"}]},{\"destination_datasource_type\":\"SQL_SERVER\",\"property_matchers\":[{\"source_property\":\"EMAIL\",\"destination_property\":\"EMAIL\"}],\"transformations\":[\"IGNORE_DOMAIN\"]}]}}"
}'{
"secret_store_type": "hashicorp_vault",
"custom_property_definition": {
"secret_store_properties": {
"environment": "STRING"
},
"permission_properties": {},
"vault_properties": {
"encryption_type": "STRING"
},
"entry_properties": {
"rotation_enabled": "BOOLEAN"
}
},
"secret_store": {
"name": "Production Vault",
"id": "prod-vault-001",
"description": "Production environment secrets",
"tags": [
{
"key": "department",
"value": "engineering"
}
],
"custom_properties": {
"environment": "production"
},
"permissions": [
{
"name": "Read",
"id": "perm-read",
"resource": "secrets/*",
"allow_identity_assume": false
},
{
"name": "Write",
"id": "perm-write",
"resource": "secrets/*",
"allow_identity_assume": true
}
],
"secret_store_vaults": [
{
"name": "API Keys",
"id": "vault-api-keys",
"vault_type": "kv",
"description": "API key storage",
"tags": [
{
"key": "category",
"value": "api-credentials"
}
],
"custom_properties": {
"encryption_type": "AES-256"
},
"entries": [
{
"name": "Stripe API Key",
"id": "entry-stripe",
"description": "Stripe payment processing key",
"custom_properties": {
"rotation_enabled": true
},
"identities": [
{
"type": "OktaUser",
"external_id": "[email protected]"
}
]
}
]
},
{
"name": "Database Credentials",
"id": "vault-db-creds",
"vault_type": "kv",
"description": "Database connection credentials",
"custom_properties": {
"encryption_type": "AES-256"
},
"entries": [
{
"name": "PostgreSQL Admin",
"id": "entry-postgres",
"description": "PostgreSQL admin credentials",
"custom_properties": {
"rotation_enabled": true
}
}
]
}
],
"identity_to_permissions": [
{
"identity": "admin-user",
"identity_type": "local_user",
"permission_assignments": [
{
"vault": [
"vault-api-keys",
"vault-db-creds"
],
"permissions": [
"Read",
"Write"
]
}
]
},
{
"identity": "developer-user",
"identity_type": "local_user",
"permission_assignments": [
{
"vault": [
"vault-api-keys"
],
"permissions": [
"Read"
]
}
]
}
]
}
}{
"secret_store_type": "custom_pam",
"custom_property_definition": {
"vault_properties": {
"rotation_policy": "STRING",
"requires_approval": "BOOLEAN"
},
"entry_properties": {
"credential_type": "STRING"
}
},
"secret_store": {
"name": "ACME Internal PAM",
"id": "pam.acme-internal.example.com",
"description": "Production internal credential management system",
"tags": [
{
"key": "environment",
"value": "production"
}
],
"permissions": [
{
"name": "View",
"id": "perm-view",
"allow_identity_assume": false
},
{
"name": "Checkout",
"id": "perm-checkout",
"allow_identity_assume": true
},
{
"name": "Rotate",
"id": "perm-rotate",
"allow_identity_assume": false
},
{
"name": "Manage",
"id": "perm-manage",
"allow_identity_assume": false
}
],
"secret_store_vaults": [
{
"name": "Production Databases",
"id": "vault-prod-databases",
"vault_type": "database",
"description": "Privileged database credentials for production systems",
"custom_properties": {
"rotation_policy": "30-day",
"requires_approval": true
},
"entries": [
{
"name": "postgres-prod-admin",
"id": "cred-pg-admin-001",
"description": "PostgreSQL production superuser",
"custom_properties": {
"credential_type": "service_account"
},
"identities": [
{
"type": "AzureADUser",
"external_id": "[email protected]"
}
]
},
{
"name": "mysql-prod-readonly",
"id": "cred-mysql-ro-001",
"description": "MySQL production read-only service account",
"custom_properties": {
"credential_type": "service_account"
}
}
]
},
{
"name": "Cloud Platform Keys",
"id": "vault-cloud-keys",
"vault_type": "cloud_credentials",
"description": "Cloud provider access keys",
"custom_properties": {
"rotation_policy": "90-day",
"requires_approval": false
},
"entries": [
{
"name": "cloud-prod-admin",
"id": "cred-cloud-admin-001",
"description": "Production cloud IAM admin access key",
"custom_properties": {
"credential_type": "access_key"
},
"identities": [
{
"type": "AzureADUser",
"external_id": "[email protected]"
}
]
}
]
}
],
"identity_to_permissions": [
{
"identity": "[email protected]",
"identity_type": "AzureADUser",
"permission_assignments": [
{
"vault": ["vault-prod-databases"],
"permissions": ["View", "Checkout"]
}
]
},
{
"identity": "[email protected]",
"identity_type": "AzureADUser",
"permission_assignments": [
{
"vault": ["vault-cloud-keys"],
"permissions": ["View", "Checkout", "Rotate"]
},
{
"vault": ["vault-prod-databases"],
"permissions": ["View"]
}
]
}
]
}
}curl -X POST "https://{VEZA_URL}/api/v1/providers/custom" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data '{"name":"MySecretStore","custom_template":"secret_store"}'curl -X POST "https://{VEZA_URL}/api/v1/providers/custom/{PROVIDER_ID}/datasources" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data '{"name":"my_secret_store_source"}'curl -X POST "https://{VEZA_URL}/api/v1/providers/custom/{PROVIDER_ID}/datasources/{DATASOURCE_ID}:push" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data "{\"json_data\": $(jq -Rs . payload.json)}"curl -X POST "https://{VEZA_URL}/api/v1/providers/custom" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data '{"name":"MySecretStore","custom_template":"secret_store"}'"secret_store": {
"name": "Production Vault",
"id": "prod-vault-001",
"description": "Production environment secrets",
"tags": [],
"custom_properties": {},
"permissions": [],
"secret_store_vaults": [],
"identity_to_permissions": []
}"permissions": [
{
"name": "Read",
"id": "perm-read",
"resource": "secrets/*",
"allow_identity_assume": false
}
]"secret_store_vaults": [
{
"name": "API Keys",
"id": "vault-api-keys",
"vault_type": "kv",
"description": "API key storage",
"tags": [],
"custom_properties": {},
"entries": []
}
]"entries": [
{
"name": "Stripe API Key",
"id": "entry-stripe",
"description": "Stripe payment processing key",
"custom_properties": {
"rotation_enabled": true
},
"identities": [
{
"type": "OktaUser",
"external_id": "[email protected]"
}
]
}
]"identities": [
{
"type": "OktaUser",
"external_id": "[email protected]"
}
]"identity_to_permissions": [
{
"identity": "admin-user",
"identity_type": "local_user",
"permission_assignments": [
{
"vault": ["vault-api-keys", "vault-db-creds"],
"permissions": ["Read", "Write"]
}
]
}
]"custom_property_definition": {
"secret_store_properties": {
"environment": "STRING"
},
"permission_properties": {},
"vault_properties": {
"encryption_type": "STRING"
},
"entry_properties": {
"rotation_enabled": "BOOLEAN"
}
}Template for pushing custom data source entities and authorization
idplocal_userlocal_grouplocal_rolelocal_access_credscurl -X POST "https://{VEZA_URL}/api/v1/providers/custom" \
-H "authorization: Bearer {API_KEY}" \
--compressed --data-binary '{"name":"DemoApp","custom_template":"application"}'curl -X POST "https://{VEZA_URL}/api/v1/providers/custom" \
-H "authorization: Bearer {API_KEY}" \
-H "Content-Type: application/json" \
--data '{
"name": "MyCustomApp",
"custom_template": "application",
"external_lifecycle_management_type": "SCIM"
}'{
"custom_property_definition": {
"applications": [
{
"application_type": "sample",
"application_properties": {},
"local_user_properties": {},
"local_group_properties": {},
"local_role_properties": {},
"resources": []
}
]
},
"applications": [
{
"name": "Sample App",
"application_type": "sample",
"description": "This is a sample app",
"local_users": [
{
"id": "0000000001",
"name": "bob",
"identities": [
"[email protected]"
],
"is_active": true,
"created_at": "2022-01-26T20:48:12.460Z"
},
{
"id": "0000000002",
"name": "jane",
"identities": [
"[email protected]"
],
"groups": [
"admins"
],
"created_at": "2021-08-13T06:28:13.250Z"
}
],
"local_groups": [
{
"id": "admins",
"name": "Administrators"
}
],
"local_roles": [],
"tags": [],
"custom_properties": {},
"resources": [
{
"id": "0001",
"name": "Entity1",
"resource_type": "thing",
"description": "Some entity in the application",
"sub_resources": [
{
"name": "Child 1",
"resource_type": "child",
"description": "My information about resource"
}
]
},
{
"id": "0002",
"name": "Entity2",
"resource_type": "thing",
"description": "Another entity in the application"
}
]
}
],
"permissions": [
{
"name": "admin",
"permission_type": [
"DataRead",
"DataWrite"
],
"apply_to_sub_resources": false,
"resource_types": []
},
{
"name": "operator",
"permission_type": [
"DataRead",
"MetadataRead"
],
"apply_to_sub_resources": false,
"resource_types": []
},
{
"name": "manager",
"permission_type": [
"MetadataWrite"
],
"apply_to_sub_resources": false,
"resource_types": []
}
],
"identity_to_permissions": [
{
"identity": "0000000001",
"identity_type": "local_user",
"application_permissions": [
{
"application": "Sample App",
"permission": "operator",
"apply_to_application": true
},
{
"application": "Sample App",
"resources": [
"0001"
],
"permission": "manager"
}
]
},
{
"identity": "admins",
"identity_type": "local_group",
"application_permissions": [
{
"application": "Sample App",
"permission": "admin",
"apply_to_application": true
}
]
}
]
}{
"applications": [
{
"name": "Sample App",
"application_type": "sample",
"description": "This is a sample app",
"local_users": [
{
"name": "bob",
"identities": [
"[email protected]"
],
"is_active": true,
"created_at": "2022-01-26T20:48:12.460Z",
"id": "0000000001"
},
{
"name": "jane",
"identities": [
"[email protected]"
],
"created_at": "2021-08-13T06:28:13.250Z",
"id": "0000000002"
}
],
"local_groups": [],
"local_roles": [
{
"id": "admin",
"name": "Administrator",
"permissions": [
"manage_users"
],
"tags": [],
"custom_properties": {}
},
{
"id": "user",
"name": "User",
"permissions": [
"view_tickets",
"close_tickets"
],
"tags": [],
"custom_properties": {}
}
],
"tags": [],
"custom_properties": {},
"resources": []
}
],
"permissions": [
{
"name": "manage_users",
"permission_type": [
"MetadataWrite"
],
"apply_to_sub_resources": false,
"resource_types": []
},
{
"name": "view_tickets",
"permission_type": [
"DataRead"
],
"apply_to_sub_resources": false,
"resource_types": []
},
{
"name": "close_tickets",
"permission_type": [
"MetadataWrite"
],
"apply_to_sub_resources": false,
"resource_types": []
}
],
"identity_to_permissions": [
{
"identity": "0000000001",
"identity_type": "local_user",
"role_assignments": [
{
"application": "Sample App",
"role": "user",
"apply_to_application": true,
"resources": []
}
]
},
{
"identity": "0000000002",
"identity_type": "local_user",
"role_assignments": [
{
"application": "Sample App",
"role": "user",
"apply_to_application": true,
"resources": []
},
{
"application": "Sample App",
"role": "admin",
"apply_to_application": true,
"resources": []
}
]
}
]
} "custom_property_definition": {
"applications": [
{
"application_type": "sample",
"application_properties": {},
"local_user_properties": {
"license_type": "STRING",
"license_expires": "TIMESTAMP"
},
"local_group_properties": {},
"local_role_properties": {},
"role_assignment_properties": {},
"access_cred_properties": {},
"resources": []
}
]
} "local_users": [
{
"id": "001010",
"name": "bob",
"identities": [
"[email protected]"
],
"groups": null,
"is_active": true,
"created_at": "2022-01-26T20:48:12.460Z",
"last_login_at": null,
"deactivated_at": null,
"password_last_changed_at": null,
"tags": [],
"custom_properties": {
"license_type": "pro",
"license_expires": "2023-01-01T00:00:00.000Z"
}
}
]{
"applications": [
{
"name": "Custom App",
"application_type": "Source Control",
"description": "Has a resource for each repository",
"custom_properties": {},
"tags": [],
"owners": [],
"local_users": [],
"local_groups": [],
"local_roles": [],
"resources": []
}
]
}"resources": [
{
"name": "Entity1",
"id": "Unique ID",
"resource_type": "thing",
"description": "Some entity in the application",
"sub_resources": [
{
"name": "Child 1",
"resource_type": "child",
"description": "My information about resource",
"sub_resources": [],
"custom_properties": {},
"tags": [],
"owners": []
}
],
"custom_properties": {},
"tags": [],
"owners": []
},
{
"name": "Entity2",
"id": "Another Unique ID",
"resource_type": "thing",
"description": "Another entity in the application",
"sub_resources": [],
"custom_properties": {},
"tags": [],
"owners": [],
}
]{
"name": "cog1",
"resource_type": "cog",
"connections": [
{
"id": "[email protected]",
"node_type": "GoogleCloudServiceAccount"
}
]
}"local_users": [
{
"id": "egray",
"name": "Evan Gray",
"email": "[email protected]",
"identities": ["[email protected]"],
"groups": ["contractors"],
"is_active": true,
"created_at": "2020-12-19T16:39:57-08:00",
"last_login_at": "2021-11-19T14:19:30-08:00",
"password_last_changed_at": null,
"deactivated_at": null,
"custom_properties": {},
"tags": [],
"owners": []
}
]"local_groups": [
{
"name": "US Contractors",
"id": "us-contractors",
"identities": ["[email protected]"],
"groups": [
"all-contractors",
"all-workers"
],
"tags": [],
"owners": []
}
]"local_roles": [
{
"name": "administrator",
"id": "0001",
"permissions": ["create","destroy"]
},
{
"name": "operator",
"id": "0002",
"permissions": ["pull", "read"],
"tags": [],
"owners": []
}
]"local_access_creds": [
{
"name": "Production API Key",
"id": "prod-key-001",
"created_at": "2023-01-15T08:00:00.000Z",
"expires_at": "2024-01-15T08:00:00.000Z",
"last_used_at": "2023-12-01T14:30:00.000Z",
"can_expire": true,
"is_active": true,
"custom_properties": {},
"tags": [],
"owners": []
}
]"permissions": [
{
"name": "Admin",
"permission_type": [
"DataRead",
"DataWrite",
"MetadataRead",
"MetadataWrite"
]
},
{
"name": "Operator",
"permission_type": [
"MetadataRead",
"DataRead"
]
},
{
"name": "Inactive",
"permission_type": [
"NonData"
]
}
]"identity_to_permissions": [
{
"identity": "Evan Gray",
"identity_type": "local_user",
"application_permissions": [
{
"application": "Veza AI",
"resources": ["terraform-dev", "prod"],
"permission": "pull"
},
{
"application": "Veza AI",
"resources": ["terraform-dev", "prod"],
"permission": "push"
}
]
}
]{
"identity": "[email protected]",
"identity_type": "idp",
"application_permissions":
[
{
"application": "source control",
"resources": ["util-tools", "terraform"],
"apply_to_application": false,
"permission": "write"
},
{
"application": "source control",
"resources": [],
"apply_to_application": true,
"permission": "read"
}
]
}{
"identity": "john_smith",
"identity_type": "local_user",
"role_assignments":[
{
"application": "custom application",
"role": "administrator",
"apply_to_application": true,
"resources": []
},
{
"application": "custom application",
"role": "ops",
"apply_to_application": false,
"resources": ["oaa-vm-1"]
}
]
} "identity_to_permissions": [
{
"identity": "0000000001",
"identity_type": "local_user",
"role_assignments": [
{
"application": "Sample App",
"role": "user",
"apply_to_application": true,
"resources": []
}
]
},
{
"identity": "0000000002",
"identity_type": "local_user",
"role_assignments": [
{
"application": "Sample App",
"role": "user",
"apply_to_application": true,
"resources": []
},
{
"application": "Sample App",
"role": "admin",
"apply_to_application": true,
"resources": []
}
]
}
]
append_helperunique_strsOAATemplateException__init__OAAPermissionOAAIdentityTypeProvider__init__serializeApplication__init__CustomApplication__init__add_accessadd_custom_permissionadd_idp_identityadd_local_groupadd_local_roleadd_local_useradd_resourceadd_tagapp_dictdefine_custom_permissionget_payloadpermissions_dictset_propertyCustomResource__init__add_accessadd_resource_connectionadd_sub_resourceadd_tagset_propertyto_dictIdentity__init__add_permissionadd_roleadd_tagget_identity_to_permissionsset_propertyLocalUserTypeLocalUser__init__add_access_credadd_groupadd_identitiesadd_identityadd_permissionadd_roleadd_tagget_identity_to_permissionsset_propertyto_dictLocalGroup__init__add_groupadd_identityadd_permissionadd_roleadd_tagget_identity_to_permissionsset_propertyto_dictIdPIdentity__init__add_permissionadd_roleadd_tagget_identity_to_permissionsset_propertyAccessCred__init__add_permissionadd_roleadd_tagget_identity_to_permissionsset_propertyto_dictLocalRole__init__add_permissionsadd_roleadd_tagset_propertyto_dictCustomPermission__init__add_resource_typeto_dictOAAPropertyTypeApplicationPropertyDefinitions__init__define_access_cred_propertydefine_application_propertydefine_local_group_propertydefine_local_role_propertydefine_local_user_propertydefine_resource_propertydefine_role_assignment_propertyto_dictvalidate_namevalidate_property_nameIdPEntityTypeIdPProviderTypeCustomIdPProvider__init__add_appadd_groupadd_userget_payloadCustomIdPDomain__init__add_tagset_propertyto_dictCustomIdPUser__init__add_app_assignmentadd_assumed_role_arnsadd_groupsadd_tagset_propertyset_source_identityto_dictCustomIdPGroup__init__add_app_assignmentadd_assumed_role_arnsadd_groupsadd_tagset_propertyto_dictCustomIdPApp__init__add_assumed_role_arnsadd_tagset_propertyto_dictIdPPropertyDefinitions__init__define_app_assignment_propertydefine_app_propertydefine_domain_propertydefine_group_propertydefine_user_propertyto_dictvalidate_property_nameTag__init__HRISProvider__init__add_employeeadd_groupget_payloadHRISSystem__init__add_idp_typeto_dictHRISEmployee__init__add_groupadd_managerset_propertyto_dictHRISGroup__init__set_propertyto_dictHRISPropertyDefinitions__init__define_employee_propertydefine_group_propertydefine_system_propertyto_dictvalidate_nameunique_id (str, optional): Unique identifier for role for reference by IDignore_none (bool, optional): Do not set property if value is None. Defaults to False.ignore_none (bool, optional): Do not set property if value is None. Defaults to False.ignore_none (bool, optional): Do not set property if value is None. Defaults to False.ignore_noneFalseappend_helper(base, addition)unique_strs(input: 'list') → list__init__(message)__init__(name, custom_template)serialize()__init__(name, application_type, description=None)__init__(name: 'str', application_type: 'str', description: 'str' = None) → Noneadd_access(identity, identity_type, permission, resource=None)
---
### <kbd>method</kbd> `add_access_cred`
```python
add_access_cred(unique_id: 'str', name: 'str') → AccessCredadd_custom_permission(
name: 'str',
permissions: 'List[OAAPermission]',
apply_to_sub_resources: 'bool' = False,
resource_types: 'List[str]' = None
) → CustomPermissionadd_idp_identity(name: 'str') → IdPIdentityadd_local_group(
name: 'str',
identities: 'List[str]' = None,
unique_id: 'str' = None
) → LocalGroupadd_local_role(
name: 'str',
permissions: 'List[str]' = None,
unique_id: 'str' = None
) → LocalRoleadd_local_user(
name: 'str',
identities: 'List[str]' = None,
groups: 'List[str]' = None,
unique_id: 'str' = None
) → LocalUseradd_resource(
name: 'str',
resource_type: 'str',
description: 'str' = None,
unique_id: 'str' = None
) → CustomResourceadd_tag(key: 'str', value: 'str' = '') → Noneapp_dict() → dictdefine_custom_permission(
custom_permission: 'CustomPermission'
) → CustomPermission
**Args:**
- <b>`custom_permission`</b> (CustomPermission): CustomPermission class
**Raises:**
- <b>`Exception`</b>: Duplicate Keys
**Returns:**
- <b>`CustomPermission`</b>: The defined custom Permission
---
### <kbd>method</kbd> `get_identity_to_permissions`
```python
get_identity_to_permissions() → listget_payload() → dictpermissions_dict() → dictset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → None__init__(
name: 'str',
resource_type: 'str',
description: 'str',
application_name: 'str',
resource_key: 'str' = None,
property_definitions: 'ApplicationPropertyDefinitions' = None,
unique_id: 'str' = None
) → Noneadd_access(identity, identity_type, permission)add_resource_connection(id: 'str', node_type: 'str') → Noneadd_sub_resource(
name: 'str',
resource_type: 'str',
description: 'str' = None,
unique_id: 'str' = None
) → CustomResourceadd_tag(key: 'str', value: 'str' = '') → Noneset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → Noneto_dict() → dict__init__(
name: 'str',
identity_type: 'OAAIdentityType',
unique_id: 'str' = None,
property_definitions: 'ApplicationPropertyDefinitions' = None
) → Noneadd_permission(
permission: 'str',
resources: 'List[CustomResource]' = None,
apply_to_application: 'bool' = False
) → Noneadd_role(
role: 'str',
resources: 'List[CustomResource]' = None,
apply_to_application: 'Optional[bool]' = None,
assignment_properties: 'Optional[dict]' = None
) → Noneadd_tag(key: 'str', value: 'str' = '') → Noneget_identity_to_permissions(application_name: 'str') → dictset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → None__init__(
name: 'str',
identities: 'List[str]' = None,
groups: 'List[str]' = None,
unique_id: 'str' = None,
property_definitions: 'ApplicationPropertyDefinitions' = None
) → Noneadd_access_cred(access_cred: 'str') → Noneadd_group(group: 'str') → Noneadd_identities(identities: 'List[str]') → Noneadd_identity(identity: 'str') → Noneadd_permission(
permission: 'str',
resources: 'List[CustomResource]' = None,
apply_to_application: 'bool' = False
) → Noneadd_role(
role: 'str',
resources: 'List[CustomResource]' = None,
apply_to_application: 'Optional[bool]' = None,
assignment_properties: 'Optional[dict]' = None
) → Noneadd_tag(key: 'str', value: 'str' = '') → Noneget_identity_to_permissions(application_name: 'str') → dictset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → Noneto_dict() → dict__init__(
name,
identities=None,
unique_id: 'str' = None,
property_definitions: 'ApplicationPropertyDefinitions' = None
)add_group(group: 'str') → Noneadd_identity(identity: 'str') → Noneadd_permission(
permission: 'str',
resources: 'List[CustomResource]' = None,
apply_to_application: 'bool' = False
) → Noneadd_role(
role: 'str',
resources: 'List[CustomResource]' = None,
apply_to_application: 'Optional[bool]' = None,
assignment_properties: 'Optional[dict]' = None
) → Noneadd_tag(key: 'str', value: 'str' = '') → Noneget_identity_to_permissions(application_name: 'str') → dictset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → Noneto_dict() → dict__init__(name: 'str') → Noneadd_permission(
permission: 'str',
resources: 'List[CustomResource]' = None,
apply_to_application: 'bool' = False
) → Noneadd_role(
role: 'str',
resources: 'List[CustomResource]' = None,
apply_to_application: 'Optional[bool]' = None,
assignment_properties: 'Optional[dict]' = None
) → Noneadd_tag(key: 'str', value: 'str' = '') → Noneget_identity_to_permissions(application_name: 'str') → dictset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → None__init__(
unique_id: 'str',
name: 'str',
property_definitions: 'ApplicationPropertyDefinitions' = None
) → Noneadd_permission(
permission: 'str',
resources: 'List[CustomResource]' = None,
apply_to_application: 'bool' = False
) → Noneadd_role(
role: 'str',
resources: 'List[CustomResource]' = None,
apply_to_application: 'Optional[bool]' = None,
assignment_properties: 'Optional[dict]' = None
) → Noneadd_tag(key: 'str', value: 'str' = '') → Noneget_identity_to_permissions(application_name: 'str') → dictset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → Noneto_dict() → dict__init__(
name: 'str',
permissions: 'List[str]' = None,
unique_id: 'str' = None,
property_definitions: 'ApplicationPropertyDefinitions' = None
) → Noneadd_permissions(permissions: 'List[str]') → Noneadd_role(role: 'str') → Noneadd_tag(key: 'str', value: 'str' = '') → Noneset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → Noneto_dict() → dict__init__(
name: 'str',
permissions: 'List[OAAPermission]',
apply_to_sub_resources: 'bool' = False,
resource_types: 'list' = None
) → Noneadd_resource_type(resource_type: 'str') → Noneto_dict() → dict__init__(application_type: 'str') → Nonedefine_access_cred_property(
name: 'str',
property_type: 'OAAPropertyType'
) → Nonedefine_application_property(
name: 'str',
property_type: 'OAAPropertyType'
) → Nonedefine_local_group_property(
name: 'str',
property_type: 'OAAPropertyType'
) → Nonedefine_local_role_property(name: 'str', property_type: 'OAAPropertyType') → Nonedefine_local_user_property(name: 'str', property_type: 'OAAPropertyType') → Nonedefine_resource_property(
resource_type: 'str',
name: 'str',
property_type: 'OAAPropertyType'
) → Nonedefine_role_assignment_property(
name: 'str',
property_type: 'OAAPropertyType'
) → Noneto_dict() → dictvalidate_name(name: 'str') → Nonevalidate_property_name(
property_name: 'str',
entity_type: 'str',
resource_type: 'str' = None
) → bool__init__(
name: 'str',
idp_type: 'str',
domain: 'str',
description: 'str' = None
) → Noneadd_app(id: 'str', name: 'str') → CustomIdPAppadd_group(
name: 'str',
full_name: 'str' = None,
identity: 'str' = None
) → CustomIdPGroupadd_user(
name: 'str',
full_name: 'str' = None,
email: 'str' = None,
identity: 'str' = None
) → CustomIdPUserget_payload() → dict__init__(
name: 'str',
property_definitions: 'IdPPropertyDefinitions' = None
) → Noneadd_tag(key: 'str', value: 'str' = '') → Noneset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → Noneto_dict() → dict__init__(
name: 'str',
email: 'str' = None,
full_name: 'str' = None,
identity: 'str' = None,
property_definitions: 'IdPPropertyDefinitions' = None
) → Noneadd_app_assignment(
id: 'str',
name: 'str',
app_id: 'str',
assignment_properties: 'Optional[dict]' = None
) → Noneadd_assumed_role_arns(arns: 'List[str]') → Noneadd_groups(group_identities: 'List[str]') → Noneadd_tag(key: 'str', value: 'str' = '') → Noneset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → Noneset_source_identity(identity: 'str', provider_type: 'IdPProviderType') → Noneto_dict() → dict__init__(
name: 'str',
full_name: 'str' = None,
identity: 'str' = None,
property_definitions: 'IdPPropertyDefinitions' = None
) → Noneadd_app_assignment(
id: 'str',
name: 'str',
app_id: 'str',
assignment_properties: 'Optional[dict]' = None
) → Noneadd_assumed_role_arns(arns: 'List[str]') → Noneadd_groups(group_identities: 'List[str]') → Noneadd_tag(key: 'str', value: 'str' = '') → Noneset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → Noneto_dict() → None__init__(
id: 'str',
name: 'str',
property_definitions: 'IdPPropertyDefinitions' = None
) → Noneadd_assumed_role_arns(arns: 'List[str]') → Noneadd_tag(key: 'str', value: 'str' = '') → Noneset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → Noneto_dict() → dict__init__() → Nonedefine_app_assignment_property(
name: 'str',
property_type: 'OAAPropertyType'
) → Nonedefine_app_property(name: 'str', property_type: 'OAAPropertyType') → Nonedefine_domain_property(name: 'str', property_type: 'OAAPropertyType') → Nonedefine_group_property(name: 'str', property_type: 'OAAPropertyType') → Nonedefine_user_property(name: 'str', property_type: 'OAAPropertyType') → Noneto_dict() → dictvalidate_property_name(property_name: 'str', entity_type: 'str') → None__init__(key: 'str', value: 'str' = '') → None__init__(name: 'str', hris_type: 'str', url: 'str')add_employee(
unique_id: 'str',
name: 'str',
employee_number: 'str',
first_name: 'str',
last_name: 'str',
is_active: 'bool',
employment_status: 'str'
) → HRISEmployeeadd_group(unique_id: 'str', name: 'str', group_type: 'str') → HRISGroupget_payload() → dict__init__(name: 'str', url: 'str' = '')add_idp_type(provider_type: 'IdPProviderType') → list[IdPProviderType]to_dict() → dict__init__(
unique_id: 'str',
name: 'str',
employee_number: 'str',
first_name: 'str',
last_name: 'str',
is_active: 'bool',
employment_status: 'str'
)add_group(group_id: 'str') → Noneadd_manager(manager_id: 'str') → Noneset_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → Noneto_dict() → dict__init__(unique_id: 'str', name: 'str', group_type: 'str')set_property(
property_name: 'str',
property_value: 'any',
ignore_none: 'bool' = False
) → Noneto_dict() → dict__init__()define_employee_property(name: 'str', property_type: 'OAAPropertyType') → Nonedefine_group_property(name: 'str', property_type: 'OAAPropertyType') → Nonedefine_system_property(name: 'str', property_type: 'OAAPropertyType') → Noneto_dict() → dictvalidate_name(name: 'str') → None