Azure AD - Link between primary and guest accounts in different tenants - azure-active-directory

We are struggling with the use case below, in a highly regulated context where audits are being run on all the Azure AD. Any help appreciated.
Context:
1 main Azure AD tenant in the company, which is an O365 tenant
(labelled as the “users tenant”)
Multiple other Azure AD tenants in
the company, which are the “applications” tenants:
Each
department/business division has its own application tenant (for
isolation purposes), to manage its Azure resources (one or several
subscriptions)
Some users from the users tenant (O365) are invited to
some applications tenants (Azure) as guest accounts
Use case to solve :
Employee is leaving the company and is removed from the “users” tenant (O365)
The company needs to remove this employee from all the “applications” tenants he/she has been added to as a guest account
Is there a way to automatically/programmatically identify and remove all of the accounts of this employee in the different AAD tenants, based on the O365 tenant ?
Is there a public “link” between AAD accounts (primary > guest) that we can leverage to achieve the identification/removal of AAD users ?
Workarounds ? Best practices ?

Based on your description, you can register an multi-tenant app in your main tenant :
After the app created , create a secret for it and note its application ID and secret , we will use it to connect to your tenants later :
Grant "User.ReadWrite.All" permission of Microsoft Graph API to this application as we will call Microsoft Graph API to delete users :
Do not forget to click "Grant admin consent for your tenant " button to finish the assign process.
letting admin of other tenants to consent to use this app by link :
https://login.microsoftonline.com/<your tenant ID>/adminConsent?client_id=<your multi-tenant app ID>
and this app will be added into other tenants as a service principle :
so that we can use this app to do some actions through all tenants.
Just run the Powershell below to delete a user from all your tenants , I have tested on my side and it works for me. Btw, pls remove all directory roles before you run it or you will get 403 error if user is assigned some admin roles .
#config your multi tenant app id and secret here.
$appid = "<YOUR MULTI TENANT APP ID>"
$secret = "<YOUR MULTI TENANT APP SECRET>"
$userEmailaddress = "<EMAIL ADDRESS OF THE USER YOU WANT TO DELETE>"
#config all your tenents here
$tenants = "<TENANT 1 ID/NAME>","TENANT 2 ID/NAME",...
#check and delete user by email address in all tenants
foreach($tenant in $tenants){
#get token to call microsoft graph api to delete users
$body=#{
    "grant_type"="client_credentials";
    "resource"="https://graph.microsoft.com";
    "client_id"=$appid;
    "client_secret" = $secret
}
 
$result=Invoke-RestMethod -Uri "https://login.windows.net/$tenant/oauth2/token" -Method POST -Body $body 
#get user object from tenant
$userguestPrefix = $userEmailaddress.Replace('#','_')
$searchURL = "https://graph.microsoft.com/v1.0/users?`$filter=startswith(userPrincipalName,'$userEmailaddress') or startswith(userPrincipalName,'$userguestPrefix')"
$searchUserResult = Invoke-RestMethod -Uri $searchURL -Method GET -Headers #{'Authorization'='Bearer '+$result.access_token}
#remove the user from tenant
if($searchUserResult.value.Length -eq 1){
echo "remove:"$searchUserResult.value[0].displayName" from tenant : $tenant"
$removeURL = "https://graph.microsoft.com/v1.0/users/" + $searchUserResult.value[0].id
Invoke-RestMethod -Uri $removeURL -Method DELETE -Headers #{'Authorization'='Bearer '+$result.access_token}
}
}
If you have any further concerns , pls feel free to let me know .

Related

How to get the resourceId when granting an appRoleAssignment to a ServicePrincipal in Azure AD?

