How to Specify the "Authorize" at the Area level with Razor Pages? - authentication

I am testing the WebApp authentication using simple cookie. The app has 2 areas: Public & Internal (see Area structure at the end of this post). Users are required to login when accessing all pages under the "Internal" area.
PROGRAM DESCRIPTION
The App is implemented with .NET 6 with Razor pages (without MVC). In the program.cs file, I tried to specify the "authorize" at the "Area" level for "Internal" area (see code segment here). The HTML 404.15 error occurred when testing the app (see HTML error in attached image below).
It looks like that "AuthorizeAreaFolder" works fine with any folder name inside of Internal area. Is there a way to setup "Authorize" at an Area level?
CONFIGURE AUTHORIZE
builder.Services.AddRazorPages(options =>
{
options.Conventions.AuthorizeAreaFolder("Internal","/");
});
HTML ERROR
WEBAPP AREAS

Make sure that your signing in page is accessible to anonymous users. An easy way to accomplish this is to add the AllowAnonymous attribute to the PageModel class of the relevant page e.g (assuming the signing in page is called Signin):
[AllowAnonymous]
public class SigninModel : PageModel

Related

Azure B2C: how to Include domain hint in Sign Up/In links from asp.net core control

I'm using Azure B2C, I would like to use Google to sign in users. I would like to do something like this in my asp.net core page to achieve it:
<a asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignIn" asp-route-domainHint="google.com">Google Sign Up/In</a>
So that the Google challenge page is used to sign in the user.
However, this code results in the non-social ("organic") sign in page being used, instead, because the domain_hint parameter is not included in the auth redirect.
Looking at the account controller code, here: https://github.com/AzureAD/microsoft-identity-web/blob/master/src/Microsoft.Identity.Web.UI/Areas/MicrosoftIdentity/Controllers/AccountController.cs
The only way to pass a domain hint to the Account controller, is by using the Challenge action.
<a asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="Challenge" asp-route-domainHint="google.com">Google Sign Up/In</a>
This almost works.
But it loops back again to Google challenge page, after you choose your google account, repeatedly.
Is there a way to pass a domain hint and use the SignIn action of the Account controller? Or some other approach for generating Sign In calls from an asp.net core page and include a domain hint?
I have seen this answer, but would prefer to not build up the entire href address from scratch: Azure B2C with domain hint instead of IdP buttons
Thanks very much
To redirect users to an external identity provider, do the following:
Check the domain name of your external identity provider. For more information, see Redirect sign-in to a social provider.
Complete the Support advanced scenarios procedure.
In the OnRedirectToIdentityProviderFunc function, add the following line of code to the OnRedirectToIdentityProvider function:
private async Task OnRedirectToIdentityProviderFunc(RedirectContext context)
{
context.ProtocolMessage.DomainHint = "facebook.com";
// More code
await Task.CompletedTask.ConfigureAwait(false);
}
https://learn.microsoft.com/en-us/azure/active-directory-b2c/enable-authentication-web-application-options#preselect-an-identity-provider
Jas Suri's answer helped quite a bit, but there are a few code-related steps that I did to complete the solution:
To get that domain_hint parameter into the authentication link, you add some code to the ConfigureServices() method of the Startup class of your ASP.NET Core project:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options =>
{
Configuration.Bind("AzureAdB2C", options); // Assuming an appsettings.json section named AzureAdB2C with config data
options.Events ??= new OpenIdConnectEvents();
options.Events.OnRedirectToIdentityProvider += OnRedirectToIdentityProviderFunc;
});
The key part was subscribing to the OnRedirectToIdentityProvider event. Add an event handler for it in Startup.cs, which could look like this:
private async Task OnRedirectToIdentityProviderFunc(RedirectContext context)
{
var domainHint = context.HttpContext.Request.Query["domainHint"];
context.ProtocolMessage.DomainHint = domainHint.Count > 0 ? domainHint[0] : null;
await Task.CompletedTask.ConfigureAwait(false);
}
The middle line above gets the domainHint from the query string. So, you must set its value in your razor view as follows. Take note of the asp-route-domainHint attribute, which ASP.NET Core adds to the rendered Href as a query string value.
<a asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignIn" asp-route-domainHint="google.com">Google Sign Up/In</a>
In the final rendered HTML, this link becomes (note the domainHint querystring parameter):
Google Sign Up/In
When a user clicks on that link, the Account controller in Microsoft.Identity.Web will redirect the user to the authentication link with Microsoft (note the domain_hint parameter near the end) which results in the social auth provider's screen being full-screen:
https://your-ADB2C-intance/your-ADB2C-domain/b2c_1a_signup_signin/oauth2/v2.0/authorize?client_id=..etc..etc....&domain_hint=google.com&state=..etc..etc..

