I am stuck.
I have a custom Umbraco controller which inherits from RenderMvcController
and when the Index()
action method is hit a file is returned. This works, but what I want to do is to protect it by decorating the action with an AuthorizeAttribute
and then requiring the user to authenticate.
namespace MyNamespace.Controllers
{
public class MyModelController : RenderMvcController
{
[Authorize]
public ActionResult Index(RenderModel model)
{
// ...
}
}
}
The authentication is to be made using OWIN and OpenId Connect against an Azure AD B2C app. This also works and is tested, but in a non-Umbraco context.
I have read numerous threads and code relating to the subject, but I am struggling to integrate it within Umbraco. I have a custom startup class which inherits from UmbracoDefaultOwinStartup
. I register a custom route to my AuthController
and configure OIDC via IAppBuilder.UseOpenIdConnectAuthentication()
.
But I need the Umbraco glue and have problems understanding how I should configure the cookies. I have checked that the startup Configuration()
method is invoked.
namespace MyNamespace
{
public class CustomOwinStartup : UmbracoDefaultOwinStartup
{
public override void Configuration(IAppBuilder app)
{
base.Configuration(app);
ConfigureAuth(app);
RouteTable.Routes.MapRoute(
"CustomAuth",
"CustomAuth/{action}",
new { controller = "Auth" }
);
}
private void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/CustomAuth/SignUpSignIn") // TODO: What should I put here?
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseOpenIdConnectAuthentication(
// Passing options that are tested and working
);
}
}
}
And then I have my auth controller which is very simple for the time being. I have no requirement to sync the auth info with Umbraco users.
namespace MyNamespace.Controllers
{
public partial class CustomAuthController : Controller
{
public CustomAuthController() : base()
{
}
public void SignUpSignIn()
{
if (!Request.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge();
return;
}
Response.Redirect("/"); // TODO: Maybe this should redirect me back to original route MyModel/Index in some way
}
}
}
If I run this and try to via my attribute-decorated custom Umbraco controller I get this error:
Page not found
No umbraco document matches the url
'/login.aspx?ReturnUrl=MYORIGINALROUTEHTTPENCODED'
. This page can be replaced with a custom 404. Check the documentation for "custom 404".
My guess is that this is because of the <authentication mode="Forms">
setting in Web.config
, but if I remove this or set the attribute mode
to "None"
, will this not impact the back-office login?
Very thankful if anyone can help me point me in the right direction!
Unfortunately I don't have enough time to set up the same environment and check everything but I will give several thoughts and post several links.
To override back office login logic you don't need to create your custom auth controller or override login page. Since Umbraco uses ASP.NET Identity for authorization you need to configure it properly in the OWIN startup and it will work as you need. Then you will use Umbraco authorization tools to check if a user can hit Index action of MyModelController.
If you need to implement custom username/password check use Umbraco extension for it. See more: https://our.umbraco.org/documentation/Reference/Security/#replacing-the-basic-username-password-check
Also you can use Umbraco extension for Active Directory. See more: https://our.umbraco.org/documentation/Reference/Security/#authenticating-with-active-directory-credentials
And about AuthorizeAttribute. You're getting not found error cause Authorize doesn't know anything about OWIN and Umbraco. It redirects to the default path which is login.aspx page and it doesn't exist in the project. You can set <authentication mode="Forms">
to None
. It won't affect Umbraco backoffice cause it uses ASP.NET Identity for it. If you want to protect some resources you can use UmbracoAuthorizeAttribute.
See more: https://our.umbraco.org/documentation/Implementation/Controllers/#mvc
Anyway read more Umbraco tutorials and docs. I hope you will find answer. Feel free to ask more.
Updated
Try to use your own version of AuthorizeAttribute. There is an example: http://www.c-sharpcorner.com/UploadFile/56fb14/custom-authorization-in-mvc/
You need to override AuthorizeCore method and return needed result from HandleUnauthorizedRequest. So you can return RedirectResult to your login page or whatever you need.
You can apply it then as
[CustomAuthorize]
public ActionResult Index(RenderModel model)
{
// ...
}
Updated 2
If custom AuthorizeAttribute doesn't help or it doesn't work you can create your ActionFilter and put authorization logic there. Of course it's not best practice but you can at least try to do it. See here: https://msdn.microsoft.com/en-us/library/gg416513(vs.98).aspx#Anchor_2