MVC3 - Call logon method from GET request - asp.net-mvc-3

I need to be able to call the built-in [HttpPost] Logon method (in the Account Controller) from a GET request. Basically, a new account would be assigned a temporary password, delivered via email. The user clicks on the link in the email (containing a userid and temp pw in the URL), which would be handled in the account controller in the MVC app. I'm not sure how to handle this. Is it possible to redirect from a GET action method on the controller, to the POST logon action method? How would this be done while maintaining the HttpContext object? It seems that this wouldn't be doable outside of just creating a new GET logon method with the user and pw strings params and recreating the logic (using MembershipServer and FormsService objects) that's in the POST method.
EDIT: For anyone following this post, the solution I wound up implementing is:
Using #Shyju's recommendation in a comment, I created a new GET action method to respond to the email link, that returns a "Register New User" view containing hidden inputs for the passed user\pw and a submit button.
The view posts back to the normal logon method. If the user or pw has not been altered, the user will be authenticated
I added a global action filter that tests for the user object property "MustChangePassword". If true, it redirects to the change password action method. This will happen for any method of any controller, except the account controller (so you can actually hit the logon, chg pw, and other methods)
Then in the "ChangePassword" POST method, a successful pw change will reset the "MustChangePassword" property to false.

You can create a unique string (use Guid) for each user and send that as the query string for the link in the email. In the GET action validate that against the user table & Temporary Password table and get the user record and consider that user as logged in user.

Related

How does Djoser account verification system really works under the hood?

So I'm currently in an attempt to make my own account verification system and I'm using some parts of Djoser as a reference. let me try to walk you to my question
Let's say you're to make a new account in Djoser app
you put in the information of your soon to be made account including email
submit the form to the backend
get an email to the whatever email account you put in earlier to verify your account
click the link in your email
get to the verify account page
now in this page there's a button to submit a UID and a token and both of those information lies in the URL.
My question is:
What are those tokens? is it JWT?
How do they work?
How can I implement that in my own projects without djoser?
The answers to your questions are immersed in the own code of djoser.
You can check djoser.email file and in the classes there, they are few methods get_context_data().
def get_context_data(self):
context = super().get_context_data()
user = context.get("user")
context["uid"] = utils.encode_uid(user.pk)
context["token"] = default_token_generator.make_token(user)
context["url"] = settings.ACTIVATION_URL.format(**context)
return context
So get the context in the class where is instance, and in this context add the 'uid' (this is basically str(pk) and coded in base64, check encode_uid()), the 'token' (just a random string created with a Django function from your Secret key; you can change the algorithm of that function and the duration of this token with PASSWORD_RESET_TIMEOUT setting) to use temporary links, and finally the URL according the action which is performed (in this case the email activation).
Other point to consider is in each of this classes has template assigned and you can override it.
Now, in the views, specifically in UserViewSet and its actions perform_create(), perform_update() and resend_activation(), if the Djoser setting SEND_ACTIVATION_EMAIL is True, call to ActivationEmail to send an email to the user address.
def perform_create(self, serializer):
user = serializer.save()
signals.user_registered.send(
sender=self.__class__, user=user, request=self.request
)
context = {"user": user}
to = [get_user_email(user)]
if settings.SEND_ACTIVATION_EMAIL:
settings.EMAIL.activation(self.request, context).send(to)
...
The email is sent and when a user click the link, whether the token is still valid and uid match (djoser.UidAndTokenSerializer), the action activation() of the same View is executed. Change the user flag 'is_active' to True and it may sent another email to confirm the activation.
If you want code your own version, as you can see, you only have to create a random token, generate some uid to identify the user in the way that you prefer. Code a pair of views that send emails with templates that permit the activation.

How to session check in only interceptor for spring boot project?

I have some controller for user update, article update, delete etc..
I don't want to check a session in controller, When a user tries to update a article, the user only can update his own article.
So, I tried to handle this action in interceptor but this approach couples interceptor with controller.
Currently, I'm checking the user action as the following...
String param = request.getParameter("id");
// A user accesses his own resource.
((String)session.getAttribute("key")).eqauls(param) == true
But, when request parameter doesn't uses directly a id,
i have to add some statement like following...
String param2 = request.getParameter("email");
// here, i have to add some logic to find the id using email.
....

After changing ASPNETDB Username via sql, User.Identity not updating

I'm calling a stored procedure to change the username. This works and the username is changed.
After I change the username, Membership.GetUser() returns null. I check User.Identity and it still has the old username and is authenticated.
First I tried calling this function (which is also called when the user first logs in)
public void Authorize(string username)
{
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, username, DateTime.Now, DateTime.Now.AddDays(5), true, string.Empty);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
authCookie.Expires = authTicket.Expiration;
HttpContext.Current.Response.Cookies.Add(authCookie);
}
Then I tried adding Membership.ValidateUser(username,password) before calling the Authorize function (since it's a test account and I do know the password) but it didn't make any difference.
Then I tried this:
FormsAuthentication.SignOut();
FormsAuthentication.SetAuthCookie(txtUserName.Text, false);
I'm confused that after I call FormsAuthentication.SignOut(), the User.Identity.IsAuthenticated is still true. Is that not supposed to be updated until after the page reloads?
I read this http://forums.asp.net/t/939408.aspx/1 which makes me think my problem is User.Identity.Name never getting updated. How do I make that happen?
Membership.GetUser() will only work for an authenticated user. Otherwise, it's going to return null. To verify you're dealing with an authenticated request call "User.Identity.IsAuthenticated" on the page. If you've got an authenticated request, but Membership.GetUser() is still returning null, then that means the username associated with the authenticated user can't be found in the Membership datasource. Verify the username of the authenticated user with "User.Identity.Name".
If you're calling one of the Membership.GetUser() overloads which takes the username and it's returning null, then that user doesn't exist in the Membership datasource (or we've got a bug). One way to easily verify this is to try a Membership.CreateUser() with the same username. If this doesn't throw an error because of a duplicate user, then you know the user never existed in the first place.
Membership.GetUser() should have never worked for an anonymous user. No support was built into Membership for handling this case.
Any changes to the FormsCookie, user account, are not reflected in the User.Identity property until the next request. This property is set by the membership provider at the start of the request when the cookie is validated. Any changes you make will be seen by in any subsequent requests.
You can manually replace User.Identity with a principal of your own, but this requires implementing your own membership provider.

