public void MatchPathToUriTemplates(string uri, string key) { // Arrange var table = new UriTemplateMatcher(); table.Add("root", "/"); table.Add("foo", "/foo/{bar}"); table.Add("kit", "/baz/kit"); table.Add("fooxy3", "/foo?x={x}&y={y}"); table.Add("baz", "/baz/{bar}"); table.Add("blob", "/baz/{bar}/blob"); table.Add("goo", "/{goo}/{bar}/blob"); table.Add("set", "/settings/{id}"); table.Add("state", "/games/{gametitle}/{gameid}/State/{stateid}"); table.Add("org", "/organization/{id}/settings/iteminsights"); table.Add("gamessetup", "/games/{gametitle}/Setup/{gamesid}"); // Act var result = table.Match(new Uri(uri, UriKind.RelativeOrAbsolute)); // Assert if (string.IsNullOrEmpty(key)) { Assert.Null(result); } else { Assert.Equal(key, result?.Key); } Assert.NotNull(table["goo"]); Assert.Null(table["goo1"]); }
public void ThrowArgumentNullExceptionForNullUriValueInMatch() { // Arrange var table = new UriTemplateMatcher(); table.Add("goo", "/{goo}/{bar}/blob"); table.Add("set", "/settings/{id}"); table.Add("org", "/organization/{id}/settings/iteminsights"); // Act and Assert Assert.Throws <ArgumentNullException>(() => table.Match(null)); }
/// <summary> /// Retrieves permissions scopes. /// </summary> /// <param name="scopeType">The type of scope to be retrieved for the target request url.</param> /// <param name="locale">The language code for the preferred localized file.</param> /// <param name="requestUrl">The target request url whose scopes are to be retrieved.</param> /// <param name="method">The target http verb of the request url whose scopes are to be retrieved.</param> /// <returns>A list of scopes for the target request url given a http verb and type of scope.</returns> public async Task <List <ScopeInformation> > GetScopesAsync(string scopeType = "DelegatedWork", string locale = DefaultLocale, string requestUrl = null, string method = null) { try { /* Add multiple checks to ensure thread that * populated scopes information successfully * completed seeding. */ if (RefreshPermissionsTables() || _scopesListTable == null || !_scopesListTable.Any()) { /* Permissions tables are not localized, so no need to keep different localized cached copies. * Refresh tables only after the specified time duration has elapsed or no cached copy exists. */ lock (_permissionsLock) { /* Ensure permissions tables are seeded by only one executing thread, * once per refresh cycle. */ if (!_permissionsRefreshed) { SeedPermissionsTables(); } } } var scopesInformationDictionary = await GetOrCreatePermissionsDescriptionsAsync(locale); if (string.IsNullOrEmpty(requestUrl)) // fetch all permissions { List <ScopeInformation> scopesListInfo = new List <ScopeInformation>(); if (scopeType.Contains(Delegated)) { if (scopesInformationDictionary.ContainsKey(Delegated)) { foreach (var scopesInfo in scopesInformationDictionary[Delegated]) { scopesListInfo.Add(scopesInfo.Value); } } } else // Application scopes { if (scopesInformationDictionary.ContainsKey(Application)) { foreach (var scopesInfo in scopesInformationDictionary[Application]) { scopesListInfo.Add(scopesInfo.Value); } } } return(scopesListInfo); } else // fetch permissions for a given request url and method { if (string.IsNullOrEmpty(method)) { throw new ArgumentNullException(nameof(method), "The HTTP method value cannot be null or empty."); } requestUrl = Regex.Replace(requestUrl, @"\?.*", string.Empty); // remove any query params requestUrl = Regex.Replace(requestUrl, @"\(.*?\)", string.Empty); // remove any '(...)' resource modifiers // Check if requestUrl is contained in our Url Template table TemplateMatch resultMatch = _urlTemplateMatcher.Match(new Uri(requestUrl.ToLower(), UriKind.RelativeOrAbsolute)); if (resultMatch == null) { return(null); } JArray resultValue = new JArray(); resultValue = (JArray)_scopesListTable[int.Parse(resultMatch.Key)]; var scopes = resultValue.FirstOrDefault(x => x.Value <string>("HttpVerb") == method)? .SelectToken(scopeType)? .Select(s => (string)s) .ToArray(); if (scopes == null) { return(null); } List <ScopeInformation> scopesList = new List <ScopeInformation>(); foreach (string scopeName in scopes) { ScopeInformation scopeInfo = null; if (scopeType.Contains(Delegated)) { if (scopesInformationDictionary[Delegated].ContainsKey(scopeName)) { scopeInfo = scopesInformationDictionary[Delegated][scopeName]; } } else // Application scopes { if (scopesInformationDictionary[Application].ContainsKey(scopeName)) { scopeInfo = scopesInformationDictionary[Application][scopeName]; } } if (scopeInfo == null) { scopesList.Add(new ScopeInformation { ScopeName = scopeName }); } else { scopesList.Add(scopeInfo); } } return(scopesList); } } catch (ArgumentNullException exception) { throw exception; } catch (ArgumentException) { return(null); // equivalent to no match for the given requestUrl } }
/// <summary> /// Retrieves permissions scopes. /// </summary> /// <param name="scopeType">The type of scope to be retrieved for the target request url.</param> /// <param name="locale">The language code for the preferred localized file.</param> /// <param name="requestUrl">Optional: The target request url whose scopes are to be retrieved.</param> /// <param name="method">Optional: The target http verb of the request url whose scopes are to be retrieved.</param> /// <param name="org">Optional: The name of the org/owner of the repo.</param> /// <param name="branchName">Optional: The name of the branch containing the files.</param> /// <returns>A list of scopes for the target request url given a http verb and type of scope.</returns> public async Task <List <ScopeInformation> > GetScopesAsync(string scopeType = "DelegatedWork", string locale = DefaultLocale, string requestUrl = null, string method = null, string org = null, string branchName = null) { try { InitializePermissions(); IDictionary <string, IDictionary <string, ScopeInformation> > scopesInformationDictionary; if (!string.IsNullOrEmpty(org) && !string.IsNullOrEmpty(branchName)) { // Creates a dict of scopes information from GitHub files scopesInformationDictionary = await GetPermissionsDescriptionsFromGithub(org, branchName, locale); } else { // Creates a dict of scopes information from cached files scopesInformationDictionary = await GetOrCreatePermissionsDescriptionsAsync(locale); } if (string.IsNullOrEmpty(requestUrl)) // fetch all permissions { List <ScopeInformation> scopesListInfo = new List <ScopeInformation>(); if (scopeType.Contains(Delegated)) { if (scopesInformationDictionary.ContainsKey(Delegated)) { foreach (var scopesInfo in scopesInformationDictionary[Delegated]) { scopesListInfo.Add(scopesInfo.Value); } } } else // Application scopes { if (scopesInformationDictionary.ContainsKey(Application)) { foreach (var scopesInfo in scopesInformationDictionary[Application]) { scopesListInfo.Add(scopesInfo.Value); } } } return(scopesListInfo); } else // fetch permissions for a given request url and method { if (string.IsNullOrEmpty(method)) { throw new ArgumentNullException(nameof(method), "The HTTP method value cannot be null or empty."); } requestUrl = Regex.Replace(requestUrl, @"\?.*", string.Empty); // remove any query params requestUrl = Regex.Replace(requestUrl, @"\(.*?\)", string.Empty); // remove any '(...)' resource modifiers // Check if requestUrl is contained in our Url Template table TemplateMatch resultMatch = _urlTemplateMatcher.Match(new Uri(requestUrl.ToLowerInvariant(), UriKind.RelativeOrAbsolute)); if (resultMatch == null) { return(null); } JArray resultValue = new JArray(); resultValue = (JArray)_scopesListTable[int.Parse(resultMatch.Key)]; var scopes = resultValue.FirstOrDefault(x => x.Value <string>("HttpVerb") == method)? .SelectToken(scopeType)? .Select(s => (string)s) .ToArray(); if (scopes == null) { return(null); } List <ScopeInformation> scopesList = new List <ScopeInformation>(); foreach (string scopeName in scopes) { ScopeInformation scopeInfo = null; if (scopeType.Contains(Delegated)) { if (scopesInformationDictionary[Delegated].ContainsKey(scopeName)) { scopeInfo = scopesInformationDictionary[Delegated][scopeName]; } } else // Application scopes { if (scopesInformationDictionary[Application].ContainsKey(scopeName)) { scopeInfo = scopesInformationDictionary[Application][scopeName]; } } if (scopeInfo == null) { scopesList.Add(new ScopeInformation { ScopeName = scopeName }); } else { scopesList.Add(scopeInfo); } } return(scopesList); } } catch (ArgumentNullException exception) { throw exception; } catch (ArgumentException) { return(null); // equivalent to no match for the given requestUrl } }
/// <summary> /// Create predicate function based on passed query parameters /// </summary> /// <param name="operationIds">Comma delimited list of operationIds or * for all operations.</param> /// <param name="tags">Comma delimited list of tags or a single regex.</param> /// <param name="url">Url path to match with Operation Ids.</param> /// <param name="graphVersion">Version of Microsoft Graph.</param> /// <param name="forceRefresh">Don't read from in-memory cache.</param> /// <returns>A predicate</returns> public static async Task <Func <OpenApiOperation, bool> > CreatePredicate(string operationIds, string tags, string url, OpenApiDocument source, bool forceRefresh = false) { if (url != null && (operationIds != null || tags != null)) { throw new InvalidOperationException("Cannot filter by url and either operationIds and tags at the same time."); } else if (operationIds != null && tags != null) { throw new InvalidOperationException("Cannot filter by operationIds and tags at the same time."); } Func <OpenApiOperation, bool> predicate; if (operationIds != null) { if (operationIds == "*") { predicate = (o) => true; // All operations } else { var operationIdsArray = operationIds.Split(','); predicate = (o) => operationIdsArray.Contains(o.OperationId); } } else if (tags != null) { var tagsArray = tags.Split(','); if (tagsArray.Length == 1) { var regex = new Regex(tagsArray[0]); predicate = (o) => o.Tags.Any(t => regex.IsMatch(t.Name)); } else { predicate = (o) => o.Tags.Any(t => tagsArray.Contains(t.Name)); } } else if (url != null) { /* Extract the respective Operation Id(s) that match the provided url path */ if (!_openApiOperationsTable.Any() || forceRefresh) { _uriTemplateTable = new UriTemplateMatcher(); _openApiOperationsTable = new Dictionary <int, OpenApiOperation[]>(); await PopulateReferenceTablesAync(source); } url = url.Replace('-', '_'); TemplateMatch resultMatch = _uriTemplateTable.Match(new Uri(url.ToLower(), UriKind.RelativeOrAbsolute)); if (resultMatch == null) { throw new ArgumentException("The url supplied could not be found."); } /* Fetch the corresponding Operations Id(s) for the matched url */ OpenApiOperation[] openApiOps = _openApiOperationsTable[int.Parse(resultMatch.Key)]; string[] operationIdsArray = openApiOps.Select(x => x.OperationId).ToArray(); predicate = (o) => operationIdsArray.Contains(o.OperationId); } else { throw new InvalidOperationException("Either operationIds, tags or url need to be specified."); } return(predicate); }