Thursday, August 27, 2009

Custom Welcome User message in SharePoint

By-default SharePoint display Logged-in user name as --- Welcome UserName,
also its displays a context menu on mouse click which performs following actions:
a) Personal Settings
b) Sign Out
c) Sign in as different user, etc

We can add / delete menu items in Welcome User's context menu.

Now consider a scenarion where we don't want context menu, just User name and Sign-Out link are needed.

To acheive above requirement, we can either create a custom WebPart or a custom UserControl.
I preferred custom UserControl, because it easy to create and deploy.

Following is the code snippet of custom UserControl (name MyWelcomeUser.ascx) -



<%@ Control Language="C#" AutoEventWireup="true" CompilationMode="Always"
EnableViewState="true" %>

<div id="divMain" runat="server" style="width: 100%;">
<table cellpadding="0" cellspacing="0">
<tr class="column_title_link tab-bg">
<td class="welcome-text">
Welcome
<asp:Label ID="LabelUserName" runat="server"
Style="padding-left: 5px; font-weight: bold;"></asp:Label>
</td>
<td>
|
</td>
<td>
<asp:HyperLink NavigateUrl="/_layouts/signout.aspx"
ID="HyperLinkSignOut" runat="server"
Text="Logout"></asp:HyperLink>
</td>
</tr>
</table>
</div>

<script language="C#" runat="server">

protected void Page_Load(Object sender, EventArgs e)
{
LabelUserName.Text = Microsoft.SharePoint.SPContext.Current.Web.CurrentUser.Name;
}

</script>




In the above code snippet I created a Label, whose text is set to current logged-in user in Page_Load event and a link to do Sign Out.
Here I am using SharePoint's default signout page.


Following is the snapshot of custom Login control...

SPSiteDataQuery in SharePoint

If we want to search some record(s) within a SPList, then SPQuery is sufficient.

But consider a scenarion, where we don't know SPList name or we want to fire a query at SPWeb (Site) level, then we have to use SPSiteDataQuery.

Syntax wise SPSiteDataQuery is same as SPQuery.
Following code snippet gives a rough idea about SPSiteDataQuery usage:



SPWeb oWebsite = SPContext.Current.Web;
SPSiteDataQuery oQuery = new SPSiteDataQuery();

string s1 = "avinash";
string s2 = "IsAdmin";

StringBuilder strb = new StringBuilder();
strb.Append("<Where><And>");
strb.AppendFormat("<Eq><FieldRef Name='LoginName' /><Value Type='Text'>{0}</Value></Eq>", s1);
strb.AppendFormat("<Eq><FieldRef Name='{0}' /><Value Type='Boolean'>1</Value></Eq>", s2);
strb.Append("</And></Where>");

oQuery.Query = strb.ToString();
oQuery.Lists = "<Lists ServerTemplate=\"100\" />";
//oQuery.ViewFields = "<FieldRef Name=\"Title\" />";

DataTable dtResults = oWebsite.GetSiteData(oQuery);

if(dtResults.Rows.Count > 0)
{
//There are some records


//dtResults.Columns.Count --- 3 --- data type : int

//dtResults.Columns[0].ColumnName --- "ListId" --- data type : string
//dtResults.Columns[1].ColumnName --- "WebId" --- data type : string
//dtResults.Columns[2].ColumnName --- "ID" --- data type : string


//In case of 1 record found
//dtResults.Rows.Count --- 1 --- data type : int

//dtResults.Rows[0][0] --- "{some GUID value}" --- data type : object {string}
//dtResults.Rows[0][1] --- "{some GUID value}" --- data type : object {string}
//dtResults.Rows[0][2] --- "6" --- data type : object {string}



//To open the SPList that contains our desired record:
string stringGuid
= dtResults.Rows[0][0].ToString().Replace("{", "").Replace("}", "");
Guid guidObject = new Guid(stringGuid);
SPList spList = oWebsite.Lists[guidObject];
}
else
{
//There is no record
}


In the above code I am looking for record that contains LoginName (SPColumn name) as "avinash" and IsAdmin (SPColumn name) is set to true.



