Question

J'ai trouvé la solution

La solution consistait à ajouter une collection de sites racine (car le code s'exécutait dans un sous-site, sans site racine).

Voir Cette solution


Mise à jour importante (basé sur les commentaires reçus jusqu'à présent)

Je n'ai pas Visual Studio installé sur le serveur SharePoint 2013.Tout le code est compilé à distance dans Visual Studio 2012 à l'aide de références aux DLL SharePoint 2013 requises et signé numériquement afin qu'il puisse être déployé dans le Global Assembly Cache sur le serveur SharePoint 2013.

Au niveau le plus élémentaire, cette affirmation échoue au point de Page_Load();

SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(
  SPContext.Current.Site.Zone
);

Parce que SPContext.Current est toujours null.

Arrière-plan

Le client a besoin que le site SharePoint soit accessible à l'aide de l'authentification par formulaire pour les utilisateurs externes et de l'authentification Windows pour les utilisateurs internes (entreprise).J'ai parcouru et configuré les deux fournisseurs d'authentification et obtenez maintenant la connexion par défaut.

Sign In

Bien que tout fonctionne, l'authentification Windows affiche toujours l'écran de sélection du fournisseur lorsque le client souhaite que l'authentification Windows passe automatiquement et affiche un écran de connexion d'authentification basée sur des formulaires en cas d'échec.

J'ai du mal avec cela depuis des jours, après avoir consulté divers blogs et articles, j'ai l'impression que je ne suis pas plus avancé et c'est déprimant.Pour le moment, je ne peux pas m'entraîner pour savoir s'il me manque quelque chose de vraiment fondamental.

Page de connexion personnalisée

La page est basée sur une fusion de ;

  1. %CommonProgramFiles%\Microsoft Shared\Web Server Extensions\15\Template\IdentityModel\Login\default.aspx
  2. %CommonProgramFiles%\Microsoft Shared\Web Server Extensions\15\Template\IdentityModel\Forms\default.aspx

Ce n'est qu'une première tentative et je réalise que je n'aurai finalement pas besoin de tous ces contrôles, je voulais juste voir comment les choses s'articulent.

Assemblage MyCustomSignInModule

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using Microsoft.IdentityModel.Web;
using Microsoft.SharePoint;
using Microsoft.SharePoint.IdentityModel;
using Microsoft.SharePoint.IdentityModel.Pages;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Claims;
using Microsoft.SharePoint.ApplicationRuntime;
using Microsoft.SharePoint.Diagnostics;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;
using System.IdentityModel.Tokens;
using System.Web.Configuration;

namespace MyCustomSignInModule
{
    public class SignInForm : FormsSignInPage
    {
        protected Label DebugText;

        private static SPIisSettings _iisSettings;

        internal static SPIisSettings iisSettings
        {
            get
            {
                if (_iisSettings == null)
                {
                    SPSecurity.RunWithElevatedPrivileges(delegate()
                    {
                        _iisSettings = SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(SPContext.Current.Site.Zone);
                    });
                }
                return _iisSettings;
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            HttpRequest request = HttpContext.Current.Request;

            bool isWindowsAuth = false;
            string username = request["username"];
            string password = request["password"];


            // If no username is provided, it'll probably be Windows Authentication (NTLMv2 protocol)
            if (String.IsNullOrEmpty(username))
            {
                isWindowsAuth = true;
            }

            try
            {

                //SPIisSettings iisSettings = SPContext.Current.Site.WebApplication.IisSettings[SPUrlZone.Default];

                if (isWindowsAuth)
                {
                    // Windows Authentication it is

                    if (iisSettings.UseWindowsClaimsAuthenticationProvider)
                    {
                        SPAuthenticationProvider provider = iisSettings.WindowsClaimsAuthenticationProvider;
                        RedirectToLoginPage(provider); // This should cause automatic sign in
                    }
                }
                else
                {
                    // FBA authentication it is.

                    SPFormsAuthenticationProvider formsClaimsAuthenticationProvider = iisSettings.FormsClaimsAuthenticationProvider;

                    SecurityToken token = SPSecurityContext.SecurityTokenForFormsAuthentication(new Uri(SPContext.Current.Web.Url), formsClaimsAuthenticationProvider.MembershipProvider, formsClaimsAuthenticationProvider.RoleProvider, username, password, SPFormsAuthenticationOption.PersistentSignInRequest);

                    if (null != token)
                    {
                        EstablishSessionWithToken(token);
                        base.RedirectToSuccessUrl();
                    }
                }
            }
            catch (Exception ex)
            {
                DebugText.Text = ex.ToString();
            }

        }

        // Microsoft.SharePoint.IdentityModel.LogonSelector
        private void RedirectToLoginPage(SPAuthenticationProvider provider)
        {
            string components = HttpContext.Current.Request.Url.GetComponents(UriComponents.Query, UriFormat.SafeUnescaped);
            string url = provider.AuthenticationRedirectionUrl.ToString();
            if (provider is SPWindowsAuthenticationProvider)
            {
                components = EnsureUrlSkipsFormsAuthModuleRedirection(components, true);
            }
            SPUtility.Redirect(url, SPRedirectFlags.Default, this.Context, components);
        }

        // Microsoft.SharePoint.Utilities.SPUtility
        private string EnsureUrlSkipsFormsAuthModuleRedirection
            (string url, bool urlIsQueryStringOnly)
        {
            if (!url.Contains("ReturnUrl="))
            {
                if (urlIsQueryStringOnly)
                {
                    url = url + (string.IsNullOrEmpty(url) ? "" : "&");
                }
                else
                {
                    url = url + ((url.IndexOf('?') == -1) ? "?" : "&");
                }
                url = url + "ReturnUrl=";
            }
            return url;
        }

        // Microsoft.SharePoint.IdentityModel.Pages.IdentityModelSignInPageBase
        private void EstablishSessionWithToken(SecurityToken securityToken)
        {
            if (securityToken == null)
            {
                throw new ArgumentNullException("securityToken");
            }
            SPFederationAuthenticationModule fam = SPFederationAuthenticationModule.Current;
            if (fam == null)
            {
                throw new InvalidOperationException();
            }

            fam.SetPrincipalAndWriteSessionToken(securityToken);
        }

        private SPAuthenticationProvider
                GetAuthenticationProvider(string providerName)
        {
            SPIisSettings iisSettings =
                SPContext.Current.Site.WebApplication.IisSettings[SPUrlZone.Default];

            foreach (SPAuthenticationProvider currentProvider in
                        iisSettings.ClaimsAuthenticationProviders)
            {
                if (currentProvider.DisplayName.ToLower() ==
                            providerName.ToLower())
                {
                    return currentProvider;
                }
            }

            return null;
        }
    }
}

Le processus

J'ai une instance de test Sharepoint exécutée sur la VM mais aucun Visual Studio n'est installé car tout le développement est effectué à distance.Le processus actuel que je suis ;

  1. Construire une bibliothèque de classes C# (ce sera MyCustomSignInModule.Dll)
  2. Signe MyCustomSignInModule.Dll afin qu'il puisse être placé dans le VM GAC.
  3. Registre MyCustomSignInModule.Dll dans le GAC sur l'instance de VM.
  4. Sauvegarder SignInForm.aspx dans le %CommonProgramFiles%\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\ ce qui est l'équivalent de <SharePointSiteRoot>/_layouts/ répertoire virtuel dans IIS.
  5. Dans le site d'administration centrale de SharePoint, définissez la page de connexion personnalisée sur ma page. ~/_layouts/SignInForm.aspx.
  6. Réinitialiser IIS en utilisant iisreset.
  7. Testez l'accès au site SharePoint (c'est là que ça tombe).

Le problème

Sign In Error

Si ce n'est pas si clair, l'erreur est la suivante :

System.NullReferenceException: Object reference not set to an instance of an object. at
MyCustomSignInModule.SignInForm.b__0() at 
Microsoft.SharePoint.SPSecurity.<>c__DisplayClass5.b__3() at
Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode) at 
Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(WaitCallback secureCode, Object param) at 
Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(CodeToRunElevated secureCode) at MyCustomSignInModule.SignInForm.get_iisSettings() at 
MyCustomSignInModule.SignInForm.Page_Load(Object sender, EventArgs e) 

SPContext.Current est nul pourquoi ?

Le NullReferenceException est causé par SPContext.Current étant nul, mais je ne peux pas comprendre pourquoi il est nul et aucun nombre d'articles que j'ai consultés jusqu'à présent ne m'a aidé à résoudre ce problème.J'espère qu'en publiant l'ensemble de mon processus ici, quelqu'un pourra m'indiquer ce qui me manque ou ce qui ne va pas.

Était-ce utile?

La solution

Je suis enfin allé au fond de la cause du problème, je voudrais tout d'abord remercier les deux @MdMazzotti et @Hugh Wood pour leur aide constante.

En fin de compte, je suis tombé sur le correctif qui s'est avéré être en partie dû à la façon dont le site a été construit.Dans mon cas particulier, le site a été construit en tant que sous-site dans SharePoint. Pour une raison quelconque, cela signifiait qu'il n'y avait pas de collection de sites à la racine du site Web SharePoint, ce qui était à l'origine du problème. Null SPContext dans mon code.

Après avoir ajouté une collection de sites racine, mon code a commencé à fonctionner comme prévu.

Autres conseils

Je ne fais que deviner, mais voici quelques éléments qui, je pense, pourraient aider.

Ajoutez ce code JavaScript à la page de connexion personnalisée (avant votre instruction if) :

SP.SOD.executeFunc('SP.js', 'SP.ClientContext');

Vous pouvez également ajouter ce JavaScript à votre page pour tester s'il fonctionne ou non, en utilisant la console :

var clientContext = new  SP.ClientContext.get_current(); 
console.log(clientContext);

Si cela renvoie quelque chose, alors nous avons progressé !Sinon, je devrai poursuivre mes recherches, car je trouve votre question intéressante.

MODIFIER

Au lieu d'utiliser ce code côté serveur :

if (_iisSettings == null)
{
   SPSecurity.RunWithElevatedPrivileges(delegate()
   {
      _iisSettings = SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(SPContext.Current.Site.Zone);
   });
}
return _iisSettings;

Essayez plutôt d'utiliser ceci :

if (_iisSettings == null)
{
   SPSecurity.RunWithElevatedPrivileges(delegate()
   {
      _iisSettings = Microsoft.SharePoint.SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(Microsoft.SharePoint.SPContext.Current.Site.Zone);
   });
}
return _iisSettings;

J'ai cherché et remarqué que dans certains des exemples de code que j'ai rencontrés, _iisSettings était différent du vôtre.C'est peut-être pour cela que votre SPContext.Current est nul ?

Veuillez vérifier cette réponse :https://stackoverflow.com/questions/5081251/how-can-this-throw-a-nullreferenceexception

SPContext.Current ne fonctionne pas sous privilèges élevés, vous devez donc réécrire comme dans la réponse ci-dessus.

Pouvez-vous consulter cet article MSDN : http://msdn.microsoft.com/en-us/library/office/ms468609(v=office.14).aspx

Je pense que parce que vous utilisez un projet de bibliothèque de classes C# dans Visual Studio, vous n'êtes pas dans un contexte Web et ne pouvez pas utiliser SPContext.Current comme expliqué dans l'article MSDN ci-dessus.

Licencié sous: CC-BY-SA avec attribution
Non affilié à sharepoint.stackexchange
scroll top