I've been following the steps to make Windows 8 Store app get an ACS token as described here:
Does the WebAuthenticationBroker work in Windows 8 Metro App post Release Candidate
However, the ResponseData property of my WebAuthenticationResult object only contains the callback uri as specified in ACS, and contains no token information. Below my code.
Authentication method of Windows 8 client
private async void Authenticate()
{
WebAuthenticationResult webAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(
WebAuthenticationOptions.None,
new Uri("https://myACSnamespace.accesscontrol.windows.net:443/v2/wsfederation?wa=wsignin1.0&wtrealm=http://localhost:12714/"),
new Uri("http://mypublicIPaddress:80/WebAppMVCAPI/api/federation/end"));
My Relying Party application Return URL is set to http://mypublicIPaddress:80/WebAppMVCAPI/api/federation/en
My controller on the web application is programmed as follows:
public class FederationController : ApiController
{
protected virtual string ExtractBootstrapToken()
{
return "Hello World";
//return HttpContext.Current.User.BootstrapToken();
}
[HttpGet]
public string Get()
{
return "Hello Get World";
}
[HttpPost]
public HttpResponseMessage Post()
{
var response = this.Request.CreateResponse(HttpStatusCode.Redirect);
response.Headers.Add("Location", "/WebAppMVCAPI/api/federation/end?acsToken=" + ExtractBootstrapToken());
return response;
}
}
}
As you can imagine, the web application is running on my IIS Server and listening on port 80. My router is configured to forward incoming requests as needed, and when I launch my web application in visual studio I have access to the application from an internet host.
The idea is to have the Windows 8 store app get a token from ACS with a Facebook login. When I launch the win8 client, the application shows a Facebook login page. I log in with my credentials successfully. However, when I look at the webauthenticationresult.responsedata property, I only see the callback uri. Also, I don't see any log in my firewall that ACS tried to post something to my callback uri.
Your replying party application return URL should be
http://mypublicIPaddress:80/WebAppMVCAPI/api/federation
not
http://mypublicIPaddress:80/WebAppMVCAPI/api/federation/end
Related
I have followed the guide from Microsoft for getting started with SignalR. This worked perfectly, and I was able to publish and deploy the application to IIS.
Now I need to communicate with the .NET application from another Windows process (specifically a Delphi program). What I want to do is to tell the .NET application to send SignalR message (i.e. invoke a method on all connected clients).
How can I accomplish this?
I'm not sure how the .NET application is being executed - does it have its own Windows process that I could send Windows messages to? Or would it be easier to send a local HTTP GET/POST request from the Delphi program to localhost? If so, how can I make the SignalR application handle it?
You can create a controller and inject the IHubContext<ChatHub>. Use the hub context to send message to clients.
public class MessageController : Controller
{
private readonly IHubContext<ChatHub> _hubContext;
public MessageController(IHubContext<MessageHub> hubContext)
{
_hubContext = hubContext;
}
[HttpPost]
public async Task<IActionResult> SendMessage([FromForm] string message)
{
await _hubContext.Clients.All.SendAsync("ReceiveMessage", message);
return Ok();
}
}
Then call this endpoint from your delphi app.
I work on a .Net core application and I need to mix windows and anonymous authentication within the same endpoint(s). So the goal is to be able to determine the windows user but the endpoint should also work when no windows user is present (aka windows authentication fails).
My problem is that when I use the Authorize attribe (as shown in the example below), the endpoint will only be called when windows authentication succeded. If I additionaly add the [AllowAnonymous] attribute, the User is never authenticated.
Example: (
[Authorize(AuthenticationSchemes = IISDefaults.AuthenticationScheme)]
public IActionResult Index()
{
_log.LogDebug("IsAuthenticated = " + this.User.Identity.IsAuthenticated.ToString());
_log.LogDebug("Authenticated Name: " + this.User.Identity.IsAuthenticated.Name);
return View();
}
How can this be done in .Net 6.0? It should be really simple as authentication and authorization should be separated but it seems they are quite intertwined. I haven't found a solution after extensive googling, checking the .net core source code and trying out myself.
Is there a good way to solve this?
Remark 1: there are solutions for .Net core 3.1 but then don't work in .Net 6 Enable both Windows authentication and Anonymous authentication in an ASP.NET Core app
Remark 2: we have endpoint that have to work with Windows Authentication only and other with anonyomous authentication. These both work fine within the same application. It is really about being able to detect the windows user in an endpoint that otherwise supports anymous authentication.
I (or better we) have found a solution that works even when Windows authentication is disabled on IIS. It is not very elegant but this is what we came up with. The idea is basically to trigger another call to an endpoint to determine if the user is actually a windows loging or not. If this call is successful, then we know we have a windows user and can act accordingly, for example do a redirect to an endpoint that requires windows authentication.
Remark: If you can control the IIS settings - which probably is often the case - , then I suggest you go with the solution proposed here:
enable-both-windows-authentication-and-anonymous-authentication-in-an-asp-net-co )
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> TestWindowsAuthAsync(CancellationToken cancellationToken)
{
using var client = new HttpClient(new HttpClientHandler()
{
UseDefaultCredentials = true
});
var response = await client.GetAsync($"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}{HttpContext.Request.PathBase}{HttpContext.Request.Path}/HasUserWindowsAuth");
if (response.IsSuccessStatusCode)
{
// Yes, now we know that user indeed has windows authentication and we can act upon it
return RedirectToAction("QuickLogin", input);
}
// No windows credentials have been passed at this point
return View();
}
[HttpGet("HasUserWindowsAuth")]
[Authorize(AuthenticationSchemes = IISDefaults.AuthenticationScheme)]
public IActionResult HasUserWindowsAuth() => Ok();
[HttpGet("QuickLogin")]
[Authorize(AuthenticationSchemes = IISDefaults.AuthenticationScheme)]
public async Task<IActionResult> QuickLoginAsync(LoginModel input, CancellationToken cancellationToken)
{
var user = this.User.Identities.FirstOrDefault(i => i System.Security.Principal.WindowsIdentity && i.IsAuthenticatd);
// do something with that user
}
I have a MVC client accessing a Web API protected by IDS4. They all run on my local machine and hosted by IIS. The app works fine when using local identity for authentication. But when I try to use Windows authentication, I keep getting "401 Unauthorized" error from the dev tool and the login box keeps coming back to the browser.
Here is the Windows Authentication IIS setting
and enabled providers
It's almost like that the user ID or password was wrong, but that's nearly impossible because that's the domain user ID and password I use for logging into the system all the time. Besides, according to my reading, Windows Authentication is supposed to be "automatic", which means I will be authenticated silently without a login box in the first place.
Update
I enabled the IIS request tracing and here is the result from the log:
As you can see from the trace log item #29, the authentication (with the user ID I typed in, "DOM\Jack.Backer") was successful. However, some authorization item (#48) failed after that. And here is the detail of the failed item:
What's interesting is that the ErrorCode says that the operation (whatever it is) completed successfully, but still I received a warning with a HttpStatus=401 and a HttpReason=Unauthorized. Apparently, this is what failed my Windows Authentication. But what is this authorization about and how do I fix it?
In case anyone interested - I finally figured this one out. It is because the code that I downloaded from IndentityServer4's quickstart site in late 2020 doesn't have some of the important pieces needed for Windows authentication. Here is what I had to add to the Challenge function of the ExternalController class
and here is the ProcessWindowsLoginAsync function
private async Task<IActionResult> ProcessWindowsLoginAsync(string returnUrl)
{
var result = await HttpContext.AuthenticateAsync(AccountOptions.WindowsAuthenticationSchemeName);
if (result?.Principal is WindowsPrincipal wp)
{
var props = new AuthenticationProperties()
{
RedirectUri = Url.Action(nameof(Callback)),
Items =
{
{ "returnUrl", returnUrl },
{ "scheme", AccountOptions.WindowsAuthenticationSchemeName },
}
};
var id = new ClaimsIdentity(AccountOptions.WindowsAuthenticationSchemeName);
id.AddClaim(new Claim(JwtClaimTypes.Subject, wp.Identity.Name));
id.AddClaim(new Claim(JwtClaimTypes.Name, wp.Identity.Name));
if (AccountOptions.IncludeWindowsGroups)
{
var wi = wp.Identity as WindowsIdentity;
var groups = wi.Groups.Translate(typeof(NTAccount));
var roles = groups.Select(x => new Claim(JwtClaimTypes.Role, x.Value));
id.AddClaims(roles);
}
await HttpContext.SignInAsync(IdentityConstants.ExternalScheme, new ClaimsPrincipal(id), props);
return Redirect(props.RedirectUri);
}
else
{
return Challenge(AccountOptions.WindowsAuthenticationSchemeName);
}
}
Now my windows authentication works with no issues.
I am attempting to deploy an asp.net core hosted blazor webassembly app to Netlify. I have published the release version of the Server project to a directory on my desktop, and uploaded it to github. I set Netlify's publish directory to wwwroot and the site does render just fine. However, if I attempt a call to an api controller, it returns a 404. Specifically, here is my code:
//Register.razor in the Client project
if (Model.Password.Length >= 6 && Model.Password == Model.ConfirmPassword)
{
await HttpClient.PostAsJsonAsync<RegisterModel>("api/Register/Post", Model);
NavigationManager.NavigateTo("/");
}
//In my controller
[Route("api/Register")]
public class RegisterController : Controller
{
private UserContext UserContext { get; set; }
private IHasher Hasher = new Pbkdf2Hasher();
public RegisterController (UserContext userContext)
{
UserContext = userContext;
}
[RequireHttps]
[HttpPost]
[Route("Post")]
public async Task Post([FromBody]RegisterModel model)
{
var user = new UserModel
{
Email = model.Email,
Password = Hasher.Hash(model.Password)
};
await UserContext.AddAsync(user);
await UserContext.SaveChangesAsync();
}
}
The url request I send is: https://(NetlifyDefaultDomain)/api/Register/Post. However, I get a 404 response. On localhost it works just fine. I'm imagining that there's a setting that I have to change somewhere in order for the request URL to work. I've tried looking but have been unable to find guidance. What do I need to change? Thanks
Edit
Here is the Program.cs file of my Client project
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddTransient(sp => new HttpClient {
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider,
ApiAuthenticationStateProvider>();
builder.Services.AddScoped<IAuthService, AuthService>();
await builder.Build().RunAsync();
}
}
Target framework is netstandard2.1, and it's webassembly 3.2.0.
Netlify is a static file host. They do not run any server-side applications like .NET core on their servers.
So you can host your Blazor client-side application on Netlify but if you want server side code to run you must host it somewhere else.
If you are looking for free hosting for your API there are some cloud providers that have a free tier. Azure has free App Service with some limits, Google cloud has a free micro VPS that can host a small app, heroku also has a free offering.
A cheap VPS from Digital Ocean, Vultr or Linode is another alternative.
I have an ASPNET Core 2 application which I am trying to Authenticate with Azure AD using OpenId. I just have boilerplate code from selecting Single Organization Authentication in the ASPNET Core 2 templates, so no custom code. I followed the article here.
The app is not able to get metadata from the Azure AD application because of proxy. The same URL returns data if I just paste it in browser.
The error I get is:
HttpRequestException: Response status code does not indicate success: 407 (Proxy Authentication Required).
System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
IOException: IDX10804: Unable to retrieve document from: 'https://login.microsoftonline.com/my-tenant-id/.well-known/openid-configuration'.
Microsoft.IdentityModel.Protocols.HttpDocumentRetriever+d__8.MoveNext()
I have another ASPNET 4.5.2 application where I am able to perform authentication with the same Azure AD app as above after setting proxy in code like below:
System.Net.HttpWebRequest.DefaultWebProxy = new WebProxy
{
Address = new Uri("http://my-company-proxy:8080"),
Credentials = new NetworkCredential
{
UserName = "proxyusername",
Password = "proxypassword"
}
};
So Essentially my problem is to get past the Proxy Authentication in ASPNET Core 2.
I have tried Microsoft.AspNetCore.Proxy package. Its pretty much broken and doesn't work for me. Also I tried adding the Proxy entries in machine.config (which are actually not required for 4.5.2 app) but that doesn't work as well. I believe getting past a corporate proxy should be very trivial, but doesn't look like it so far.
Tratcher's comment pointed me in the right direction and I got it working, but just to help everyone with it, below is what you need to do:
builder.AddOpenIdConnect(options => options.BackchannelHttpHandler = new HttpClientHandler
{
UseProxy = true,
Proxy = new WebProxy
{
Credentials = new NetworkCredential
{
UserName = "myusername",
Password = "mypassword"
},
Address = new Uri("http://url:port")
}
});
In Full .net framework setting up a proxy is using a config setting
entry but to use an HTTP proxy in .net core ,you have to implement
IWebProxy interface.
Microsoft.AspNetCore.Proxy is proxy middleware which serves a different purpose (to setup reverse proxy) not as an http proxy .Refer this article for more details
To implement a webproxy in .net core,
public class MyHttpProxy : IWebProxy
{
public MyHttpProxy()
{
//here you can load it from your custom config settings
this.ProxyUri = new Uri(proxyUri);
}
public Uri ProxyUri { get; set; }
public ICredentials Credentials { get; set; }
public Uri GetProxy(Uri destination)
{
return this.ProxyUri;
}
public bool IsBypassed(Uri host)
{
//you can proxy all requests or implement bypass urls based on config settings
return false;
}
}
var config = new HttpClientHandler
{
UseProxy = true,
Proxy = new MyHttpProxy()
};
//then you can simply pass the config to HttpClient
var http = new HttpClient(config)
checkout https://msdn.microsoft.com/en-us/library/system.net.iwebproxy(v=vs.100).aspx