Quick re-cap:
1) Open SPWeb
2) Build query
3) Create SPSiteDataQuery object
4) Set following properties of SPSiteDataQuery's object -
a) Query
b) Lists
c) ViewFields
5) Get DataTable by executing query on SPWeb
6) Check number of Rows in DataTable
7) If record(s) found, then get GUID of SPList
8) Get SPList based on GUID
9) Do required operation on SPList



Following are the ServerTemplate IDs for List:



100 Generic list, 101 Document library, 102 Survey, 103 Links list, 104 Announcements list, 105 Contacts list, 106 Events list, 107 Tasks list, 108 Discussion board, 109 Picture library, 110 Data sources, 111 Site template gallery, 112 User Information list, 113 Web Part gallery, 114 List template gallery, 115 XML Form library, 116 Master pages gallery, 117 No-Code Workflows, 118 Custom Workflow Process, 119 Wiki Page library, 120 Custom grid for a list, 130 Data Connection library, 140 Workflow History, 150 Gantt Tasks list, 200 Meeting Series list, 201 Meeting Agenda list, 202 Meeting Attendees list, 204 Meeting Decisions list, 207 Meeting Objectives list, 210 Meeting text box, 211 Meeting Things To Bring list, 212 Meeting Workspace Pages list, 300 Portal Sites list, 301 Blog Posts list, 302 Blog Comments list, 303 Blog Categories list, 850 Page Library, 1100 Issue tracking, 1200 Administrator tasks list, 2002 Personal document library, 2003 Private document library



Reference Links:

Server Template Numbers
SPSiteDataQuery 1
SPSiteDataQuery 1
SPSiteDataQuery 1

Saturday, August 8, 2009

Configuring Forms Based Authentication (FBA) in SharePoint


If we want to configure Forms Based Authentication (FBA) in SharePoint,
then we have to follow following steps -

Configuration Steps:
1) Setup the membership data store.
2) Create an ASP.Net Web Site to manage Roles and Users.
3) Open ASP.Net Web Site’s Web Administration Tool.
4) Create a new Web Application from SharePoint Central Administration site.
5) Extend Web Application
6) Change Authentication Provider for Forms based site.
7) Change configuration files settings.
8) Change policy for Web Application
9) Add users/roles as site administrator (Primary and Secondary).
10) Check Forms Based Authentication



Now I will explain each steps in some detail -



1) Setup the membership data store.

To create database, Microsoft has provided a tool/ utility called aspnet_regsql.exe that creates a database for us.
This utility can be found in
%windir%\Microsoft.Net\Framework\vx.x.xxxxx folder.

Double click or run aspnet_regsql.exe,
it opens a pop-up window as demonstrated in following images :




[Figure - 1]



[Figure - 2]



[Figure - 3]
Note: Enter your Server Name and Database name in fields.




[Figure - 4]



[Figure - 5]



[Figure - 6]


Note: Check whether your custom MembershipDB is accessible by NT AUTHORITY\ NETWORK SERVICE or not.

Steps:
a) Open MS SQL Server Management Studio
b) Select SERVER (in Tree-node at left side)
c) Select Security
d) Select Logins
e) Select NT AUTHORITY\NETWORK SERVICE
f) Right-click on it, select Properties
g) Its pop-ups Login Properties window.
Select User Mapping (in Tree-node at left side)
h) Check your database name in top-right pane and
its corresponding access in bottom-right pane.
i) Click OK.
j) Then to check effective permissions of your custom MembershipDB,
select DB from left side tree view.
Server – Databases – custom MembershipDB
k) Right-click on custom MembershipDB, select Properties.
l) In Database Properties window, select Permission
(in left pane).
m) Select NT AUTHORITY\NETWORK SERVICE (in right pane),
click Effective Permissions button.
n) Check whether it has required permissions or not.
If not then assign required permissions.




2) Create a new ASP.Net Web Site to manage Roles and Users.

Do following changes in temporary ASP.Net web site's configuration file:

Web site’s configuration file (web.config) ---



