Is there a way to search profiles in MOSS from the object model? I need to search for profiles that have a certain value set on their profile and then perform some action for them.
I need to write some c# code that can search the profiles database and return the matching profiles. Basically,
List of Profiles = Select Profiles From Profile Store Where Profile Property Value = SomeValue
I'm trying to avoid the following:
private IEnumerable<UserProfile> SearchProfiles(string value) {
ServerContext serverContext = ServerContext.GetContext(SPContext.Current.Site);
UserProfileManager profileManager = new UserProfileManager(serverContext);
foreach (UserProfile profile in profileManager) {
if ((string)profile["MyProp"].Value == value) {
yield return profile;
}
}
}
This is possible using the FullTextSqlQuery class:
FullTextSqlQuery q = new FullTextSqlQuery(ServerContext.Current);
q.ResultTypes = ResultType.RelevantResults;
q.QueryText = "SELECT UserName, Email, PreferredName FROM SCOPE() WHERE \"scope\" = 'People' AND Department = 'IT'";
ResultTableCollection tables = q.Execute();
ResultTable results = tables[ResultType.RelevantResults];
This class allows you to query a specific scope (i.e. people) and filter them based on properties using the WHERE clause, which looks basically the same as a regular Sql Query.
To be able to search and filter on (custom) user profile properties, the profile property needs to have a mapping in the Shared Service Provider's metadata settings. Most out of the box user profile properties already have these, custom properties you have to add yourself.
More info on managed properties here.
Two things:
when running with elevated privileges we need to create a new SPSite object within the call and load the security context from there. DO NOT use the context obtained using SPContext.Current.Site.
Hence:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite("<your site url>"))
{
ServerContext context = ServerContext.GetContext(site);
UserProfileManager profileManager = new
UserProfileManager(context);
foreach (UserProfile profile in profileManager)
{
// your code
}
}
}
make sure that the app pool account has appropriate user permissions in SSP. i.e. (use personal features, manage user profiles)
Related
TFS 2012 and later as well as VSTS have a concept of a Team Administrator. I've looked all over the API for a simple way to set and retrieve the value through code to make it easier to provision these settings, but could not find it.
Reflectoring through the Server Object Model for the web UI gives hints for how to do it, but it relies on a number of private methods to get this done. Especially the part that calculates the Security Scope Token is hidden magic.
It took quite a bit of digging to find this old blogpost from 2013 which details how to do this, and I don't seem to be the only person who got stumped by the private methods. In the end they also ended up using Reflection to call the private method to retrieve the token:
This functionality is now available through the TFS Team Tools:
TFS Team Tools
Retrieve
Find the security group matching the team, use it to calculate the team's token, get the people who are part of that special security namespace:
public List<string> ListTeamAdministrators(string team, out string message)
{
// Retrieve the default team.
TeamFoundationTeam t = this.teamService.ReadTeam(this.projectInfo.Uri, team, null);
List<string> lst = null;
message = "";
if (t == null)
{
message = "Team [" + team + "] not found";
}
else
{
// Get security namespace for the project collection.
ISecurityService securityService = this.teamProjectCollection.GetService<ISecurityService>();
SecurityNamespace securityNamespace =
securityService.GetSecurityNamespace(FrameworkSecurity.IdentitiesNamespaceId);
// Use reflection to retrieve a security token for the team.
var token = GetTeamAdminstratorsToken(t);
// Retrieve an ACL object for all the team members.
var allMembers = t.GetMembers(this.teamProjectCollection, MembershipQuery.Expanded)
.ToArray();
AccessControlList acl =
securityNamespace.QueryAccessControlList(token, allMembers.Select(m => m.Descriptor), true);
// Retrieve the team administrator SIDs by querying the ACL entries.
var entries = acl.AccessControlEntries;
var admins = entries.Where(e => (e.Allow & 15) == 15).Select(e => e.Descriptor.Identifier);
// Finally, retrieve the actual TeamFoundationIdentity objects from the SIDs.
var adminIdentities = allMembers.Where(m => admins.Contains(m.Descriptor.Identifier));
lst = adminIdentities.Select(i => i.DisplayName).ToList();
}
return lst;
}
private static string GetTeamAdminstratorsToken(TeamFoundationTeam team)
{
return IdentityHelper.CreateSecurityToken(team.Identity);
}
Set
Setting works in a similar fashion. Grab the token and then add the users unique identifier to the Access Control List:
IdentityDescriptor descriptor = GetMemberDescriptor(memberId);
securityNamespace.SetPermissions(token, descriptor, 15, 0, false);
Remove
And removing a person from the list is then, of course, easy to guess;
IdentityDescriptor descriptor = GetMemberDescriptor(memberId);
securityNamespace.RemovePermissions(token, descriptor, 15);
I need to check if a user (who is connected to a Project Collection) is a member of the administrators group of the Project Collection or not. Also, I need to do the same for a Project.
I need the most correct way of doing so.
Currently I am using the following method, but I'm not sure if it is the perfect way.
//Get the IdentityManagementService from the Project Collection
IIdentityManagementService LIdentityService = (IIdentityManagementService)ProjectCollection.GetService(typeof(IIdentityManagementService));
//Search for user identity by user name
TeamFoundationIdentity LUserIdentity = LIdentityService.ReadIdentity(IdentitySearchFactor.AccountName, {Username}, MembershipQuery.Expanded, ReadIdentityOptions.None);
//Get Guid of the same Project Collection to use as scope
String Id = ProjectCollection.InstanceId.ToString();
//Get the Administrators group for Project Collection scope *
TeamFoundationIdentity LAdminIdentity = LIdentityService.ReadIdentity(IdentitySearchFactor.AdministratorsGroup, Id, MembershipQuery.Expanded, ReadIdentityOptions.None);
IsAdmin = false;
//Traverse through the groups of the user and check if administrators group is also one of them
foreach (IdentityDescriptor member in LUserIdentity.MemberOf)
{
if (member.Identifier.Equals(LAdminIdentity.Descriptor.Identifier, StringComparison.CurrentCultureIgnoreCase))
IsAdmin = true;
}
This works fine on one setup but on another setup of Team Foundation Server it gives the following error while getting the administrators group.
"The Team Foundation Identity Scope {Guid of the project collection} does not exist."
I have web application that uses the Authorize attribute with roles specified to restrict access to some pages:
[Authorize(Roles = "AD_group1, AD_group2")]
The question is - is there any way I can get some kind of an Active Directory groupId for authorized user (no matter int or string)?
upd:
Basic idea is to store some table in database, containing templates which should be separate for every group. e.g. users in group1 can have some templates for fast answer to typical questions while group2 doesn't have any of them, or have some other templates
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");
// or if you want the currently logged in user - you can also use:
// UserPrincipal user = UserPrincipal.Current;
if(user != null)
{
// get all groups the user is a member of
foreach(GroupPrincipal group in user.GetAuthorizationGroups())
{
string distinguishedName = group.DistinguishedName;
Guid groupGuid = group.Guid;
}
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
In Umbraco 4.11 using the default member provider, is it possible to access the profile of a user who is not logged in?
I've added the custom profile properties to the web.config, added the same props on the MemberType in the back office and I'm creating the profile by doing this:
MembershipUser member = System.Web.Security.Membership.CreateUser(username, password, email);
var profile = System.Web.Profile.ProfileBase.Create(member.UserName);
profile["FirstName"] = "John";
profile.Save();
I can get the current logged in users profile by doing this:
var currentUser = umbraco.cms.businesslogic.member.Member.GetCurrentMember();
But how do I get the profile of a user who is not logged in?
eg. I tried:
var profile = System.Web.Profile.ProfileManager.FindProfilesByUserName(System.Web.Profile.ProfileAuthenticationOption.All, username);
But this results in a "Specified Method Not Supported" exception.
This will be used in an admin service which performs a periodic sync with an external provider so there will be no user context.
You use ProfileBase.Create() again. Don't worry, it doesn't actually "create" the profile again.
var profile = ProfileBase.Create(username);
string firstName = profile["FirstName"];
For more information, refer to:
How to get another user's profile in ASP.NET MVC?
Membership providers
I am trying to update the profiles of users in my SSP Application and I have 10000 records. Most of them are being updated for the first time and there are 21 records which are getting updated everytime I run the code.
I don't know why this is happening..
Could any body help me what's happening with my code.
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPSite sc = new SPSite("http://xxxxx:81");
ServerContext context = ServerContext.GetContext(sc);
HttpContext currentContext = HttpContext.Current;
HttpContext.Current = null;
UserProfileManager profileManager = new UserProfileManager(context);
foreach (UserProfile profile in profileManager)
{
if (profile[PropertyConstants.PreferredName].ToString().Contains("Domain\\"))
{
profile[PropertyConstants.PreferredName].ToString().Replace("Domain\\", "").ToString();
profile.Commit();
NoOfUser++;
}
}
Thank You
Hari Gillala
NHS Direct
You are aware that there is a user profile import option in the SSP already are you? If you import AD properties only, use that. Only create a timerjob when the profile data is coming from another source. If there are any non-standard properties in AD, you can map those too by creating new profile properties and defining which AD property they map to.