Change VSO user's sign-in address - azure-active-directory

We have a Visual Studio Online account that is backed by an Azure Directory (that is synced from an on-premise Active Directory). For a variety of reasons I won't go into:
Originally the Azure Directory was synced with accounts in the form "joebloggs#ourdomain.com" (i.e without a dot in the name part).
VSO invites were sent out to users, using that dot-less form of their address, and we've been using VSO quite happily for a number of months.
Our infrastructure team now want to use the dotted version of the directory names, so "joe.bloggs#ourdomain.com", within our Azure Directory.
I am trying to find a way to change the sign-in address of all our existing VSO users to be a dotted version of their name. I have been trying to use the 'Microsoft.VisualStudio.Services.Identity.Client' libraries to make these changes with code like the following:
using Microsoft.TeamFoundation;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.VisualStudio.Services.Client;
using Microsoft.VisualStudio.Services.Identity;
using Microsoft.VisualStudio.Services.Identity.Client;
public static void Main(string[] args)
{
UpdateUser();
}
private static void UpdateUser()
{
var vssAccountUrl = "https://ourVssAccount.vssps.visualstudio.com/";
var creds = new VssClientCredentials(false);
var vssConnection = new VssConnection(new Uri(vssAccountUrl), creds);
var identityClient = vssConnection.GetClient<IdentityHttpClient>();
var user = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.DisplayName, "Joe Bloggs").Result.FirstOrDefault();
user.SetProperty("Account", "joe.bloggs#rspb.org.uk");
user.SetProperty("Mail", "joe.bloggs#rspb.org.uk");
var t = identityClient.UpdateIdentityAsync(user, null).Result;
Console.Write(user);
}
The call to create a new connection produces a prompt for me to sign in, which I do. I am an admin in the VSO. The call to UpdateIdentityAsync though produces the following exception:
{"Access Denied: Mashton needs the following permission(s) to perform this action: Edit collection-level information"}
Checking my specific permissions within VSO I do have these permissions, as I am an admin for the entire Team Found Server.
Is the exception misleading: does it really need permissions somewhere else?
What is the accepted way to change the sign-in address associated with a VSO user?

Do all dot-less form address have been changed to dotted version of the directory names in your Azure Directory? If the address have been changed in your Azure Directory, you can:
1.Disconnect your account from the directory.
2.Reconnect your account to the directory that you want.
Detailed steps you can refer to https://www.visualstudio.com/get-started/setup/manage-organization-access-for-your-account-vs

Related

Accessing user details using Active Directory in an ASP.NET Core MVC app with Windows authentication