<configuration>
<!--Remaining settings-->

<connectionStrings>
<add name="CustomMembershipDBCNX"
connectionString="SERVER=Server-Name; DATABASE=CustomMembershipDB;
TRUSTED_CONNECTION=true;"
providerName="System.Data.SqlClient" />
</connectionStrings>

<system.web>
<!--Remaining settings-->

<machineKey validationKey="Copy-it-from-sharepoint-site-cofig-file"
decryptionKey="Copy-it-from-sharepoint-site-cofig-file"
validation="SHA1" />

<authentication mode="Forms">
<forms loginUrl="/_layouts/login.aspx" />
</authentication>

<membership defaultProvider="CustomMembershipProvider">
<providers>
<add name="CustomMembershipProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="CustomMembershipDBCNX"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
applicationName="/"
requiresUniqueEmail="false"
passwordFormat="Hashed"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="1"
passwordAttemptWindow="10"
passwordStrengthRegularExpression=""
/>
</providers>
</membership>

<roleManager enabled="true" defaultProvider="CustomRoleProvider">
<providers>
<add name="CustomRoleProvider"
connectionStringName="CustomMembershipDBCNX"
applicationName="/"
type="System.Web.Security.SqlRoleProvider, System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
/>
</providers>
</roleManager>
</system.web>
</configuration>




Changed following 4 settings in above snippet (quick review):
a) connectionStrings
b) machineKey
c) authentication
d) membership
e) roleManager



3) Open ASP.Net Web Site’s Web Administration Tool

Go To ---
Menu -> Website -> ASP.Net Configuration




[Figure - 7]


a) Security tab: To manage/create Roles and User
b) Provider tab: To test both Custom membership and role provider
(click Select a different provider for each feature (advanced) link).



4) Create a new Web Application from SharePoint Central Administration site

Step:

Central Administration > Application Management >
Create or Extend Web Application > Create New Web Application

After creating the Web Application create Site Collection (link gets displayed after completing the above step)



5) Extend Web Application

Note: Select proper site (from top-right dropdown) that you want to extend.
Step:

Central Administration > Application Management > Create or Extend Web Application > Extend Web Application to Another IIS Web Site

In above step/page select Zone as Extranet or Internet as per your requirement.



6) Change Authentication Provider for Forms based site

Note: Select proper site and zone (from top-right dropdown) whose Authentication Provider you want to change to Forms Based.

Step:

Central Administration > Application Management > Authentication Providers > Edit Authentication

a) Select Authentication Type as Forms.
b) Disable Anonymous access
c) Enter custom Membership provider name
d) Enter custom Role manager name

Save the changes.



7) Change configuration files settings

Changes required in SharePoint Central Administration configuration file (web.config).

IMPORTANT: Do take the back-up of web.config file.





<configuration>
<SharePoint>
<!--Remaining settings-->

<PeoplePickerWildcards>
<clear />
<add key="AspNetSqlMembershipProvider" value="%" />
<add key="CustomMembershipProvider" value="%" />
</PeoplePickerWildcards>

</SharePoint>
<!--Remaining settings-->

<connectionStrings>
<add name="CustomMembershipDBCNX"
connectionString="SERVER=Server-Name; DATABASE=CustomMembershipDB;
TRUSTED_CONNECTION=true;"
providerName="System.Data.SqlClient" />
</connectionStrings>

<system.web>
<!--Remaining settings-->

<membership>
<providers>
<add name="CustomMembershipProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="CustomMembershipDBCNX"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
applicationName="/"
requiresUniqueEmail="false"
passwordFormat="Hashed"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="1"
passwordAttemptWindow="10"
passwordStrengthRegularExpression=""
/>
</providers>
</membership>

<roleManager enabled="true" defaultProvider="AspNetWindowsTokenRoleProvider">
<providers>
<add name="CustomRoleProvider"
connectionStringName="CustomMembershipDBCNX"
applicationName="/"
type="System.Web.Security.SqlRoleProvider, System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
/>
</providers>
</roleManager>
</system.web>
</configuration>






