Authorize for Azure AD groups in asp.net mvc - asp.net

I am trying to use authorization on specific page views in controllers with [Authorize(Policy = "nameOfPolicy")] but I keep getting "Access denied" even though I have access to the Azure AD group that I have entered in my policy.
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Get the scopes from the configuration (appsettings.json)
var initialScopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
// Add sign-in with Microsoft
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
// Add the possibility of acquiring a token to call a protected web API
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
// Enables controllers and pages to get GraphServiceClient by dependency injection
// And use an in memory token cache
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddDistributedTokenCaches();
services.AddAuthorization(options =>
{
options.AddPolicy("it", policy => policy.RequireClaim("groups", "Azure group ID here"));
});
// Register AadService and PbiEmbedService for dependency injection
services.AddScoped(typeof(AadService))
.AddScoped(typeof(PbiEmbedService))
.AddScoped(typeof(PowerBiServiceApi));
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
// Enables a UI and controller for sign in and sign out.
services.AddRazorPages()
.AddMicrosoftIdentityUI();
// Session/cookie variables etc
services.AddDistributedMemoryCache();
services.AddSession();
// Loading appsettings.json in C# Model classes
services.Configure<AzureAd>(Configuration.GetSection("AzureAd"))
.Configure<PowerBI>(Configuration.GetSection("PowerBI"));
// Add the UI support to handle claims challenges
services.AddServerSideBlazor()
.AddMicrosoftIdentityConsentHandler();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
And in my controller this is how I try to use the Authorize:
[AuthorizeForScopes(ScopeKeySection = "DownstreamApi:Scopes")]
[Authorize(Policy = "it")]
public Task<IActionResult> Index()

To authorize for Azure AD groups in asp.net MVC.
I have followed the below steps and able to authorize.
Create an APP in Azure AD and register the App.
Using the ID tokens in authentication for the App.
Set the RedirectionUrl in azure for the App from the authentication tab.
Choose the ASP.Net MVC application from Visual studio templates and install the below NuGet packages.
NuGets
Microsoft.AspNetCore.Authentication.AzureAD.UI
Microsoft.Identity.Web
In Startup.cs class make the below changes to register or configure the services of Authentication
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApp(Configuartion.GetSetion("AzureAd"));
services.AddControllersWithViews();
}
And you need add app.UseAuthentication () method along with app.UseAuthorization() in startup.cs class.
And you need to use the TenantId , ClientId and RedirectionUrl in the Settings.Json file.
appsettings.json
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "Project",
"ClientId": "",
"TenantId": "",
"CallbackPath": "/signin-oidc"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
launchSettings.Json
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:42313",
"sslPort": 44302
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"MVC_APP": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:41222",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Authorize attribute need to be add at the controller level.
[Authorize]
public class HomeController : Controller

Related

How to use Azure AD with OpenId Connect in a iFrame

I've just been looking for hours for a way to call a web app in an iFrame that is protected with OpenId Connect SSO.
Current status is that either the following message appears with the link https://localhost:5001/signin-oidc.
Or the following error message with the link https://localhost:5001 :
If the application is called directly via the browser, then the login screen of Azure appears as desired. Only when I go via the iFrame, nothing works anymore. Even if I open the application first and log in, it does not work with iFrame.
The settings were made with the default template of Rider
csproj
...
<UserSecretsId>SomeGuideWithName</UserSecretsId>
<WebProject_DirectoryAccessLevelKey>0</WebProject_DirectoryAccessLevelKey>
...
App.razor
<CascadingAuthenticationState>
<Router AppAssembly="#typeof(App).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="#routeData" DefaultLayout="#typeof(MainLayout)"/>
<FocusOnNavigate RouteData="#routeData" Selector="h1"/>
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="#typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
appsettings.json
xxx --> Secreds that are correct.
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "xxx.onmicrosoft.com",
"TenantId": "xxx",
"ClientId": "xxx",
"CallbackPath": "/signin-oidc"
}
Program.cs
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using MitAuth.Data;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddControllersWithViews()
.AddMicrosoftIdentityUI();
builder.Services.AddAuthorization(
options =>
{
// By default, all incoming requests will be authorized according to the default policy
options.FallbackPolicy = options.DefaultPolicy;
}
);
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor()
.AddMicrosoftIdentityConsentHandler();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
Generated Cookies
The goal is to have application A (Caller) embed an iFrame that application B (OpenIdConnect protected).
Questions:
Do I need to reconfigure anything in App B?
Do I need to do anything else in App A?
Is there any token or similar that has to be passed on?
I tried to reproduce the scenario in my environment:
I got the same error:
System.Exception: An error was encountered while handling the remote login.
---> System.Exception: OpenIdConnectAuthenticationHandler: message.State is null or empty.
Here due to misconfiguration in callback path I got the error.
In your case check without giving callbackpath in both code and portal.
Appsettings.json:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "mytenantxxx.onmicrosoft.com",
"TenantId": "fbxxxxxxxxxxxxf3b0",
"ClientSecret": "xxxx",
"ClientId": "xxxx",
"CallbackPath": "/"
},
I have configured following redirect urls in portal.
My application url uses http protocol http://localhost:44328
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));
services.AddControllersWithViews()
.AddMicrosoftIdentityUI();
services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy
options.FallbackPolicy = options.DefaultPolicy;
});
services.AddRazorPages();
services.AddServerSideBlazor()
.AddMicrosoftIdentityConsentHandler();
services.AddSingleton<WeatherForecastService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
IdentityModelEventSource.ShowPII = true;
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
When I changed the CallbackPath value to /signin-oidc , that error was resolved.
Appsettings.json:
"AzureAd": {
...
"CallbackPath": "/signin-oidc"
},
Also check Exception: Correlation failed. AAD + Azure Front Door

How can I pass the connectionstring from my selected publish-profile into the configuration of my Startup.cs-File?

We have two different connectionstrings in the file appsettings.json. DevConnection is the database for our test system. ProdConnection is the database for our productive system:
{
"ConnectionStrings": {
"DevConnection": "server=TestServer;Database=MyDatabase;user id=sql-User;Password=***;",
"ProdConnection": "server=ProdServer;Database=MyDatabase;user id=sql-User;Password=***;"
},
[...]
}
We have also two publishing profiles for test-server and productive-server. One for the testsystem. One for the productive system. We want to apply the connectionstrings DevConnection/ProdConnection for the publishing profiles test-server and productive-server:
How can I pass the connectionstring from my selected publish-profile into the configuration of my Startup.cs-File?
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
services.AddControllers().AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null);
services.AddDbContext<KundenDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("?")));
}
Here is the structure of appsettings.json:
You can add different connction according to different environments.
You can add this to appsettings.Production.json:
"ConnectionStrings": {
"Connection": "server=ProdServer;Database=MyDatabase;user id=sql-User;Password=***;"
},
add this to appsettings.Development.json:
"ConnectionStrings": {
"Connection": "server=TestServer;Database=MyDatabase;user id=sql-User;Password=***;",
},
startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
services.AddControllers().AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null);
services.AddDbContext<KundenDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Connection")));
}

OrchardCore Multi Tennant with Web Api

Is it possible to use the multi tennant features of OrchardCore in a Web API project?
I have created an empty project in Visual Studio using the using the "ASP.NET Core Web Application" -> "API" template and added a reference to OrchardCore.Application.Mvc.Targets.
My StartUp class looks like this:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddOrchardCore().AddMvc().WithTenants();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseOrchardCore(builder =>
{
builder.UseHttpsRedirection();
builder.UseRouting();
builder.UseAuthorization();
builder.UseEndpoints(endpoints => { endpoints.MapControllers(); });
});
}
}
I have also added the following to appsetting.json:
"OrchardCore": {
"Default": {
"State": "Running",
"RequestUrlHost": null,
"RequestUrlPrefix": null,
"Features": [],
"CustomTitle": "Default Tenant",
"CustomSetting": "Custom setting for Default tenant"
},
"CustomerA": {
"State": "Running",
"RequestUrlHost": null,
"RequestUrlPrefix": "customer-a",
"Features": [ "Module1" ],
"CustomTitle": "Customer A",
"CustomSetting": "Custom setting for Customer A"
},
"CustomerB": {
"State": "Running",
"RequestUrlHost": null,
"RequestUrlPrefix": "customer-b",
"Features": [ "Module1", "Module2" ],
"CustomTitle": "Customer B",
"CustomSetting": "Custom setting for Customer B"
}
When I run the application the default https://localhost:44370/weatherforecast route works but https://localhost:44370/customer-b/weatherforecast returns a 404.
I think it may be the way I am using AddControllers or UseOrchardCore. For example if I comment out AddControllers I get an InvalidOperationException becuase UseAuthorization no longer works.
Using Core 3.1
I did this in my StartUp to let me use controllers instead of pages.
Keep in mind that you have to add OrchardCore.Module.Targets to each module and then import the module to the main project.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new TenantViewLocationExpander());
});
/*
* Needed for authorization and such.
*/
services.AddControllersWithViews();
/*
* Add multitenancy
*/
services.AddOrchardCore()
.Configure((tenantAppBuilder, endpointBuilder, tenantScopeServiceProvier) =>
{
/*
* Map our routes
*/
endpointBuilder.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
}).AddMvc()
.WithTenants();
}

