Authentication Succeeds when Debugging but Fails on Azure App Service - c#

I am simply getting some users from SharePoint using CSOM using the below method. This has always worked for me and I've had no issues.
All of a sudden, when I try calling this method today it fails with this error
The sign-in name or password does not match one in the Microsoft account system.
at Microsoft.SharePoint.Client.Idcrl.IdcrlAuth.GetServiceToken(String securityXml, String serviceTarget, String servicePolicy)
at Microsoft.SharePoint.Client.Idcrl.IdcrlAuth.GetServiceToken(String username, String password, String serviceTarget, String servicePolicy)
at Microsoft.SharePoint.Client.Idcrl.SharePointOnlineAuthenticationProvider.GetAuthenticationCookie(Uri url, String username, SecureString password, Boolean alwaysThrowOnFailure, EventHandler`1 executingWebRequest)
at Microsoft.SharePoint.Client.SharePointOnlineCredentials.GetAuthenticationCookie(Uri url, Boolean refresh, Boolean alwaysThrowOnFailure)
at Microsoft.SharePoint.Client.ClientRuntimeContext.SetupRequestCredential(ClientRuntimeContext context, HttpWebRequest request)
at Microsoft.SharePoint.Client.SPWebRequestExecutor.GetRequestStream()
at Microsoft.SharePoint.Client.ClientContext.GetFormDigestInfoPrivate()
at Microsoft.SharePoint.Client.ClientContext.EnsureFormDigest()
at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery()
at SharePointLibrary.SPClient.GetAllUsers() in C:\Users\bassie\source\repos\TFS\ADVWKSP\SharePointLibrary\SPClientUsers.cs:line 39
But it only fails after publishing to Azure.
I have logged the username and password being used to the Azure applications streams, and they are definitely correct, and the same ones being used when debugging on my machine.
How is this possible? Am I going crazy?
Constructor
public SPClient(string url)
{
baseUrl = url;
var userName = ConfigurationManager.ConnectionStrings["SPsvcUsername"].ConnectionString;
var password = ConfigurationManager.ConnectionStrings["SPsvcPassword"].ConnectionString;
Trace.TraceInformation(userName);
Trace.TraceInformation(password);
var securePassword = new SecureString();
foreach (var c in password)
{
securePassword.AppendChar(c);
}
credentials = new SharePointOnlineCredentials(userName, securePassword);
}
Get Users method
public IEnumerable<SharePointUser> GetAllUsers()
{
var spUsers = new List<SharePointUser>();
using (var clientContext = new ClientContext(baseUrl))
{
clientContext.Credentials = credentials;
var web = clientContext.Web;
var list = clientContext.Web.SiteUserInfoList;
var users = list.GetItems(new CamlQuery());
clientContext.Load(users, includes => includes.Include(
f => f["GUID"],
f => f["FirstName"],
f => f["LastName"],
f => f["UserName"],
f => f["Picture"],
f => f.DisplayName));
clientContext.ExecuteQuery();
foreach (var user in users)
{
var imagePath = (FieldUrlValue)user.FieldValues["Picture"];
spUsers.Add(new SharePointUser()
{
FirstName = (user.FieldValues["FirstName"] is string firstName) ? firstName : string.Empty,
LastName = (user.FieldValues["LastName"] is string lastName) ? lastName : string.Empty,
UserName = (user.FieldValues["UserName"] is string userName) ? userName.ToLower() : string.Empty,
ImagePath = (user.FieldValues["Picture"] is FieldUrl pictureUrl) ? pictureUrl.ToString() : string.Empty,
DisplayName = user.DisplayName
});
}
}
return spUsers;
}

Since the credentials are correct, it may be that Multi-Factor Authentication is enabled and a policy may be triggering it for this account. If that is the case, you could disable MFA for that specific account.
Also, the AuthenticationManager class that is part of the PnP Core library may be beneficial as it is helpful for various authentication scenarios.

Related

Add Site Collection Admin using SharePoint CSOM and .Net 6

I'm struggeling to understand how to use SharePoint CSOM to add a user as Site Collection Admin.
So far this code works for a Global Admin to add a user as Site Colleciton Admin, eventhough the Global Admin is not included as Site Admin.
I've tried to run the code as normal user which is only Site Collection Admin, to add another user as Site Colleciton Admin. But then I get some errors:
If I use the SharePoint Admin URL to get the Access Token, then the code crash on row #48 as 401 "Unauthorized"
If I use the Site Collection URL to get the Access Token, I get error when trying to get the acces token saying that Site is doesn't exist on the environment.
If I use the root site URL ("https://domain-admin.sharepoint.com/) to get the Access Token, then the code crash on row #51 as 401 "Unauthorized".
I'm using the PnP.PowerShell code as reference: https://github.com/pnp/powershell/blob/dev/src/Commands/Admin/SetTenantSite.cs#L547-L574
And my process is pretty much the same as here: MSAL AD token not valid with SharePoint Online CSOM
But I don't have clear if it's a issue of access token or the CSOM commands I use.
Does anyone has any idea how to move forward?
btw, I guess if I use the Global Admin account I only need to use tenant.SetSiteAdmin(siteCollection, userEmail, true);. I read somewhere that even for global admin I need EnsureUser(userEmail);, but so far the code seems working without it.
using Microsoft.Identity.Client;
using Microsoft.SharePoint.Client;
namespace ScriptTester
{
internal class Program
{
static async Task Main(string[] args)
{
await AddUserAdmin();
}
public static async Task AddUserAdmin()
{
string siteAdmin = "https://domain-admin.sharepoint.com/";
string siteRoot = "https://domain.sharepoint.com/";
string siteCollection = "https://domain.sharepoint.com/sites/SiteName/";
string userEmail = "_email";
string accessToken = await GetAccessToken(siteRoot);
using (var context = new Microsoft.SharePoint.Client.ClientContext(siteRoot))
{
context.ExecutingWebRequest += (sender, e) =>
{
e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + accessToken;
};
var tenant = new Microsoft.Online.SharePoint.TenantAdministration.Tenant(context);
try
{
addLog("Try using tenant context");
tenant.SetSiteAdmin(siteCollection, userEmail, true);
tenant.Context.ExecuteQueryRetry();
}
catch (Exception ex)
{
addLog("Failed using Tenant context");
addLog(ex.Message);
using (var site = tenant.Context.Clone(siteCollection))
{
var user = site.Web.EnsureUser(userEmail);
user.Update();
user.IsSiteAdmin= true;
site.Load(user);
site.ExecuteQueryRetry();
tenant.SetSiteAdmin(siteCollection, userEmail, true);
tenant.Context.ExecuteQueryRetry();
}
}
}
}
public static async Task<string> GetAccessToken(string siteUrl)
{
string tenantId = "xxxx-xxxx-xxxx-xxxx-xxx";
string clientId = "xxxx-xxxx-xxxx-xxxx-xxx";
Uri authority = new Uri($"https://login.microsoftonline.com/{tenantId}");
string redirectUri = "http://localhost";
string defaultPermissions = siteUrl + "/.default";
string[] scopes = new string[] { defaultPermissions };
var app = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(authority)
.WithRedirectUri(redirectUri)
.Build();
AuthenticationResult result;
result = await app.AcquireTokenInteractive(scopes)
.WithUseEmbeddedWebView(false)
.ExecuteAsync();
return result.AccessToken;
}
}
}
I will recommend you to use PnP Core component to access site collection and add admin. Please refer to the following code
string siteUrl = "https://xxx.sharepoint.com/";
string userName = "xxxx#xxx.onmicrosoft.com";
string password = "*******";
AuthenticationManager authManager = new AuthenticationManager();
try
{
using (var clientContext = authManager.GetSharePointOnlineAuthenticatedContextTenant(siteUrl, userName, password))
{
List<UserEntity> admins = new List<UserEntity>();
UserEntity admin = new UserEntity();
admin.LoginName = "nirmal";
admins.Add(admin);
clientContext.Site.RootWeb.AddAdministrators(admins, true);
Console.WriteLine("User added as Site Collection Admin");
Console.ReadKey();
}
}
catch (Exception ex)
{
Console.WriteLine("Error Message: " + ex.Message);
Console.ReadKey();
}

Authenticate under user profile on SharePoint On-Premises with ADFS

I have some problems with ADFS authentication with c#. I got an application that should authenticate under some user profile on ShaprePoint On-Premises site. This site has ADFS authentication. I found some examples, but every time I got an error. And I don't know why. I am using OfficeDevPnP AuthenticationManager classes.
Here is code.
string webUrl = #"https://site.domain.com/";
string userName = "UserName";
string password = "password";
string domain = "site.domain.com";
string sts = "adfs.domain.com";
string idpld = clientIdpl;
OfficeDevPnP.Core.AuthenticationManager am = new OfficeDevPnP.Core.AuthenticationManager();
using (var ctx = am.GetADFSUserNameMixedAuthenticatedContext(webUrl, userName, password, domain, sts, idpld))
{
//Trying to load web element
Web web = ctx.Web;
ctx.Load(web, w => w.Title, w => w.ServerRelativeUrl, w => w.AlternateCssUrl);
ctx.ExecuteQueryRetry();
}
An error: Invalid URI: The format of the URI could not be determined.

Active Directory - Getting "The Server could not be contacted" Error

I'm trying to create a DLL that gets all the users from a certain OU group in Active Directory, but I'm getting this two errors:
System.DirectoryServices.AccountManagement.PrincipalServerDownException: The server could not be contacted. and
System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable.
My code is currently this:
public static void GetAllADUsers(string output, string filter, int mode) {
List<string> allUsers = new List<string>();
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "LDAP://mydomain.COM", filter);
UserPrincipal qbeUser = new UserPrincipal(ctx);
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
foreach (var found in srch.FindAll()) {
allUsers.Add(found.DisplayName);
}
if(mode == 1)
File.WriteAllText(output, allUsers.ToString());
else
File.AppendAllText(output, allUsers.ToString());
}
My input parameters are:
PCControl.PCC:GetAllADUsers("C:\temp\users.csv", "OU=Users,OU=...,OU=...,DC=mydomain,DC=com", 1).
I don't know if this helps, but I'm able to use this function into my DLL:
(That's where I got the PrincipalContext)
new DirectorySearcher(new DirectoryEntry("LDAP://mydomain.COM", user, password) {
AuthenticationType = AuthenticationTypes.Secure,
Username = user,
Password = password
}) {
Filter = "(objectclass=user)"
}.FindOne().Properties["displayname"][0].ToString();
Any sugestions on how I can fix this?

Microsoft.SharePoint.Client.IdcrlException: 'The sign-in name or password---' Even WITH Pnp Authentication Manager

I have signed up for the Office 365 Developer Edition with Microsoft 365 E5 Developer (without Windows and Audio Conferencing). I am writing codes to connect to the Sharepoint of developer domain. Following are my codes:
public static String GetList( ICredentials credentials)
{
var authManager = new OfficeDevPnP.Core.AuthenticationManager();
using (ClientContext clientContext =
authManager.GetWebLoginClientContext("https://xxx.sharepoint.com"))
{
clientContext.Credentials = credentials;
Web web = clientContext.Web;
clientContext.Load(web,
webSite => webSite.Title);
clientContext.ExecuteQuery();
return web.Title;
}
}
public string callSharepoint()
{
const string userName = "Username#domain.onmicrosoft.com";
const string password = "xxxx";
var securePassword = new SecureString();
foreach (var c in password)
{
securePassword.AppendChar(c);
}
var credentials = new SharePointOnlineCredentials(userName, securePassword);
var list = GetList(credentials);
return list.ToString();
}
While running, it first asks to enter Microsoft Office credentials, and then it does verification by sending code to contact number and then after verification is completed it throws an Exception on Line
clientContext.ExecuteQuery(). The Exception is as follow:
Microsoft.SharePoint.Client.IdcrlException: 'The sign-in name or password does not match one in the Microsoft account system.'
The credentials I am using is of Admin Account with role Global Administrator. I also tried to add new user account in that Active Directory and tried that credentials but still got the same exception on the same place.
I even try to remove Pnp Authorization, Enable and disable Multi factor Authorization, but no success. However, I can successfully log in into the Sharepoint site on browser by using exactly same credentials.
What I think is, there is most likely a problem in the setup which I did while setting office account developer subscription. And maybe nothing is wrong with the code because I used the same codes to log in to my organization's Sharepoint and it works perfectly fine. Maybe I need something else to be configured in my developer's Office Account.
Please let me know if anyone already has some knowledge about this problem.
You have init the credential so you could use it directly, if issue exists, should be related to your user account or license.
public static String GetList(ICredentials credentials)
{
//var authManager = new OfficeDevPnP.Core.AuthenticationManager();
//using (ClientContext clientContext =
//authManager.GetWebLoginClientContext("https://xxx.sharepoint.com/sites/lee"))
//{
//}
using (ClientContext clientContext = new ClientContext("https://xxx.sharepoint.com/sites/lee"))
{
clientContext.Credentials = credentials;
Web web = clientContext.Web;
clientContext.Load(web,
webSite => webSite.Title);
clientContext.ExecuteQuery();
return web.Title;
}
}
public string callSharepoint()
{
const string userName = "user#xxx.onmicrosoft.com";
const string password = "password";
var securePassword = new SecureString();
foreach (var c in password)
{
securePassword.AppendChar(c);
}
var credentials = new SharePointOnlineCredentials(userName, securePassword);
var list = GetList(credentials);
return list.ToString();
}
Ok I found the solution.
That is I don't need this line of code:
clientContext.Credentials = credentials;
Since MFA is enabled, so when I logged in via Pnp Authenticator, it should use that user account. Instead of the one which is passed via SharePointOnlineCredentials.

Getting SharePoint Site Title

I've having difficulty following this guide
http://dotnetbyexample.blogspot.co.uk/2011/03/sharepoint-client-object-model-sites.html
I've created the helper class as advised:
namespace TestSharepoint
{
public class SharepointHelper
{
private ClientContext clientContext;
private Web rootWeb;
public SharepointHelper(string url, string username, string password)
{
clientContext = new ClientContext(url);
var credentials = new NetworkCredential(username, password, "oshirowanen.com");
clientContext.Credentials = credentials;
rootWeb = clientContext.Web;
clientContext.Load(rootWeb);
}
}
}
However, I do not want to create another site, as I already have a site, so I wanted to test the next part by retrieving the existing sites title:
public Web GetWebByTitle(string siteTitle)
{
var query = clientContext.LoadQuery(
rootWeb.Webs.Where(p => p.Title == siteTitle));
clientContext.ExecuteQuery();
return query.FirstOrDefault();
}
and added this to the form load event:
var sh = new SharepointHelper("https://sharepoint.oshirowanen.com/sites/oshirodev/", "sharepoint_admin_user", "sharepoint_admin_password");
var w = sh.GetWebByTitle("Oshirowanen SharePoint");
Console.WriteLine(w.Title);
What I am getting confused about is, why I am typing in the title of the site which I want to receive the title of??? So I think I am not using this properly?
The error I get is:
An unhandled exception of type 'System.NullReferenceException' occurred in SharePointProgramming.exe
Additional information: Object reference not set to an instance of an object.
Any idea what I am doing wrong?
The username and password I have used has full SharePoint privileges.
I am using Visual Studio 2013, C#, .NET 4.0, and SharePoint 2010.
To fetch the title of the site your just need the value of the variable web.title.
namespace TestSharepoint
{
public class SharepointHelper
{
private ClientContext clientContext;
private Web rootWeb;
public SharepointHelper(string url, string username, string password)
{
clientContext = new ClientContext(url);
var credentials = new NetworkCredential(username, password, "oshirowanen.com");
clientContext.Credentials = credentials;
rootWeb = clientContext.Web;
clientContext.Load(rootWeb,web=>web.title);
clientContent.ExecuteQuery();
string siteTitle=web.title;
}
}
}

Categories

Resources