Forms Authentication in SharePoint Products and Technologies (Part
2): Membership and Role Provider Samples
Summary: Explore details of developing a custom membership and role provider for Microsoft Office SharePoint
Server (MOSS) 2007 and Windows SharePoint Services 3.0, including the minimum required interfaces and how to
register and debug your custom provider. This article is part 2 of 3. (26 printed pages)
Steve Peschka, Microsoft Corporation
December 2007
Applies to: Microsoft Office SharePoint Server 2007, Windows SharePoint Services 3.0
Contents
z
Developing Custom Membership and Role Providers
z
Applying the XML File for the Data Source
z
Inheriting from the Membership and Role Base Classes
z
Minimum Interfaces Required by MOSS and Windows SharePoint Services
z
Registering the Custom Provider
z
Debugging the Custom Provider
z
Writing a Custom Forms Logon Page
z
Using Web Services with a Site Protected by Forms Authentication
z
Additional Resources
Read part 1 and part 3:
Forms Authentication in SharePoint Products and Technologies (Part 1): Introduction
[ http://msdn2.microsoft.com/en-us/library/bb975136(printer).aspx ]
Forms Authentication in SharePoint Products and Technologies (Part 3): Forms Authentication vs. Windows
Authentication
[ http://msdn2.microsoft.com/en-us/library/bb977430(printer).aspx ]
Developing Custom Membership and Role Providers
Applying the XML File for the Data Source
©2008 Microsoft Corporation. All rights
reserved.
Microsoft Office SharePoint Server (MOSS) 2007 and Windows SharePoint Services 3.0 (in this article series,
collectively referred to as SharePoint Products and Technologies) are built upon the ASP.NET 2.0 Framework. As
such, support for forms authentication extends not only to the membership and role providers that are included
with ASP.NET, MOSS, and Windows SharePoint Services, but also to custom membership and role providers. The
custom provider is required to inherit only from the ASP.NET membership or role base class respectively, and to
implement a limited set of interfaces on those classes.
Note:
Addressing this part of the Microsoft .NET Framework extensively is beyond the scope of this article. For
more information about the membership and role provider base classes, see
System.Web.Security.Membership
[ http://msdn2.microsoft.com/en-us/library/dazakw52
(printer).aspx ] and
System.Web.Security.RoleProvider
[ http://msdn2.microsoft.com/en-
us/library/kkdz3641(printer).aspx ] .
We now describe how to write a custom provider for users and roles that uses an XML file for the directory
information. The format of the XML file looks like the following code.
Important:
Strona 1 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Membership...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
Inheriting from the Membership and Role Base Classes
It is NOT a safe or secure practice to include unencrypted passwords in a clear text file, as displayed in
the following code example. We are using it in this case only to simplify the explanation of developing
custom providers. This is not an acceptable design for a production application. When storing sensitive
information in a configuration file for an application, you should encrypt the sensitive values by using
Protected Configuration. For more information, see
Encrypting Configuration Information Using
Protected Configuration
[ http://msdn2.microsoft.com/en-us/library/53tyfkaw(printer).aspx ] and
Securing Membership
[ http://msdn2.microsoft.com/en-us/library/ms178398(printer).aspx ] . If you
take the approach used as an example in this article, you are responsible for encrypting and decrypting
the data within your provider.
<
Users
>
<
User
name="user1" email="user1@microsoft.com" password="test" created="7/15/2007"
>
<
Groups
>
<
Group
>
Administrators
</
Group
>
<
Group
>
Authors
</
Group
>
<
Group
>
Readers
</
Group
>
</
Groups
>
</
User
>
<
User
name="user2" email="user2@microsoft.com" password="test" created="7/31/2007"
>
<
Groups
>
<
Group
>
Readers
</
Group
>
</
Groups
>
</
User
>
<
User
name="user3" email="user3@microsoft.com" password="test" created="8/15/2007"
>
<
Groups
>
<
Group
>
Designers
</
Group
>
<
Group
>
Readers
</
Group
>
</
Groups
>
</
User
>
</
Users
>
Xml
Copy Code
The base class that is used for membership is
System.Web.Security.MembershipProvider
[ http://msdn2.microsoft.com/en-us/library/sfka4yf8(printer).aspx ] ; if you are writing a custom membership
provider you must inherit from this class.
The base class that is used for roles is System.Web.Security.RoleProvider; if you are writing a custom role
provider you must inherit from this class.
using
System.Web;
using
System.Web.Security;
using
System.Xml;
using
System.Configuration;
namespace
Microsoft.IW
{
public
class
customUser : MembershipProvider
{
// This is not necessary for every provider; we are doing
// it for this one provider so that we can ensure our XML
// file is set up correctly.
private
XmlDocument xDoc =
null
;
// Code in here.
}
public
class
customRole : RoleProvider
{
// This is not necessary for every provider; we are doing
// it for this one provider so that we can ensure our XML
// file is set up correctly.
private
XmlDocument xDoc =
null
;
//Code in here.
}
}
C#
Copy Code
Imports
System.Web
Imports
System.Web.Security
Imports
System.Xml
Visual Basic
Copy Code
Strona 2 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Membership...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
Minimum Interfaces Required by MOSS and Windows SharePoint Services
Imports
System.Configuration
Namespace
Microsoft.IW
Public
Class
customUser
Inherits
MembershipProvider
' This is not necessary for every provider; we are doing
' it for this one provider so that we can ensure our XML
' file is set up correctly.
Private
xDoc
As
XmlDocument =
Nothing
' Code in here.
End
Class
Public
Class
customRole
Inherits
RoleProvider
' This is not necessary for every provider; we are doing
' it for this one provider so that we can ensure our XML
' file is set up correctly.
Private
xDoc
As
XmlDocument =
Nothing
' Code in here.
End
Class
End
Namespace
Both the MembershipProvider class and the RoleProvider class include several methods and properties. To
use the provider, only a subset of those is required by MOSS and Windows SharePoint Services.
To use the MembershipProvider, you must implement the following methods:
z
System.Web.Security.MembershipProvider.GetUser
[ http://msdn2.microsoft.com/en-us/library/ms152043
(printer).aspx ]
z
System.Web.Security.MembershipProvider.GetUserNameByEmail(System.String)
[ http://msdn2.microsoft.com/en-us/library/57hsxfsd(printer).aspx ]
z
System.Web.Security.MembershipProvider.ValidateUser(System.String,System.String)
[ http://msdn2.microsoft.com/en-us/library/05d03b82(printer).aspx ]
z
System.Web.Security.MembershipProvider.FindUsersByEmail
(System.String,System.Int32,System.Int32,System.Int32)
[ http://msdn2.microsoft.com/en-
us/library/96e54ch9(printer).aspx ]
z
System.Web.Security.MembershipProvider.FindUsersByName
(System.String,System.Int32,System.Int32,System.Int32)
[ http://msdn2.microsoft.com/en-
us/library/89e8kx21(printer).aspx ]
To use the RoleProvider, you must implement the following methods:
z
System.Web.Security.RoleProvider.GetRolesForUser(System.String)
[ http://msdn2.microsoft.com/en-
us/library/wzdyk8sx(printer).aspx ]
z
System.Web.Security.RoleProvider.RoleExists(System.String)
[ http://msdn2.microsoft.com/en-
us/library/5t22kc66(printer).aspx ]
In addition to the methods that SharePoint Products and Technologies require, the class contract requires you to
implement some additional methods and properties. In those cases, you can either implement the functionality or
choose to throw a
System.NotSupportedException
[ http://msdn2.microsoft.com/en-us/library/8a7a4e64
(printer).aspx ] . For example, the MembershipProvider requires a
System.Web.Security.MembershipProvider.ChangePassword(System.String,System.String,System.String)
[ http://msdn2.microsoft.com/en-us/library/bdt44e91(printer).aspx ] method; if you do not want to support that
functionality, your override of that method should resemble the following code.
Note:
The following section contains several code examples meant to demonstrate only the implementation of
the minimum interfaces required to have a custom membership and role provider that is usable with
MOSS 2007 and Windows SharePoint Services 3.0. They are not meant to demonstrate coding best
practices.
Strona 3 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Membership...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
As with most custom providers, this example includes special code to work with the data store: in this case, an
XML file. A simple helper class was developed to read the file from a hard-coded location on disk and store it in
cache. The item was added into cache with a dependency so that if the file on disk changes, such as when a user
is added or removed, the XML file is purged from cache. Following is the code for the helper class.
public
override
bool
ChangePassword(
string
username,
string
oldPassword,
string
newPassword)
{
throw
new
NotSupportedException();
}
C#
Copy Code
Public
Overrides
Function
ChangePassword(
ByVal
username
As
String
,
ByVal
oldPassword
As
String
,
ByVal
newPassword
As
String
)
As
Boolean
Throw
New
NotSupportedException()
End
Function
Visual Basic
Copy Code
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Xml;
using
System.Diagnostics;
using
System.Web;
namespace
Microsoft.IW
{
internal
class
Helper
{
private
const
string
XML_PATH =
"c:\\inetpub\\wwwroot\\userdata\\users.xml"
;
private
const
string
XML_CACHE =
"xmlUserDocFile"
;
public
static
XmlDocument GetXmlFile()
{
// This helper function looks for the XML document
// in cache; if it is there,
// it pulls it out of cache. Otherwise, it loads
// it into an XML document
// and stores it in cache with a file cache
// dependency, so that if the
// the XML file changes it will be flushed out
// of cache and have to be reread and reloaded.
XmlDocument xDoc =
null
;
try
{
// Look for the item in cache.
if
(HttpContext.Current.Cache[XML_CACHE] ==
null
)
{
// Create a new document.
xDoc =
new
XmlDocument();
// Load it from disk.
xDoc.Load(XML_PATH);
// Save it to cache.
HttpContext.Current.Cache.Insert(XML_CACHE,
xDoc,
new
System.Web.Caching.CacheDependency(XML_PATH));
}
else
xDoc =
(XmlDocument)HttpContext.Current.Cache[XML_CACHE];
}
catch
(Exception ex)
{
// Try writing to the event log.
try
{
EventLog.WriteEntry(
"fbaSharp Custom Provider"
,
"Error loading user xml file: "
+
ex.Message, EventLogEntryType.Error);
}
C#
Copy Code
Strona 4 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Membership...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
Functions Required in a Custom Membership Provider
catch
{
// Ignore.
}
}
return
xDoc;
}
}
}
Imports
System.Xml
Imports
System.Diagnostics
Imports
System.Web
Namespace
Microsoft.IW
Friend
Class
Helper
Private
Const
XML_PATH
As
String
= _
"c:\inetpub\wwwroot\userdata\users.xml"
Private
Const
XML_CACHE
As
String
=
"xmlUserDocFile"
Public
Shared
Function
GetXmlFile()
As
XmlDocument
' This helper function looks for the XML document
' in cache; if it is there, it pulls it out of cache.
' Otherwise, it loads it into an XML document and
' stores it in cache with a file cache dependency,
' so that if the XML file changes it will be
' flushed out of cache and have to be reread
' and reloaded.
Dim
xDoc
As
XmlDocument =
Nothing
Try
' Look for the item in cache.
If
HttpContext.Current.Cache(XML_CACHE)
Is
Nothing
Then
' Create a new document.
xDoc =
New
XmlDocument
' Load it from disk.
xDoc.Load(XML_PATH)
' Save it to cache.
HttpContext.Current.Cache.Insert(XML_CACHE, xDoc, _
New
System.Web.Caching.CacheDependency(XML_PATH))
Else
xDoc = HttpContext.Current.Cache(XML_CACHE)
End
If
Catch
ex
As
Exception
' Try writing to event log.
Try
EventLog.WriteEntry(
"fbaVB Custom Provider"
, _
"Error loading user xml file: "
& _
ex.Message, EventLogEntryType.Error)
Catch
logEx
As
Exception
' Ignore.
End
Try
End
Try
Return
xDoc
End
Function
End
Class
End
Namespace
Visual Basic
Copy Code
The following sections describe the functions (methods) required in a custom membership provider.
GetUser Method
The GetUser function has two overridden implementations and returns a
System.Web.Security.MembershipUser
[ http://msdn2.microsoft.com/en-us/library/d1b506ez(printer).aspx ] object based on user name and a flag that
indicates whether a user is online. As with any class, the author must determine whether and how to use the
parameters that are passed to it. For example, in most cases it is unlikely that you would change the return value
from this function based only on whether the user is online. Notice that the providerUserKey is useful only if
you are using a single Membership database to store users for multiple applications and you need to distinguish
Strona 5 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Membership...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
in which of those applications the user exists. You can find more detail about this parameter on MSDN in the
Membership classes materials that are referenced at the beginning of this article. This parameter is controlled in
the applicationName attribute of the add element in the web.config file that is used to define a membership
provider.
public
override MembershipUser GetUser(object providerUserKey,
bool
userIsOnline)
{
MembershipUser ret =
null
;
XmlNode xNode =
null
;
try
{
// Get the XML document.
xDoc = Helper.GetXmlFile();
// Proceed if it contains something.
if
(xDoc !=
null
)
{
// Look for a user with a name that matches.
xNode = xDoc.SelectSingleNode(
"/Users/User[@name='"
+
providerUserKey.ToString() +
"']"
);
// Determine whether there are any matches.
if
(xNode !=
null
)
{
// Create a new membershipusercollection.
ret =
new
MembershipUser(Membership.Provider.Name,
xNode.Attributes[
"name"
].Value.ToString(),
xNode.Attributes[
"name"
].Value.ToString(),
xNode.Attributes[
"email"
].Value.ToString(),
string
.Empty,
string
.Empty,
true
,
false
,
DateTime.Parse(xNode.Attributes[
"created"
].Value.ToString()),
DateTime.Today, DateTime.Today, DateTime.Today,
DateTime.MinValue);
}
}
}
catch
{
// Take appropriate action.
}
// Return the results.
return
ret;
}
public
override MembershipUser GetUser(
string
username,
bool
userIsOnline)
{
MembershipUser ret =
null
;
XmlNode xNode =
null
;
try
{
// Get the XML document.
xDoc = Helper.GetXmlFile();
// Proceed if it contains something.
if
(xDoc !=
null
)
{
// Look for a user with a name that matches.
xNode = xDoc.SelectSingleNode(
"/Users/User[@name='"
+
username +
"']"
);
// See if there are any matches.
if
(xNode !=
null
)
{
// Create a new membershipusercollection.
ret =
new
MembershipUser(Membership.Provider.Name,
xNode.Attributes[
"name"
].Value.ToString(),
xNode.Attributes[
"name"
].Value.ToString(),
xNode.Attributes[
"email"
].Value.ToString(),
string
.Empty,
string
.Empty,
true
,
false
,
DateTime.Parse(xNode.Attributes[
"created"
].Value.ToString()),
DateTime.Today, DateTime.Today, DateTime.Today,
DateTime.MinValue);
C#
Copy Code
Strona 6 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Membership...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
}
}
}
catch
{
// Take appropriate action.
}
// Return the results.
return
ret;
}
Public
Overloads
Overrides
Function
GetUser(_
ByVal
providerUserKey
As
Object
,
ByVal
userIsOnline
As
Boolean
) _
As
System.Web.Security.MembershipUser
Dim
ret
As
MembershipUser =
Nothing
Dim
xNode
As
XmlNode =
Nothing
Try
' Get the XML document.
xDoc = Helper.GetXmlFile()
' Proceed if it contains something.
If
xDoc IsNot
Nothing
Then
' Look for a user with a name that matches.
xNode = xDoc.SelectSingleNode("/Users/User[@name=
'" & _
providerUserKey.ToString() & "
']")
' See if there are any matches.
If
xNode IsNot
Nothing
Then
'Create a new membershipusercollection.
ret =
New
MembershipUser(Membership.Provider.Name, _
xNode.Attributes(
"name"
).Value.ToString(), _
xNode.Attributes(
"name"
).Value.ToString(), _
xNode.Attributes(
"email"
).Value.ToString(), _
String
.Empty,
String
.Empty,
True
,
False
, _
Date
.Parse(xNode.Attributes(
"created"
).Value.ToString()), _
Date
.Today,
Date
.Today,
Date
.Today,
Date
.MinValue)
End
If
End
If
Catch
ex
As
Exception
'Take appropriate action.
End
Try
' Return the results.
Return
ret
End
Function
Public
Overloads
Overrides
Function
GetUser( _
ByVal
username
As
String
,ByVal userIsOnline
As
Boolean
) _
As
System.Web.Security.MembershipUser
Dim
ret
As
MembershipUser =
Nothing
Dim
xNode
As
XmlNode =
Nothing
Try
' Get the XML document.
xDoc = Helper.GetXmlFile()
' Proceed if it contains something.
If
xDoc IsNot
Nothing
Then
' Look for a user with a name that matches.
xNode = xDoc.SelectSingleNode("/Users/User[@name=
'" & _
username & "
']")
' See if there are any matches.
If
xNode IsNot
Nothing
Then
' Create a new membershipusercollection.
ret =
New
MembershipUser(Membership.Provider.Name, _
xNode.Attributes(
"name"
).Value.ToString(), _
xNode.Attributes(
"name"
).Value.ToString(), _
xNode.Attributes(
"email"
).Value.ToString(), _
String
.Empty,
String
.Empty,
True
,
False
, _
Visual Basic
Copy Code
Strona 7 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Membership...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
GetUserNameByEmail Method
The GetUserNameByEmail function takes an e-mail address as a parameter and looks for a user with that e-
mail address. If it finds such a user, it returns the user name.
Date
.Parse(xNode.Attributes(
"created"
).Value.ToString()), _
Date
.Today,
Date
.Today,
Date
.Today,
Date
.MinValue)
End
If
End
If
Catch
ex
As
Exception
'Take appropriate action.
End
Try
' Return the results.
Return
ret
End
Function
public
override
string
GetUserNameByEmail(
string
email)
{
string
ret =
string
.Empty;
XmlNode xNode =
null
;
try
{
// Get the XML document.
xDoc = Helper.GetXmlFile();
// Proceed if it contains something.
if
(xDoc !=
null
)
{
// Look for the user.
xNode = xDoc.SelectSingleNode(
"/Users/User[@email='"
+
email +
"']"
);
// See if it found a match.
if
(xNode !=
null
)
ret = xNode.Attributes[
"name"
].Value.ToString();
}
}
catch
{
// Take appropriate action.
}
// Return the results.
return
ret;
}
C#
Copy Code
Public
Overrides
Function
GetUserNameByEmail(
ByVal
As
String
) _
As
String
Dim
ret
As
String
=
String
.Empty
Dim
xNode
As
XmlNode =
Nothing
Try
' Get the XML document.
xDoc = Helper.GetXmlFile()
' Proceed if it contains something.
If
xDoc IsNot
Nothing
Then
' Look for the user.
xNode = xDoc.SelectSingleNode("/Users/User[@email=
'" & _
email & "
']")
' See if it found a match.
If
xNode IsNot
Nothing
Then
_
ret = xNode.Attributes(
"name"
).Value.ToString
End
If
Catch
ex
As
Exception
' Take appropriate action.
End
Try
' Return the results.
Visual Basic
Copy Code
Strona 8 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Membership...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
ValidateUser Method
The ValidateUser function takes a user name and password and verifies whether it is correct.
Return
ret
End
Function
public
override
bool
ValidateUser(
string
username,
string
password)
{
bool
ret =
false
;
XmlNode xNode =
null
;
try
{
// Get the XML document.
xDoc = Helper.GetXmlFile();
// Proceed if it contains something.
if
(xDoc !=
null
)
{
// Look for the user.
xNode = xDoc.SelectSingleNode(
"/Users/User[@name='"
+
username +
"']"
);
// See if it found a match.
if
(xNode !=
null
)
{
// Look for the password attribute to see if it matches.
if
(xNode.Attributes[
"password"
].Value.ToString() == password)
ret =
true
;
}
}
}
catch
{
// Take appropriate action.
}
// Return the results.
return
ret;
}
C#
Copy Code
Public
Overrides
Function
ValidateUser(
ByVal
username
As
String
, _
ByVal
password
As
String
)
As
Boolean
Dim
ret
As
Boolean
=
False
Dim
xNode
As
XmlNode =
Nothing
Try
' Get the XML document.
xDoc = Helper.GetXmlFile()
' Proceed if it contains something.
If
xDoc IsNot
Nothing
Then
' Look for the user.
xNode = xDoc.SelectSingleNode("/Users/User[@name=
'" & _
username & "
']")
' See if it found a match.
If
xNode IsNot
Nothing
Then
' Look for the password attribute to see if it matches.
If
xNode.Attributes(
"password"
).Value.ToString = password
Then
_
ret =
True
End
If
End
If
Catch
ex
As
Exception
' Take appropriate action.
End
Try
' Return the results.
Return
ret
End
Function
Visual Basic
Copy Code
Strona 9 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Membership...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
FindUsersByEmail Method
The FindUsersByEmail function takes an e-mail address as a parameter and finds all users whose e-mail
addresses start with that value. It returns a
System.Web.Security.MembershipUserCollection
[ http://msdn2.microsoft.com/en-us/library/3xe386wc(printer).aspx ] object.
public
override MembershipUserCollection FindUsersByEmail(
string
emailToMatch,
int
pageIndex,
int
pageSize, out
int
totalRecords)
{
MembershipUserCollection ret =
null
;
XmlNodeList xList =
null
;
// Initialize the number of records found.
totalRecords = 0;
try
{
// Get the XML document.
xDoc = Helper.GetXmlFile();
// Proceed if it contains something.
if
(xDoc !=
null
)
{
// Look for users with matching e-mail addresses.
xList = xDoc.SelectNodes(
"/Users/User[starts-with(@email, '"
+
emailToMatch +
"')]"
);
// See if there are any matches.
if
((xList !=
null
) && (xList.Count > 0))
{
// Set the number of records found.
totalRecords = xList.Count;
// Create a new membershipusercollection.
ret =
new
MembershipUserCollection();
// Enumerate each match and add it to the collection.
foreach
(XmlNode xNode
in
xList)
{
ret.Add(
new
MembershipUser(Membership.Provider.Name,
xNode.Attributes[
"name"
].Value.ToString(),
xNode.Attributes[
"name"
].Value.ToString(),
xNode.Attributes[
"email"
].Value.ToString(),
string
.Empty,
string
.Empty,
true
,
false
,
DateTime.Parse(xNode.Attributes[
"created"
].Value.ToString()),
DateTime.Today, DateTime.Today, DateTime.Today,
DateTime.MinValue));
}
}
}
}
catch
{
// Take appropriate action.
}
// Return the results.
return
ret;
}
C#
Copy Code
Public
Overrides
Function
FindUsersByEmail(
ByVal
emailToMatch
As
_
String
,
ByVal
pageIndex
As
Integer
,
ByVal
pageSize
As
Integer
, _
ByRef
totalRecords
As
Integer
)
As
_
System.Web.Security.MembershipUserCollection
Dim
ret
As
MembershipUserCollection =
Nothing
Dim
xList
As
XmlNodeList =
Nothing
' Initialize the number of records found.
totalRecords = 0
Try
' Get the XML document.
xDoc = Helper.GetXmlFile()
Visual Basic
Copy Code
Strona 10 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
FindUsersByName Method
The FindUserByName function works the same way that the FindUserByEmail function does; however, it takes
a user name (full or partial) as a parameter.
' Proceed if it contains something.
If
xDoc IsNot
Nothing
Then
' Look for users with matching e-mail addresses.
xList = xDoc.SelectNodes("/Users/User[starts-with(@email,
'" & _
emailToMatch & "
')]")
' See if there are any matches.
If
xList IsNot
Nothing
AndAlso
xList.Count > 0
Then
' Set the number of records found.
totalRecords = xList.Count
' Create a new membershipusercollection.
ret =
New
MembershipUserCollection()
' Enumerate each match and add it to the collection.
For
Each
xNode
As
XmlNode
In
xList
ret.Add(
New
MembershipUser(Membership.Provider.Name, _
xNode.Attributes(
"name"
).Value.ToString(), _
xNode.Attributes(
"name"
).Value.ToString(), _
xNode.Attributes(
"email"
).Value.ToString(), _
String
.Empty,
String
.Empty,
True
,
False
, _
Date
.Parse(xNode.Attributes(
"created"
).Value.ToString()), _
Date
.Today,
Date
.Today,
Date
.Today,
Date
.MinValue))
Next
End
If
End
If
Catch
ex
As
Exception
' Take appropriate action.
End
Try
' Return the results.
Return
ret
End
Function
public
override MembershipUserCollection FindUsersByName(
string
usernameToMatch,
int
pageIndex,
int
pageSize, out
int
totalRecords)
{
MembershipUserCollection ret =
null
;
XmlNodeList xList =
null
;
// Initialize the number of records found.
totalRecords = 0;
try
{
// Get the XML document.
xDoc = Helper.GetXmlFile();
// Proceed if it contains something.
if
(xDoc !=
null
)
{
// Look for users with matching e-mail addresses.
xList = xDoc.SelectNodes(
"/Users/User[starts-with(@name, '"
+
usernameToMatch +
"')]"
);
// See if there are any matches.
if
((xList !=
null
) && (xList.Count > 0))
{
// Create a new membershipusercollection.
ret =
new
MembershipUserCollection();
// Enumerate each match and add it to the collection.
foreach
(XmlNode xNode
in
xList)
{
ret.Add(
new
MembershipUser(Membership.Provider.Name,
xNode.Attributes[
"name"
].Value.ToString(),
xNode.Attributes[
"name"
].Value.ToString(),
xNode.Attributes[
"email"
].Value.ToString(),
string
.Empty,
string
.Empty,
true
,
false
,
C#
Copy Code
Strona 11 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
Functions Required in a Custom Role Provider
DateTime.Parse(xNode.Attributes[
"created"
].Value.ToString()),
DateTime.Today, DateTime.Today, DateTime.Today,
DateTime.MinValue));
}
}
}
}
catch
{
// Take appropriate action.
}
// Return the results.
return
ret;
}
Public
Overrides
Function
FindUsersByName( _
ByVal
usernameToMatch
As
String
,
ByVal
pageIndex
As
Integer
, _
ByVal
pageSize
As
Integer
,
ByRef
totalRecords
As
Integer
) _
As
System.Web.Security.MembershipUserCollection
Dim
ret
As
MembershipUserCollection =
Nothing
Dim
xList
As
XmlNodeList =
Nothing
' Initialize the number of records found.
totalRecords = 0
Try
' Get the XML document.
xDoc = Helper.GetXmlFile()
' Proceed if it contains something.
If
xDoc IsNot
Nothing
Then
' Look for users with matching e-mail addresses.
xList = xDoc.SelectNodes("/Users/User[starts-with(@name,
'" & _
usernameToMatch & "
')]")
' See if there are any matches.
If
xList IsNot
Nothing
AndAlso
xList.Count > 0
Then
'create a new membershipusercollection
ret =
New
MembershipUserCollection()
' Enumerate each match and add it to the collection.
For
Each
xNode
As
XmlNode
In
xList
ret.Add(
New
MembershipUser(Membership.Provider.Name, _
xNode.Attributes(
"name"
).Value.ToString(), _
xNode.Attributes(
"name"
).Value.ToString(), _
xNode.Attributes(
"email"
).Value.ToString(), _
String
.Empty,
String
.Empty,
True
,
False
, _
Date
.Parse(xNode.Attributes(
"created"
).Value.ToString()), _
Date
.Today,
Date
.Today,
Date
.Today,
Date
.MinValue))
Next
End
If
End
If
Catch
ex
As
Exception
' Take appropriate action.
End
Try
' Return the results.
Return
ret
End
Function
Visual Basic
Copy Code
The following sections describe functions (methods) that are required in a custom role provider.
GetRolesForUser Method
The GetRolesForUser function takes a user name as a parameter and returns a string array that contains the
names of all groups to which the user belongs.
Important:
Strona 12 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
You must understand one limitation when you are writing code for the GetRolesForUser method. The
role provider has a property named
System.Web.Security.Roles.CacheRolesInCookie
[ http://msdn2.microsoft.com/en-us/library/f46tewk7(printer).aspx ] . Unfortunately, because of a bug
that exists in ASP.NET at the time this article was written, that attribute is not honored, and the role
provider's GetRolesForUser method is called every time. In practice, the GetRolesForUser method is
called at least once for every user, for every page that he or she visits in the SharePoint site. Because
of this, you should implement your own caching mechanism in the GetRolesForUser method in any
custom role provider.
public
override
string
[] GetRolesForUser(
string
username)
{
string
[] ret =
null
;
XmlNode xNode =
null
;
XmlNodeList xList =
null
;
try
{
// Get the XML document.
xDoc = Helper.GetXmlFile();
// Proceed if it contains something.
if
(xDoc !=
null
)
{
// Look for the user.
xNode = xDoc.SelectSingleNode(
"/Users/User[@name='"
+
username +
"']"
);
// See if it found a match.
if
(xNode !=
null
)
{
// Get the collection of group nodes.
xList = xNode.ChildNodes[0].ChildNodes;
// Resize the array based on number of child nodes.
ret =
new
string
[xList.Count];
// Enumerate all the groups in the Groups/Group subnodes
// and add to return value.
for
(
int
cnt = 0;cnt < xList.Count;cnt++)
{
ret[cnt] = xList.Item(cnt).InnerText;
}
}
}
}
catch
{
// Take appropriate action.
}
//Return the results.
return
ret;
}
C#
Copy Code
Public
Overrides
Function
GetRolesForUser(
ByVal
username
As
String
) _
As
String
()
Dim
ret
As
String
() =
Nothing
Dim
xNode
As
XmlNode =
Nothing
Dim
xList
As
XmlNodeList =
Nothing
Try
' Get the XML document.
xDoc = Helper.GetXmlFile()
' Proceed if it contains something.
If
xDoc IsNot
Nothing
Then
' Look for the user.
xNode = xDoc.SelectSingleNode("/Users/User[@name=
'" & _
username & "
']")
' See if it found a match.
If
xNode IsNot
Nothing
Then
Visual Basic
Copy Code
Strona 13 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
RoleExists Method
The RoleExists function takes a role name as a parameter. If the role exists, the function returns true;
otherwise, it returns false.
' Get the collection of group nodes.
xList = xNode.ChildNodes(0).ChildNodes
' Resize the array based on number of child nodes.
ReDim
ret(xList.Count - 1)
' Enumerate all the groups in the Groups/Group subnodes and
' add to return value.
For
cnt
As
Integer
= 0
To
xList.Count - 1
ret(cnt) = xList.Item(cnt).InnerText
Next
End
If
End
If
Catch
ex
As
Exception
' Take appropriate action.
End
Try
' Return the results.
Return
ret
End
Function
public
override
bool
RoleExists(
string
roleName)
{
bool
ret =
false
;
XmlNode xNode =
null
;
try
{
// Get the XML document.
xDoc = Helper.GetXmlFile();
// Proceed if it contains something.
if
(xDoc !=
null
)
{
// Look for the role.
xNode = xDoc.SelectSingleNode(
"/Users/User[Groups/Group='"
+
roleName +
"']"
);
// Return true if it found a match.
if
(xNode !=
null
) ret =
true
;
}
}
catch
{
// Take appropriate action.
}
// Return the results.
return
ret;
}
C#
Copy Code
Public
Overrides
Function
RoleExists(
ByVal
roleName
As
String
) _
As
Boolean
Dim
ret
As
Boolean
=
False
Dim
xNode
As
XmlNode =
Nothing
Try
' Get the XML document.
xDoc = Helper.GetXmlFile()
' Proceed if it contains something.
If
xDoc IsNot
Nothing
Then
' Look for the role.
xNode = xDoc.SelectSingleNode("/Users/User[Groups/Group=
'" & _
roleName & "
']")
' Return true if it found a match.
If
xNode IsNot
Nothing
Then
ret =
True
Visual Basic
Copy Code
Strona 14 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
Registering the Custom Provider
End
If
Catch
ex
As
Exception
' Take appropriate action.
End
Try
' Return the results.
Return
ret
End
Function
Now that you understand the minimum required interfaces for a custom Membership and Role provider to work
with MOSS 2007 and Windows SharePoint Services 3.0. your next step is to register the custom provider.
To be able to use a custom provider, you must provide a strong name for the assembly it uses, and then register
it in the global assembly cache.
To strong name the assembly
1. In Microsoft Visual Studio, right-click the project name, and then click Properties.
2. Click the Signing tab, and then select Sign the assembly.
3. In the Choose a strong name key file list, click <New…>.
4. In the Create Strong Name Key dialog box, type a name for the key file, optionally type a password for the
key file, and then click OK.
When you compile the assembly, it builds with the strong name you provided.
You can now add your strong-named assembly to the global assembly cache in several ways, but the most
common way is to use the
gacutil.exe
[ http://msdn2.microsoft.com/en-us/library/ex0ss12c(printer).aspx ] utility
with the /i option. For more information about installing an assembly in the global assembly cache, see
How to:
Install an Assembly into the Global Assembly Cache
[ http://msdn2.microsoft.com/en-us/library/dkkx7f79
(printer).aspx ] .
After you register the assembly, you can extend a Web application into a zone and configure it to use your
custom provider (described in the "Setting Up Forms Authentication" section of
Forms Authentication in
SharePoint Products and Technologies (Part 1): Introduction
[ http://msdn2.microsoft.com/en-
us/library/bb975136(printer).aspx ] ).
Following are two different example entries for the custom provider, reflecting that the Microsoft Visual C# and
Microsoft Visual Basic assemblies were created with different names. In the examples, when you configure the
authentication provider for the zone, the authentication method should be Forms, the membership provider
name should be fbaUser, and the role manager name should be fbaRole.
For the Visual C# assembly, use the following code.
For the Visual Basic assembly, use the following code.
Note:
Because the strong name for an assembly that you compile on your computer will differ from the
following example, the entries for your custom provider will also differ slightly; specifically the
PublicKeyToken value will be different.
<
membership
defaultProvider="fbaUser"
>
<
providers
>
<
add
name="fbaUser" type="Microsoft.IW.customUser, fbaSharp, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=b74d22b2d68547b5"
/>
</
providers
>
</
membership
>
<
roleManager
enabled="true" defaultProvider="fbaRole"
>
<
providers
>
<
add
name="fbaRole" type="Microsoft.IW.customRole, fbaSharp, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=b74d22b2d68547b5"
/>
</
providers
>
</
roleManager
>
Xml
Copy Code
Strona 15 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
Debugging the Custom Provider
<
membership
defaultProvider="fbaUser"
>
<
providers
>
<
add
name="fbaUser" type="Microsoft.IW.customUser, fbaVB, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=ddd85720e6ace42b"
/>
</
providers
>
</
membership
>
<
roleManager
enabled="true" defaultProvider="fbaRole"
>
<
providers
>
<
add
name="fbaRole" type="Microsoft.IW.customRole, fbaVB, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=ddd85720e6ace42b"
/>
</
providers
>
</
roleManager
>
Xml
Copy Code
Now that you have compiled the assembly, registered it, and configured a new zone to use the custom provider,
you can use and (optionally) debug the provider. You would debug the custom provider in the same way that you
would debug any other assembly that is used by another process. In this case, the process that is consuming the
assembly is the w3wp.exe process.
To debug the provider, you set the breakpoints you want in the code, and then attach to the w3wp.exe process.
To attach to the w3wp.exe
1. In Visual Studio, on the Tools menu, click Attach to Process to open the Attach to Process dialog box.
2. In Available Processes, select the w3wp.exe process, and then click Select.
z
If you do not see any w3wp processes, select Show processes from all users.
z
Also, if you have recently performed an iisreset, you must navigate to a page in the SharePoint site to
create a new w3wp.exe process. Conversely, you might also find multiple w3wp.exe processes running.
In such a case, select all w3wp.exe processes. This ensures that you attach to the process that is
running your provider assembly.
After you attach the w3wp.exe process, try logging on to the site. If you attached a breakpoint on the
ValidateUser method of your membership provider, the breakpoint should be hit at the time you log on. If the
breakpoint is not hit, you should try reattaching to the w3wp.exe process; another process might have started in
connection with logging on to the site. The processes that are already attached appear dimmed (they are
disabled); any new w3wp.exe processes appear black and are enabled to allow attachments.
As you log on and navigate to pages, you should see breakpoints being hit in both the membership and role
providers. To test your providers further, try using the People Picker to search for users and roles to add to
SharePoint groups. This triggers breakpoints set in any of the membership and role provider methods. The
number of times the breakpoints are hit varies on what is being done. When you use the People Picker, some
methods such as FindUserByEmail can be called more than once. The number of times the role provider is
called for any given page can vary also. The role provider is called for each item on the page that requires
authentication. Some examples of items are navigation, list view Web Parts, or parts that are targeted at
audiences. As a result, the GetRolesForUser method in the role provider is called one or more times for every
user on each page view.
Figure 1 and Figure 2 show the People Picker, configured to use the custom membership and role providers.
Notice the account name for the entities matches the name attribute of the membership and role provider, as
described earlier.
Figure 1. Select People and Groups - membership provider name
Strona 16 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
Writing a Custom Forms Logon Page
Figure 2. Select People and Groups - role provider name
You may have scenarios that have special logon requirements that cannot be addressed by the default SharePoint
forms logon page. For example, you may need to implement a second authentication factor such as Secure ID.
Fortunately, because SharePoint Products and Technologies are built on top of ASP.NET 2.0, you can create a
custom logon page with your own logon logic, and integrate it directly into MOSS or Windows SharePoint
Services.
Creating a Standard ASP.NET Web Site
Strona 17 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
The easiest way to create a custom logon page is to build a standard ASP.NET Web application. This enables you
to create a site and easily debug the code behind for your forms logon page to ensure that it is working correctly.
When you do this, you should configure your site to use the same membership and role provider that you intend
to use with MOSS or Windows SharePoint Services.
In the scenario for this article, we built a custom forms logon page for two reasons:
z
To show a custom policy condition that all site users must agree to before using the site.
z
To force certain users to use two-factor authentication, where the second factor is Secure ID.
We have created an ASPX page named customLogin.aspx and added it to the site. It contains the following:
z
Edit boxes for user name, password, and Secure ID number
z
A check box for a persistent authorization cookie
z
A button to perform the logon process
Figure 3 shows how the page should look.
Figure 3. customLogin.aspx page
The web.config file was modified to do the following:
z
Use forms authentication and the fbaVB membership and role provider described earlier in this article, in
the section
Registering the Custom Provider
.
z
Deny access to anonymous users.
Default.aspx was also added to the site when the project was created, and it is used in the site for testing.
Adding Code Behind the Logon Page
In the code behind the logon page, you should first validate the credentials. You can use the ValidateUser
method of the Membership class to do this. If the credentials are valid, you can redirect the user to the site;
otherwise, prompt them to reenter their credentials.
if
(Membership.ValidateUser(UserTxt.Text, PwdTxt.Text))
{
// Do Secure ID thing here.
// Redirect the user to the requested page.
FormsAuthentication.RedirectFromLoginPage(UserTxt.Text,
SaveChk.Checked);
}
else
StatusLbl.Text =
"The credentials you entered are not valid. "
+
"Please try again."
;
C#
Copy Code
If
Membership.ValidateUser(UserTxt.Text, PwdTxt.Text)
Then
Visual Basic
Copy Code
Strona 18 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
For the Secure ID component, this example simulates only the process that a user or another system that
requires additional authentication processing would go through. In this example, the page is hard-coded to
prompt a specific user for a Secure ID number; in practice you could query a database or Web service (or
whatever is appropriate) to determine how to process users. After prompting the user for the Secure ID
credentials, it allows them to pass.
Compiling the Application into an Assembly
After you complete the simple ASP.NET application and have the forms logon page working correctly, your next
step is to compile it and use it in MOSS or Windows SharePoint Services. You can use the Web site project that is
new with Visual Studio 2005 to create the Web application. Alternatively, with Service Pack 1 of Visual Studio you
can also create the Web project model that is similar to Visual Studio 2003, in that you can compile the project
into a single assembly (.dll file).
For the remainder of this section, we assume that you have compiled the project into a single assembly. If you
use the Visual Studio 2005 style of Web site project, you can still make the application work, but you must use
the
ASP.NET Compilation Tool (Aspnet_compiler.exe)
[ http://msdn2.microsoft.com/en-us/library/ms229863
(printer).aspx ] to precompile it. If you use that approach, ensure that you include the -u parameter when you
compile so that you can update the assembly later.
Copying Files and Registering the Assembly
Following are the steps to make the custom logon page available to MOSS or Windows SharePoint Services.
To enable the use of the custom logon page by SharePoint Products and Technologies
1. Copy the logon page to the _layouts directory. The default path is C:\Program Files\Common
Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS
.
2. Create a bin directory on the file system at the top-level (root) of your SharePoint Web application that will
use your custom logon page. For the examples used in this article, the default directory would be in the path
C:\Inetpub\wwwroot\wss\VirtualDirectories\ www.contoso.com80
. Then, copy the compiled assembly
for the custom forms application to the bin directory that you created.
3. Register the compiled assembly for the custom forms application in the global assembly cache. You can do
this by using the
Global Assembly Cache Tool (Gacutil.exe)
[ http://msdn2.microsoft.com/en-
us/library/ex0ss12c(printer).aspx ] with the /i option. For more details about installing an assembly in the
global assembly cache, see
How to: Install an Assembly into the Global Assembly Cache
' Do Secure ID thing here.
' Redirect the user to the requested page.
FormsAuthentication.RedirectFromLoginPage(UserTxt.Text, _
SaveChk.Checked)
Else
StatusLbl.Text =
"The credentials you entered are not valid. "
& _
Please
try
again."
End
If
// Instead of redirecting user3, ask for a Secure ID number.
if
(UserTxt.Text.ToLower() ==
"user3"
)
{
// Update UI.
StatusLbl.Text =
"Please enter your Secure ID number"
;
LogPnl.Visible =
false
;
SecurePnl.Visible =
true
;
}
C#
Copy Code
' Instead of redirecting user3, ask for a Secure ID number.
If
UserTxt.Text.ToLower() =
"user3"
Then
' Update UI.
StatusLbl.Text =
"Please enter your Secure ID number"
LogPnl.Visible =
False
SecurePnl.Visible =
True
End
If
Visual Basic
Copy Code
Note:
It is often easier to debug integrated solutions such as this if you use the latter approach and compile
the Web application into a single DLL.
Strona 19 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
[ http://msdn2.microsoft.com/en-us/library/dkkx7f79(printer).aspx ] .
You must also update the web.config file for the Web application that is going to use the custom logon page.
To update the web.config file for the Web application
1. Open the web.config file.
2. In the authentication section, locate the forms element.
3. In the forms element, change the loginUrl attribute to point to your new custom forms logon page; for
example, _layouts/customLogin.aspx.
4. Perform an iisreset.
You should now be able to use the custom logon page.
Following is an example of what the page looks like when used with the Contoso site described earlier in this
article.
Figure 4. customLogin.aspx page on Contoso site
The interface is obviously not quite what one would expect from a SharePoint site. Fortunately, you can copy
elements from the login.aspx page that is included with SharePoint Products and Technologies and paste them
into the custom logon page to give it the SharePoint appearance.
To modify the custom logon page to give it the SharePoint appearance
1. In the @ Page directive at the top of the page, add the following master page attribute.
2. Remove the following lines from near the top of the page.
3. Add the following lines directly below the @ Page directive.
Note:
This step is important; things might not work correctly if you do not perform an iisreset.
MasterPageFile="~/_layouts/simple.master"
Html
Copy Code
<!
DOCTYPE
html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<
html
>
<
head
id="Head1" runat="server"
>
<
title
>
Untitled Page
</
title
>
</
head
>
<
body
>
<
form
id="form1" runat="server"
>
Html
Copy Code
Html
Copy Code
Strona 20 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
4. Remove the following lines from the bottom of the page.
5. Add the following line to the bottom of the page.
Try logging on to the site again; you may need to refresh the page. After you refresh, the page should look like
Figure 5 and Figure 6.
Figure 5. Updated customLogin.aspx on Contoso site - enter user name and password
Figure 6. Updated customLogin.aspx on Contoso site - enter Secure ID
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%
@ Register Tagprefix="SharePoint"
Namespace="Microsoft.SharePoint.WebControls"
Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c"
%>
<%
@ Register Tagprefix="Utilities"
Namespace="Microsoft.SharePoint.Utilities"
Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c"
%>
<%@ Import Namespace="Microsoft.SharePoint" %>
<asp:Content ContentPlaceHolderId="PlaceHolderPageTitle" runat="server">
<
SharePoint:EncodedLiteral
runat="server" text="
<%
$Resources:wss,login_pagetitle
%
>
" EncodeMethod='HtmlEncode'
/>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderTitleBreadcrumb" runat="server">
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderPageTitleInTitleArea" runat="server">
<
SharePoint:EncodedLiteral
runat="server" text="
<%
$Resources:wss,login_pagetitle
%
>
" EncodeMethod='HtmlEncode'
/>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderSiteName" runat="server"/>
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
</
form
>
</
body
>
</
html
>
Html
Copy Code
</asp:Content>
Html
Copy Code
Strona 21 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
Using Web Services with a Site Protected by Forms Authentication
Using the SharePoint Web services with a site secured with forms authentication works; however, the process
differs from what you would do to use Web services for a site that is secured with Windows authentication. The
primary difference is that you must obtain an authentication cookie and then use that cookie when accessing the
Web services in the site protected by forms authentication.
Fortunately, SharePoint Products and Technologies provide a new Web service that makes it easier to work in this
scenario: the
Authentication Web service
[ http://msdn2.microsoft.com/en-us/library/aa979750(printer).aspx ] .
It has a method named
Login
[ http://msdn2.microsoft.com/en-us/library/aa979746(printer).aspx ] that, when
called, places an authentication cookie in the proxy's
System.Web.Services.Protocols.HttpWebClientProtocol.CookieContainer
[ http://msdn2.microsoft.com/en-
us/library/yta0fyx9(printer).aspx ] collection. That cookie can then be used in subsequent requests to other Web
services in the site that is protected by forms authentication to authenticate the request.
For purposes of creating your Web service proxies (such as
adding Web references in Visual Studio
[ http://msdn2.microsoft.com/en-us/library/8dcbc50t(printer).aspx ] ), use a Windows authentication–protected
site. In most cases, the Visual Studio Add Web Reference wizard does not work with a SharePoint site that is
protected by forms authentication. For this example, we retrieve all of the lists in the site by using the
Lists Web
service
[ http://msdn2.microsoft.com/en-us/library/ms774654(printer).aspx ] .
To retrieve all lists in the site by using the Lists Web services
1. Start Visual Studio, and create a Windows Application project.
2. Add a button and text box to Form1.
3. Change the text box properties so that Multiline is True and Scrollbars is Vertical.
4. Resize the text box to fill the form under the button.
5. Add a Web reference to the Authentication Web service in the site that is protected by forms
authentication; the Authentication Web service can be found in the path
http://siteCollectionName/_vti_bin/authentication.asmx
. Name this Web reference fbaAuth.
6. Add a second Web reference to the Lists Web service; it can be found in the path
http://siteCollectionName/_vti_bin/lists.asmx
. Name this Web reference fbaLists.
7. On the form, double-click Button1 to switch to code view and create an event handler for the click event.
Create two variables for the Web service proxies, as shown in the following code.
Note:
By default, a zone that is configured to use forms authentication does not enable Client Integration
features. This option, which is found on the Authentication Provider page in SharePoint Central
Administration, must be turned on if you want to use the SharePoint Web services. When this option is
turned off, SharePoint Products and Technologies also turn off support for remote interfaces, such as
Web services.
fbaAuth.Authentication auth =
new
fbaAuth.Authentication();
fbaLists.Lists lists =
new
fbaLists.Lists();
C#
Copy Code
Strona 22 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
Additional Resources
8. Create a CookieContainer collection object for the Authentication class proxy; the authentication cookie
will be stored in this container after calling the Login method.
9. Call the Login method, and check the result from that call, as shown in the following code.
If the Login method succeeds, the proxy for the Authentication Web service has a valid authentication cookie in
its CookieContainer collection. To reuse this cookie, just set the CookieContainer property for the Lists Web
service proxy equal to the CookieContainer property of the Authentication Web service proxy. You can then
make calls to the Lists Web service, and the authentication cookie will be used to authenticate and authorize the
request. That means that when you make a Web service request, the cookie with authenticate and authorize the
request based on the permissions of whatever account was used to create the authentication cookie.
Following is the remainder of the code sample.
This concludes part 2 of this article series.
Next step:
Forms Authentication in SharePoint Products and Technologies (Part 3): Forms Authentication vs.
Windows Authentication
[ http://msdn2.microsoft.com/en-us/library/bb977430(printer).aspx ] .
Dim
auth
As
New
fbaAuth.Authentication()
Dim
lists
As
New
fbaLists.Lists()
Visual Basic
Copy Code
auth.CookieContainer =
new
System.Net.CookieContainer();
auth.AllowAutoRedirect =
true
;
fbaAuth.LoginResult lr = auth.Login(
"myUserName"
,
"myUserPassword"
);
if
(lr.ErrorCode == fbaAuth.LoginErrorCode.NoError)
{
//Now we can talk to the Lists Web service.
}
C#
Copy Code
auth.CookieContainer =
New
System.Net.CookieContainer()
auth.AllowAutoRedirect =
True
Dim
lr
As
fbaAuth.LoginResult = auth.Login(
"myUserName"
, _
"myUserPassword"
)
If
lr.ErrorCode = fbaAuth.LoginErrorCode.NoError
Then
'Now we can talk to the Lists Web service.
End
If
Visual Basic
Copy Code
if
(lr.ErrorCode == fbaAuth.LoginErrorCode.NoError)
{
// Now we can talk to the Lists Web service.
lists.CookieContainer = auth.CookieContainer;
XmlNode xData = lists.GetListCollection();
}
C#
Copy Code
If
lr.ErrorCode = fbaAuth.LoginErrorCode.NoError
Then
' Now we can talk to the Lists Web service.
lists.CookieContainer = auth.CookieContainer
Dim
xData
As
XmlNode = lists.GetListCollection()
End
If
Visual Basic
Copy Code
For more information, see the following resources:
Strona 23 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx
z
Forms Authentication in SharePoint Products and Technologies (Part 1): Introduction
[ http://msdn2.microsoft.com/en-us/library/bb975136(printer).aspx ]
z
Forms Authentication in SharePoint Products and Technologies (Part 3): Forms Authentication vs. Windows
Authentication
[ http://msdn2.microsoft.com/en-us/library/bb977430(printer).aspx ]
z
What Every SharePoint Administrator Needs to Know About Alternate Access Mappings Part 1 of 3
[ http://blogs.msdn.com/sharepoint/archive/2007/03/06/what-every-sharepoint-administrator-needs-to-
know-about-alternate-access-mappings-part-1.aspx ]
z
What Every SharePoint Administrator Needs to Know About Alternate Access Mappings Part 2 of 3
[ http://blogs.msdn.com/sharepoint/archive/2007/03/19/what-every-sharepoint-administrator-needs-to-
know-about-alternate-access-mappings-part-2-of-3.aspx ]
z
What Every SharePoint Administrator Needs to Know About Alternate Access Mappings Part 3 of 3
[ http://blogs.msdn.com/sharepoint/archive/2007/04/18/what-every-sharepoint-administrator-needs-to-
know-about-alternate-access-mappings-part-3-of-3.aspx ]
z
Configuring Multiple Authentication Providers for SharePoint 2007
[ http://blogs.msdn.com/sharepoint/archive/2006/08/16/702010.aspx ]
z
SharePoint Server 2007 Developer Portal
[ http://msdn2.microsoft.com/en-us/office/aa905503.aspx ]
z
How to Use ADFS to Turn MOSS 2007 into a Claims-Aware Application
[ http://blogs.msdn.com/sharepoint/archive/2007/02/15/how-to-use-adfs-to-turn-moss-2007-into-a-
claims-aware-application.aspx ]
z
Plan Authentication Settings for Web Applications in Office SharePoint Server
[ http://technet2.microsoft.com/Office/en-us/library/d3e0e0fc-77b6-4109-87d6-53ad088db01d1033.mspx?
mfr=true ]
z
How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI
[ http://msdn2.microsoft.com/en-
us/library/ms998280(printer).aspx ]
z
How To: Encrypt Configuration Sections in ASP.NET 2.0 Using RSA
[ http://msdn2.microsoft.com/en-
us/library/ms998283(printer).aspx ]
z
User Security Attributes
[ http://msdn2.microsoft.com/en-us/library/ms677943(printer).aspx ]
z
Office Developer Center
[ http://msdn.microsoft.com/office ]
z
Windows SharePoint Services Developer Center
[ http://msdn.microsoft.com/wss ]
Community Content
Strona 24 z 24
Forms Authentication in SharePoint Products and Technologies (Part 2): Members...
2008-02-22
http://msdn2.microsoft.com/en-us/library/bb975135(printer).aspx