How do I get User Profile Data from Janrain in Rails - ruby-on-rails

How can I store values of a registration form which are going to Janrain database through Janrain capture authentication in my local postgresql database. My application is in RoR.

Firstly, you shouldn't need to store registration form data in your own database. That would be redundant when using Janrain Registration.
Once the user is authenticated and the Janrain OAuth token has been sent to the Registration widget you can use that token to call the entity endpoint:
https://SOME_APP_NAME.janraincapture.com/entity?access_token=someaccesstoken
This will return the authenticated user's profile data in json format. You can filter out fields using the attributes parameter as documented here: https://docs.janrain.com/api/registration/entity/
https://SOME_APP_NAME.janraincapture.com/entity?access_token=someaccesstoken&attributes='["uuid","familyName","givenName"]'
You should probably bind to the Janrain Registrations Javascript event handler: "onCaptureCreateSession" which when fired will contain the access token. You can then send that token to your server where it can make the entity api call and then store any relevant data in your server (if necessary).
janrain.events.onCaptureSessionCreated.addHandler(function(result) {
//make an ajax call to your server here with the token:
var token = result.accessToken
});
If you absolutely must get form field data before the form is submitted you could bind to the form's onSubmit event and simply retrieve the field data from the form before it is submitted. This should be achievable using plain Javascript or most mainstream libraries.
Here's an example that should get you started:
janrain.events.onCaptureRenderComplete.addHandler(function(result) {
if (result.renderingBuiltInScreen == false) {
//NOTE: screen names can be configuration dependent.
if(result.screen == "traditionalRegistration" || result.screen == "socialRegistration"){
//bind to rendered form here and do stuff
//form names and field names are configuration dependent.
}
}
}

Related

Apereo CAS 6.0.x Pass the login form field to the resolved attributes

I need to add a field to the CAS 6.0.X login screen (language selector) that is not used to authenticate users but I need it after logging in.
How can I do to pass this field added to the form to the data that is passed to the client application in the "principal" object.
In the end I have achieved what I needed. We have overwritten the jdbc support module to add checks and there I have put the following code that helps me to retrieve parameters of the request.
HttpServletRequest request = ((ServletRequestAttributes)
RequestContextHolder.currentRequestAttributes()).getRequest();
String[] fields = fieldsToPrincipal.split(",");
for(String field : fields2Principal)
{
dbFields.put( field.trim() , request.getParameter( field.trim() ) );
}
fieldsToPrincipal It is a string of form field names that I want to send the applications through the "principal" map attributes.
Now in the properties files I have 2 properties in which I report the names of the fields. The default property that tells you which fields will be retrieved for the principal and my custom property where I indicate which fields will come from the form
cas.authn.jdbc.query[0].principalAttributeList:USERID, USERNAME, LANGUAGE_SELECTED
cas.custom.properties.jdbc.loginfields.to.principal=LANGUAGE_SELECTED

Force a user to re-enter credentials before submit

Using MVC5, i have an application which a user must be logged into, and then can perform standard actions on some data (create, edit, delete).
I would like to add a credentials prompt, whenever a certain task if performed. So say for example a user is editing a row of data. I want them to be prompted to enter their login credentials again when they hit the Save button, before the row is updated. To be clear, they are ALREADY logged in, i just want to force them to re-confirm their credentials before being allowed to save.
How can i do this in the controller? I want a seperate screen/popup to show, asking for username and password (which will then be checked to ensure correct user credentials) before allowing update of the data.
I looked at creating a new method in the controller, which is passed a username and password, which looks after checking the users credentials again. But how do I go about calling this from the Edit screen, when I also need a popup to appear? Do i go down the route of adding a hidden div on the Edit view, which shows when the user clicks the Save button, and it then calls the method?
Generally, you're expected to attempt a solution, first. Then, if you run into specific issues, you can ask a question about those specific issues. I will tell you that this should be relatively straight-forward. All you need is for the user to re-enter their password. Just add a password input to your edit form and bind it to something on your view model, or you can simply bind it directly to an action parameter, in addition to your view model:
[HttpPost]
public ActionResult MyAction(MyViewModel model, string password)
If you want it to be done in a popup, simply include the popup HTML within the form (so the that the input in the popup will be part of the form) or you'll need to use JavaScript to set another input within the form, which would be bound to either a view model property or action param. Either way, the point is that the password should be posted along with the rest of the form data.
Once inside your post action, you can verify the password by manually:
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
var verifyPassword = UserManager.PasswordHasher.VerifyHashedPassword(user.PasswordHash, password);
if (verifyPassword == PasswordVerificationResult.Failed)
{
ModelState.AddModelError("", "Password incorrect.");
// If password is incorrect, ModelState will be invalid now
}
if (ModelState.IsValid)
{
// save posted data
}
It sounds like you'd ideally want an action which you can call asynchronously from the client. While this can take the form of a standard MVC controller action, you may want to consider building this into a Web API controller (Generally we would use Web API controllers to serve up non-HTML responses). You can read more about Web API in many places on the web so I won't go into that now, but let's say you have a HttpResponseMessage result method which looks like this:
[HttpPost]
public HttpResponseMessage CheckCredentials(string username, string password)
{
// Check user credentials and return either one of the following results:
// If credentials valid
return Request.CreateResponse(HttpStatusCode.OK);
// If not valid
return Request.CreateErrorResponse(HttpStatusCode.BadRequest);
}
Using this pattern you could return a '200 OK' response for valid credentials and a '400 Bad Request' for invalid credentials.
As you already stated, you could have the HTML content required for authentication prompt hidden on the page. When the user performs an action which requires authentication, you could render the popup. When the user submits the popup you could fire off an asynchronous request to the Web API endpoint which you created earlier. Depending on the response you get back, you either proceed with the task or prompt for credentials again with an error message.
Obviously as you'd be sending user credentials over a we request, make sure you're making use of HTTPS.
EDIT:
As Chris mentioned below, this solution leaves your 'quick check' in the hands of the client. While this is fine when you simply want to provide a way to stop the user from easily carrying out an action without re-entering their credentials, you should not rely entirely on it.
You could store the username and password as hidden fields and include them with your main synchronous POST. This would allow you to check that the user entered valid credentials from the server.

how to verify referrer inside a MVC or Web Api ajax call

my MVC app has common ajax methods (in web api and regular controller). I'd like to authorize these calls based on which area (view) of my app the call is coming from. The problem I am facing is how to verify the origin of the ajax call.
I realize that this is not easily possible since ajax calls are easy to spoof, but since I have full control of how the view gets rendered (full page source) perhaps there is a way to embed anti-forgery type tokens that could later be verified to a Url Referrer.
Authentication is already handled and I can safely verify the identity of the call, the only problem is verifying which URL (MVC route) the call came from. More specifically, preventing the user from being able to spoof the origin of the ajax call.
I tried creating a custom authorization header and passing it between view render and ajax calls, and that works, but still easy to spoof (since a user could sniff the headers from another part of the site and re-use those). In the end I am not sure how to safely verify that the header has not been spoofed. The only thing that comes to mind is encoding some info about the original context inside the token, and validating it somehow against incoming call context (the one that's passing the token in ajax call).
I see that MVC has AntiForgery token capabilities, but I am not sure if that can solve my problem. If so I'd like to know how it could be used to verify that /api/common/update was called from /home/index vs /user/setup (both of these calls are valid).
Again, i'd like a way to verify which page an ajax call is coming from, and user identity is not the issue.
update
as per #Sarathy recommended I tried implementing anti-forgery token. As far as I can tell this works by adding a hidden field with token on each page, and comparing it to a token set in a cookie. Here is my implementation of custom action filter attribute that does token validation:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var req = filterContext.RequestContext.HttpContext.Request;
var fToken = req.Headers["X-Request-Verification-Token"];
var cookie = req.Cookies[AntiForgeryConfig.CookieName];
var cToken = cookie != null
? cookie.Value
: "null";
log.Info("filter \ntoken:{0} \ncookie:{1}", fToken, cToken);
AntiForgery.Validate(cToken, fToken);
base.OnActionExecuting(filterContext);
}
then my anti forgery additional data provider looks like this:
public class MyAntiForgeryProvider : IAntiForgeryAdditionalDataProvider
{
public string GetAdditionalData(System.Web.HttpContextBase context)
{
var ad = string.Format("{0}-{1}",context.Request.Url, new Random().Next(9999));
log.Info("antiforgery AntiForgeryProvider.GetAdditionalData Request.AdditionalData: {0}", ad);
log.Info("antiforgery AntiForgeryProvider.GetAdditionalData Request.UrlReferrer: {0}", context.Request.UrlReferrer);
return ad;
}
public bool ValidateAdditionalData(System.Web.HttpContextBase context, string additionalData)
{
log.Info("antiforgery AntiForgeryProvider.ValidateAdditionalData Request.Url: {0}", context.Request.Url);
log.Info("antiforgery AntiForgeryProvider.ValidateAdditionalData additionalData: {0}", additionalData);
return true;
}
this works, in that i can see correct pages logged in the provider, and anti forgery breaks w/out the tokens.
however, unless i did something wrong, this seems trivial to spoof. for example
if i go to pageA and copy the token form pageB (just the form token, not even the cookie token), this still succeeds, and in my logs i see pageB while executing ajax method from pageA
confirmed that this is pretty easy to spoof.
I am using csrf to generate ajax tokens like this:
public static string MyForgeryToken(this HtmlHelper htmlHelper)
{
var c = htmlHelper.ViewContext.RequestContext.HttpContext.Request.Cookies[AntiForgeryConfig.CookieName];
string cookieToken, formToken;
AntiForgery.GetTokens(c != null ? c.Value : null, out cookieToken, out formToken);
return formToken;
}
I then pass the form token back with each ajax call and have a custom actionfilterattribute where I read/validate it along with cookie token
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var req = filterContext.RequestContext.HttpContext.Request;
var fToken = req.Headers[GlobalConstants.AntiForgeKey];
var cookie = req.Cookies[AntiForgeryConfig.CookieName];
var cToken = cookie != null
? cookie.Value
: "null";
log.Info("MyAntiForgeryAttribute.OnActionExecuting. \ntoken:{0} \ncookie:{1}", fToken, cToken);
AntiForgery.Validate(cToken, fToken);
this all works (changing anything about the token throws correct exception), then in my IAntiForgeryAdditionalDataProvider I can see what it thinks it's processing.
as soon as i override the csrf token from another view, it thinks it's that view. I don't even have to tamper with the UrlReferrer to break this :/
one way this could work if i could force the cookie to be different on every page load
I am assuming you can use IAntiForgeryAdditionalDataProvider for this.
public class CustomDataProvider : IAntiForgeryAdditionalDataProvider
{
public string GetAdditionalData(HttpContextBase context)
{
// Return the current request url or build a route or create a hash from a set of items from the current context.
return context.Request.Url.ToString();
}
public bool ValidateAdditionalData(HttpContextBase context, string additionalData)
{
// Check whether the allowed list contains additional data or delegate the validation to a separate component.
return false;
}
}
Register the provider in App_Start like below.
AntiForgeryConfig.AdditionalDataProvider = new CustomDataProvider();
https://msdn.microsoft.com/en-us/library/system.web.helpers.iantiforgeryadditionaldataprovider(v=vs.111).aspx
Hope this helps in your scenario.
You mentioned in your question that you're looking for Anti-forgery token capabilities.
Hence, I think what you're asking about is an anti-CSRF solution (CSRF=cross site request forgery).
One way to do this is to render a true random number (a one-time token) into your page, then passing it on each request, which can be done by adding a key/value pair to the request header and then checked at the backend (i.e. inside your controller). This is a challenge-response approach.
As you mentioned, in the server-side code you can use
var fToken = req.Headers["X-Request-Verification-Token"];
to get it from the requesting page.
To pass it along from each client AJAX request of the page, you can use
var tokenValue = '6427083747'; // replace this by rendered random token
$(document).ajaxSend(function (event, jqxhr, settings) {
jqxhr.setRequestHeader('X-Request-Verification-Token', tokenValue);
});
or you can set it for each request by using
var tokenValue = '2347893735'; // replace this by rendered random token
$.ajax({
url: 'foo/bar',
headers: { 'X-Request-Verification-Token': tokenValue }
});
Note that tokenValue needs to contain the random number which was rendered by the web server when the web page was sent to the client.
I would not use cookies for this, because cookies don't protect you against CSRF - you need to ensure that the page, which is requesting is the same as the page which was rendered (and hence created by the web server). A page being on a different tab in the same browser window could use the cookie as well.
Details can be found on the OWASP project page, in the OWASP CSRF prevention cheat sheet.
My quick interim solution was to use custom tokens created on each page load (guid which i keep track of in my token cache), which are passed as headers in all ajax calls. Additionally i create a original url hash and combine it into the custom auth token.
in my ajax methods I then extract the hash and compare it with UrlReferrer hash to ensure that hasn't been tampered with.
since the custom token is always different it's less obvious to guess what's going on as token appears to be different on every page load. however this is not secure because with enough effort the url hash can be uncovered. The exposure is somewhat limited because user identity is not the problem so worst case is a given user would gain write access to another section of the site but only as himself. My site is internal and i am auditing every move so any temper attempts would be caught quickly.
I am using both jQuery and angular so appending tokens with all requests like this:
var __key = '#Html.GetHeaderKey()' //helper method to get key from http header
//jQuery
$.ajaxSetup({
beforeSend: function (xhr, settings) {
xhr.setRequestHeader('X-Nothing-To-See-Here', __key); // totally inconspicuous
})
//angular
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.common['X-Nothing-To-See-Here'] = __key;
});
update
the downside of this approach is that custom tokens need to be persisted across a web farm or app restarts. Based on #Sarathy's idea I am trying to side step this by leveraging MVC anti forgery framework. Basically add/remove my "salt" and let the framework manage the actual token validation. That way it's a bit less to manage for me. Will post more details once i verify that this is working.
So this is going to be one of those "you're doing it wrong" answers that I don't like, and so I apologize up front. In any case, from the question and comments, I'm going to propose you approach the problem differently. Instead of thinking about where did the request come from, think about what is the request trying to do. You need to determine if the user can do that.
My guess as to why this is hard in your case is I think you have made your api interface too generic. From your example api "api/common/update" I'm guessing you have a generic update api that can update anything, and you want to protect updating data X from a page that is only supposed to access data Y. If I'm off base there then ignore me. :)
So my answer would be: don't do that. Change your api around so it starts with the data you want to work with: api/dataX api/dataY. Then use user roles to protect those api methods appropriately. Behind the scenes you can still have a common update routine if you like that and it works for you, but keep the api interface more concrete.
If you really don't want to have an api for each table, and if its appropriate for you situation, perhaps you can at least have an api for protected/admin tables and a separate api for the standard tables. A lot of "if"s, but maybe this would work for your situation.
In addition, if your user can update some dataX but not other dataX, then you will have to do some sort of checking against your data, ideally against some root object and whether your user is authorized to see/use that root object.
So to summarize, avoid an overly generic api interface. By being more concrete you can use the existing security tools to help you.
And good luck!

