In Previous article we have seen how to configure the Form based authentication (FBA) for Claims Authentication.
Step 1: Create a new page CustomLoginPage.aspx under _Layouts Mapped Folder
As we have seen in our previous article, SharePoint provides two basic forms for Claims authentication by default.
- Stored at “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\IDENTITYMODEL\LOGIN\Default.aspx” : This displays the log on selector and provide options as windows or FBA in drop down list.
- Stored at “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\IDENTITYMODEL\FORMS\Default.aspx” : This is followed by the above form if user selects FBA as login option.
Create new CustomLoginPage.aspx and replace following html code. This code is taken 2nd file mentioned above to create our new custom login form. Here I tried to merge above two forms in one form by adding extra link below password to login using Windows Authentication.
Because of the below functionality if user is FBA user then he/she can directly enter the credentials and try to sing in. if he/she wishes to sign in using windows authentication then he/she can make use of “Windows Authentication” Link
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %> <%@ Assembly Name="Microsoft.SharePoint.IdentityModel, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%> <%@ Page Language="C#" Inherits="MyApplication.Layouts.CustomLoginPage" CodeBehind="CustomLoginPage.aspx.cs" MasterPageFile="~/_layouts/simple.master" %> <%@ Import Namespace="Microsoft.SharePoint.WebControls" %> <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import Namespace="Microsoft.SharePoint" %> <%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<asp:Content ContentPlaceHolderId="PlaceHolderPageTitle" runat="server"> <SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" Id="ClaimsFormsPageTitle" text="<%$Resources:wss, login_pagetitle%>"/> </asp:Content> <asp:Content ContentPlaceHolderId="PlaceHolderPageTitleInTitleArea" runat="server"> <SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" Id="ClaimsFormsPageTitleInTitleArea" text="<%$Resources:wss, login_pagetitle%>"/> </asp:Content> <asp:Content ContentPlaceHolderId="PlaceHolderSiteName" runat="server"/> <asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
<div id="divSignInControl" style="display:block" runat="server"> <div id="SslWarning" style="color:red;display:none"> <SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" Id="ClaimsFormsPageMessage" text="<%$Resources:wss,SSL_warning%>" /> </div> <script language="javascript" > if (document.location.protocol != 'https:') { var SslWarning = document.getElementById('SslWarning'); SslWarning.style.display = ''; } </script>
<asp:login id="signInControl" FailureText="<%$Resources:wss,login_pageFailureText%>" runat="server" width="100%" OnAuthenticate="signInControl_Authenticate"> <layouttemplate> <asp:label id="FailureText" class="ms-error" runat="server"/> <table width="100%"> <tr> <td nowrap="nowrap"><SharePoint:EncodedLiteral ID="EncodedLiteral1" runat="server" text="<%$Resources:wss,login_pageUserName%>" EncodeMethod='HtmlEncode'/></td> <td width="100%"><asp:textbox id="UserName" autocomplete="off" runat="server" class="ms-inputuserfield" width="99%" /></td> </tr> <tr> <td nowrap="nowrap"><SharePoint:EncodedLiteral ID="EncodedLiteral2" runat="server" text="<%$Resources:wss,login_pagePassword%>" EncodeMethod='HtmlEncode'/></td> <td width="100%"><asp:textbox id="password" TextMode="Password" autocomplete="off" runat="server" class="ms-inputuserfield" width="99%"/></td> </tr> <tr> <td colspan="2" align="right"><asp:button id="login" commandname="Login" text="<%$Resources:wss,login_pagetitle%>" runat="server" /></td> </tr> <tr> <td colspan="2"> <asp:label id="lblWindowsSignin" Text="Sign in automatically using" runat="server"/> <asp:LinkButton id="lnkWindowsAuth" Text="Windows Authentication" OnClick="lnkWindowsAuth_Click" runat="server"/> <%--<asp:checkbox id="RememberMe" text="<%$SPHtmlEncodedResources:wss,login_pageRememberMe%>" runat="server" />--%></td> </tr> </table> </layouttemplate> </asp:login> </div> </asp:Content> |
Step 2: Modify Code behind CustomLoginPage.aspx.cs for Authentication process
Derive the page class from “IdentityModelSignInPageBase”. This gives you freedom to develop the page freely in your custom format. Do not forget to include following namespaces
- Microsoft.SharePoint.IdentityModel.Pages
- Microsoft.SharePoint.IdentityModel
- System.IdentityModel.Tokens
to use above namespaces you need to add Microsoft.SharePoint.IdentityModel dll. in reference. This dll can be found at “C:\Windows\assembly\GAC_MSIL\Microsoft.SharePoint.IdentityModel\14.0.0.0__71e9bce111e9429c\Microsoft.SharePoint.IdentityModel.dll”.
using System; using Microsoft.SharePoint; using Microsoft.SharePoint.IdentityModel.Pages; using System.Web.UI.WebControls; using Microsoft.SharePoint.IdentityModel; using Microsoft.SharePoint.Utilities; using Microsoft.SharePoint.Administration; using System.IdentityModel.Tokens; using System.Web;
namespace MyApplication.Layouts { public partial class CustomLoginPage : IdentityModelSignInPageBase { protected void Page_Load(object sender, EventArgs e) { }
/// <summary> /// Establish the token /// </summary> /// <param name="securityToken"></param> private void EstablishSessionWithToken(SecurityToken securityToken) { if (null == securityToken) { throw new ArgumentNullException("securityToken"); } SPFederationAuthenticationModule fam = SPFederationAuthenticationModule.Current; if (null == fam) { throw new ArgumentException(null, "MyApplication Authentication Module"); }
fam.SetPrincipalAndWriteSessionToken(securityToken); }
/// <summary> /// Called after user is successfully logged in /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void signInControl_Authenticate(object sender, AuthenticateEventArgs e) { SecurityToken token = null; Login formsLoginControl = sender as Login; if (null != (token = GetSecurityToken(formsLoginControl.UserName, formsLoginControl.Password))) { EstablishSessionWithToken(token); e.Authenticated = true; base.RedirectToSuccessUrl(); } }
/// <summary> /// Get IIS Settings /// </summary> private SPIisSettings IisSettings { get {
SPWebApplication webApp = SPWebApplication.Lookup(new Uri(SPContext.Current.Web.Url)); SPIisSettings settings = webApp.IisSettings[SPUrlZone.Default]; return settings; } }
/// <summary> /// Get security Token /// </summary> /// <param name="formsLoginControl"></param> /// <returns></returns> private SecurityToken GetSecurityToken(string username, string password) { SecurityToken token = null; SPIisSettings iisSettings = IisSettings; Uri appliesTo = base.AppliesTo;
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) return null;
SPFormsAuthenticationProvider authProvider = iisSettings.FormsClaimsAuthenticationProvider; token = SPSecurityContext.SecurityTokenForFormsAuthentication( appliesTo, authProvider.MembershipProvider, authProvider.RoleProvider, username, password);
return token; }
/// <summary> /// Log on with Windows Authentication /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void lnkWindowsAuth_Click(object sender, EventArgs e) { string components = HttpContext.Current.Request.Url.GetComponents( UriComponents.Query, UriFormat.SafeUnescaped); SPUtility.Redirect("/_windows/default.aspx", SPRedirectFlags.Default, this.Context, components); } }
} |
Step 3: Create a feature to change Sign in Page for Web Application
We made our Custom Login Page. Since SharePoint still shows default sing in page and we can change that manually from Central Admin as well as through the feature.
To Change Sing in Page manually:
- Browse to Central Admin > Managed Web Application
- Select Web Application.
- Select “Authentication Provider“ button from Ribbon.
- Select “Default” Zone.
- Select “Custom Sign In Page” option in “Sign in Page” section.
- Add CustomLoginPage.aspx path to the textbox “/_layouts/MyApplication/CustomLoginPage.aspx”.
- Click on “OK” button to save.
- Close “Default” zone window.
- Visit the Web site to see changed effect.
To Change Sing in Page using Feature:
It is possible to change the Custom Sign in Page using feature activated/deactivated events.
- Create blank feature “CustomLoginPageSetting”
- Set Feature Scope as “WebApplication”
- “ApplyCustomSignInPage” & “RemoveCustomSigninPage” are methods which allows you to set/reset Login Custom Page.
- It is necessary to call Provision() method of Web Application to ensure the changes to get propagate to the configuration file & content database if necessary.
- Feature can be activated for particular Web Application in Central Admin.
using System; using System.Runtime.InteropServices; using System.Security.Permissions; using Microsoft.SharePoint; using Microsoft.SharePoint.Security; using Microsoft.SharePoint.Administration; using System.Reflection;
namespace MyApplication.Features.CustomLoginPageSetting { /// <summary> /// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade. /// </summary> /// <remarks> /// The GUID attached to this class may be used during packaging and should not be modified. /// </remarks>
[Guid("04b80854-ec00-4d09-ad7e-107179b9e3e1")] public class CustomLoginPageSettingEventReceiver : SPFeatureReceiver { const string CUSTOM_LOGIN_PAGE = "/_layouts/MyApplication/CustomLoginPage.aspx";
#region "Public methods" public override void FeatureActivated(SPFeatureReceiverProperties properties) { SPSecurity.RunWithElevatedPrivileges(delegate() { try { // Step1. Change the Default Sign in Page to Custom Sign In Page SPWebApplication webApp = properties.Feature.Parent as SPWebApplication; ApplyCustomSignInPage(webApp); } catch (Exception ex) { } }); }
/// <summary> /// Feature Deactivation /// </summary> /// <param name="properties"></param> public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { SPSecurity.RunWithElevatedPrivileges(delegate() { try { // Step1. Remove custom Sign in Page SPWebApplication webApp = properties.Feature.Parent as SPWebApplication; RemoveCustomSignInPage(webApp); } catch (Exception ex) { } }); } #endregion "Public methods"
#region "Private methods" /// <summary> /// Change the custom Sign In Page /// </summary> /// <param name="site"></param> private void ApplyCustomSignInPage(SPWebApplication webApp) { var iisSettings = webApp.GetIisSettingsWithFallback(SPUrlZone.Default); var signInUrlProperty = iisSettings.ClaimsAuthenticationRedirectionUrl;
// this works, because the protocol is included in the string Uri serverUri = new Uri(webApp.Sites[0].Url); // needs UriKind arg, or UriFormatException is thrown Uri relativeUri = new Uri(CUSTOM_LOGIN_PAGE, UriKind.Relative); // Uri(Uri, Uri) is the preferred constructor in this case Uri fullUri = new Uri(serverUri, relativeUri);
// update the custom Sign in page url to Custom Sign Page iisSettings.ClaimsAuthenticationRedirectionUrl = fullUri; webApp.Update(true); webApp.Provision(); }
/// <summary> /// Change the custom Sign In Page /// </summary> /// <param name="site"></param> private void RemoveCustomSignInPage(SPWebApplication webApp) { var iisSettings = webApp.GetIisSettingsWithFallback(SPUrlZone.Default); var signInUrlProperty = iisSettings.ClaimsAuthenticationRedirectionUrl;
// Reset to Default to Sign in Page iisSettings.ClaimsAuthenticationRedirectionUrl = null; webApp.Update(true); webApp.Provision(); } #endregion } } |
5 comments:
Nice blog. I regularly visit your blog to learn about SharePoint programming. In the above post you have explained the complete process to design a custom sign in page. Thanks for the details.
electronic signature for sharepoint
I tried implementing this with Sharepoint 2013. I changed the version of the assemblies.
I now get a http 403 forbidden when going to the site. It does not show the custom page.
How do I solve this?
Nice post, but i got this error
'stats.Layouts.login' is not allowed here because it does not extend class 'System.Web.UI.Page'.
I know that you extend the page to IdentityModelSignInPageBase
public partial class login : IdentityModelSignInPageBase
Wooh this is very informative article. Thank you so much..!
Rakesh
Please let me know how to create a Custom Login Page for a 0365 sharepoint site with Claims based authentication. We can not deploy any solution on Cloud so let me now if its possible to achieve using Sandbox
Post a Comment