close

Security & Identity Management Considerations for Application Development

Posted by Errin O'Connor on May, 08, 2015 12:05

There are various security, identity management, and authentication considerations when developing custom applications and related features in SharePoint 2013, Office 365, SharePoint Online, and Microsoft Azure.

You should always keep in mind SharePoint 2013’s “claims first” authentication architecture during your development, as well as in discussions with the business about their custom requirements.

With SharePoint 2013’s user authentication based on claims, user authentication results in creation of a claims token, which tracks name-value pairs related to the token subject. These claims tokens are stored in memory using the FEDAUTH token format.

Overview of App Authentication

SharePoint 2013’s app authentication is supported in CSOM as well as in REST API endpoints but is not supported for custom web services.

Three types of app authentication are utilized by SharePoint 2013:

  • Internal authentication
  • External authentication using server-to-server trusts
  • External authentication using OAuth

Internal Authentication

Internal authentication is utilized when an incoming call targets a CSOM or REST API endpoint or when an incoming call carries a claims token with an established user identity.

Internal authentication is also utilized when an incoming call targets the URL of an existing SharePoint 2013 app web. This authentication does not support app-only authentication to elevate privilege(s).

There is no programming effort required in terms of access tokens; internal authentication is automatically utilized with client-side calls from pages in the app web, and it can also be utilized from remote web pages that are using the cross-domain library.

External Authentication

External authentication, which users both S2S and OAuth, is utilized for server-side code in the “remote web” and issues CSOM or REST API calls against the SharePoint host. The incoming calls can target host web and other sites within your organization’s tenancy.

External authentication does require custom app code to be developed to create and manage access tokens which carry the app’s identity as well as user identity because the app is required to transmit an access token in the request header when making a call to SharePoint 2013.

Apps Granted Permissions

In SharePoint 2013, how an app is granted permissions is not identical to how a user is granted permissions. App permissions have only two options, which are that they are or are not granted permissions, because it is really a simple “yes or no” type of scenario.

App permissions have no permissions hierarchy, unlike the user permissions strategy and available security hierarchy within a given site collection.

Apps with Default Permissions

An app that has been provided with default permissions has full control over the app web, as well as access to incoming query string parameters, but does not have default access to the host web.

An app with default permissions must include a permission request within its application manifest because the installer actually grants or denies permissions during the installation of the app and will automatically cancel any app install if permissions are denied.

Adding a Permission Request

As mentioned previously, an app must have a permissions request added to its application manifest. You can achieve this by opening the AppManifest.xml file in the manifest designer in Visual Studio and adding a permission request for each permission to SharePoint that the web application requires.

The Visual Studio 2013 SDK provides for project templates, tools, tests, and reference assemblies that are required to build extensions for Visual Studio 2013.

EPC Group’s Nationally Recognized Practice Areas

EPC Group leading Custom Application DevelopmentSharePointOffice 365, Infrastructure Design and Business Intelligence Practice areas continue to lead the way in providing our clients with the most up-to-date and relevant information that is tailored to their individual business and functional needs.

Additional “From the Consulting Trenches” strategies and methodologies are covered in EPC Group’s new book, “SharePoint 2013 Field Guide: Advice from the Consulting Trenches” covering not only SharePoint 2013, Office 365 and SharePoint Online but Information Management, ECM\RM and overall compliance strategies in this ever changing world of “Hybrid IT.”

[gravityforms id=41 title=”true” description=”false”]
<div class='gf_browser_unknown gform_wrapper exit_intent_popup_wrapper' id='gform_wrapper_41' ><form method='post' enctype='multipart/form-data' id='gform_41' class='exit_intent_popup' action='/security-identity-management-consulting/'> <div class='gform_heading'> <h3 class='gform_title'>Exit Intent</h3> <span class='gform_description'></span> </div> <div class='gform_body'><ul id='gform_fields_41' class='gform_fields top_label form_sublabel_below description_below'><li id='field_41_1' class='gfield gform_hidden field_sublabel_below field_description_below gfield_visibility_visible' ><input name='input_1' id='input_41_1' type='hidden' class='gform_hidden' aria-invalid="false" value='https://www.epcgroup.net/security-identity-management-consulting/' /></li><li id='field_41_9' class='gfield gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_41_9' >Full Name<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_text'><input name='input_9' id='input_41_9' type='text' value='' class='medium' placeholder='Full Name' aria-required="true" aria-invalid="false" /></div></li><li id='field_41_6' class='gfield gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_41_6' >Email<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_email'> <input name='input_6' id='input_41_6' type='text' value='' class='medium' placeholder='Email Address' aria-required="true" aria-invalid="false" /> </div></li><li id='field_41_7' class='gfield gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_41_7' >Phone<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_phone'><input name='input_7' id='input_41_7' type='text' value='' class='medium' placeholder='Phone Number' aria-required="true" aria-invalid="false" /></div></li><li id='field_41_10' class='gfield gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_41_10' >Company Name<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_text'><input name='input_10' id='input_41_10' type='text' value='' class='medium' placeholder='Company Name' aria-required="true" aria-invalid="false" /></div></li><li id='field_41_8' class='gfield field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_41_8' >Message</label><div class='ginput_container ginput_container_textarea'><textarea name='input_8' id='input_41_8' class='textarea medium' placeholder='Type your message here...' aria-invalid="false" rows='10' cols='50'></textarea></div></li> </ul></div> <div class='gform_footer top_label'> <input type='submit' id='gform_submit_button_41' class='gform_button button' value='Submit' onclick='if(window["gf_submitting_41"]){return false;} window["gf_submitting_41"]=true; ' onkeypress='if( event.keyCode == 13 ){ if(window["gf_submitting_41"]){return false;} window["gf_submitting_41"]=true; jQuery("#gform_41").trigger("submit",[true]); }' /> <input type='hidden' class='gform_hidden' name='is_submit_41' value='1' /> <input type='hidden' class='gform_hidden' name='gform_submit' value='41' /> <input type='hidden' class='gform_hidden' name='gform_unique_id' value='' /> <input type='hidden' class='gform_hidden' name='state_41' value='WyJbXSIsIjEwNTJhNGVmMWMyNzI3YTJmMjdiZTA1NjU4ZDMzYzY3Il0=' /> <input type='hidden' class='gform_hidden' name='gform_target_page_number_41' id='gform_target_page_number_41' value='0' /> <input type='hidden' class='gform_hidden' name='gform_source_page_number_41' id='gform_source_page_number_41' value='1' /> <input type='hidden' name='gform_field_values' value='' /> </div> </form> </div><script type='text/javascript'> jQuery(document).bind('gform_post_render', function(event, formId, currentPage){if(formId == 41) {if(typeof Placeholders != 'undefined'){ Placeholders.enable(); }jQuery('#input_41_7').mask('(999) 999-9999').bind('keypress', function(e){if(e.which == 13){jQuery(this).blur();} } );} } );jQuery(document).bind('gform_post_conditional_logic', function(event, formId, fields, isInit){} );</script><script type='text/javascript'> jQuery(document).ready(function(){jQuery(document).trigger('gform_post_render', [41, 1]) } ); </script>