-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(ui/ingest): ingestion form for Okta and AzureAD #9829
Changes from 3 commits
51dafa4
34fbaee
c1c8b4a
2236145
932de89
f763396
94a89f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
import { RecipeField, FieldType, setListValuesOnRecipe } from './common'; | ||
|
||
const validateURL = (fieldName) => { | ||
return { | ||
validator(_, value) { | ||
const URLPattern = new RegExp(/^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=.]+$/); | ||
const isURLValid = URLPattern.test(value); | ||
if (!value || isURLValid) { | ||
return Promise.resolve(); | ||
} | ||
return Promise.reject(new Error(`A valid ${fieldName} is required.`)); | ||
}, | ||
}; | ||
}; | ||
|
||
export const AZURE_CLIENT_ID: RecipeField = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add option for stateful ingestion in advanced section |
||
name: 'client_id', | ||
label: 'Client ID', | ||
tooltip: 'Application ID. Found in your app registration on Azure AD Portal', | ||
type: FieldType.TEXT, | ||
fieldPath: 'source.config.client_id', | ||
placeholder: '00000000-0000-0000-0000-000000000000', | ||
required: true, | ||
rules: null, | ||
}; | ||
|
||
export const AZURE_TENANT_ID: RecipeField = { | ||
name: 'tenant_id', | ||
label: 'Tenant ID', | ||
tooltip: 'Directory ID. Found in your app registration on Azure AD Portal', | ||
type: FieldType.TEXT, | ||
fieldPath: 'source.config.tenant_id', | ||
placeholder: '00000000-0000-0000-0000-000000000000', | ||
required: true, | ||
rules: null, | ||
}; | ||
|
||
export const AZURE_CLIENT_SECRET: RecipeField = { | ||
name: 'client_secret', | ||
label: 'Client Secret', | ||
tooltip: 'The Azure client secret.', | ||
type: FieldType.SECRET, | ||
fieldPath: 'source.config.client_secret', | ||
placeholder: '00000000-0000-0000-0000-000000000000', | ||
required: true, | ||
rules: null, | ||
}; | ||
|
||
export const AZURE_REDIRECT_URL: RecipeField = { | ||
name: 'redirect', | ||
label: 'Redirect URL', | ||
tooltip: 'Redirect URL. Found in your app registration on Azure AD Portal.', | ||
type: FieldType.TEXT, | ||
fieldPath: 'source.config.redirect', | ||
placeholder: 'https://login.microsoftonline.com/common/oauth2/nativeclient', | ||
required: true, | ||
rules: [() => validateURL('Redirect URI')], | ||
}; | ||
|
||
export const AZURE_AUTHORITY_URL: RecipeField = { | ||
name: 'authority', | ||
label: 'Authority URL', | ||
tooltip: 'Is a URL that indicates a directory that MSAL can request tokens from..', | ||
type: FieldType.TEXT, | ||
fieldPath: 'source.config.authority', | ||
placeholder: 'https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000', | ||
required: true, | ||
rules: [() => validateURL('Azure authority URL')], | ||
}; | ||
|
||
export const AZURE_TOKEN_URL: RecipeField = { | ||
name: 'token_url', | ||
label: 'Token URL', | ||
tooltip: | ||
'The token URL that acquires a token from Azure AD for authorizing requests. This source will only work with v1.0 endpoint.', | ||
type: FieldType.TEXT, | ||
fieldPath: 'source.config.token_url', | ||
placeholder: 'https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/token', | ||
required: true, | ||
rules: [() => validateURL('Azure token URL')], | ||
}; | ||
|
||
export const AZURE_GRAPH_URL: RecipeField = { | ||
name: 'graph_url', | ||
label: 'Graph URL', | ||
tooltip: 'Microsoft Graph API endpoint', | ||
type: FieldType.TEXT, | ||
fieldPath: 'source.config.graph_url', | ||
placeholder: 'https://graph.microsoft.com/v1.0', | ||
required: true, | ||
rules: [() => validateURL('Graph url URL')], | ||
}; | ||
|
||
export const AZURE_INGEST_USERS: RecipeField = { | ||
name: 'ingest_users', | ||
label: 'Ingest Users', | ||
tooltip: 'Flag to determine whether to ingest users from Azure AD or not.', | ||
type: FieldType.BOOLEAN, | ||
fieldPath: 'source.config.ingest_users', | ||
rules: null, | ||
}; | ||
|
||
export const AZURE_INGEST_GROUPS: RecipeField = { | ||
name: 'ingest_groups', | ||
label: 'Ingest Groups', | ||
tooltip: 'Flag to determine whether to ingest groups from Azure AD or not.', | ||
type: FieldType.BOOLEAN, | ||
fieldPath: 'source.config.ingest_groups', | ||
rules: null, | ||
}; | ||
|
||
const schemaAllowFieldPathGroup = 'source.config.groups_pattern.allow'; | ||
export const GROUP_ALLOW: RecipeField = { | ||
name: 'groups.allow', | ||
label: 'Allow Patterns', | ||
tooltip: | ||
'Only include specific schemas by providing the name of a schema, or a regular expression (regex) to include specific schemas. If not provided, all schemas inside allowed databases will be included.', | ||
placeholder: 'group_pattern', | ||
type: FieldType.LIST, | ||
buttonLabel: 'Add pattern', | ||
fieldPath: schemaAllowFieldPathGroup, | ||
rules: null, | ||
section: 'Group', | ||
setValueOnRecipeOverride: (recipe: any, values: string[]) => | ||
setListValuesOnRecipe(recipe, values, schemaAllowFieldPathGroup), | ||
}; | ||
|
||
const schemaDenyFieldPathGroup = 'source.config.groups_pattern.deny'; | ||
export const GROUP_DENY: RecipeField = { | ||
name: 'groups.deny', | ||
label: 'Deny Patterns', | ||
tooltip: | ||
'Exclude specific schemas by providing the name of a schema, or a regular expression (regex). If not provided, all schemas inside allowed databases will be included. Deny patterns always take precedence over allow patterns.', | ||
placeholder: 'user_pattern', | ||
type: FieldType.LIST, | ||
buttonLabel: 'Add pattern', | ||
fieldPath: schemaDenyFieldPathGroup, | ||
rules: null, | ||
section: 'Group', | ||
setValueOnRecipeOverride: (recipe: any, values: string[]) => | ||
setListValuesOnRecipe(recipe, values, schemaDenyFieldPathGroup), | ||
}; | ||
|
||
const schemaAllowFieldPathUser = 'source.config.users_pattern.allow'; | ||
export const USER_ALLOW: RecipeField = { | ||
name: 'user.allow', | ||
label: 'Allow Patterns', | ||
tooltip: | ||
'Exclude specific schemas by providing the name of a schema, or a regular expression (regex). If not provided, all schemas inside allowed databases will be included. Deny patterns always take precedence over allow patterns.', | ||
placeholder: 'user_pattern', | ||
type: FieldType.LIST, | ||
buttonLabel: 'Add pattern', | ||
fieldPath: schemaAllowFieldPathUser, | ||
rules: null, | ||
section: 'User', | ||
setValueOnRecipeOverride: (recipe: any, values: string[]) => | ||
setListValuesOnRecipe(recipe, values, schemaAllowFieldPathUser), | ||
}; | ||
|
||
const schemaDenyFieldPathUser = 'source.config.users_pattern.deny'; | ||
export const USER_DENY: RecipeField = { | ||
name: 'user.deny', | ||
label: 'Deny Patterns', | ||
tooltip: | ||
'Exclude specific schemas by providing the name of a schema, or a regular expression (regex). If not provided, all schemas inside allowed databases will be included. Deny patterns always take precedence over allow patterns.', | ||
placeholder: 'user_pattern', | ||
type: FieldType.LIST, | ||
buttonLabel: 'Add pattern', | ||
fieldPath: schemaDenyFieldPathUser, | ||
rules: null, | ||
section: 'User', | ||
setValueOnRecipeOverride: (recipe: any, values: string[]) => | ||
setListValuesOnRecipe(recipe, values, schemaDenyFieldPathUser), | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import { RecipeField, FieldType, setListValuesOnRecipe } from './common'; | ||
|
||
const validateURL = (fieldName) => { | ||
return { | ||
validator(_, value) { | ||
const URLPattern = new RegExp(/^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=.]+$/); | ||
const isURLValid = URLPattern.test(value); | ||
if (!value || isURLValid) { | ||
return Promise.resolve(); | ||
} | ||
return Promise.reject(new Error(`A valid ${fieldName} is required.`)); | ||
}, | ||
}; | ||
}; | ||
|
||
export const OKTA_DOMAIN_URL: RecipeField = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add option for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add option for |
||
name: 'okta_domain', | ||
label: 'Okta Domain URL', | ||
tooltip: 'The location of your Okta Domain, without a protocol.', | ||
type: FieldType.TEXT, | ||
fieldPath: 'source.config.okta_domain', | ||
placeholder: 'dev-35531955.okta.com', | ||
required: true, | ||
rules: [() => validateURL('Okta Domain URL')], | ||
}; | ||
|
||
export const OKTA_API_TOKEN: RecipeField = { | ||
name: 'credential.project_id', | ||
label: 'Token', | ||
tooltip: 'An API token generated for the DataHub application inside your Okta Developer Console.', | ||
type: FieldType.SECRET, | ||
fieldPath: 'source.config.okta_api_token', | ||
placeholder: 'd0121d0000882411234e11166c6aaa23ed5d74e0', | ||
rules: null, | ||
required: true, | ||
}; | ||
|
||
export const POFILE_TO_USER: RecipeField = { | ||
name: 'okta_profile_to_username_attr', | ||
label: 'Okta Profile to Username attribute', | ||
tooltip: 'Which Okta User Profile attribute to use as input to DataHub username mapping. Common values used are - login, email.', | ||
type: FieldType.TEXT, | ||
fieldPath: 'source.config.okta_profile_to_username_attr', | ||
placeholder: 'usename', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change this to be Add another option for Move both to Advanced section There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Can I change source.config.okta_profile_to_username_attr to source.config.email, or is it only the placeholder that needs to be changed? Additionally, should I move the okta_profile_to_username_regex in advance section or filter section? |
||
rules: null, | ||
}; | ||
|
||
export const POFILE_TO_GROUP: RecipeField = { | ||
name: 'okta_profile_to_group_name_attr', | ||
label: 'Okta Profile to group name attribute', | ||
tooltip: 'Which Okta Group Profile attribute to use as input to DataHub group name mapping.', | ||
type: FieldType.TEXT, | ||
fieldPath: 'source.config.okta_profile_to_group_name_attr', | ||
placeholder: 'Group name', | ||
rules: null, | ||
}; | ||
|
||
|
||
const schemaAllowFieldPath = 'source.config.okta_profile_to_username_attr_regex.allow'; | ||
export const POFILE_TO_USER_REGX_ALLOW: RecipeField = { | ||
name: 'user.allow', | ||
label: 'Allow Patterns', | ||
tooltip: | ||
'Only include specific schemas by providing the name of a schema, or a regular expression (regex) to include specific schemas. If not provided, all schemas inside allowed databases will be included.', | ||
placeholder: 'user_pattern', | ||
type: FieldType.LIST, | ||
buttonLabel: 'Add pattern', | ||
fieldPath: schemaAllowFieldPath, | ||
rules: null, | ||
section: 'Profile To User Attribute', | ||
setValueOnRecipeOverride: (recipe: any, values: string[]) => | ||
setListValuesOnRecipe(recipe, values, schemaAllowFieldPath), | ||
}; | ||
|
||
|
||
const schemaDenyFieldPath = 'source.config.okta_profile_to_username_attr_regex.deny'; | ||
export const POFILE_TO_USER_REGX_DENY: RecipeField = { | ||
name: 'user.deny', | ||
label: 'Deny Patterns', | ||
tooltip: | ||
'Only include specific schemas by providing the name of a schema, or a regular expression (regex) to include specific schemas. If not provided, all schemas inside allowed databases will be included.', | ||
placeholder: 'user_pattern', | ||
type: FieldType.LIST, | ||
buttonLabel: 'Add pattern', | ||
fieldPath: schemaDenyFieldPath, | ||
rules: null, | ||
section: 'Profile To User Attribute', | ||
setValueOnRecipeOverride: (recipe: any, values: string[]) => | ||
setListValuesOnRecipe(recipe, values, schemaDenyFieldPath), | ||
}; | ||
|
||
|
||
const schemaAllowFieldPathForGroup = 'source.config.okta_profile_to_group_name_regex.allow'; | ||
export const POFILE_TO_GROUP_REGX_ALLOW: RecipeField = { | ||
name: 'group.allow', | ||
label: 'Allow Patterns', | ||
tooltip: | ||
'Only include specific schemas by providing the name of a schema, or a regular expression (regex) to include specific schemas. If not provided, all schemas inside allowed databases will be included.', | ||
placeholder: 'group_pattern', | ||
type: FieldType.LIST, | ||
buttonLabel: 'Add pattern', | ||
fieldPath: schemaAllowFieldPathForGroup, | ||
rules: null, | ||
section: 'Profile To Group Attribute', | ||
setValueOnRecipeOverride: (recipe: any, values: string[]) => | ||
setListValuesOnRecipe(recipe, values, schemaAllowFieldPathForGroup), | ||
}; | ||
|
||
const schemaDenyFieldPathForGroup = 'source.config.okta_profile_to_group_name_regex.deny'; | ||
export const POFILE_TO_GROUP_REGX_DENY: RecipeField = { | ||
name: 'group.deny', | ||
label: 'Deny Patterns', | ||
tooltip: | ||
'Only include specific schemas by providing the name of a schema, or a regular expression (regex) to include specific schemas. If not provided, all schemas inside allowed databases will be included.', | ||
placeholder: 'group_pattern', | ||
type: FieldType.LIST, | ||
buttonLabel: 'Add pattern', | ||
fieldPath: schemaDenyFieldPathForGroup, | ||
rules: null, | ||
section: 'Profile To Group Attribute', | ||
setValueOnRecipeOverride: (recipe: any, values: string[]) => | ||
setListValuesOnRecipe(recipe, values, schemaDenyFieldPathForGroup), | ||
}; | ||
|
||
|
||
|
||
export const INGEST_USERS: RecipeField = { | ||
name: 'ingest_users', | ||
label: 'Ingest Users', | ||
tooltip: 'Whether users should be ingested into DataHub.', | ||
type: FieldType.BOOLEAN, | ||
fieldPath: 'source.config.ingest_users', | ||
rules: null, | ||
}; | ||
|
||
export const INGEST_GROUPS: RecipeField = { | ||
name: 'ingest_groups', | ||
label: 'Ingest Groups', | ||
tooltip: 'Whether groups should be ingested into DataHub.', | ||
type: FieldType.BOOLEAN, | ||
fieldPath: 'source.config.ingest_groups', | ||
rules: null, | ||
}; | ||
|
||
|
||
export const INCLUDE_DEPROVISIONED_USERS: RecipeField = { | ||
name: 'include_deprovisioned_users', | ||
label: 'Include deprovisioned users', | ||
tooltip: 'Whether to ingest users in the DEPROVISIONED state from Okta.', | ||
type: FieldType.BOOLEAN, | ||
fieldPath: 'source.config.include_deprovisioned_users', | ||
rules: null, | ||
}; | ||
export const INCLUDE_SUSPENDED_USERS: RecipeField = { | ||
name: 'include_suspended_users', | ||
label: 'Include suspended users', | ||
tooltip: 'Whether to ingest users in the SUSPENDED state from Okta.', | ||
type: FieldType.BOOLEAN, | ||
fieldPath: 'source.config.include_suspended_users', | ||
rules: null, | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it looks like this function was copied from
csv.ts
- let's bring that function to a new sharedutils.ts
file and import it in the three recipes instead of copying it twice.Then, it would be nice to have unit tests on that utility function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated!