AAD V2 in ASP.NET Core WebAPI with JwtBearer - asp.net

Need your help with the below problem. I'm creating a webapi in .netcore in VS2017, and I'm trying to use the new model of authentication with https://apps.dev.microsoft.com/.
I register the app, create the reply URL to https://localhost:44337/signin-oidc
In .netcore I have the below config
"Authentication": {
"AzureAd": {
"AADInstance": "https://login.microsoftonline.com/",
"Audience": "<my audience>/<Name Of The App Registered>",
"ClientId": "<Registered App ID>",
"Domain": "<Domain of AAD>",
"TenantId": "<Tenant ID of AAD>"
}
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
Now I'm testing with a Universal App, but, whenever after trying login, always send me this error:
Additional technical information:
Correlation ID: a14b452f-457a-46e6-9601-67383df6ba1a
Timestamp: 2017-05-11 09:42:56Z
AADSTS50011: The reply address 'urn:ietf:wg:oauth:2.0:oob' does not match the reply addresses configured for the application: '<My Application ID>'. More details: not specified
I already confirm the AppID in apps.dev.microsoft.com, and I have also registered the app in AAD (with different ID, I cannot control that)
This is the code of Startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = Configuration["Authentication: AzureAd:AADInstance"] + Configuration["Authentication: AzureAd:TenantId"],
Audience = Configuration["Authentication:AzureAd:Audience"],
TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidIssuer = Configuration["Authentication: AzureAd:AADInstance"] + Configuration["Authentication: AzureAd:TenantId"] + "/ v2.0"
}
});
app.UseMvc();
}
Thanks in advance for your help,

Your UWP App must be registred as a native applcation with the following reply url: urn:ietf:wg:oauth:2.0:oob. Also you have to grant permission for the UWP app to call your API.

Ok, I already solve this problem. Thank you Martin for the help, the solution is similar to your recommendation.
The solution to this problem is:
On https://apps.dev.microsoft.com/ you need to register a new platform as Native and keep that values.

Related

.Net Core ILogger saves Critical as Error

In my test POST action am saving 4 different logs (Information, Warning, Error & Critical) into Windows EventLog.
I can see all four in Event viewer but one of them has wrong level. It is marker as 'Error' but it should be marked as 'critical'
Program.cs
return Host.CreateDefaultBuilder(args)
.ConfigureLogging(logger =>
{
logger.ClearProviders();
logger.AddEventLog(new EventLogSettings
{
SourceName = "Website API",
LogName = "Website API"
});
})...
appsettings.json
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
},
"EventLog": {
"LogLevel": {
"Default": "Warning"
}
}
}
Controller
public async Task<IActionResult> TestEndPoint()
{
_logger.LogInformation("LogInformation");
_logger.LogWarning("LogWarning");
_logger.LogError("LogError");
_logger.LogCritical("LogCritical");
return Ok(null);
}
Application: REST API - .NET 5.0
How to log an Event log in the Critical level?
How to create CRITICAL events for Windows Event Viewer?
The critical log level in the EventLog is reserved for system/kernel stuff. There is no same-same mapping between EventLog's critical and .Net Core's critical, it's just mapped as error. It's unfortunate that they have the same name, but different meaning in these two contexts, which maybe confusing.

Request ignored because of CORS in IdentityServer4

I have 3 projects:
Client App
ASP.NET API App
IdentityServer4 MVC App
I am able to send a request from API to IDP but trying to send a request from Client to IDP yields
"CORS request made for path: /api/Trial/TrialAction from origin: https://localhost:44389 but
was ignored because path was not for an allowed IdentityServer CORS endpoint"
even though I added the following to the IDP:
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", policyBuilder => policyBuilder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
and
// ...
app.UseRouting();
app.UseIdentityServer();
app.UseCors("CorsPolicy");
app.UseAuthorization();
// ...
The interesting part is, I can send a request from API to IDP without adding CORS configuration to IDP. What am I doing wrong?
Config.cs:
public static class Config
{
public static IEnumerable<IdentityResource> Ids =>
new IdentityResource[]
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Email(),
};
public static IEnumerable<ApiResource> Apis =>
new ApiResource[]
{
new ApiResource("myapi",
"My API",
new [] { "membershipType" }
)
};
public static IEnumerable<Client> Clients =>
new Client[]
{
new Client
{
ClientId = "mywebclient",
ClientName = "My Web Client",
AllowedGrantTypes = GrantTypes.Code, // Authorization code flow with PKCE protection
RequireClientSecret = false, // Without client secret
RequirePkce = true,
RedirectUris = { "https://localhost:44389/authentication/login-callback" },
PostLogoutRedirectUris = { "https://localhost:44389/authentication/logout-callback" },
AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"albidersapi"
},
AllowedCorsOrigins = { "https://localhost:44389" },
RequireConsent = false,
}
};
}
do yo have the client and API in the same project as IdentityServer? I typically recommend that you keep them apart.
A wild guess could be to swap these two lines:
app.UseIdentityServer();
app.UseCors("CorsPolicy");
Because apparently IdentityServer captures the request to the API?
The most likely issue is that your call from your client to your API is not including the access token.
The debug log is coming from this file here. If you look at where your debug statement is originating from you will see that it is checking if the path matches any within IdentityServerOptions.Cors.CorsPaths. Here is an image of what those paths generally are from a debug service I made.
These paths are just the default information and authentication endpoints for IdentityServer4. In other words it thinks your request is unauthenticated because it likely isn't including the access token.
If you are using IdentityServer4's template logging implementation with Serilog, then you can also add this to your appsettings.json to see what the ASP.NET Core CORS middleware has to say. It will be logging after IdentityServer4's log
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.Authentication": "Debug",
"Microsoft.AspNetCore.Cors": "Information",
"System": "Warning"
}
}
}
Here is what my debug log looked like when I made a request to an endpoint with a proper CORS policy, but the request didn't include its access token.
[21:05:47 Debug] IdentityServer.Hosting.CorsPolicyProvider CORS request made for path: /api/v1.0/users/{guid}/organizations from origin: https://localhost:44459 but was ignored because path was not for an allowed IdentityServer CORS endpoint
[21:05:47 Information] Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware No CORS policy found for the specified request.
So it's not a CORS issue really. It's an access token or authentication issue. It is also possible, however, that your endpoint isn't being hit properly. However, you should be receiving a 404 on the client in addition to the log seen above.

RabbitMQ Connection refused 127.0.0.1:5672

I am preparing a simple ASP.NET Core MVC web application.
I have installed RabbitMQ server to my laptop. RabbitMQ Management UI is running on localhost:15672.
Rabbit MQ cluster name is like: rabbit#CR00001.ABC.COM.LOCAL
I am trying to send message to rabbitmq in controller. But I am getting None of the specified endpoints were reachable error.
If I use 'localhost' as host name, I get Connection refused 127.0.0.1:5672 in inner exceptions.
If I use rabbit as host name, I get Name or service not known
I've tried to solve the problem according to other StackOverflow questions, however, none of them could solved my problem.
Home controller:
[HttpPost]
public void SendMessage([FromBody]Message message)
{
try
{
var factory = new ConnectionFactory()
{
UserName = _username,
Password = _password,
HostName = _hostname,
VirtualHost = "/",
Port = _port,
};
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: _queueName,
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
var body = Encoding.UTF8.GetBytes(message.Text);
channel.BasicPublish(exchange: "",
routingKey: _queueName,
basicProperties: null,
body: body);
}
}
catch (Exception ex)
{
}
}
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"RabbitMq": {
"Hostname": "localhost",
"QueueName": "WordQueue",
"UserName": "test",
"Password": "test",
"Port": 5672
}
}
Here is test user configuration in Rabbit MQ Management UI
Have you setup your test user in the UI portal? This is probably the cause of your connection refused error. You can setup users via http://localhost:15672/#/users.
You should also debug your factory to check that your config values are being passed in correctly
I would also suggest that you pop some code in your catch to ensure you aren't missing an exception
The references to http://rabbit are for use within containers. These will only work if you are running both your ASPNET and Rabbit applications within a containerised network (for example Docker Compose). I found using containers was a much better approach for learning RabbitMq.
Apprciate that this is going a little off-topic now, but if you are not familiar with containerisation I would suggest taking a look at this post (and the respective series) from Wolfgang Ofner https://www.programmingwithwolfgang.com/rabbitmq-in-an-asp-net-core-3-1-microservice/ and the getting started with Docker from Brad Traversy on YouTube https://www.youtube.com/watch?v=Kyx2PsuwomE
After create user, do not forget set permissions,
basicaly,
can access virtual hosts (/)
set topic permission (AMQP default)
Note: of course you can use rabbitmq ui for this operation (create user and permissions).
var factory = new ConnectionFactory() { HostName = "hostname_or_ip_adres_here", UserName="username here..", Password="psw here.."
};
this will work !

AWS .NET Core Worker Service using AWS local profile for development is trying to access IAM credentials from instance profile?

I have a .NET Core Worker service using AWS SQS to read messages off a queue. For local development I'm using a default profile with access/secret key stored in that. My appSettings.json is set up as follows:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
},
"TargetCloudWatchGroup": "/aws/insite/workers"
},
"App": {
"TaskProcessDelay": 10000,
"Environment": "NA",
"WorkerType": "INCOMING"
},
"AWS": {
"Region": "ap-southeast-2",
"Profile": "default",
"ProfilesLocation": "C:\\Users\\JMatson\\.aws\\credentials",
"AwsQueueLongPollTimeSeconds": 5,
"QueueUrl": "https://sqs.ap-southeast-2.amazonaws.com/712510509017/insite-incoming-dev"
}
}
I'm using DI to set up the services:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
//var options = hostContext.Configuration.GetAWSOptions();
services.AddDefaultAWSOptions(hostContext.Configuration.GetAWSOptions());
services.AddHostedService<Worker>();
services.AddSingleton<ILogger, Logger>(); // Using my own basic wrapper around NLog for the moment, pumped to CloudWatch.
services.AddAWSService<IAmazonSQS>();
});
But when I run the program in debug, it fails to read a message off the queue within Worker.cs with the following error:
An exception of type 'Amazon.Runtime.AmazonServiceException' occurred in System.Private.CoreLib.dll but was not handled in user code: 'Unable to get IAM security credentials from EC2 Instance Metadata Service.'
On startup it seems like after a couple of tries along the credentials chain it finds my credentials?
[40m[32minfo[39m[22m[49m: AWSSDK[0]
Failed to find AWS credentials for the profile default
AWSSDK: Information: Failed to find AWS credentials for the profile default
[40m[32minfo[39m[22m[49m: AWSSDK[0]
Found credentials using the AWS SDK's default credential search
AWSSDK: Information: Found credentials using the AWS SDK's default credential search
So why is it failing? If I check the immediate window I can see it's picking up my setttings:
?hostContext.Configuration.GetAWSOptions().Profile
"default"
?hostContext.Configuration.GetAWSOptions().ProfilesLocation
"C:\\Users\\JMatson\\.aws\\credentials"

Ocelot gateway dotnet core running under custom authentication trying to make downstream request with app pool identity

I am running a dotnet 2.2 Ocelot apigateway. What I am trying to achieve is passing a custom api key to the gateway and authorize the token to proceed the request down the chain. This is working fine. However the second piece to this is I'd like for it to run under a windows account application pool identity, and proxy the request into a Windows Authentication protected endpoint. Is this something that is achievable?
My application pool is set on the gateway to a custom domain account, however my requests to the windows authenticated endpoints through the gateway are being rejected with 401 unauthorized. Whereas if i just change the call to a non windows auth protected endpoint the gateway returns the results to me.
Any guidance on this setup of failure points to check or if this is not a feasible approach? I'm hoping the requests would flow as the custom identity account.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.Configure<IISServerOptions>(options =>
{
options.AutomaticAuthentication = true;
});
services.AddOcelot();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication().UseOcelot().Wait();
}
Program.cs
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(
ic => ic.AddJsonFile(Path.Combine("configuration", "configuration.json")))
.UseStartup<Startup>();
configuration.jcs
"ReRoutes": [
{
"DownstreamPathTemplate": "/{url}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "somesamplehostname.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/{url}",
"UpstreamHttpMethod": [ "Get" ],
"AuthenticationOptions": {
"AuthenticationProviderKey": "Windows"
}
}
]
Soo here here's what you need to do:
Add The windows auth service:
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.0&tabs=visual-studio
Set a name identifier to the service you have just initialized by setting DefaultScheme = "≤NAME>";
and set this to your AuthenticationProviderKey parameter in Ocelot.
It should work like a charm then

Resources