ChangePassword control without provider - asp.net

Is there a way to make ChangePassword control work without Membership provider? Like the same way Login control works through an Authenticate event, could I make this component to use my password changing function and then showing success view without me writing custom provider?
Thanks,
Eugene.
EDIT:
Just to clarify after some research through Reflector I came to conclusion that this control is totally useless without MembershipProvider. Every logic bit, like reading configuration file and validating user inputs is outsourced to providers, so you have to write this generic code as well.
This is the list of functions sufficient to make this control work:
public bool ChangePassword(string username, string oldPassword, string newPassword)
public MembershipUser GetUser(string username, bool userIsOnline)
public int MinRequiredNonAlphanumericCharacters { get; }
public int MinRequiredPasswordLength { get; }
The last two are only used for error message if you return false from ChangePassword function.

Looking at the .NET 3.5 source through reflector, when the ChangePassword button event gets detected by protected OnBubbleEvent, it calls AttemptChangePassword(). The implementation of that method looks roughly like this:
private void AttemptChangePassword() {
...
this.OnChangingPassword(loginCancelEventArgs);
if(!e.Cancel) {
MembershipProvider provider = LoginUtil.GetProvider(this.MembershipProvider);
...
}
It looks like you could:
Add a handler to the ChangingPassword event
In that event handler use the control's UserName and NewPassword properties to do your own custom work.
On success either redirect to a new URL or set the cancel flag on the event args and hide the ChangePassword control manually. There does not appear to be an easy way to use the SuccessView with this technique.
So it looks like it's somewhat possible, but the control definitely wasn't designed with this use in mind -- it's pretty well hard-wired to MembershipProvider.

Related

Is it possible to validate a property using data-annotation asynchronously with ASP.NET Core?

I have an asp.net core 3.1 based project. I need to add a custom validation rule that will require a database call in ordered to determine the validity of the value.
For example, when creating a new user, I need to validate that there is no other username in the database with the same username before allowing the user to be created.
If I can create a custom attribute UniqueUsername, then I should be able to do something like this
public class UniqueUsername : ValidationAttribute
{
private readonly UserManager _manager = manager;
public UniqueUsername (UserManager manager)
{
_manager = manager;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
string username = value.ToString();
if(_manager.Exists(username))
{
return new ValidationResult("The username provided belong to a different user.");
}
return ValidationResult.Success;
}
}
But, _manager.Exists(username) is a synchronous call. I want to avoid blocking the main thread, so I want a way to call await _manager.ExistsAsync(username) instead to avoid blocking the main thread.
Is there a way to create an attribute that would validate a single property and write errors "if any" to the ModelState?
If this isn't possible using data-annotation, is there an different way to validate property while writting errors to ModelState so when ModelState.IsValid() or TryValidateModel(model) are called, the attribute is called?
The data-annotations you add in your model are meant to validate the data present within the model (although some can also be translated into your database). These are meant to be reused even if you were to use your models on a client framework.
You can use the ModelState functions you mentioned to make async calls to your database. If you want to remove the logic from your controller, you can create utility functions to do so.
If you are open to third-party libraries, there is a great and popular validations library called Fluent Validation. Here is a documentation on how you can make async calls with it: https://docs.fluentvalidation.net/en/latest/async.html

Are there any packages etc implementing dynamic role controller access for MVC3?

I have statically allowed access to controllers/action methods using the standard Authorize attribute with roles. I am using the default ASP.Net Membership Provider.
One of our clients wants finer grained access control. They would like to be able to dynamically assign which roles can access which controllers/actions etc. I've seen answers saying implement a CustomAuthorize Attribute.
Just wondered if there were any toolkits etc to this. It seems a reasonably standard feature. I guess something like this http://kbochevski.blogspot.com/2009/11/mvc-custom-authorization.html
Try a custom attribute like this:
public class DynamicAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var controllerName = httpContext.Request.RequestContext.RouteData.Values["controller"];
var actionName = httpContext.Request.RequestContext.RouteData.Values["action"];
// Get this string (roles) from a database or somewhere dynamic using the controllerName and actionName
Roles = "Role1,Role2,Role3"; // i.e. GetRolesFromDatabase(controllerName, actionName);
return base.AuthorizeCore(httpContext);
}
}
Just put this attribute on any action method that requires authorization and do a look up in a database with the controller name and action name to get the required roles.
Hope this helps,
Mark

