Problem with default site mapping

Oct 11, 2013 at 2:52 PM
I have successfully installed this, but I'm having a weird problem. Internally it works fine with the IP ranges I have mapped. Externally, everyone gets the forms-based login page (_forms/default.aspx). I want external users to get the default login page so they can choose between forms-based auth and Windows Auth. I followed the code here:
To set the default login page (the page that will be used if no IP match) use default as key value:
$config.SingInPageMappings.Add("default","<path>")
$config.Update()
This is the command I used:
$config.SingInPageMappings.Add("default","/_login/default.aspx")
$config.Update()
This is not working, something is appending an additional "_login/" to the URL and external users are being redirected to https://sharepoint.website.com/_login/_login/default.aspx. I have tried various combinations of mappings "default.aspx, /default.aspx, ./default.aspx) and then external users just get a page can not be displayed error. Can someone please tell me what I am doing wrong? Thanks!!
Nov 8, 2013 at 6:13 PM
I can't be the only person with this problem, can I??
Dec 11, 2013 at 9:05 PM
Nope. I'm having the exact same problem and have yet to find a solution. Have you had any luck?
Dec 12, 2013 at 2:33 AM
No, no luck yet.
May 14, 2014 at 1:25 AM
This appears to be an issue with the _login/default.aspx page redirecting back to the autoselect.aspx page. It's likely your configuration for the default login page is set up as "_login/autoselect.aspx" rather than "/_login/autoselect.aspx". This means that when the default.aspx page attempts to redirect, it appends on the extra "_login" segment.

However, this is only a symptom of the true cause since if you do configure your default login page with the preceding "/" you'll be stuck in an infinite loop (you can use Fiddler2 to see this in action). What I don't understand is how to prevent the default.aspx page from redirecting.
May 14, 2014 at 2:07 AM
FYI - I just figured out this issue:

After a bit of research, I figured out the issue causing the default code not to work. The issue is that we’re attempting to redirect to the default.aspx page when there is no match for the user’s IP address, however, after inspecting the code from the default.aspx page I found that the default.aspx page is redirecting back to our autoselect.aspx:
Uri claimsAuthenticationLoginRedirectionUrl = base.IisSettings.GetClaimsAuthenticationLoginRedirectionUrl(true);
if (null != claimsAuthenticationLoginRedirectionUrl) {
    string components = HttpContext.Current.Request.Url.GetComponents(UriComponents.Query, UriFormat.SafeUnescaped);
    SPUtility.Redirect(claimsAuthenticationLoginRedirectionUrl.ToString(), SPRedirectFlags.Default, this.Context, components);
}
The first line “GetClaimsAuthenticationLoginRedirectionUrl” gets the URL we set for the login page - in my case "/_login/autoselect.aspx". If that command returns a value, the user is then redirected to the page, otherwise the method returns and the current page (default.aspx) is rendered to the user.
May 24, 2014 at 11:20 PM
I knew it was a problem in the code because I've tried many URL combinations and none of them worked.
Oct 8, 2014 at 6:32 PM
I'm also seeing this issue, I see that mcandelo identified the issue, any clue on an acceptable fix or workaround? Thanks!
Oct 9, 2014 at 2:42 PM
My solution was to re-implement the login page functionality on the autoselect.aspx page. It was actually quite simple to do - just grab the default.aspx from the 14/15 hive and plug the controls into your custom login page. You'll also need to extend the class behind the login page and override the onload method. This way if the IP doesn't match any selection, you can just render the page (rather than redirect).
Oct 10, 2014 at 1:47 PM
Edited Oct 10, 2014 at 1:48 PM
MrClean asked me to post the code from my solution, so here it is below. Note there are references to some of the other classes in the project, but the bit of logic I've referred to is in the files below.

autoselect.aspx
<%@ 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"%>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharepointIdentity" Namespace="Microsoft.SharePoint.IdentityModel" Assembly="Microsoft.SharePoint.IdentityModel, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Page Language="C#" Inherits="Jornata.SharePoint.ProviderAutoSelect" MasterPageFile="~/_layouts/simple.master"  %>

<asp:Content ID="Content2" ContentPlaceHolderId="PlaceHolderPageTitle" runat="server">
    <SharePoint:EncodedLiteral runat="server"  EncodeMethod="HtmlEncode" Id="ClaimsLogonPageTitle" />
</asp:Content>

<asp:Content ID="Content3" ContentPlaceHolderId="PlaceHolderPageTitleInTitleArea" runat="server">
    <SharePoint:EncodedLiteral runat="server"  EncodeMethod="HtmlEncode" Id="ClaimsLogonPageTitleInTitleArea" />
</asp:Content>

<asp:Content ID="Content4" ContentPlaceHolderId="PlaceHolderSiteName" runat="server"/>

<asp:Content ID="Content1" ContentPlaceHolderId="PlaceHolderMain" runat="server">
    <SharePoint:EncodedLiteral runat="server"  EncodeMethod="HtmlEncode" Id="ClaimsLogonPageMessage" />
    <br />
    <br />
    <SharepointIdentity:LogonSelector ID="ClaimsLogonSelector" runat="server" />