Cannot use same razor page for two addresses

I what to use the same razor page in more than one position in my web app.
I have the page /one and I want to reach also with /two and /three.
I can do it with the AddPageRoute :
options.Conventions.AddPageRoute("/one", "two");
options.Conventions.AddPageRoute("/one", "three");
But the taghelpers in the page always render formaction="/three?handler=Update" pointing to the last route, same for /one, /two or /three
This make impossible use the same razor page in different position in my web application.
Git sample : https://github.com/enricoe73/OnePage2Routes.git
You can reach the page using any of the routes you defined, but the outbound URL generation components in the framework (tag helpers, IUrlHelper etc) will always use the last route registered when generating an outbound URL, so the order in which the routes are registered plays a part.
If that doesn't suit you (because you may want to point to different routes at different times, for instance), the solution is to use the standard HTML formaction attribute instead of the custom asp-* attributes that belong to the tag helper:
<button formaction="/two?handler=update">Update</button>

Customize Identity Server 4 Login UI for Hosted Blazor WebAssembly

I have a solution based on the Visual Studio template that is successfully using IdentityServer4.
What think I understand is:
The IS4 integration implements endpoints at /authentication/{action}, e.g. authentication/login
IS4 routes that request to host/Identity/Account/Login.cshtml. I have scaffolded identity so I can see that .cshtml file in my project.
The code-behind Login.cshtml.cs takes care of speaking with SignInManager, etc.
In the client project the "LoginDisplay.razor" component redirects to /authentication/login when I click the login button. I presume that this is where step 1 above is invoked, which redirects to the location in step 2.
Fine. Now, I want to customise the whole login UI.
From instructions at: https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/additional-scenarios?view=aspnetcore-5.0 I can see that:
I can configure authentication paths to be anything I want. For example:
builder.Services.AddApiAuthorization(options => {
options.AuthenticationPaths.LogInPath = "security/login";
})
So, I have created a razor component to handle security/login:
#page "/security/{action}"
#using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="#Action">
<LoggingIn>
This is the new login page
</LoggingIn>
</RemoteAuthenticatorView>
#code{
[Parameter] public string Action { get; set; }
}
My expectation was that after clicking "Login", I would be routed to the above and presented with a page that just said:
"This is the new login page"
and thought that from there, I would:
Customise the UI within the <LoggingIn> fragment.
Make a call to an API that would then replicate the logic in the scaffolded login.cshtml file that actually logs the user in.
That line of code from the login.cshtml.cs file looks like this:
var result = await _signInManager.PasswordSignInAsync(
Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
However, it seems that the razor component I created for /security/login is simply a 'transient' message that appears before being routed to the scaffolded login.csthml file.
So, to me, it seems that I am unable to actually change the physical page used to collect the user's credentials. I am only able to change the transient screen that appears before the originally scaffolded login page is shown.
Does this mean that if I want a customised UI for logging in I need to directly edit the scaffolded page as opposed to creating a whole new UI in the WebAssembly project that calls an APIController that I create to take care of using SignInManager?
It would actually be a lot less work to do that than to take the approach of creating a Client-side UI that calls an API that I create, etc. so, with hindsight, editing the scaffolded cshtml file is probably the best way to go. But am still confused as to what value is really being brought by being able to configure options.AuthenticationPaths.LogInPath.

Disable Links to My Site profiles in Sharepoint 2010

I would like to utilize some of the social collaboration features in Sharepoint 2010, such as the Noteboard webpart and tagging, but do not want to use the My Site profile pages.
I have already built a custom control that redirects from the userdisp.aspx page to a custom user profile page. I would like to continue to use that custom profile page. However, it seems like user profile links that are generated by the Noteboard webpart, for example, go directly to the /Sites/MySites/person.aspx page without being routed through the /_layouts/userdisp.aspx page. So my profile redirect control doesn't catch it.
In Sharepoint Central Admin, under Manage Service Applications > User Profile Service Application > Manage User Permissions, I have only checked the box for "Use Social Features", not "Create Personal Site," so I am not sure why the profile page is not linking to the old userdisp.aspx page.
Is it possible to redirect these links back to the userdisp.aspx page?
It appears to be hardcoded into the webpart.
I looked at Microsoft.SharePoint.Portal.WebControls.SocialCommentControl and the link comes from UserProfile.PublicUrl, which is defined as:
public override Uri PublicUrl
{
get
{
string userProfileUrl = UserProfileGlobal.GetUserProfileURL(
this.m_objManager.UserProfileApplicationProxy,
this.m_objManager.PartitionID,
"?accountname=",
this.m_UserProfileFields["AccountName"].ToString());
if (!string.IsNullOrEmpty(userProfileUrl))
return new Uri(userProfileUrl);
else
return (Uri) null;
}
}
which eventually calls:
internal static string GetUserProfileURL(string profileWebUrl, string strIdentifier, string strValue)
{
if (string.IsNullOrEmpty(profileWebUrl))
return (string) null;
else
return PersonalSpaceGlobal.EnsureTrailingSlash(profileWebUrl)
+ "Person.aspx"
+ strIdentifier
+ (strIdentifier.Equals("?accountname=", StringComparison.OrdinalIgnoreCase)
? SPHttpUtility.UrlKeyValueEncode(strValue).Replace(":", "%3A")
: SPHttpUtility.UrlKeyValueEncode(strValue));
}
I can think of two workarounds:
Add jQuery to your page to change the URL (selector = span.socialcomment-username > a)
Create your own webpart containing a custom control that inherits from SocialCommentControl, which overrides RenderComment.
Overriding RenderComment is probably going to be messy. You will need to copy the decompiled code for the method just to change the following into your own code:
SocialCommentControl._GetProperty(
comment,
SocialCommentControl.SocialCommentProperty.PublicPage)
Hopefully, there are no internal method calls within RenderComment's 67 lines of code. Otherwise, it is going to be a lot more difficult to implement. It would be a lot easier if you could simply override _GetProperty, but unfortunately, it is a static method.
All of that to say, I would probably recommend the jQuery option over extending SocialCommentControl.

wicket authentication / login

I am following this tutorial http://wicket.wordpress.com/2010/01/08/template-for-building-authenticated-webapplication/ in order to learn how to make login and authentication using wicket.
My question/problem is that my login area is on the header and therefor one can login on every page.
If my application class should inherit AuthenticatedWebApplication, then I must override getSignInPageClass method. What page class should I provide?
Is there any other best tutorial to add authentication using wicket?
The sign in page is displayed when the user attempts to access a Page or other component which requires authorization to create. If your application allows login on every page, then none of your pages require authorization, and the sign in page will never be displayed. I suggest you set it to the home page.
As all your pages are visible, you can't use the #AuthorizeInstantiation annotation on your page classes. Instead, you must control visibility of components within the page using the RENDER action instead. For example,
MetaDataRoleAuthorizationStrategy.authorize(mycomponent, RENDER, "SYSADMIN");
The only example I can find is at wicketstuff.org.