Very simple single user login in ASP.NET MVC2?

I'm building my site, and I want to restrict a part of my site (The admin parts) from normal public display.
I am using LINQ for database access.
I have a Service class to handle calls to the database through LINQ
I have the whole site running, except for the Login part.
So far I have only been able to find examples using MembershipProvider and/or RoleProviders etc. And to be honest, it does seem like too much work for what I want. All this has to do is to let you in if you type the correct password in the input fields.
Can i really not avoid the Providers?
Since you only have a single user you don't need to create a database dependency. You can make a very simple authorization service based off of a hard coded credentials. For example,
public class AuthorizationService{
private AuthorizationService(){}
public static readonly AuthorizationService Instance = new AuthorizationService();
private const string HardCodedAdminUsername = "someone";
private const string HardCodedAdminPassword = "secret";
private readonly string AuthorizationKey = "ADMIN_AUTHORIZATION";
public bool Login(string username, string password, HttpSessionStateBase session){
if(username.ToLowerInvariant().Trim()==HardCodedAdminUsername && password.ToLowerInvariant().Trim()==HardCodedAdminPassword){
session[AuthorizationKey] = true;
return true;
}
return false;
}
public void Logout(HttpSessionStateBase session){
session[AuthorizationKey] = false;
}
public bool IsAdmin(HttpSessionStateBase session){
return session[AuthorizationKey] == true;
}
}
Then you can build a custom IAuthorizationFilter like:
public class SimpleAuthFilterAttribute: FilterAttribute, IAuthorizationFilter{
public void OnAuthorization(AuthorizationContext filterContext){
if(!AuthorizationService.Instance.IsAdmin(filterContext.HttpContext.Session)){
throw new UnauthorizedAccessException();
}
}
}
Then all you have to do is decorate the protected controller actions with the SimpleAuthFilter and you're application's login suddenly works. Yay! (Note, I wrote all this code in the StackOverflow answer window, so you may need to clean up typos, etc. before it actually works)
Also, you could refactor this to omit the username if you find that unnecessary. You will need to create a controller action for Login and Logout that make the corresponding calls to the AuthorizationService, if you want your protected controller actions to ever be accessible.
Its worth building a light-weight Membership Provider with minimal implementation; GetUser, ValidateUser etc methods. YOu dont need to implement the whole thing. It just helps with authorising pages and checking User.Identity etc when needed. You also dont need the RoleProvider or ProfileProvider to do this.
Its also scalable for the future.
UPDATE
You just need to implement the core methods to valudate and get the user and insert your own validation/data access code.
Something like this....
web.config settings:
<membership defaultProvider="ApplicationMembershipProvider">
<providers>
<clear/>
<add name="ApplicationMembershipProvider" type="YourNamespace.ApplicationMembershipProvider"/>
</providers>
</membership>
Login Code:
if (Membership.ValidateUser(username, password))
{
FormsAuthentication.SetAuthCookie(username, false);
}
You can set the status (logged in or not) in a session variable. Set the variable to true if the user entered the correct password, then on every page you want to restrict access, check if the variable is true.
#KristianB a while ago I gave an answer to this SO question. I believe it may be useful since it's very straightforward to implement and at the same time it's better than hardcoding a username and a password in your code.
Good luck!

Intercept Unity 2.0 HandlerAttribute without an interface