I was trying to access user information like first name, last name of the user in my ASP.NET Core MVC project with Windows authentication. I actually make it work after searching for a solution on the web but I am quite new to this stuff and beginner level programmer so not understanding what is happening in the part that I just copy paste in my project.
I couldn't find any explanation in that website as well. I would be really happy if someone can explain this to me. Many thanks in advance.
The website reference for this code: https://sensibledev.com/how-to-get-user-details-from-active-directory/
Home controller:
var username = User.Identity.Name;
using (var context = new PrincipalContext(ContextType.Domain, "yourdomain"))
{
var user = UserPrincipal.FindByIdentity(context, username);
if (user != null)
{
ViewData["UserName"] = user.Name;
ViewData["EmailAddress"] = user.EmailAddress;
ViewData["FullName"] = user.DisplayName;
ViewData["GivenName"] = user.GivenName;
}
}
That code takes the username of the user who logged into your website and looks it up on your domain to find more information about the person.
var username = User.Identity.Name;
The User property is ControllerBase.User, which refers to the user currently logged into your website. Since you're using Windows Authentication, this will refer to an Active Directory user. User.Identity.Name gets just the username.
The rest is for looking up the account in Active Directory.
new PrincipalContext(ContextType.Domain, "yourdomain")
This means "I want to talk to a domain called yourdomain".
UserPrincipal.FindByIdentity(context, username)
UserPrincipal.FindByIdentity finds an account on the domain. So this is saying "find this username on the domain".
Then the users details from the account are put into the ViewData collection so that the data is accessible in the view. More details on that here.
From your website's perspective, all Windows code runs under some Windows account.
If you use IIS and Forms authentication for example, then Windows knows nothing about you - you are likely to be running under an anonymous account name which all users will run under. If you drill down through your running code, it is possible to find different Windows accounts at different code levels, such as in your top level code, the underlying IIS thread, etc.
You are trying to use Windows accounts for your web site but you have to ensure that the web server it is running on is also using Windows Authentication - I know you checked this option when creating your site.
Your user identity can be cast to various types because it has to work seamlessly whichever authentication methodology is in use. You can also check your user to see if it is of a particular security regime.
Have a look at https://learn.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.1&tabs=visual-studio
You get the security principle information using
var context = new PrincipalContext(ContextType.Domain, "yourdomain")
PrincipleContext is the class that has the information once you create a new instance of it, passing in parameters for the type of domain (an enumeration) and the name of your domain (a string).
The USING block ensures that the instance is disposed once the block completes - otherwise you have to call DISPOSE on that instance yourself (remember if there is an exception you might not have captured this so you will at least have to manage this scenario.
Once you have an instance of of your domain context you can use it to search (in the case of Windows, the LDAP database) for users, whether by SID or unique name, in your case (every name must be unique - two users in the domain cannot have the same name).
The website has the security ID of the user, the code you are following gets a Domain object for that user which has the properties you will display. You could call other objects that might tell you which Windows Security Groups the user is a member off. In that way you can have a web site where a users ability to view a web page or click a button is down to which Groups in the Domain the user is a member of.

Change User Name In Azure Active Directory

I have an Azure Active Directory (AAD) set up in my Azure subscription associated with an email address of mine, which we'll call A.
Some time later, I updated my Microsoft Account to use a new email address B as the primary email address, with A being associated with it still so it can still be used and the two email addresses treated as being one.
In AAD there is one user, whose user Id is A which appears not to be able to be changed as it is greyed-out. Attempting to add B fails with the error: You cannot add yourself.
Is there a way I can force the user name of the AAD user to be B instead of A?
The reason I ask is because I am trying to setup an Azure Key Vault in my subscription as it appears to be failing because whether or not I sign in as A or B in Azure Powershell, I am always signed in as B. This then causes this error message, which I appear to be unable to work around:
New-AzureKeyVault : Cannot find the Active Directory object 'B' in tenant
'{Tenant Id}'. Please make sure that the user or application service principal you are
authorizing is registered in the current subscription's Azure Active directory. The TenantID displayed by the cmdlet
'get-AzureSubscription -current' is the current subscription's Azure Active directory.
Can you check that you are using the latest bits for Key Vault PowerShell?
I talked with some folks internally and we believe that an experience like this may be expected if you are using an older version of the PowerShell CMDLETs, but the lastest version should be update to date and not run into the issue you are having.
If you find that you still hit this issue after upgrading, we may have a bug on our side that we should fix.
In that case, my suggestion is for you to create a new Admin User. Then delete the old Admin Account (you may need to Transfer Onwership of your AAD Subscription to the new Admin), and then recreate your account, which will pull the lastest information from that user.
However, I only reccommend trying this after having updated the PowerShell bits.
Please let us know if either of these methods resolves your issues.
Thanks,
Shawn Tabrizi

How can an ASP.NET website authorize using Active Directory Groups without login prompts?

I want to build an intranet website that doesn't login-prompt a user that is already logged in to the AD (on a company computer in the same domain as the IIS server). So far, all my attempts have resulted in a basic login prompt or not being able to read HttpContext.User.Identity.Name. The User object would then be used to check if that user is a member of a certain Active Directory group in the domain.
I've seen different solutions that require the user to add a Trusted site in the browser or registry edits. That is not what the product owner would like. Would it be possible to create a completely automatic experience (the user would have had to log in to their computer anyway)?
MyAuthorizeAttribute
The code below is found inside my custom AuthorizeAttribute that is put on the index method of my home controller. This shouldn't matter though, because it works once there is a User object and the controller is called. Users that are members of the group will continue to the start page, others wont.
PrincipalContext context = new PrincipalContext(ContextType.Domain, "<domain name>");
UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(context, httpContext.User.Identity.Name);
if (userPrincipal != null)
{
if (userPrincipal.IsMemberOf(context, IdentityType.SamAccountName, "<group name>"))
{
// The user belongs to the group
return true;
}
}
// The user is not a member of the group, handle the unauthorized request
return false;
Web.config
<authentication mode="Windows" />
<authorization>
<allow users="*" />
</authorization>
IIS
Site:
Authentication: only Windows enabled (I've tried with anonymous but I can't retrieve any User info)
edit: Provider: NTLM
Application Pool:
.NET 4.0.30319
Integrated
Identity: Network Service (I've tried app pool as well, but one solution suggested network service)
For what it's worth, within the context of Windows Auth, the user's roles are equivalent to their AD group memberships. As a result, you can simply use the standard AuthorizeAttribute and remove your custom one entirely.
[Authorize(Roles = "<domain>\<group>")]
There's not enough to work with here to tell you what the actual problem you're having is, but removing custom stuff you added, which is always prone to failure, is a good first step in reducing the variables.

User.IsInRole("fake group") results in "The trust relationship between the primary domain and the trusted domain failed"

I have an MVC 3 app, using Windows Authentication with Claims using WIF 4.5.
Access to the application is controlled (currently) via membership in an AD group:
<deny users="?" />
<allow roles="domain\somegroup" />
<deny users="*" />
In addition to the AD groups, we have custom roles that need to be added. (This app is being converted from Forms to Windows authentication)
To support these custom roles (until they are managed in AD), we are adding them as ClaimTypes.GroupSid claims to the user, so that existing code utilizing [Authorize("ADMIN")] and User.IsInRole("ADMIN") continues to function:
Application_PostAuthenticateRequest(object sender, EventArgs e)
{
var identity = ClaimsPrincipal.Current.Identity as WindowsIdentity;
var roles = userDAL.GetRoles(identity.Name);
foreach(var role in roles)
{
identity.AddClaim(new Claim(ClaimTypes.GroupSid, role));
}
}
And this is all working as expected.
Except when the current user is NOT a member of some custom role (like ADMIN) and that role also doesn't exist in AD
We use [Authorize("ADMIN")] on Controller Action Methods, as well as various instances of User.IsInRole("ADMIN") depending in the scenario. It's in those instances where the error occurs and the app blows up.
The AD infrastructure is in the midst of an upgrade/migration. I'm not privy to all the details there, but I do know there are a handful of domains, supposedly with trust between them, and it's been alluded to me by the infrastructure folks that these trust relationships are up and running.
So really I guess I'm wondering 2 things:
This really doesn't seem like something our code should have to handle. So what could really be wrong with the domain? Can I find out what 'trusted' domain the trust relationship is failing for?
What is the best way to work around this? I dislike the idea of writing helper methods & Authorize() subclasses just to trap this exception.
Please go to inetmgr, sites, default web site, site name, iis group, double-click authentication, disable anonymous authentication, then reset the app pool.
This appears to happen when windows cannot decipher the roles defined under the 'authorization, allow roles' tag in the web.config file. For testing comment out the custom roles tags from the web.config file. The issue appears to be caused when mixing up Forms authentication and Windows authentication. The magic happens in the Global.asax file Application_PostAuthenticateRequest method, when using Forms authentication you can Cast the User.Identity as FormsIdentity, then create the custom identity from the FormsIdentity Ticket, then create the custom principle from the custom identity, you will then be able to attach the CustomPrincipal to the Current User and Current Principal, ie.
Dim fIdent As FormsIdentity = CType(User.Identity, FormsIdentity)
Dim ci As New CustomIdentity(fIdent.Ticket)
Dim cp As New CustomPrincipal(ci)
HttpContext.Current.User = cp : Thread.CurrentPrincipal = cp
For IIS you want to enable Forms authentication and anonymous authentication, everything else should be disabled. When using Windows authentication the Global.asax file Application_PostAuthenticateRequest method can create the custom principle directly from the User.Identity ie.
Dim cp As New CustomPrincipal(User.Identity)
HttpContext.Current.User = cp : Thread.CurrentPrincipal = cp
In this case the IIS settings should be Windows authentication and ASP.Net Impersonation is enabled and everything else is disabled.
Getting these authentication methods mixed up results in the 'The trust relationship between the primary domain and the trusted domain failed' error because if your Application_PostAuthenticateRequest method is not implementing the CustomPrinciple for some reason then windows will try to use the built in IsInRole function that checks the role against the domain roles instead of using your custom IsInRole that is in your CustomPrinciple code behind file.
Here is a useful article and links:
http://www.codeproject.com/Articles/8819/Authorize-and-authenticate-users-with-AD
https://msdn.microsoft.com/en-us/library/ff647405.aspx
https://support.microsoft.com/en-us/kb/306359
This happens if you have a trusted domain configuration that is not available, IsInRole searches the group in the trusted doamins as well, and if the trusted domain is not available, throws the Trust exemption.

WCF Service Impersonate One User But Still User Windows Authentication?

I am using LinqToEntitiesDomainService to connect to a SQL Server Database. This requires Windows Authentication, which I have working.
I wrote a web service that uses Activator.CreateInstance(...) to run an executable on the server. I would like this to use Windows Authentication, as well. However, I need the service to have the proper permissions to run the executable.
When I run the service right now, it works fine. My account has the proper roles to authenticate. I also have god-like permissions on the server, which allows me to have the Activator.CreateInstance(...) command work.
While other users who have the proper roles can authenticate, their account doesn't have permissions on the server, nor should it.
Is there some (preferably, easy) way to run the service as one user, but have all of the authentication done with windows authentication? It would also be best if I could do it all in just one app pool...
Thank You!
Yes you can, take a look at this article. This shows some techniques for impersonating users.
using (WindowsImpersonationContext impersonationContext =
((WindowsIdentity)User.Identity).Impersonate())
{
// do something as current user
}
Or in WCF you can also define this declaritively.
public class HelloService : IHelloService
{
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string Hello(string message)
{
return "hello";
}
}
Note these two techniques impersonate the client (caller).
To impersonate another user explicitly you need some P/Invoke. There's a project here that wraps it all up for you quite neatly. You can then do this:
using (new Impersonator("myUsername", "myDomainname", "myPassword"))
{
// do something as myUsername
}

Resources