Closed farlee2121 closed 4 years ago
First of all, are you sure your Startup
is correctly invoked?
I now feel quite silly. You, sir, are a champion.
Don't hesitate to add some details on what was causing that. It may help other people π
Good point. I was working in a new MVC 5 project straight from the template, but I forgot to change the identity option from 'none' to individual accounts.
This means that the project doesn't come with Microsoft.Owin.Host.SystemWeb out of the box. It also doesn't install that library when you install the other requisite Owin packages or if you choose to add an Owin startup file through the 'add new' menu.
Installing Microsoft.Owin.Host.SystemWeb fixed the issue
Makes total sense π
2 things First, I've been digging through the issues a lot to understand some aspects of the framework. I really appreciate how patient and encouraging you are with people's questions.
Second, the example I found on challenging requests from event handlers doesn't seem to be current.
For posterity, I was able to achieve it with
var owinContext = HttpContext.Current.GetOwinContext();
var userInfo = owinContext?.Authentication?.User?.Identity;
if (userInfo == null || userInfo.IsAuthenticated == false)
{
owinContext.Authentication.Challenge(relevant_auth_type);
context.SkipRequest();
}
I really appreciate how patient and encouraging you are with people's questions.
Thanks π€
Second, the example I found on challenging requests from event handlers doesn't seem to be current.
That's because the sample uses ASP.NET Core instead of OWIN/Katana (the authentication APIs have changed quite a lot in ASP.NET Core 2.0).
Your snippet looks good. I have 2 remarks, tho':
var manager = context.Transaction.GetOwinRequest()?.Context.Authentication ??
throw new InvalidOperationException("The OWIN authentication manager couldn't be resolved.");
context.HandleResponse()
didn't work in your case: context.SkipRequest()
might not be the best option, as it will allow OWIN to keep invoking the pipeline: assuming there's nothing to handle your request, it will reach the final 404 handler. Of course, the authentication middleware responding to the triggered challenge will ultimately rewrite the response, but it would be better to use context.HandleResponse()
if you can, to avoid unnecessary processing.In case you'd prefer using the pass-through mode, here's an example of how to use it with an ASP.NET MVC 5 controller (it's for the token endpoint, but it works exactly the same way with the authorization endpoint):
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Web;
using System.Web.Mvc;
using Microsoft.Owin.Security;
using OpenIddict.Abstractions;
using OpenIddict.Server.Owin;
using Owin;
using static OpenIddict.Abstractions.OpenIddictConstants;
namespace OpenIddictAspNetDemo.Controllers
{
public class ConnectController : Controller
{
[HttpPost]
public ActionResult Token()
{
var request = HttpContext.GetOwinContext()?.GetOpenIddictServerRequest() ??
throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
if (request.IsPasswordGrantType())
{
// Validate the username/password parameters.
if (!string.Equals(request.Username, "alice@wonderland.com", StringComparison.Ordinal) ||
!string.Equals(request.Password, "P@ssw0rd", StringComparison.Ordinal))
{
return new ChallengeResult(
authenticationType: OpenIddictServerOwinDefaults.AuthenticationType,
properties: new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerOwinConstants.Properties.Error] = Errors.InvalidGrant,
[OpenIddictServerOwinConstants.Properties.ErrorDescription] = "The username/password couple is invalid."
}));
}
var principal = new ClaimsPrincipal(new ClaimsIdentity(OpenIddictServerOwinDefaults.AuthenticationType));
principal.SetClaim(Claims.Subject, "Bob");
// Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
return new SignInResult((ClaimsIdentity) principal.Identity);
}
throw new InvalidOperationException("The specified grant type is not supported.");
}
internal class SignInResult : ActionResult
{
public SignInResult(ClaimsIdentity identity)
=> Identity = identity ?? throw new ArgumentNullException(nameof(identity));
public ClaimsIdentity Identity { get; }
public override void ExecuteResult(ControllerContext context)
=> context.HttpContext.GetOwinContext().Authentication.SignIn(Identity);
}
internal class ChallengeResult : ActionResult
{
public ChallengeResult(string authenticationType, AuthenticationProperties properties)
{
AuthenticationType = authenticationType;
Properties = properties;
}
public string AuthenticationType { get; }
public AuthenticationProperties Properties { get; }
public override void ExecuteResult(ControllerContext context)
=> context.HttpContext.GetOwinContext().Authentication.Challenge(Properties, AuthenticationType);
}
}
}
Ah. I figured it should be possible to get the Authentication context off of the event context. I first looked for it on Principle, got as far as context.Transaction.GetOwinRequest()
, and got tripped up at Context. This is definitely a nicer solution.
HandleResponse()
does work. I just misinterpreted the description thinking that it would prevent my login flow from taking over. It doesn't because the challenge writes a response rather than some internal call or middleware.
I was trying to avoid the pass through option, since I'm working with two company-owned sites that will always have an implicit grant. It's good to see that option laid out clearly out though.
I'm trying to get OpenIddict running with Asp.Net 4.8 and MVC 5.
I first followed the OWIN example at https://kevinchalet.com/2020/03/03/adding-openiddict-3-0-to-an-owin-application/. I am using the the recommended AutoFac registration method.
I was able to get this working properly. The tutorial says that the same should apply for other hosts, including System.Web.
However, I cannot get through to the token endpoint (or authorization endpoint if I try to add that). It always returns a 404.
So far I've tried
app.UseAutofacMvc();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
andbuilder.RegisterControllers(typeof(MvcApplication).Assembly);
app.Map('/test', b => b.Run(ctx => ctx.Response.WriteAsync("hello"));
My suspicion is that this is a routing issue, but I just can't seem to find the right lead to figure it out.
Are there any special requirements for using OpenIddict with MVC 5?