I'm a first-time user of the AOP features of Unity 2.0 and would like some advice. My goal is to be able to log method calls in an ASPX page, like so:
public partial class Page2 : Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
[Log]
private void Testing()
{
}
}
Here is the code for the LogAttribute:
public class LogAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new LogHandler(Order);
}
}
Now the LogHandler:
public class LogHandler : ICallHandler
{
public LogHandler(int order)
{
Order = order;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
string className = input.MethodBase.DeclaringType.Name;
string methodName = input.MethodBase.Name;
string preMethodMessage = string.Format("{0}.{1}", className, methodName);
System.Diagnostics.Debug.WriteLine(preMethodMessage);
return getNext()(input, getNext);
}
public int Order { get; set; }
}
The problem I have is how to use the [Log] attribute. I've seen plenty of example of how to configure the interception settings, for example:
container.AddNewExtension<Interception>();
container.Configure<Interception>().SetDefaultInterceptorFor<ILogger>(new InterfaceInterceptor());
But this implies that I have an interface to intercept, which I don't. I have the ASPX page which uses the [Log] attribute.
so how can I configure Unity to make use of the [Log] attribute? I've done this before using PostSharp and would like to be able to use Unity to do the same.
Cheers.
Jas.
You're unfortunately not going to get this to work in an ASP.NET page with Unity interception.
Unity interception uses a runtime interception model. Depending on the interceptor you choose, you'll either get a subclass with virtual method overrides to call the call handlers (VirtualMethodInterceptor) or a separate proxy object (Interface or TransparentProxyInterceptor) which execute the call handlers and then forward to the real object.
Here's the issue - ASP.NET controls creation and calls to your page, and there's no easy way to hook into them. Without controlling the creation of the page object, you can't use the VirtualMethodInterceptor, because that requires that you instantiate a subclass. And you can't use the proxy version either, because you need ASP.NET to make calls through the proxy.
PostSharp gets around this because it's actually rewriting your IL at compile time.
Assuming you could hook into the creation of the page object, you'd have to use the VirtualMethodInterceptor here. It's a private method, so you want logging on "self" calls (calls from one method of the object into another method on the same object). The proxy-based interceptors can't see those, since the proxy is a separate instance.
I expect there is a hook somewhere to customize how ASP.NET creates object - BuildManager maybe? But I don't know enough about the details, and I expect it'll require some pretty serious hacking to get work.
So, how do you get around this? My recommendation (actually, I'd recommend this anyway) is to use the Model-View-Presenter pattern for your ASP.NET pages. Make the page object itself dumb. All it does is forward calls to a separate object, the Presenter. The Presenter is where your real logic is, and is independent of the details of ASP.NET. You get a huge gain in testability, and you can intercept calls on the presenter without all the difficulty that ASP.NET gives you.

Custom IPrincipal together with WindowsAuthentication

Is there any good way of combining ASP.NET Windows Authentication with a custom IPrincipal/IIdentity object? I need to store the user's email address and have done so for Forms Authentication using a custom IIdentity/IPrincipal pair that I added to the Context.CurrentUser during the AuthenticateRequest event.
How would I best go by to accomplish this using WindowsAuthentication?
Maybe you could create your "ExtendedWindowsPrincipal" as a derived class based on WindowsPrincipal, and just add your extra data to the derived class?
That way, your ExtendedWindowsPrincipal would still be recognized anywhere where a WindowsPricinpal is needed.
OR: since you're talking about using Windows Authentication, you're probably in a Windows network - is there an Active Directory or a user database somewhere, where you could look up your e-mail address that you're interested in instead of storing it in the principal?
Marc
I ended up refactoring my initial solution into replacing the Principal instead of the Identity as I originally thought. Replacing the Identity proved troublesome, since i ran into security problems when creating an instance of a new extended WindowsPrincipal.
public class ExtendedWindowsPrincipal : WindowsPrincipal
{
private readonly string _email;
public ExtendedWindowsPrincipal(WindowsIdentity ntIdentity,
string email) : base(ntIdentity)
{
_email = email;
}
public string Email
{
get { return _email; }
}
}
In my Authentication module i replaced the principal on the HttpContext like this:
var currentUser = (WindowsIdentity)HttpContext.Current.User.Identity;
HttpContext.Current.User =
new ExtendedWindowsPrincipal(currentUser, userEmail);

Resources