Why is my List.GetUserEffectivePermissions() method not working? - c#

I'm developing a process in C# with the SharePoint 2013 Client Side Object Model. I need to retrieve the SharePoint List Permissions of a given user, that will be different than the user that is executing the code.
using SP = Microsoft.SharePoint.Client;
SP.ClientContext SpContext = new SP.ClientContext("SITEURL");
SP.Web SiteWeb = SpContext.Web;
SP.List Lst = SpContext.Web.Lists.GetByTitle("LIST");
var ClientUserEffPerms = Lst.GetUserEffectivePermissions(#"<domain>\<username>");
SpContext.Load(SiteWeb, S => S.EffectiveBasePermissions);
SpContext.Load(Lst, L => L.EffectiveBasePermissions);
SpContext.ExecuteQuery();
After this code executes, the ClientUserEffPerms.Value (BasePermissions) object does not represent the permissions of the given user correctly. The object isn't null, but it represents the user as having no permissions. The user has at minimum view and edit permissions and I can confirm this by viewing/editing List Items using the web browser as this user.
The code executing user has permission to enumerate permissions at both the Web and List level. I've confirmed this with the code below, both booleans resolve to true.
bool SvcUserHasSiteEnumPermsPerm = SiteWeb.EffectiveBasePermissions.Has(SP.PermissionKind.EnumeratePermissions);
bool SvcUserHasListEnumPermsPerm = Lst.EffectiveBasePermissions.Has(SP.PermissionKind.EnumeratePermissions);
Can anyone help me determine what is wrong with my GetUserEffectivePermissions() method?

When you call GetUserEffectivePermissions you need to pass in the full claims token version of the login name, which looks something like this:
i:0#.w|domain\user
You can get this by loading the LoginName property on a user object:
clientContext.Load(clientContext.Web.CurrentUser, i => i.LoginName);
clientContext.ExecuteQuery();
Of course, that's for the current user, so you'll need to acquire the user you actually want first.

Related

Can't Get All Users in a Role using built in methods

I am using the default ASP identity modelin my MVC application.
as per this post, I want to get a list of users which are in a role:
var users = Roles.GetUsersInRole("employee");
However, this always throws
The role 'employee' was not found.
Even though that role definitely does exist.
I can confirm this, as I am able to call :
User.IsInRole("employee")
For the current user, and this returns true.
I also noticed that these methods always return empty arrays:
var r = Roles.GetAllRoles();
var au = Membership.GetAllUsers();
Why is this?
I know I can get the roles by directly making calls to the database context, but why can't I use the built in methods?

Unable to get some user account information in UWP app - In-premise active directory (Not Azure AD)

In a UWP app, I have enabled the User Account Information capability.
I need to get the username and the domain name (each of them separately) of the currently logged on user (The users are logged on with an in-premise Active Directory account - Not Azure AD).
For example, the user would log in to the Active Directory domain domain1 using the username user1. i.e. domain1\user1.
I am using the following code to try to get the required details:
IReadOnlyList<User> users = await User.FindAllAsync();
var user = users.FirstOrDefault();
// get domain
var data1 = await user.GetPropertyAsync(KnownUserProperties.DomainName);
string strDomainName = (string)data1;
// get username
var data2 = await user.GetPropertyAsync(KnownUserProperties.AccountName);
string strUserName = (string)data2;
Issues:
strDomainName returns domain1.com\user1. Why does this include the .com part for all our domains? On c# winforms applications we can easily get domain1\user1 without any issue.
strUserName returns an empty string. i.e. "". Why does this not return any value?
I also checked the following:
KnownUserProperties.FirstName returns an empty string. i.e. ""
KnownUserProperties.LastName returns an empty string. i.e. ""
KnownUserProperties.PrincipalName returns an empty string. i.e. ""
KnownUserProperties.ProviderName returns an empty string. i.e. ""
KnownUserProperties.GuestHost returns an empty string. i.e. ""
Is there anything else I need to enable similar to the User Account Information capability? Or are there any other permissions that need to be granted to the app to get this information?
I understand that I can get the value of strDomainName and perform string functions to get what I need. But I want to know if there is any way to get this information directly. Also curious why KnownUserProperties.AccountName and other properties listed above such as FirstName, LastName etc. just returns an empty string.
I am running the following version of Windows:
I have the following set as the Target version and Min Version:
To verify, I also tested with the UserInfo sample project by Microsoft from GitHub and I got the following output:
The following was automatically enabled in Settings > Privacy > Account Info.
TestApp is the app I tried with and User Info C# Sample is the sample app from GitHub:
Update:
After also enabling the Enterprise Authentication capability, KnownUserProperties.PrincipalName does return the expected value. i.e. user1#domain1.com.
However, other properties listed above such as FirstName, LastName etc. just returns an empty string and I am still unable to find any property that returns domain1\user1 (without the .com part)
The Information you are trying to access are not reliable, as they (as you mentioned) do not have to be set and also they can be restricted access to via privacy settings in general.
I had a similar problem and would advise you to use the UWP OneDrive API
using Microsoft.OneDrive.Sdk;
and then request wl.basic scope. This scope contains at least a reliable username.
public static async Task<bool> GetAuthenticatedClient()
{
string oneDriveConsumerBaseUrl = "https://api.onedrive.com/v1.0";
var scopes = new List<string>
{
"wl.signin",
"wl.basic",
};
Task authTask;
var onlineIdAuthProvider = new OnlineIdAuthenticationProvider(scopes.ToArray());
authTask = onlineIdAuthProvider.RestoreMostRecentFromCacheOrAuthenticateUserAsync();
oneDriveClient = new OneDriveClient(oneDriveConsumerBaseUrl, onlineIdAuthProvider);
AuthProvider = onlineIdAuthProvider;
try
{
await authTask;
if (!AuthProvider.IsAuthenticated)
{
return false;
}
}
catch (ServiceException exception)
{
// Swallow the auth exception but write message for debugging.
//Debug.WriteLine(exception.Error.Message);
return false;
}
return true;
}
As for the domain, I'm not sure, but you could try to access it via Environment.UserDomainName like described on MSDN or with Windows.Networking.Connectivity.NetworkInformation.GetHostNames() like described here.
I found another possible solution to this. If you are still debugging this locally or the app was already installed on the target machine, I could enable the capabality User Account Information but this was not propagated to the actual installed app:
when your search for your app name in the start menu and then right click the entry and select App settings you get something like this:
As soon as I enabled the highlighted option (basically it says 'Account information') it worked.

Sharepoint Client Object Model edit Author and Editor fields

I'm trying to put the current user logged in my MVC 5 application (with windows authentication) into the Author and Editor fields of a new ListItem.
I didn't succeed to just pass the user credentials to the SharePoint Client context, so I tried to edit these two fields instead using SharePoint Client Object Model
using SP = Microsoft.SharePoint.Client;
...
SP.User SPuser = context.Web.EnsureUser(Request.LogonUserIdentity.Name);
//SP.User SPuser = context.Web.EnsureUser("mydomain\\someuser"); //same result as above
context.Load(SPuser);
context.ExecuteQuery();
SP.FieldUserValue userValue = new SP.FieldUserValue();
userValue.LookupId = SPuser.Id;
SP.ListItem documentLi = documentFile.ListItemAllFields;
...
//We don't want the application pool identity here, but the current user
documentLi["Author"] = userValue;
documentLi["Editor"] = userValue;
documentLi.Update();
context.ExecuteQuery();
It works fine in localhost, but nothing happens when I try it on the server : these two fields keeps the application pool identity.
What did I miss ?
I found what was the problem : in localhost the application pool identity is my user which has full control on the sharepoint list unlike the application pool identity in IIS (it just had contribute permission), it worked fine once I promoted it with full control as well.

Active Directory property "badPwdCount"

Problem:
We've upgraded the AD server from 2003 to 2008 and due to some "bad code", where developer has coded in such a way that, he directly casts "badPwdCount" property value to INT and it blows up because of NULL value conversion - NULL reference exception - NULL cannot be converted to INT.
Bigger problem:
We cannot do a deployment at this point because there are over 100 individual apps that depended on this change and we're looking for a least involved way of dealing with it for now.
Background:
Now the way this "badPwdCount" property works is, that when user logs on to the domain, it will get set to zero, otherwise it's NULL. The problem is that none of these users are ever going to log on interactively because they're external and we authenticate them via API and they cannot log in using the API either..
Question:
Does anyone know if this value is in the registry or somewhere, where I can get to it and set it to zero? Was also thinking of initiating a log in per user via a script, but wanted to gather other ideas too...
MSDN page for badPwdCount:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms675244(v=vs.85).aspx
Normally this would be easy, all you would need to do is update all the users in active directory and set the value to 0 if it is null. There are various ways you could do this, for example a script or code, or a bulk update tool.
In this case, badPwdCount is a special property that is not replicated (i.e. it is different for each domain controller) and so far as I can tell, there is no way to update it manually or by script, however, I think I have a solution for you.
You should be able to easily trigger a single failed login for every user in active directory against each domain controller, causing the value to be incremented.
Since you tagged your post with C#, here is some C# code that will do the trick for you:
using System.DirectoryServices.AccountManagement;
using System.DirectoryServices.ActiveDirectory;
...
using (Domain domain = Domain.GetComputerDomain())
{
foreach (DomainController domainController in domain.DomainControllers)
{
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domainController.Name))
using (UserPrincipal userPrincipal = new UserPrincipal(context))
using (PrincipalSearcher searcher = new PrincipalSearcher(userPrincipal))
using (PrincipalSearchResult<Principal> results = searcher.FindAll())
{
foreach (UserPrincipal user in results.OfType<UserPrincipal>())
{
context.ValidateCredentials(user.SamAccountName, "THEREISNOWAYTHISISTHECORRECTPASSWORD");
}
}
}
}
PS. If this screws up your AD I take no responsibility for it!