Reposting data through a generic method that is independent of form model in ASP MVC

This is the client's request: in some cases there are several forms that don't require authentication or it takes too long for a logged user to finish completing a form and the session expires. In theses cases he wants to retain the data when the user submits the form by serializing and storing it in a SQL table and then, after the user (re)logs in, he is redirected to the respective form and that is repopulated with the data retrieved from the database and deserialized.
The problem is that he wants all the logic of the storing, retrieving and resending the data in the authorization code block. I know how to do the storing, serialization, retrieving, deserialization of data and the user redirection to the respective page, but I don't know hoe to make it generic so that it works for every model on every form.
The client does not want any code for this task done in the form action method. For example:
[HttpPost]
[Authorize]
public ActionResult Create(Post post)
{
if (ModelState.IsValid)
{
post.CreatedBy = (Guid)Membership.GetUser().ProviderUserKey;
post.CreateTime = DateTime.Now;
repo.Add(post);
repo.Save();
return RedirectToAction("Index");
}
else
{
return View(post);
}
}
As you can see he wants to keep it as clean as possible. He had this suggestion:
The server receives a HTTP request in RAW text format. Using this text, it builds the objects (RequestContext, FormCollection collection, etc. etc.). So, you should be able to build in a hook and e.g. save the raw request. After succesfull login, this previous raw text of the HTTP request could be injected in the handling.
I don't really know how to do that or even if it is possible in MVC.
If someone can help I'll be extremely grateful.
Thanks,
ABTeam
The proper way to do this is to capture the user's progress in the database, and provide a mechanism for returning them to the next step in the process. This can be done with a ?step=n parameter in the URL. If the user gets logged off, they can log back in and be returned to the correct step in the process.
Your client's request for doing this in the authorization code block is not an appropriate use of functionality. That's not the purpose of the authorization block, and attempting to do business logic there, in the manner that the client describes, will almost certainly compromise security and result in unmaintainable code.
The authorization block is not the right place for it, but you may be able to do something fairly generic with action filters.
Load the saved data in OnActionExecuting. I'm not sure if you'll be able to get it passed to the action method as a parameter, but at the least you should be able to add it into ViewData so it can be used as a starting point for generating the model for the form page.
Not sure if the model will be available for saving before ActionExecuting, but if not the model as it exists after the action method runs should be an appropriate alternative.