Changed following 4 settings in above snippet (quick review):
a) PeoplePickerWildcards – To detect your custom provider
b) connectionStrings
c) membership – Don’t specify default provider
d) roleManager – Change default provider to AspNetWindowsTokenRoleProvider

Note : Don’t change MachineKey.



Now made following changes in SharePoint Web Application's (created in step 4) configuration file (default one with Windows authentication) (web.config)





<configuration>
<SharePoint>
<!--Remaining settings-->

<PeoplePickerWildcards>
<clear />
<add key="AspNetSqlMembershipProvider" value="%" />
<add key="CustomMembershipProvider" value="%" />
</PeoplePickerWildcards>

</SharePoint>
<!--Remaining settings-->

<connectionStrings>
<add name="CustomMembershipDBCNX"
connectionString="SERVER=Server-Name; DATABASE=CustomMembershipDB;
TRUSTED_CONNECTION=true;"
providerName="System.Data.SqlClient" />
</connectionStrings>

<system.web>
<!--Remaining settings-->

<membership defaultProvider="CustomMembershipProvider">
<providers>
<add name="CustomMembershipProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="CustomMembershipDBCNX"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
applicationName="/"
requiresUniqueEmail="false"
passwordFormat="Hashed"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="1"
passwordAttemptWindow="10"
passwordStrengthRegularExpression=""
/>
</providers>
</membership>

<roleManager enabled="true" defaultProvider="CustomRoleProvider">
<providers>
<add name="CustomRoleProvider"
connectionStringName="CustomMembershipDBCNX"
applicationName="/"
type="System.Web.Security.SqlRoleProvider, System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
/>
</providers>
</roleManager>
</system.web>
</configuration>







Changed following 4 settings in above snippet (quick review):
a) PeoplePickerWildcards – To detect your custom provider
b) connectionStrings
c) membership
d) roleManager

Note : Don’t change MachineKey.



Repeat above configuration changes for Forms Based Web Application’s (created in step 5) configuration file (web.config)
(port number will be different).

The only difference in case of Forms Based Web Application’s config file will be:




<configuration>
<system.web>
<!--Remaining settings-->

<authentication mode="Forms">
<forms loginUrl="/_layouts/login.aspx"
timeout="120"
cookieless="UseCookies"
slidingExpiration="true" />
</authentication>
</system.web>
</configuration>





Changed following 5 settings in Forms based site's config (quick review):
a) PeoplePickerWildcards – To detect your custom provider
b) connectionStrings
c) membership
d) roleManager
e) Authentication – It will be automatically set by STEP 6.


So in total, we have to change 3 configuration files:
a) SharePoint’s Central Administration
b) Web Application with Default zone (Windows) [created in step 4]
c) Web Application with Internet/Extranet zone (Forms) [created in step 5]



8) Change policy for Web Application

Note: Select proper site (from top-right dropdown).

Step:

Central Administration > Application Management > Policy for Web Application

Click Add Users (top-left) to add new users/roles. Assign permission as per requirement.
Common Error: Access Denied

Steps to solve above error :

a) Go to --- SharePoint Central Administration > Application Management > Policy for Web Application
b) Select proper Web Application (from top-right)
c) Click "Add User" (top-left)
d) Add required User or Role in it.
e) Grant it "Full Control" (as per requirement) out of following options:
• Full Control - Has full control.
• Full Read - Has full read-only access.
• Deny Write - Has no write access.
• Deny All - Has no access.



9) Add users/roles as site administrator (Primary and Secondary)

Note: Select proper site (from top-right dropdown).

Step:

Central Administration > Application Management > Site Collection Owners



10) Open Forms based URL in browser; it will redirect you to login page

It means site is properly configured for Forms Based Authentication (FBA).

Enter the <Username> and <Password> (refer step 3) in login page; if you are able to login, its mean database is properly configured.
Otherwise check username, password, roles in DB and also the effective permissions of NT AUTHORITY\NETWORK SERVICE.



References:
1. simple-talk FBA

2. msdn FBA

3. codeproject FBA

4. hiddensharepointfeatures FBA

Google