</asp:Content>
ProviderAutoSelect.cs
namespace Jornata.SharePoint {
    public class ProviderAutoSelect : MultiLogonPage {
        public static Dictionary<string, Regex> wildcardMatchExpressions = new Dictionary<string, Regex>();

        protected override void OnLoad(EventArgs e) {
            if (SPContext.Current == null) return;
            if (SPContext.Current.Site == null) return;
            if (SPContext.Current.Site.WebApplication == null) return;

            SPWebApplication app = SPContext.Current.Site.WebApplication;

            AutoSelectConfiguration config = app.GetChild<AutoSelectConfiguration>("AutoSelectConfig");

            // TODO: needs some collection checking before using the indexer, to avoid KeyNotFoundException
            SPAlternateUrl u = app.AlternateUrls[Request.Url];
            SPUrlZone zone = u.UrlZone;

            string components = Request.Url.GetComponents(UriComponents.Query, UriFormat.SafeUnescaped);

            SPIisSettings settings = app.IisSettings.Values.First();

            string ip = IpNetworking.GetIP4Address();

            var signinPageMappings = config.SingInPageMappings;
            string targetProvider = this.GetMatchingProvider(ip, config);

            if (!string.IsNullOrEmpty(targetProvider)) {
                SPAuthenticationProvider provider = this.GetAuthProvider(targetProvider, settings);

                string url = provider.AuthenticationRedirectionUrl.ToString();
                if (signinPageMappings.ContainsKey(provider.DisplayName)) {
                    url = signinPageMappings[provider.DisplayName];
                }

                if (provider is SPWindowsAuthenticationProvider) {
                    components = EnsureReturnUrl(components);
                }

                SPUtility.Redirect(url, SPRedirectFlags.Default, this.Context, components);
            }

            this.ClaimsLogonPageTitle.Text = SPHttpUtility.NoEncode((string)HttpContext.GetGlobalResourceObject("wss", "login_pagetitle", Thread.CurrentThread.CurrentUICulture));
            this.ClaimsLogonPageTitleInTitleArea.Text = SPHttpUtility.NoEncode((string)HttpContext.GetGlobalResourceObject("wss", "login_pagetitle", Thread.CurrentThread.CurrentUICulture));
            this.ClaimsLogonPageMessage.Text = SPHttpUtility.NoEncode(SPResource.GetString("SelectAuthenticationMethod", new object[0]));
            this.ClaimsLogonSelector.Focus();
        }

        protected SPAuthenticationProvider GetAuthProvider(string targetProvider, SPIisSettings settings) {
            SPAuthenticationProvider returnValue = null;
            returnValue = settings.ClaimsAuthenticationProviders.FirstOrDefault((provider) => {
                return string.Compare(provider.DisplayName, targetProvider, StringComparison.CurrentCultureIgnoreCase) == 0 ||
                       string.Compare(provider.ClaimProviderName, targetProvider, StringComparison.CurrentCultureIgnoreCase) == 0;
            });
            if (returnValue == null) {
                throw new InvalidOperationException(string.Format("Could not find target provider {0}", targetProvider));
            }
            return returnValue;
        }

        protected string GetMatchingProvider(string clientIp, AutoSelectConfiguration config) {
            string returnValue = null;
            if (config != null) {
                KeyValuePair<string, string> mapping = config.ProviderMappings.FirstOrDefault((pair) => { return this.IpWildcardMatch(clientIp, pair.Key); });
                if (mapping.Value != null) {
                    returnValue = mapping.Value;
                }
            }
            return returnValue;
        }

        protected bool IpWildcardMatch(string clientIp, string wildcardIp) {
            Regex regex = ProviderAutoSelect.GetMatchExpression(wildcardIp);
            return regex.IsMatch(clientIp);
        }

        protected static Regex GetMatchExpression(string wildcardIp) {
            Regex returnValue;
            if (!ProviderAutoSelect.wildcardMatchExpressions.ContainsKey(wildcardIp)) {
                string expression = wildcardIp.Replace(".", @"\.").Replace("*", @"(2[0-4]\d|25[0-5]|[01]?\d\d?)");
                ProviderAutoSelect.wildcardMatchExpressions[wildcardIp] = new Regex(expression);
            }
            returnValue = ProviderAutoSelect.wildcardMatchExpressions[wildcardIp];
            return returnValue;
        }

        protected void Page_Load(object sender, EventArgs e) {
            System.Diagnostics.Debug.Write("wt");

        }

        private string EnsureReturnUrl(string queryString) {
            if (string.IsNullOrEmpty(queryString)) {
                queryString = "?";
            }
            if (!queryString.Contains("ReturnUrl=")) {
                if (!string.IsNullOrEmpty(queryString)) {
                    queryString = queryString + "&";
                }
                queryString = queryString + "ReturnUrl=/";
            }

            return queryString;
        }

    }
}
Best of luck!
Dec 8, 2015 at 9:51 AM
Hello,

I know this post is rather old, but is the solution that mcandelo provided the only solution for this issue?

Thanks for any help with this.

v/r
James Shidell