MVC - open page in View mode - asp.net-mvc-views

Hi
I am trying to see if anybody has a briliant idea on how to implement View mode concept in MVC. So if the user opens a page, the page should open in view mode (all controls disabled), if they dont have edit priviledges else should open as normal. Please note that the View page has partial pages as well

I think you have total control on your page under MVC framework. If you are using standard MVC method to generate input controls, you could do following ways.
#Html.TextBox("MyTextBoxID", Model==null?"":Model.MyFieldValue, new {disabled = "disabled})
If you are not using standard MVC method to generate input controls. You can create your own method to generate input controls. For example in MyExt.cs
public static class MyExt
{
public static MvcHtmlString MyTextBox(this HtmlHelper html, string id, object value)
{
// check user privilege
if (CurrentUser.CanEditThisPage /*Implement your own logic here */)
return html.TextBox(id, value);
else
return html.TextBox(id, value, new {disabled = "disabled"});
}
}
And in your page
#using MyNamespace
...
#Html.MyTextBox("MyTextBoxID", Mode==null?"":Model.MyFieldValue)
Another Way
Pass an indicator from server side to client side and using javascript or JQuery to disable all controls.
#Html.Hidden("CanEdit", CurrentUser.CanEditThisPage)
In javascript
void pageLoad() {
if ($("#CanEdit").val() == "true"))
$("input").attr("disabled", "disabled");
}
Something like that (not sure about correctness of syntax :P)

Related

Is Qooxdoo protected against XSS

I'm looking for informations about security on Qooxdoo.
I want to check my app vs OWASP top 10
A point to review is the XSS OWASP A3 XSS
How can I be sure that Qooxdoo is secure against XSS attacks ?
Does Qooxdoo use some sanitizer tools ?
SOLVED
A short answer from all the discussions. Yes Qooxdoo is XSS safe. By default, no javascript value in any field will be executed.
But, if you use rich=true, you have to check input/output
A common XSS attack vector are situations where an attacker somehow inputs JS code into a web application, such that this code then shows up in the DOM of a webpage and gets thus activated.
To protect against this kind of XSS, you must make sure that the backend server does not send user generated (un-cleaned) html towards the browser ... (this has nothing to do with qooxdoo).
That said, the regular qooxdoo widgets do not in general display data as html so you are reasonably safe even without a clever server. The exception is the qx.ui.basic.Label widget and its descendants. The Label widget has the ability to display HTML directly if you set the rich property. The rich property is set to false by default, but if you enable it, you have to make sure you don't display 'dangerous' html content.
Only very few (non essential) qooxdoo widgets allow you to insert HTML code into the DOM. In these instance you have to take care to sanitize the data. The widgets in question are:
qx.ui.embed.Html
qx.ui.table.cellrenderer.Html
qx.ui.progressive.renderer.table.cell.Html
qx.ui.virtual.cell.Html
qx.ui.virtual.layer.HtmlCell
qx.ui.virtual.layer.HtmlCellSpan
If you do use qx.html.* and qx.bom.*and qx.dom.* objects to work with the DOM directly, you are beyond the reach of qooxoo and have to take care to act accordingly.
Another important attack vector are authentication cookies. Most of the attacks work by getting the browser to send a request together with the cookie to its server without the user being aware it.
Qooxdoo itself does not require you to use cookies at all. Since qooxdoo applications by design run in a single browser window, you can work without ever using cookies. An easy way of implementing something like this is to have a 'server access singleton' which takes care of all the communication with the backend and supplies the access token in a special header added to every request.
The code below could serve as a guide ... for the cookie problem.
qx.Class.define('myapp.Server', {
extend : qx.io.remote.Rpc,
type : "singleton",
construct : function() {
this.base(arguments);
this.set({
timeout : 60000,
url : 'QX-JSON-RPC/',
serviceName : 'default'
});
},
properties: {
sessionCookie: {
init: null,
nullable: true
}
},
members : {
/**
* override the request creation, to add our 'cookie' header
*/
createRequest: function() {
var req = this.base(arguments);
var cookie = this.getSessionCookie();
if (cookie){
req.setRequestHeader('X-Session-Cookie',this.getSessionCookie());
}
return req;
}
}
});
and if you provide a login popup window in myapp.uiLogin you could replace
the standard callAsync by adding the following to popup a login window if the backend is unhappy with your request.
/**
* A asyncCall handler which tries to
* login in the case of a permission exception.
*
* #param handler {Function} the callback function.
* #param methodName {String} the name of the method to call.
* #return {var} the method call reference.
*/
callAsync : function(handler, methodName) {
var origArguments = arguments;
var origThis = this;
var origHandler = handler;
var that = this;
var superHandler = function(ret, exc, id) {
if (exc && exc.code == 6) {
var login = myapp.uiLogin.getInstance();
login.addListenerOnce('login', function(e) {
var ret = e.getData();
that.setSessionCookie(ret.sessionCookie);
origArguments.callee.base.apply(origThis, origArguments);
});
login.open();
return;
}
origHandler(ret, exc, id);
};
if (methodName != 'login') {
arguments[0] = superHandler;
}
arguments.callee.base.apply(this, arguments);
},
take a look at the CallBackery application to see how this works in a real application.

