We would like to build an Admin Checklist page that allows our network administrators to quickly view all the setting in the IIS and web config to easily trouble an issue. the web config is fairly easy but I'm not sure how to get the stuff from IIS. (App Pool Name and type, Machine Key, Anonymous Authentication, etc.) I'm sure it can be done, I just don't know how.
Thanks,
Rhonda
The information you're looking for are exposed in the IIS .Net APIs. You can find them in \windows\system32\inetsrv (they are Microsoft.Web.Administration.dll, and maybe Microsoft.Web.Management.dll).
Sample code to get ID and application pool name for each site :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Web.Administration;
namespace ConsoleApplication79
{
class Program
{
static void Main(string[] args)
{
ServerManager s = new ServerManager();
var q = s.Sites.Select(aSite => new
{
ID = aSite.Id,
AppPoolName = aSite.Applications.First().ApplicationPoolName
});
foreach (var item in q)
{
Console.WriteLine("ID: {0}, PoolName: {1}", item.ID, item.AppPoolName);
}
}
}
}
Related
I have a blob storage container that stores HTML files. With the public access level, I can see the HTML, but the idea is to set it to private. I want to have users authenticate and access the HTML file.
For that I created an Azure Function with the most relevant part of the code being:
#r "Newtonsoft.Json"
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
public static async Task<IActionResult> Run(HttpRequest req, ILogger log, string version, string route)
{
var blobUri = "https://mybloburi.blob.core.windows.net/" + route;
var expiresOn = req.Headers.FirstOrDefault(p => p.Key.Equals("x-ms-token-aad-expires-on",
StringComparison.OrdinalIgnoreCase)).Value.FirstOrDefault();
log.LogInformation($"expires On : {expiresOn}");
log.LogInformation($"blob uri : {blobUri}");
var isTokenExpired = (DateTime.Parse(expiresOn, styles: DateTimeStyles.AdjustToUniversal) - DateTime.UtcNow).TotalMinutes < 5;
var bearerToken = isTokenExpired? await RefreshToken(req, log) : req.Headers.
FirstOrDefault(p => p.Key.Equals("x-ms-token-aad-access-token", StringComparison.OrdinalIgnoreCase)).
Value.FirstOrDefault();
log.LogInformation($"bearer token: {bearerToken}");
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate");
client.DefaultRequestHeaders.Add("Accept", "*/*");
client.DefaultRequestHeaders.Add("x-ms-version", "2017-11-09");
var response = await client.GetAsync(blobUri);
log.LogInformation($"response: {response}");
var contentType = response.Content.Headers.FirstOrDefault(p => p.Key.Equals("Content-Type", StringComparison.OrdinalIgnoreCase));
var byteArray = await response.Content.ReadAsByteArrayAsync();
const string defaultContentType = "application/octet-stream";
return new FileContentResult(byteArray, contentType.Value.Any() ? contentType.Value.First() : defaultContentType);
}
}
In the Integration section of the Azure Function, I added this config:
Then I created an App Registration. Under the Authorization option of the Azure Function, I enabled the App Service Authentication. In there I added a new Identity Provider as Microsoft and as a provider I added the created App Registration. I created a Role Group with access to the Blob Storage Container and set its App Id to the "Allowed token audiences".
When I test, I am able to authenticate to the AAD. However, the HTTP Client get function fails with
<Code>AuthenticationFailed</Code>
<Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
I don't know what other configuration to do and I cant seem to find anything in the documentation that could help
As suggested by #Thomas. Yes, we do have a static website where we have a streamlined authentication.
For which you will be having a by default access to a series of pre-configured providers, or you can even register a custom provider.
To configure static web apps for using it as an API function for role assignment you need to add rolesSource property to auth and that is the path of API function.
{
"auth": {
"rolesSource": "/api/GetRoles",
"identityProviders": {
// ...
}
}
}
For more information you can check this document.
As part of an Azure DevOps pipeline, I would like to promote packages in our own NuGet feed to 'Release' view as part of the release build.
I have an application that traverses all project.assets.json files and find names and versions of packages used by the projects in the solution.
This list is reduced by pattern matching on names to our own packages.
Previously I have succesfully used the BuildHttpClient from Microsoft.TeamFoundation.Build.WebApi to access information about builds and build artifacts.
What are the available tools for accessing Nuget Packages, feeds and views?
The REST API is described here: https://learn.microsoft.com/en-us/rest/api/azure/devops/artifactspackagetypes/nuget/update%20package%20versions?view=azure-devops-rest-6.0, but I would hate to implement the classes myself, if there is a library for the purpose.
Nuget - Update Package Versions has a flaw - there is no {project} relevans for packages.
By adding Microsoft.VisualStudio.Services.Packaging.Client Version 16.179.0-preview we get the classes, we need as long as we are building .Net Framework 4.6.2 or later (no netstandard yet).
based on this, I built the following helper class (no exception handling or threading to keep it simple):
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Microsoft.VisualStudio.Services.NuGet.WebApi.Types;
using Microsoft.VisualStudio.Services.Packaging.Shared.WebApi;
using Newtonsoft.Json;
namespace PromotePackages
{
public class PromotePackageBatch
{
private readonly string _organization;
private readonly string _feedId;
private readonly string _token;
public PromotePackageBatch(string organization, string feedId, string token)
{
_organization = organization;
_feedId = feedId;
_token = token;
}
public void PromotePackagesToView(IDictionary<string, string> Libraries, string viewName)
{
var packs = new List<MinimalPackageDetails>();
foreach (var kvp in Libraries)
{
packs.Add(new MinimalPackageDetails
{
Id = kvp.Key,
Version = kvp.Value
});
}
using (HttpClient client = new HttpClient())
{
NuGetPackagesBatchRequest req = new NuGetPackagesBatchRequest
{
Data = new BatchPromoteData
{
ViewId = viewName
},
Operation = 0,
Packages = packs
};
var httpContent = new StringContent(JsonConvert.SerializeObject(req), Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", _token))));
var response = client.PostAsync(BuildUri(), httpContent).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
}
}
private Uri BuildUri()
{
return new Uri($"https://pkgs.dev.azure.com/{_organization}/_apis/packaging/feeds/{_feedId}/nuget/packagesbatch?api-version=6.0-preview.1");
}
}
}
By reference to this doc: Azure DevOps Services .NET SDK API Reference, searching for any managed APIs by typing in the box, but we don’t find such library which implements this Rest API: NuGet - Update Package Versions.
You could create a new issue in the MicrosoftDocs/feedback repository on GitHub for this feedback.
And now we suggest that you directly use this Rest API to implement this.
I've been following this documentation for using Azure AD B2C for authentication in a blazor web app
https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/hosted-with-azure-active-directory-b2c?view=aspnetcore-5.0
After following this documentation, we're left with a solution containing a server and a client, both running on https port 5001. Now, i'd like to switch to using an external api, rather than the one running on port 5001.
Everything seems good and authentication succeeds when manually using the access token retrieved by blazor. But blazor is only automatically attaching the authentication headers to requests starting with https://localhost:5001.
When i'm instead using https://localhost:5003, the authentication header is left empty.
Is there something i can add to the provider options of my MsalAuthentication, in order for it to pass this access token to my api running on https://localhost:5003?
builder.Services.AddHttpClient("{MyAssembly}.ServerAPI", client => client.BaseAddress = new Uri("https://localhost:5003"))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("{MyAssembly}.ServerAPI"));
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAdB2C", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://{myproject}.onmicrosoft.com/e3b857b7-df50-4633-ae02-df4d4b20e911/API.Access openid offline_access");
});
If you want to make outgoing requests to URIs that aren't within the app's base URI, you can create a custom AuthorizationMessageHandler class to implement it. For more details, please refer to here
For example
Create Custom AuthorizationMessageHandler class
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
{
public CustomAuthorizationMessageHandler(IAccessTokenProvider provider,
NavigationManager navigationManager)
: base(provider, navigationManager)
{
ConfigureHandler(
authorizedUrls: new[] { "https://localhost:44389/" },
scopes: new[] { "https://<>.onmicrosoft.com/api/user_impersonation" });
}
}
Add the following code in Program.cs.
using System;
using System.Net.Http;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Text;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace WebB2C
{
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped<CustomAuthorizationMessageHandler>();
builder.Services.AddHttpClient("ServerAPI", client =>
client.BaseAddress = new Uri("https://localhost:44389/"))
.AddHttpMessageHandler<CustomAuthorizationMessageHandler>();
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
.CreateClient("ServerAPI"));
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAdB2C", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://<>.onmicrosoft.com/api/user_impersonation");
options.ProviderOptions.DefaultAccessTokenScopes.Add("openid");
options.ProviderOptions.DefaultAccessTokenScopes.Add("offline_access");
});
await builder.Build().RunAsync();
}
}
}
I'm using the following code to connect. I can connect to other Azure Resources ok.
But for one resource I get the following error: URL and Key are correct.
{"A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond"}
The Code is as follows
_searchClient = new SearchServiceClient(searchServiceName, new
SearchCredentials(apiKey));
_httpClient.DefaultRequestHeaders.Add("api-key", apiKey);
_searchServiceEndpoint = String.Format("https://{0}.{1}",
searchServiceName, _searchClient.SearchDnsSuffix);
bool result = RunAsync().GetAwaiter().GetResult();
Any ideas? thx in advance? How can I troubleshoot this?
I will show how this is done in c#
you will need a appsettings.json
you will need this code in the program.cs file
there are a lot of other files in the example from the document
that you may need to use , learn and edit for ur usecase
When working in c# and azure, always know what is unique about the file structured your solution first. This is why we build the examples from the docs as we learn the solution. Next we must study the different blocks of code that when executed deliver one feature or functionality to the solution as a whole.
appsettings.json
{
"SearchServiceName": "[Put your search service name here]",
"SearchIndexName": "hotels",
"SearchServiceAdminApiKey": "[Put your primary or secondary Admin API key here]",
"SearchServiceQueryApiKey": "[Put your primary or secondary Query API key here]"
}
Program.cs
namespace AzureSearch.SDKHowTo
{
using System;
using System.Linq;
using System.Threading;
using Microsoft.Azure.Search;
using Microsoft.Azure.Search.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Spatial;
// This sample shows how to delete, create, upload documents and query an index
static void Main(string[] args)
{
IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
IConfigurationRoot configuration = builder.Build();
SearchServiceClient serviceClient = CreateSearchServiceClient(configuration);
string indexName = configuration["SearchIndexName"];
Console.WriteLine("{0}", "Deleting index...\n");
DeleteIndexIfExists(indexName, serviceClient);
Console.WriteLine("{0}", "Creating index...\n");
CreateIndex(indexName, serviceClient);
ISearchIndexClient indexClient = serviceClient.Indexes.GetClient(indexName);
Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(indexClient);
ISearchIndexClient indexClientForQueries = CreateSearchIndexClient(indexName, configuration);
RunQueries(indexClientForQueries);
Console.WriteLine("{0}", "Complete. Press any key to end application...\n");
Console.ReadKey();
}
private static SearchServiceClient CreateSearchServiceClient(IConfigurationRoot configuration)
{
string searchServiceName = configuration["SearchServiceName"];
string adminApiKey = configuration["SearchServiceAdminApiKey"];
SearchServiceClient serviceClient = new SearchServiceClient(searchServiceName, new SearchCredentials(adminApiKey));
return serviceClient;
}
private static SearchIndexClient CreateSearchIndexClient(string indexName, IConfigurationRoot configuration)
{
string searchServiceName = configuration["SearchServiceName"];
string queryApiKey = configuration["SearchServiceQueryApiKey"];
SearchIndexClient indexClient = new SearchIndexClient(searchServiceName, indexName, new SearchCredentials(queryApiKey));
return indexClient;
}
private static void DeleteIndexIfExists(string indexName, SearchServiceClient serviceClient)
{
if (serviceClient.Indexes.Exists(indexName))
{
serviceClient.Indexes.Delete(indexName);
}
}
private static void CreateIndex(string indexName, SearchServiceClient serviceClient)
{
var definition = new Index()
{
Name = indexName,
Fields = FieldBuilder.BuildForType<Hotel>()
};
serviceClient.Indexes.Create(definition);
}}
Azure concepts to learn
How and why we create azure clients
Why do we use appsettings.json
What is some example file structures for azure search solutions
What coding lanague do you want to use to build that solutio
do u want to use the azure sdk
How to find and create api keys
C# concepts to learn
What is an interface and how do you use it
How to import one file in the file structure into another
How the main function works
How to call variables in to a function
How to call a function with a function
How to write server side code vs client side code
How to deploy c# code to azure
What version of c# are u using What’s is asp.net and what version will u use
What is asp.net core and what version will u use
As u can see azure and c# have a high learning curve.
Luckily you have stack overflow and documentation to research all of the above questions and more:)
For how u would troubleshoot...what I do is research each block of code in the documentation example and run all of the code locally. Then I test each block of code one at a time. Ur always testing data flowing thought the block of code. So you can just console log the result of a block a code by creating a test varable and print that varable to the console.
Because each block of Code represents one feature or functionality, each test will output either a pass or fail delivery of that feature or functionality. Thus you can design functionality, implement that design and create a test for new Feature.
I have small RESTful API written in ASP.NET core and I am looking into how to add authentication to it using Active Directory. I have to use our companies server for authentication using AD but I do not see any tutorials of how to do this.
I guess that JWT authentication is not what I am looking for or I might be wrong and misunderstand something. I am total noob in question of authentication.
I know we have solved that in one of the nodejs project of ours and it was not that straight forward. I would appreciate any help in that matter.
As of today, System.DirectoryServices hasn't been implemented in ASP.NET Core yet, but we could use Novell.Directory.Ldap.NETStandard.
You can install the package via NuGet Novell.Directory.Ldap.NETStandard.
Sample code -
using Novell.Directory.Ldap;
namespace YourNamespace
{
public class LdapAuthenticationService : IAuthenticationService
{
public bool ValidateUser(string domainName, string username, string password)
{
string userDn = $"{username}#{domainName}";
try
{
using (var connection = new LdapConnection {SecureSocketLayer = false})
{
connection.Connect(domainName, LdapConnection.DEFAULT_PORT);
connection.Bind(userDn, password);
if (connection.Bound)
return true;
}
}
catch (LdapException ex)
{
// Log exception
}
return false;
}
}
}