I am trying to Grant Admin Consent of a API in an Azure AD application through Graph API. I created the App, created its Client Secret, then created a Service Principal to which I want to add AppRoleAssignment.
The API call to do so requires three attributes in the body (Documentation)
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var appRoleAssignment = new AppRoleAssignment
{
PrincipalId = {Input the Service Principal Id},
ResourceId = {? Where to get this value?},
AppRoleId = {Input the App role of the API I added to my Azure AD App}
};
await graphClient.ServicePrincipals["{servicePrincipal-id}"].AppRoleAssignments
.Request()
.AddAsync(appRoleAssignment);
My question is where to get the ResourceId from? Knowing that this is different from one tenant to the other.
Please note that if I grant the admin consent manually, then run this API call
var appRoleAssignments = GraphAppClient.ServicePrincipals[servicePrincipalId].AppRoleAssignments.Request().GetAsync().Result;
Then revoke the consent, get the ResourceId from what the API returned, and then use it in the original call, the admin consent works fine.
The documentation for the appRoleAssignment resource type says the following about the resourceId property:
The unique identifier (id) for the resource service principal for which the assignment is made.
A good approach to find a service principal in a tenant is to search the servicePrincipals collection, filtering on the appId or servicePrincipalName properties.For example, to search for the Microsoft Graph service principal by its identifier URI:
GET https://graph.microsoft.com/v1.0/servicePrincipals
?$filter=servicePrincipalNames/any(n:n eq 'https://graph.microsoft.com')
Or to find it by its appId:
GET https://graph.microsoft.com/v1.0/servicePrincipals
?$filter=appId eq '00000003-0000-0000-c000-000000000000'
With the Microsoft Graph SDK for .NET, this would look something like this:
var r = await graphServiceClient.ServicePrincipals
.Request()
.Filter("appId eq '00000003-0000-0000-c000-000000000000'")
.GetAsync();
Using Microsoft Graph PowerShell, things look very similar:
$r = Get-MgServicePrincipal -Filter "appId eq '00000003-0000-0000-c000-000000000000'"
Using the Azure portal, each app under "Enterprise apps" corresponds to a service principal, and the "Properties" page shows its object ID.
(Once you have the service principal, you can use its appRoles collection to see the list of app roles it publishes, often useful to get the app role's id, which you'll need for the appRoleId property.)
I ended up figuring it out. The resourceId of every set of permission you are trying to add is the objectId of the app in Entreprise Applications. It sounds very confusing, but if you are trying to add Graph API permissions, you need to go to enterprise applications, find GraphAPI, and then find its ObjectId. That is your resourceId.

Does what you send in Scope Governs whether you can login with Microsoft Account using Azure AD V2 Endpoints