C# MVC4 windows username and cookie issues

First, I'm sad to say I'm not sure whether this code should be in the _Layout.cshtml or somewhere in the controller. It needs to run on all pages, so I've put it in the _Layout.cshtml page.
This is for an intranet web app. What I'm attempting to do is this: if a cookie (holding the user's userid) is not found, get the windows username, run it through a class that will go into the database and get the corresponding user's username, and - if we get a user id back - make a cookie containing it. Doesn't sound too hard, but one line in particular, and various incarnations of it, is refusing to be supportive. Here's the code as a whole.
if(!Context.Response.Cookies.AllKeys.Contains("userid")){
var winuser = System.Web.HttpContext.Current.User.Identity.Name;
var winuserid = myprojectname.Models.MyIntranetDataContext.getUserId(winuser).UserID();
if (winuserid == null) {
Response.Redirect("/someotherpage");
} else {
HttpCookie cookieuser = new HttpCookie("userid");
DateTime now = DateTime.Now;
cookieuser.Value = winuserid;
cookieuser.Expires = now.AddMonths(1);
Response.Cookies.Add(cookieuser);
}
}
Line 2 - var winuser... - appears to be the problem. In this current incarnation, I'm getting a build error: An object reference is required for the non-static field, method, or property 'myprojectname.Models.MyIntranetDataContext.getUserId(string)'
It doesn't like it when I add a .ToString to it either.
I've tried making winuser this as well:
Page.User.Identity.Name;
That gave no build errors. When I attempt to Start Debugging, she blows up with this beauty of an error: 'Cannot perform runtime binding on a null reference'
Once I get the windows username, all will be well.
Really, this isn't about cookies, or even mvc to much of an extent (except maybe guidance on where to put this code - the _Layout.cshtml?). Really it's about getting the windows username, which I seem unable to do. Thanks in advance for any assistance you are able to provide.
Note, the above names aren't actual - just for example only.
If they are on the domain, couldn't you use something like the following to retrieve that information?
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal principal = (WindowsPrincipal)Thread.CurrentPrincipal;
WindowsIdentity identity = (WindowsIdentity)principal.Identity;
String userName= principal.Identity.Name;

Categories