protected override void FillHierarchy(Uri context, string[] entityTypes, string hierarchyNodeID, int numberOfLevels, Microsoft.SharePoint.WebControls.SPProviderHierarchyTree hierarchy) { AzureCPLogging.Log(String.Format("[{0}] FillHierarchy called", ProviderInternalName), TraceSeverity.VerboseEx, EventSeverity.Information, AzureCPLogging.Categories.Core); SPSecurity.RunWithElevatedPrivileges(delegate () { if (!Initialize(context, entityTypes)) return; this.Lock_Config.EnterReadLock(); try { if (hierarchyNodeID == null) { // Root level //foreach (var azureObject in FinalAttributeList.Where(x => !String.IsNullOrEmpty(x.peoplePickerAttributeHierarchyNodeId) && !x.CreateAsIdentityClaim && entityTypes.Contains(x.ClaimEntityType))) foreach (var azureObject in this.ProcessedAzureObjects.FindAll(x => !x.CreateAsIdentityClaim && entityTypes.Contains(x.ClaimEntityType))) { hierarchy.AddChild( new Microsoft.SharePoint.WebControls.SPProviderHierarchyNode( _ProviderInternalName, azureObject.ClaimTypeMappingName, azureObject.ClaimType, true)); } } } catch (Exception ex) { AzureCPLogging.LogException(ProviderInternalName, "in FillHierarchy", AzureCPLogging.Categories.Claims_Picking, ex); } finally { this.Lock_Config.ExitReadLock(); } }); }
protected override void FillSearch(Uri context, string[] entityTypes, string searchPattern, string hierarchyNodeID, int maxCount, Microsoft.SharePoint.WebControls.SPProviderHierarchyTree searchTree) { AzureCPLogging.Log(String.Format("[{0}] FillSearch called, incoming input: \"{1}\"", ProviderInternalName, searchPattern), TraceSeverity.VerboseEx, EventSeverity.Information, AzureCPLogging.Categories.Core); SPSecurity.RunWithElevatedPrivileges(delegate () { if (!Initialize(context, entityTypes)) return; this.Lock_Config.EnterReadLock(); try { string input = searchPattern; SPProviderHierarchyNode matchNode = null; // List<T>.FindAll returns an empty list if no result found: http://msdn.microsoft.com/en-us/library/fh1w7y8z(v=vs.110).aspx List<AzureADObject> azureObjects; if (!String.IsNullOrEmpty(hierarchyNodeID)) { // Restrict search to objects currently selected in the hierarchy (may return multiple results if identity claim type) azureObjects = this.ProcessedAzureObjects.FindAll(x => String.Equals(x.ClaimType, hierarchyNodeID, StringComparison.InvariantCultureIgnoreCase) && entityTypes.Contains(x.ClaimEntityType)); } else { azureObjects = this.ProcessedAzureObjects.FindAll(x => entityTypes.Contains(x.ClaimEntityType)); } if (this.CurrentConfiguration.AlwaysResolveUserInput) { List<PickerEntity> entities = CreatePickerEntityForSpecificClaimTypes( input, azureObjects.FindAll(x => !x.CreateAsIdentityClaim), false); if (entities != null) { foreach (var entity in entities) { // Add current PickerEntity to the corresponding attribute in the hierarchy // Use Claim type has key string entityClaimType = entity.Claim.ClaimType; // ClaimTypeMappingName cannot be null as it is value of SPClaimTypeMapping.IncomingClaimTypeDisplayName, which is mandatory string ClaimTypeMappingName = azureObjects .First(x => !x.CreateAsIdentityClaim && String.Equals(x.ClaimType, entityClaimType, StringComparison.InvariantCultureIgnoreCase)) .ClaimTypeMappingName; if (searchTree.HasChild(entityClaimType)) { matchNode = searchTree.Children.First(x => String.Equals(x.HierarchyNodeID, entityClaimType, StringComparison.InvariantCultureIgnoreCase)); } else { matchNode = new SPProviderHierarchyNode(_ProviderInternalName, ClaimTypeMappingName, entityClaimType, true); searchTree.AddChild(matchNode); } matchNode.AddEntity(entity); AzureCPLogging.Log(String.Format("[{0}] Added permission created without AAD lookup because AzureCP configured to always resolve input: claim value: \"{1}\", claim type: \"{2}\" to the list of results.", ProviderInternalName, entity.Claim.Value, entity.Claim.ClaimType), TraceSeverity.Medium, EventSeverity.Information, AzureCPLogging.Categories.Claims_Picking); } } return; } // Check if input starts with PrefixToBypassLookup in a AzureADObject List<AzureADObject> objectsMatchingInputPrefix = azureObjects.FindAll(x => !String.IsNullOrEmpty(x.PrefixToBypassLookup) && input.StartsWith(x.PrefixToBypassLookup, StringComparison.InvariantCultureIgnoreCase)); if (objectsMatchingInputPrefix.Count > 0) { // Input has a prefix, so it should be validated with no lookup AzureADObject objectMatchingInputPrefix = objectsMatchingInputPrefix.First(); if (objectsMatchingInputPrefix.Count > 1) { // Multiple objects have same prefix, which is bad AzureCPLogging.Log(String.Format("[{0}] Multiple objects have same prefix {1}, which is bad.", ProviderInternalName, objectMatchingInputPrefix.PrefixToBypassLookup), TraceSeverity.Unexpected, EventSeverity.Error, AzureCPLogging.Categories.Claims_Picking); return; } PickerEntity entity = CreatePickerEntityForSpecificClaimType( input.Substring(objectMatchingInputPrefix.PrefixToBypassLookup.Length), objectMatchingInputPrefix, true); if (searchTree.HasChild(objectMatchingInputPrefix.ClaimType)) { matchNode = searchTree.Children.First(x => String.Equals(x.HierarchyNodeID, objectMatchingInputPrefix.ClaimType, StringComparison.InvariantCultureIgnoreCase)); } else { matchNode = new SPProviderHierarchyNode(_ProviderInternalName, objectMatchingInputPrefix.ClaimTypeMappingName, objectMatchingInputPrefix.ClaimType, true); searchTree.AddChild(matchNode); } matchNode.AddEntity(entity); AzureCPLogging.Log(String.Format("[{0}] Added permission created without AAD lookup because input matches a keyword: claim value: \"{1}\", claim type: \"{2}\" to the list of results.", ProviderInternalName, entity.Claim.Value, entity.Claim.ClaimType), TraceSeverity.Medium, EventSeverity.Information, AzureCPLogging.Categories.Claims_Picking); } else { // Perform AAD lookup // Claims provider is called by static methods in SPClaimProviderOperations class. As a consequence, results must be declared in the method (and not in the class) to ensure that each thread has it own unique collection List<AzurecpResult> results = new List<AzurecpResult>(); BuildFilterAndProcessResults( input, azureObjects, this.CurrentConfiguration.FilterExactMatchOnly, context, entityTypes, ref results); if (results != null && results.Count > 0) { foreach (var result in results) { // Add current PickerEntity to the corresponding attribute in the hierarchy if (searchTree.HasChild(result.AzureObject.ClaimType)) { matchNode = searchTree.Children.First(x => x.HierarchyNodeID == result.AzureObject.ClaimType); } else { matchNode = new SPProviderHierarchyNode(_ProviderInternalName, result.AzureObject.ClaimTypeMappingName, result.AzureObject.ClaimType, true); searchTree.AddChild(matchNode); } matchNode.AddEntity(result.PickerEntity); AzureCPLogging.Log(String.Format("[{0}] Added permission created with AAD lookup: claim value: \"{1}\", claim type: \"{2}\" to the list of results.", ProviderInternalName, result.PickerEntity.Claim.Value, result.PickerEntity.Claim.ClaimType), TraceSeverity.Medium, EventSeverity.Information, AzureCPLogging.Categories.Claims_Picking); } } } } catch (Exception ex) { AzureCPLogging.LogException(ProviderInternalName, "in FillSearch", AzureCPLogging.Categories.Claims_Picking, ex); } finally { this.Lock_Config.ExitReadLock(); } }); }