Can I have multiple POST actions for an ApiController?

The scenario:
a User class has several groups of properties: password, address, preference, roles.
We need different Ajax calls to update the (1) user password, (2) user profile, (3) roles a user is in.
All the tutorials and examples only shows one POST action to update the whole User class. My question is how we can update only part of the class.
For example, when updating the user password, we will:
Display a text box to collect new password from user input.
Make an Ajax call that only POST the new password together with the userId (like: {id=3, newPassword=xxxxx}) to the WebAPI POST action.
That action will only update the password for the user.
One solution: (the easiest to think of)
Call the GET action with the userId to retrieve all the data for a user
Update the password in the user data with the values obtained from the web user input
Call the POST action with the updated data, which contains all properties in the User class.
That POST action will update the whole data without knowing only the password is changed.
The benefit: only one POST action is needed for the ApiController.
The shortcoming: we have to Ajax twice.
So, is it possible that we can have multiple POST actions in one ApiController? For example, PostPassword(userId, password), PostProfile(userId, profile) and PostRoles(userId, roles).
In this way, we will only call PostPassword to send the password to ApiController. In client side, there will be only one Ajax call. It is on the server where we will do the update. The benefit is of course the reduced data transferred over Internet.
If it is possible, what is the correct way to direct all different POST calls to their corresponding actions in the ApiController?
Please help us. Thank you all.
Most of cases, needless to have muptile post actions, I think. The typical case is consumer needs to edit user. So, s/he needs to load user data first to show on the edit form. After editing, consumer can click Save button to submit data and call POST action on api controller.
If your case is different, you should have nullable property for value type, and then the logic which should be checked in controller is if any property is null, it should not update this property into database.
You can only have one post action per controller action name. That is, you cannot do
// NOT VALID:
public ActionResult UpdateUser(string newPassword) { }
public ActionResult UpdateUser(List<string> newRoles) { }
However, parameters of the action can certainly be nullable. If a given property is not supplied in a given HTTP request, the value of the property in the controller would be null.
// VALID:
public ActionResult UpdateUser(string newPassword, List<string> newRoles)
{
if (newPassword != null) { } // It must have been supplied
if (newRoles != null) { } // It must have been supplied
}
Alternatively, you can have related controller actions that each handle one of your use cases, e.g. UpdatePassword(...), UpdateAddress(...), ...

ASP.Net MVC 3 Querystring Parameter

I am developing an ASP.Net MVC 3 Web Application. Within some of my Views I display tabular data to the user, and beside each record in the table there is an Edit link. When the user clicks this link it takes them to an edit page where they can edit and update the record.
My issue is that once the user clicks the edit link, the URL becomes something like this
http://www.mytestsite.com/myData/edit/3
The '3' is the ID of the record to be updated, however, there is nothing stopping the user from changing the '3' to another digit, and this then means they can edit potentially a record which does not belong to them.
Does anyone have a solution on how I can prevent this from happening?
Thanks for you help.
You need to introduce Authentication and Authorisation into your application. Here is one article of many out there on how to get started with this. You will additionally need to work out how to store logged on user identity and then how to attach this to the record when it was created in the first place. You must then validate, on the server, that the subsequent edit request is being made by the user who created the record in the first place (or by a user who has a role on your system which allows them to do this, such as an Administrator).
Even if the ID wasn't being displayed on the URL a malicious user could still manipulate the HTTP Request to pass an ID of their choice. In any secure system you should always, always, always validate that the currently logged on user genuinely has permission to carry out the requested action. You should never rely on what comes back from the browser to determine this (aside from the authentication context which is managed securely by the MVC framework. Usually).
I believe you should have the information about who have the edit permission on this purticular resource, in your tables. Ex : in your table you might have the "CreatedById" column where you store the ID of the user who created this record. Now in your edit action method, you check the "CreatedById" of the current Item is same as of the "UserId" of the Current user (you maye get this from the session, if you stored it there). Something like this.
public ActionResult Edit(int id)
{
int currentUserID=1; // TO DO : get this value from session or somewhere
ProductVieWModel product=myRepo.GetProduct(id);
if(product!=null)
{
if(product.CreatedById==currentUserID)
{
return View(product);
}
else
{
return View("NotAutherized");
}
}
return View("ProdcutNotFound");
}
You should try using the GUID data type as it helps in these kind of situations, and the user cannot easily guess the next value

Resources