I have registered a application using the App Registration (Preview) Blade and added the Azure Service Management API as API Permissions I downloaded the MSAL based Sample from
https://github.com/azure-samples/active-directory-dotnet-webapp-openidconnect-v2
Now in startup.auth.cs if i change the Scope i.e keep openid and add https://management.azure.com and then run and try and Login with a Microsoft Account i get the following error
This Doesn't Look like a Work or School Email you cant Sign-in here with Personal Account use your work or School Account Instead.
if i remove the Scope for https://managment.azure.com and just keep Openid profile offline_access i get the Consent Screen and Login
new OpenIdConnectAuthenticationOptions
{
// The Authority represents the v2.0 endpoint - https://login.microsoftonline.com/common/v2.0
// The Scope describes the initial permissions that your app will need. See https://azure.microsoft.com/documentation/articles/active-directory-v2-scopes/
ClientId = clientId,
Authority = String.Format(CultureInfo.InvariantCulture, aadInstance, "common", "/v2.0"),
RedirectUri = redirectUri,
Scope = "openid https://management.azure.com/.default",
PostLogoutRedirectUri = redirectUri,
I am Expecting to have the user Login and Obtain a Token for management API , i am Looking for Reasons for getting the above Error is this Expected ? The Account that i am using exists in my directory as a Member . this works if i use a Managed user(user#tenant.onmicrosoft.com) to Login
Since personal MS accounts cannot be used to manage Azure subscriptions unless they are added to an Azure AD, you should use the organizations endpoint instead of common.
In v1 "common" meant any AAD tenant.
In v2 "common" means any AAD tenant + any personal MS account.
If you wanted only personal accounts, you can use "consumers".
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc#fetch-the-openid-connect-metadata-document
You can use "organizations" to allow any AAD tenant but disallow MS accounts.
Of course a user can just edit the URL and login with a personal MS account anyway, so you'll want to check the tenant id of the logged in user.
The tenant id for MS accounts is always 9188040d-6c67-4c5b-b112-36a304b66dad, per the docs: https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens#payload-claims.
So check the idp claim.

Grant service principal access to application in other tenant

I have an Azure AD service principal in one tenant (OneTenant) that I would like to give access to an application in another tenant (OtherTenant).
The service principal in tenant OneTenant is a managed service identity for an Azure Logic App. So what I actually want is to call an API from my Logic App. This API is protected by an Azure AD application in OtherTenant.
The application in OtherTenant defines a number of roles and the service principal in OneTenant should have one of these roles so it can call the API.
I tried the following:
set the app in OtherTenant to multi-tenant
ran the following PS command to attempt to add the SP to a role in the app:
New-AzureADServiceAppRoleAssignment `
-ObjectId <object-id-of-sp-in-one-tenant> `
-Id <role-id> `
-PrincipalId <object-id-of-sp-in-one-tenant> `
-ResourceId <app-id-in-other-tenant>
(both logged in in OneTenant and OtherTenant)
This gives an error stating that either app-id-in-other-tenant or object-id-of-sp-in-one-tenant can not be found, depending on where I am signed in.
I also tried creating a Service Principal in OneTenant based on the app-id from OtherTenant In that case I get an error message: Authenticating principal does not have permission to instantiate multi-tenantapplications and there is not matching Applicationin the request tenant.
Ok, I finally got around to testing if the solution presented by Rohit Saigal works. It does point in the right direction but is not complete.
First step is to create a service principal in OneTenant that represents the application in OtherTenant. So while signed in to OneTenant, run the following script:
$spInOneTenant = New-AzureADServicePrincipal -AppId <app-id-in-other-tenant>
Next step is to run the New-AzureADServiceAppRoleAssignment cmdlet with the following parameters:
New-AzureADServiceAppRoleAssignment `
-Id <role-id> `
-ObjectId <object-id-of-sp-in-one-tenant> `
-PrincipalId <object-id-of-sp-in-one-tenant> `
-ResourceId $spInOneTenant.ObjectId
The trick is to use the object id of the service principal you created in the previous step as the ResourceId.
Taking the command as is from your question:
New-AzureADServiceAppRoleAssignment `
-ObjectId <object-id-of-sp-in-one-tenant> `
-Id <role-id> `
-PrincipalId <object-id-of-sp-in-one-tenant> `
-ResourceId <app-id-in-other-tenant>
Try changing the last parameter value i.e. ResourceId
Currently you're passing <app-id-in-other-tenant>
Replace that with <object-id-of-API-in-other-tenant>
The question/answers presented here were helpful, but yet it took me some time to work through the details and actually make it work, so allow me to elaborate some more on the above, as it might help others too.
Scenario
Two tenants:
Home Tenant.
Other Tenant.
One Azure App Service API app, with access managed by the Home Tenant.
One Logic app placed in a subscription in Other Tenant that need to securely access the API app in the Home Tenant.
Approach
Application registration
For the API app to delegate identity and access management to Azure AD an application is registered in the home tenant’s Azure Active Directory. The application is registered as a multi-tenant app.
You also need to create an app role (see documentation: How to: Add app roles in your application and receive them in the token), lets call it read.weather.
Configuration of Other Tenant and Logic App
To provide the Logic App access to the API app do this:
Enable a system assigned identity for the logic app - i.e. use Managed Identity. Note down the system assigned managed identity Object ID ({18a…}), you will need it in a minute.
Create a service principal for the application in the Other Tenant using this command, where appId is the appId of the application registered in Home Tenant (e.g. lets say it’s {1a3} here):
New-AzureADServicePrincipal -AppId {appId}
This command will output a json document which includes among other things an objectId for the service principal just created.
[... more json ...]
"objectId": "b08{…}",
[... more json...]
You should also see the appRoles, including the app role read.weather you just created, om the json output from the New-AzureADServicePrincipal command:
[... more json...]
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"description": "Read the weather.",
"displayName": "Read Weather",
"id": "46f{…}",
"isEnabled": true,
"value": "read.weather"
}
],
[... more json...]
To tie it all together make an app role assignment using the command:
New-AzureADServiceAppRoleAssignment -Id {app role ide} -ObjectId {system assigned identity object id} -PrincipalId {system assigned identity object id} -ResourceId {object id of service principal}
E.g. something like this:
New-AzureADServiceAppRoleAssignment -Id 46f… -ObjectId 18a… -PrincipalId 18a… -ResourceId b08…
Now we are ready to set up the HTTP request in the Logic App using the URI to the API app using Managed Identity for authentication.
Notice that the audience is needed and has the form: api://{appId}.
But wait…!
Does this mean that anyone could do this, if only they know the appId of your application registration, and wouldn’t this compromise the security of the API app?
Yes, it does, and yes indeed it could compromise the security of the API app.
If you look at the access token being created and used as bearer from the Logic App it is a valid access token, which contains all the necessary claims, including the app role(s). The access token is however issued by Other Tenant and not Home Tenant.
Therefore, if you have a multi tenanted application and you want to guard it against this scenario, then you could check the issuer (tid more likely) of the incoming access token calling the API and only accept it if the issuer is the Home Tenant, or you could make the application a single tenant app.
Or, you could require that the issuer matches a list of tenants that the API trusts.

Adding users with roles into app registration

I can see you can create app registrations with graph API but is it possible to add users and roles to an app registration?
If you want to assign a user to that application, in one of the specified app roles, you'll need to set the appRoleAssignment on the user . If using Azure AD Graph api , you could use below rest api :
https://graph.windows.net/{tenant-id}/users/{username}/appRoleAssignments?api-version={api-version}
Content-Type:application/json
Authorization: Bearer {token}
{
"id": "RoleID",
"principalId": "UserObjectID",
"principalType": "User",
"resourceId": "servicePrincipalID"
}
id: This is the Id for the Role you are assigning. These Ids can be found in the Application's Manifest. Or you could use below api to get the specific role defined for your application(appRoles claim):
https://graph.windows.net/{tenant}/applications/{ObjectIDOfApplication}?api-version=1.6
principalId :This is the Obeject Id of the User you are assigning the role to.
principalType :If you are assigning this role to a User then this is set to the string User .
resourceId : Service Principal ID of the application . To get service principal id , you could use below api (objectId claim) :
https://graph.windows.net/{tenant}/servicePrincipals?api-version=1.6&$filter=appId eq 'appid'
Application role assignments are available in the Microsoft Graph Beta endpoint: see Update approleassignment
To give you an idea of what could do to add app role assignments to a user, I suggest you look at the Configure.ps1 PowerShell script of the active-directory-dotnet-webapp-roleclaims sample on GitHub, which creates test users of a given role and updates the application registration. This is in PowerShell, but you should be able to adapt it to using MSGraph