Sitecore|WFFM| Custom Error Message with details| on Same Page with Form

I have a Web Form for Marketer set up done for one of my Pages.
I have Custom Submit Action written for it as shown below in the code snippet -
public class **CustomFormSubmit : ISaveAction**
{
public void Execute(ID formid, AdaptedResultList fields, params object[] data)
{
try
{
**//var returnValue= Custom Logic to save form data // returns true or false**
}
catch (Exception ex)
{
Logger.Log(ex.Message + ":" + builder, ExceptionCategory.Error);
throw;
}
}
In my above Web form - Success Mode is - SuccessMode/Redirect and I have a success Page configured for it.
My requirement in above scenario is to keep user on the same Page(with Form) if returnValue is false . (as shown in above code snippet)
Can anyone Please guide me in the above scenario as - how to keep user on the same Page with values filled in the form so that user can submit it again.
Product Details - 7.2 rev. 141226 , Web Forms for Marketers 2.4 rev.140117
To add further details -
I am not sure how can I go back to my page instead of the redirection in case if return is false in the above code snippet.
As soon the submit button is clicked the above function- Execute- gets called.
How do I go back to the Page - Do I need to override any function or customize something.
If any exception comes while saving data- then the control goes back to the same Page with all values filled by user retained -with the Save Action Failed Message which is configured in Sitecore .
So my requirement will be to go to to the form as happening in case of Exception when false comes as return value while saving data and to put customised Error Messages which might change each time, so not statically configured ,rather a dynamic one.
Thanks!
Saurabh
One option will be to redirect to the original page with the Form on.
Enable your form to populate the fields via Query String using the ReadQueryString property, via Presentation Details of the Form Renderer:
So on false of your Save Action you create a collection of query strings with the name of each Field, as it appears in the Form, followed by the User's value.
The code below will loop through all your fields and arrange them into a QueryString with its FieldName and Value;
string urlOfForm = HttpContext.Current.Request.Url.AbsolutePath;
var queryString = new StringBuilder("?");
foreach (AdaptedControlResult field in fields)
{
queryString.Append(string.Format("{0}={1}&", field.FieldName, field.Value));
}
urlOfForm = urlOfForm + queryString;
HttpContext.Current.Response.Redirect(urlOfForm);
Sitecore will then automatically populate the appropriate fields with the values, achieving your requirement.
EDIT
I have found that most Exceptions thrown will take the user back to the Form with their values populated. You can then pass in the cause of the failure to write to your CRM. See below for Example
if (submitFailed)
{
throw new Exception("The email address entered already exists in our System");
}
The complexity then comes in dynamically swapping out the Save Action Failed Message to show this Exception Message. All posts I find about custom Save Action Message state the only real approach is to redirect via your Custom Save Action to a different page showing a different message. Which is not suitable to your requirements.
I have found the pipeline Args you are going to need to patch FormSubmitFailedArgs and SubmitFailedArgs. The Former will need the following change
public FormSubmitFailedArgs(ID formID, AdaptedResultList fields, ID actionFailed, Exception ex)
: base(formID, actionFailed, ex)
{
this.Fields = fields;
this.ErrorMessage = ex.Message;
}
and the Latter will need
public SubmitFailedArgs(ID formID, ID actionFailed, string errorMessage, Exception innerException)
{
this.FormID = formID;
this.ActionFailed = actionFailed;
this.ErrorMessage = innerException.Message;
this.InnerException = innerException;
}
Location and Styling of Submit Message:
You need to find the FormRender sublayout file, this is defaulted to website\sitecore modules\Web\Web Forms for Marketers\Control\SitecoreSimpleFormAscx.ascx inside there you will find a compont called SubmitSummary this renders out the submit message so move it to where you require.
Also note it references the CssClass scfSubmitSummary this is what you will need to target to change the styling of the Message. This Answer is already REALLY long so I won't give a blow by blow how to change the styling of that class, see here for example - http://www.awareweb.com/awareblog/10-1-13-wffmguide
Pipeline Patching
I've dug in deeper, in order to use the custom Args we created for using the exception error message you will need to control the Pipeline which ultimately uses those Args, this is the processor Sitecore.Form.Core.Pipelines.FormSubmit.FormatMessage, Sitecore.Forms.Core in the <errorSubmit> Pipeline.
From my investigation it shouldn't take much effort then its a matter of patching it, you can modify if the Sitecore.Forms.config directly or use patch:instead from a config file within the App_Config/Includes folder - see here for more info.
One option would be to create a Custom Form Verification Action. You could save the data here, although it would be better to verify the data against your API here and then save the data in custom save action, simply since this seems more logical as to how WFFM was meant to function.
using Sitecore.Data;
using Sitecore.Form.Core.Controls.Data;
using Sitecore.Form.Core.Submit;
using System;
using System.Collections.Generic;
namespace Custom.WFFM
{
public class CustomVerificationStep : BaseCheckAction
{
public string FailedMessage { get; set; }
public override void Execute(ID formid, IEnumerable<ControlResult> fields)
{
// Call your API
// You have access to the fields, so you can pass them through as parameters to your if needed
bool flag = ServiceAPI.ValidateUserData(param1, param2, etc);
if (!flag)
{
throw new Exception(string.Format(this.FailedMessage ?? "There was an error while verifying the data against the service call"));
}
}
public override ActionState QueryState(ActionContext context)
{
return ActionState.DisabledSingleCall;
}
}
}
Create the corresponding Verification Action under /sitecore/system/Modules/Web Forms for Marketers/Settings/Actions/Form Verification:
You can change the error message by setting it in the Parameters field as <FailedMessage>Custom Failed Error Message</FailedMessage>.
And then add your verification step to your form:
If you need a different error message per form then you can set the error message to display from the Error Messages tab.
The user will then be returned to the same without any of the save actions being called and the form fields still filled in.

Enrolling Anonymous Users in Engagement Plans

I know that it is possible to enroll users in an engagement plan from with Sitecore by adding them to a specific state in the plan when they visit a campaign URL, adding them when they submit a Web Forms for Marketers Form, and manually adding them in the Supervisor interface.
Additionally, I know that you can use the API to add a user as described here:
http://briancaos.wordpress.com/2013/06/03/programming-for-sitecore-dms-engagement-plans/
However, that method requires a username.
I would like to enroll anonymous users in an engagement plan when they visit any page represented by a particular template in Sitecore (ie, page from the Product template). Is this possible using the API?
To expand on my above comment, and to supplement your own answer, here's a processor that you could add to the after the ItemResolver in the httpRequestBegin pipeline that would achieve the desired result. It is a very basic version that you could embellish as you see fit
class CampaignRedirect
{
public void Process(HttpRequestArgs args)
{
var request = HttpContext.Current.Request;
// must not already have the querystring in the URL
if(request.QueryString["sc_camp"] != null &&
request.QueryString["sc_camp"] != "XXXXXXXX")
return;
// must have a context item
if(Sitecore.Context.Item == null)
return;
var item = Sitecore.Context.Item;
// must be the right template
if(item.TemplateID.ToString() != "{XXXXXXXXX-XXXX-XXXXXX}")
return;
var basicUrl = LinkManager.GetItemUrl(item);
var response = HttpContext.Current.Response;
response.Redirect(basicUrl + "?sc_camp=XXXXXXX");
}
}
If you're not familiar with adding processors, take a look here.
Per Sitecore support, this is not currently possible. However, I was able to achieve what I wanted by adding a jQuery AJAX call to the campaign URL to the sublayout used by the page type in question. Naturally this only works for clients with JS enabled, but for my purposes, that is not an issue.
<script type="text/javascript">$(function() { $.get('/?sc_camp=[campaignid]'); });</script>
Edited 2014-05-19
I found a way to do this via the Sitecore API. This is rough and needs to check for null values, exceptions, etc., but it does work:
string cookieVal = Request.Cookies["SC_ANALYTICS_GLOBAL_COOKIE"].Value;
List<Guid> guids = new List<Guid>() {
new Guid(cookieVal)
};
Guid automationStateId = new Guid("{24963AE9-1C8C-4E18-8EEE-01BC249D1F1B}");
Guid automationId = Sitecore.Context.Database.GetItem(new Sitecore.Data.ID(automationStateId)).ParentID.ToGuid();
Sitecore.Analytics.Automation.Data.AutomationManager.Provider.CreateAutomationStatesFromBulk(guids, automationId, automationStateId);

Can Glass.Mapper V3 support language fallback (field-level and item-level)?

We just updated our project to use Glass.Mapper V3. We LOVE it. But we've encountered an issue. It doesn't seem to respect language fallback.
We have our site set up so that if a user picks a non-default language, they will see the item of that language if it exists. If not, they will see the default ("fallback") language version. We have also set this up at the field level, so that if there is a non-default version of an item but not all the fields are changed, any unchanged fields will fall back to the default language version's value for that field.
Is there anything we can do to enable Glass to use language fallback?
I am updating this with a bit of background on why we do the check. If you ask for a Sitecore item that doesn't exist you get a null value, so that is simple to handle. However if you ask for a Sitecore item that doesn't exist in that particular language returns an item with no versions. This means we have to do this check because otherwise Glass would end up returning empty class which I don't think makes much sense.
This answer will get a little experimental.
First in the the Spherical.cs file you need to disable the check:
protected void Application_BeginRequest()
{
Sitecore.Context.Items["Disable"] = new VersionCountDisabler();
}
We can then move the check to later on to the Object Construction pipeline. First create a task:
public class FallbackCheckTask : IObjectConstructionTask
{
public void Execute(ObjectConstructionArgs args)
{
if (args.Result == null)
{
var scContext = args.AbstractTypeCreationContext as SitecoreTypeCreationContext;
if (scContext.Item == null)
{
args.AbortPipeline();
return;
}
//this checks to see if the item was created by the fallback module
if (scContext.Item is Sitecore.Data.Managers.StubItem)
{
return;
}
// we could be trying to convert rendering parameters to a glass model, and if so, just return.
if (String.Compare(scContext.Item.Paths.FullPath, "[orphan]/renderingParameters", true) == 0)
{
return;
}
if (scContext.Item.Versions.Count == 0)
{
args.AbortPipeline();
return;
}
}
}
}
Then finally register this task in the GlassMapperScCustom class:
public static void CastleConfig(IWindsorContainer container){
var config = new Config();
container.Register(
Component.For<IObjectConstructionTask>().ImplementedBy<FallbackCheckTask>().LifestyleTransient()
);
container.Install(new SitecoreInstaller(config));
}
I haven't tested this but it should in theory work <- disclaimer ;-)
There are few potential issues with provided solution when sitecore 7 (7.2) + IoC + solr + mvc is used.
When using IoC ex Winsdor please make sure that your Global.asax looks like this one <%# Application Codebehind="Global.asax.cs" Inherits="Sitecore.ContentSearch.SolrProvider.CastleWindsorIntegration.WindsorApplication" Language="C#" %>. Once, by mistake this file has been changed to <%# Application Codebehind="Global.asax.cs" Inherits="Merck.Manuals.Web.Global" Language="C#" %> and language fallback was not working. Also the errors we were getting wasn't descriptive as we thought that solr schema is incorrect.
Code Sitecore.Context.Items["Disable"] = new VersionCountDisabler(); can be added to PreprocessRequestProcessor and it works fine which is better solution that modifying global.asax.

Extending MVC FoolProof validation

I would like to use MVC FoolProof Validation in my MVC 3 application.
I need a Numeric validation and also accepts N/A or n/a. So i decided to create my own custom validation attribute like NumericAllowNAAttribute and add a jQuery validation custom adopter method.
I revisited MVC Foolproof and decided to use that, since it has other helpful method build already. I want those also. Now how can i write a CustomValidationAttribute that works on client side using jQuery validate and Server side?
Searched google on extending MVC Foolproof i didnt get any.
Is any one came across extending or implementing this kind of
validation works in server and client with jQuery validation plugin?
You can extend foolproof MVC by defining a new attribute that inherits ContingentValidationAttribute (or one of the other attributes in foolproof, but continent is pretty close to barebones).
You will need to define the following method overrides.
public override bool IsValid(object value, object dependentValue, object container)
protected override IEnumerable<KeyValuePair<string, object>> GetClientValidationParameters()
public override string ClientTypeName
ClientTypeName string value is used by jquery unobtrusive validation.
Also, be sure to register your adapter with DataAnnotationsModelValidatorProvider (foolproof does it in the constructor for their classes).
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MyCustomValidationAttribute), typeof(FoolproofValidator));
Once you've defined your server-side validation logic you will need to register with jquery unobtrusive validation on the client-side:
jQuery.validator.addMethod("clienttypenameyouemitontheserver", function(value, element, params) {
// perform your checks here and return true or false
return true;
});
var $Unob = $.validator.unobtrusive;
$Unob.adapters.add("clienttypenameyouemitontheserver", ["param1", "param2", "paramZ"], function (options) {
var value = {
param1: options.params.param1,
param2: options.params.param2,
paramZ: options.params.paramZ
};
setValidationValues(options, "clienttypenameyouemitontheserver", value);
});