Azure AD B2C Web API Using .NET Core 2

I’m trying to call a Web API from a Web App both protected by Azure AD B2C. The App signs in fine with the Azure sign in page. But when I call my [Authorize] endpoint on my API I get a 401 unauthorized response.
I thought this is supposed to work right out of the box using VS2017 and ASP.NET Core 2.1. When I created both apps I specified “Individual User Accounts” for authentication and “Connect to an existing user store in the cloud”. The examples I’ve found seem to be from .NET Core 1 or older and no longer relevant or using deprecated setups.
I have the App in the API access section with read and write scopes in Azure.
How do I successfully authorize my App to call my API?
Here’s my App Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
.AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
My App appsettings.json:
{
"AzureAdB2C": {
"Instance": "https://myCompanyPassport.b2clogin.com/tfp/",
"ClientId": "51dde0de-a204-4b67-b890-068846e17ff1",
"ClientSecret": "------------------------",
"CallbackPath": "/signin-oidc",
"Domain": "myCompanyPassport.onmicrosoft.com",
"SignUpSignInPolicyId": "B2C_1_myCompanySignUpSignIn",
"ResetPasswordPolicyId": "B2C_1_myCompanyPasswordReset",
"EditProfilePolicyId": "B2C_1_myCompanyProfile",
"TaskServiceUrl": "https://localhost:44337/",
"ApiIdentifier": "https://myCompanyPassport.onmicrosoft.com/taskapi",
"ReadScope": "read",
"WriteScope": "write"
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
Here’s my API Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseMvc();
}
My API appsettings.json:
{
"AzureAdB2C": {
"Instance": "https://myCompanyPassport.b2clogin.com/tfp/",
"ClientId": "213764b3-8c2a-4bf6-9e69-355495a8f14e",
"ClientSecret": "------------------------",
"Domain": "myCompanyPassport.onmicrosoft.com",
"SignUpSignInPolicyId": "B2C_1_myCompanySignUpSignIn",
"ReadScope": "read",
"WriteScope": "write"
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
Did you try this ( addazureadbearer api )
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddAzureAdBearer(options => Configuration.Bind("AzureAd", options));

Log to Console with .Net Core 2.0 web application

I'm giving my first steps with .Net Core
Just created a web Hello world with
dotnet new web
I can see there's some kind of logging enabled. I just want to log something to the Console.
But I don't know how to access the logger from
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!!!");
});
I tried with Console.WriteLine but it obviously didn't work.
Also tried with NLog following this guide https://github.com/NLog/NLog.Web/wiki/Getting-started-with-ASP.NET-Core-(csproj---vs2017) but I don't know how to inject the logger.
I'm just trying to look around for educational purposes, not looking for a real logger, so perhaps there's a better/easier option.
I could achieve it with this:
[...]
using Microsoft.Extensions.Logging;
[...]
namespace web
{
public class Startup
{
ILogger log;
public Startup(ILoggerFactory loggerFactory)
{
log = loggerFactory.CreateLogger("Logger");
}
[...]
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
loggerFactory.AddDebug();
[...]
app.Run(async (context) =>
{
log.LogInformation("logging!");
await context.Response.WriteAsync("Hello World!");
});
}
}
}
also had to add an appsettings.json file to the root of the project
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

Resources