I have a class "User" that is inherited by two other classes(LocalUser and Donor). I have created a custom membership provider for ASP.net forms authentication and overridden the ValidateUser() method. In the ValidateUser() method of my custom membership provider, I need to pass in a parameter to know whether the "User" to validate is "LocalUser" or "Donor" and accordingly validate the user against the database. The problem is that ValidateUser() takes only two parameters (username and password). So there is no scope for me to push in another one. One thing that came to my mind was to set a session variable but then I was looking for a cleaner approach. Any suggestions?
Just create an overridden version of your Validate method, taking 3 parameters and call it directly like:
((MyCustomMembershipProvider)Membership.Provider).Validate( username, pass, anything );
The only drawback of such approach is that you can no longer rely on the automatic invocation of the two-parameter version of the Validate method, if and only if it is automatically called from somewhere (for example from the asp:Login control)
You could send both username and usertype in username field and then parse it in ValidateUser method? Like this: username|userType. Of course, you should forbid entering delimiter in username field.
Related
I know that I can set allowed fields within the method that is annotated with #InitBinder by calling setAllowedFields on WebDataBinder object. But can I do the same, but only for a specific controller or controller's method? I have a simple form that allows a guest to create a user account and I have another form that allows the login user to update his/her information. In the first form, I want to allow user to insert all the fields(username, password, etc), but in the second form, I want to disallow user to change one of the fields that are allowed in the first form(for example, I want to disallow user to change his/her username). How can I do that?
Apparently you can do that by just defining in each controller a method annotated with #InitBinder. Each #InitBinder method and the settings you make in this method are dedicated to the method handlers defined in the controller that contains the method annotated with #InitBinder.Thus,in my case,i just could define another method annotated with #InitBinder in another controller and set whatever fields i want to be allowed there.
I've created a User custom class in my Bundle. It inherits from the BaseUser class of FOSUserBundle.
In my class, I've defined several attributes which are entities of my Bundle, like Adress, Avis etc.
I have defined the formType of all my forms with data_class User.
It allows me to retrieve interesting user information like username (!) and displaying it in my forms.
BUT when I validate my forms it asks me to fill the plainPassword field of User class as it is a mandatory attribute.
First I wanted to retrieve the password from database to fill it in the form before displaying it but it seems impossible as a security measure.
So I've tried to stock it in the session (ugly I know) after registration but it seems not possible to force the form data with a value (surely because it is a password type field)...
So question is : what would you do ?
But what is the purpose of retrieving it?
You want to modify any of user's data like username or email?
Remember you can have /profile 'module' in FOSUser Bundle, which is used for modifing for example username and email.
For changing password you have separate 'module' change password (I don't remember path). Maybe that's what you are looking for? Of course that way user can edit only his own data. These modules are ready to use by deafault (you have to provide routing for them).
If you want for example, that admin modifies the other user's data that can be interesting for you:
In case of password, take a look at column in db called 'salt', which is used for encoding password in db. If you try to save password in db without salting it won't work - so I think if you want to change the password in db by some custom action - you have to set plain password and the it will be automatically encoded.
If you want to fill some form's fields by default read something about forms in Symfony, Fields types and something about their additional features and remember that password field require individuall approach.
I would not store the users plain password anywhere, let alone display it in the browser.
Playing with plain text passwords like you are doing is major security threat to your application, and any and all users using it.
The default User class in FOSUserBundle has two fields for the password, password and plainPassword. That plain password is filled in by the form, then, in the controller, the password field is generated by whatever encryption method you have configured for the firewall. The new user is then added to the database and the plain password field is cleared and never used again.
If you are trying to set up a forgot password solution, I would recommend emailing the user with some kind of unique key (as a URL parameter), ask them to confirm then give them the opportunity to update their password.
Let's assume I implemented token based authorization with a custom filter attribute as described here.
Let's also assume, I have a controller that returns tasks:
public IEnumerable<Task> Get()
{
// return tasks for authorized user
}
Now, how would I go about returning only the tasks for the authorized user? Passing the user ID as a query parameter is not an option - it is forbidden to request the tasks of a different user.
you could enrich the HttpRouteData from your action filter and read it in the controller action. actionContext.ControllerContext.RouteData.Values.Add("UserId", someVaue );
You could also use the System.Runtime.Remoting.Messaging.CallContext class ( GetData and SetData )
In the code in the sample you linked to, they are encrypting the user's name in the token. In the filter they are getting this token from an http header, decrypting it back to the username, and querying it against an AuthorizedUserRepository.
AuthorizedUserRepository.GetUsers().First(x => x.Name == RSAClass.Decrypt(token));
You can certainly use a userid instead of the name, and work against a real repository instead of this sample one. You could either do all of this over again in the controller action or constructor, or you could pass it along the route data or some ThreadStatic property. If you want to get really fancy, you could implement claims based security and set a claim on the current thread's principal. Really it doesn't matter how you pass it along.
Ultimately you would just use this value in a where clause of a query or linq statement to filter down to the data you want the user to be allowed to access.
We know that authorization's stuff is a cross cutting concern, and we do anything we could to avoid merge business logic in our views.
But I still not find an elegant way to filter UI components (e.g. widgets, form elements, tables, etc) using the current user roles without contaminate the view with business logic. same applies for model binding.
Example
Form: Product Creation
Fields:
Name
Price
Discount
Roles:
Role Administrator
Is allowed to see and modify the Name field
Is allowed to see and modify the Price field
Is allowed to see and modify the Discount
Role Administrator assistant
Is allowed to see and modify the Name
Is allowed to see and modify the Price
Fields shown in each role are different, also model binding needs to ignore the discount field for 'Administrator assistant' role.
How would you do it?
On way I could think to do this is create your own versions of the input extension methods. For example instead of TextBox you could create TextBoxRoles and define it like this:
public static MvcHtmlString TextBoxRoles(
this HtmlHelper htmlHelper,
string name,
string RolesEdit,
string RolesView
)
Then in code it would look like this:
<%= Html.TextBoxRoles("Price", "Administrator","Administrator,Assistant") %>
Then your implementation of TextBoxRoles would check the roles of the current user via User.IsInRole() to determine what should appear on the page.
Of course you would have to do this for every input extension method you use.
Since you already have both the current user and access to the authorization provider in your controllers this is an ideal responsibility for them. Using a naive implementation you might pass a collection of widgets to your view after you filtered which widgets the current user has access to. In the case of your form field, things might get hairy when you consider client side validation.
The binding part would be the most straight forward of all, having a custom binder for these special cases will do the trick specially well since it will have access to the controller context and you can grab the current user from there and bind the values according to your role definitions.
What about something like LinFu, an AOP framework? If it's crosscutting, then declare it is so and treat it as such.
I am trying to implement a custom membership provider and want to change the GetUser method. The problem is that GetUser returns MembershipUser and I want to return MyMembershipUser which has two additional properties FirstName and LastName. I can create a new method in my membership provider which returns MyMembershipUser but then I think it won't make any sense.
How would I go about doing this?
That would defeat the purpose of the Membership classes. Do something like this if you need to access other properties:
var user = Membership.GetUser(userName, true) as MyMembershipUser;
Really you should have a separate Profile class that handles things that MembershipUser does not provide.
var profile = Profile.GetProfile(Membership.GetUser(userName, true));
You should go for Profile Provider.
check this link, you have either SqlStoredProcedureProfileProvider and SqlTableProfileProvider, this way you have ability to store Profile data “in the clear” in the database, letting you query the db whenever u want.
"you can implement whatever business logic you need in the stored procedures to map the Profile data to your own database schema and database logic."
If MembershipUser is the base class of MyMembershipUser then you can return instances of MyMembershipUser even though the return type of GetUser() is MembershipUser and then, if necessary, cast them back to MyMembershipUser (but do you really need to do that?)
BTW, this is an example of polymorphism.