How to programatically create applications in Azure AD

I'm currently creating my applications on Azure Active directory manually whenever there is a request for a new environment. I was exploring ways to create these applications from the code via REST API. I had success in creating users and groups on existing applications by using 'client_credentials' as shown.
ClientCredential clientCred = new ClientCredential(clientID, clientSecret);
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(resAzureGraphAPI, clientCred);
In similar fashion I tried to use the 'access_token' generated from above to create a new application
adClient.Applications.AddApplicationAsync(newApplication).Wait()
But this throws an error- "Insufficient privileges to complete the operation."
I looked at other threads and the Azure AD msdn page and turns out the client_credentials flow does not support creating/updating applications.
Adding Applications programmatically in Azure AD using Client Credentials Flow
The above thread also mentioned that way to workaround it was by using the 'grant_type=password' flow. I tried it as suggested but I keep getting the following error which doesn't make sense to me.
"error": "invalid_grant",
"error_description": "AADSTS50034: To sign into this application the account must be added to the 1283y812-2u3u-u293u91-u293u1 directory.\r\nTrace ID: 66da9cf9-603f-4f4e-817a-cd4774619631\r\nCorrelation ID: 7990c26f-b8ef-4054-9c0b-a346aa7b5035\r\nTimestamp: 2016-02-21 23:36:52Z",
"error_codes": [
50034
],
Here is the payload and the endpoint that I'm hitting. The user that is passed is the owner of the AD where I want to create the application
endpoint:https://login.windows.net/mytenantID/oauth2/token
post data
resource 00000002-0000-0000-c000-000000000000
client_id id
client_secret secret
grant_type password
username principal#mydomain.com
password password
scope openid
Any thoughts or suggestions of where I might be going wrong would be appreciated.
You can use PowerShell to create your apps:
$servicePrincipalName =”Your Client App Name”
$sp = New-MsolServicePrincipal -ServicePrincipalNames $servicePrincipalName -DisplayName $servicePrincipalName -AppPrincipalId “Your Client ID"
New-MsolServicePrincipalCredential -ObjectId $sp.ObjectId -Type Password -Value “Your client secret”
Add-MsolRoleMember -RoleObjectId “62e90394-69f5-4237-9190-012177145e10" -RoleMemberType ServicePrincipal -RoleMemberObjectId $sp.ObjectId
The role denoted by 62e90394-69f5-4237-9190-012177145e10 is the Admin role, and this can be adjusted as required to the ObjectId of any other role. Run Get-MsolRole to get a list of roles and ObjectIds.
You could then run this code from your App or run it manually. You will also need to run your connection code before the above, something along the lines of:
$loginAsUserName = "Your Tenancy Admin Account"
$loginAsPassword = "Your Tenancy Admin Account Password"
$secpasswd = ConvertTo-SecureString $loginAsPassword -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential ($loginAsUserName, $secpasswd)
Connect-MsolService -Credential $creds
I was able to create the application in my tenant. The AD tenant which I was using to create the application under was verified for a different domain. Basically I ended up plugging in an user from that domain and using the resource_type=password flow was able to generate an access token. Next, firing the following lines of code did the trick
ActiveDirectoryClient adClient = new ActiveDirectoryClient(
serviceRoot,
AccessToken);
adClient.Applications.AddApplicationAsync(newApplication).Wait();
Check the following things which seem to be a little off in your POST to the OAuth Token endpoint:
When wanting access to the Graph API of your Azure AD, you will need to pass https://graph.windows.net as the resource body parameter; this is (imho) not well documented, but that's what you need to do
As client_id and client_secret you need to pass the Client ID and the Key of a predefined Application inside your Azure AD which in turn you have granted permissions on a per user level to; these need to be sufficient to add applications
See here: https://msdn.microsoft.com/Library/Azure/Ad/Graph/howto/azure-ad-graph-api-permission-scopes?f=255&MSPPError=-2147217396
The scope parameter is not used, I think; you will get the claims you defined inside the Azure AD management portal back (the assigned permissions for your application)
This should render you an access token you can then subsequently use on the https://graph.windows.net/tenantId/ end points.

Resources