Where to store common action parameter data in asp.net mvc application

Our web application needs one common parameter in every action method.
In our case it is the customer account id and we need to support the following scenarios
a. A group of users might have the same account id which can be derived from the user profile.
b. Customer Support team should be able explicitly supply the account id of a customer and also should be able to switch the account on any page
We are trying to not to use asp.net session to store this kind of data.
Are there any other options to store and manage this kind of common parameter data?
Write it out as an ecrypted value to hidden field on your master page and supply the value to every view. When the user is in a a customer role, place a change account "control" on the page that is able to retrieve and update the account data -- via AJAX, perhaps -- to change the current account id. It might be easiest to do this with a custom base controller which gets the data via the ValueProvider directly and stores it as a property on the page rather than having it be a parameter to every method.
Use Routing for the value. So if you need to change the id you can use another URL or post it as a parameter.
Whenever you need the value just ask the ValueProvider for it.
In case it is blank - use the one from user profile.
Of course you'd better write small method that will do just that:
// Register route like:
route.MapRoute("ProvidesAccountId", "{controller}/{id}/account{accountId}/{action}.aspx")
// Property on the base controller
protected Account CurrentAccount {
get {
var accountId = ValueProvider.GetValue<int?>("accountId"); // GetValue is just a helper
if (accountId.HasValue)
return YourRepositor.GetAccountBy(accountId.Value);
return CurrentUser.Account;
}
}
Not to use current user's account hit the URL: Profile/123/account/Edit.aspx
To use another account you can hit the URL: Profile/123/account-456/Edit.aspx
You get the idea.
Cheers,
Dmitriy.

Resources