Microsoft Graph API - Get Enterprise Applications Azure AD - azure-active-directory

I'm wondering how to retrieve my enterprise apps with Graph API.
Is it really done by accessing the service principals? Because if I get the service principals, the display names are different than in the Azure AD UI.
Thanks!

I found the solution. Here is how to fetch enterprise apps only in C#:
var servicePrincipals = await _graphServiceClient
.ServicePrincipals
.Request()
.GetAsync();
foreach (var app in servicePrincipals )
{
foreach (var tag in app.Tags)
{
if (tag == "WindowsAzureActiveDirectoryIntegratedApp")
{
// do something with enterprise app
}
}
}

Related

Authorization on a Blazor Server app using Microsoft Identity (Azure AD Authentication) doesn't work

Forgive me if this is an obvious question with an easy answer but for the life of me I cannot get my app to behave the way I want.
When I normally use MS Identity in my Blazor apps I can create roles and policies which all come from a SQL database. For this B2B app I need to use Azure AD and the groups within there to authenticate and authorize access.
At the moment the whole app is secured because the default policy is being applied to all parts of the site but I would like to use [Authorize(Policy = "ViewCustomer")] for example to ensure users have the right permission to view a particular part.
I am sure that this part of my program.cs is missing policies and is part of the problem:
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
Trouble is I don't have a clue how to create these so they refer to groups (or similar) in the Azure AD tenant. My complete program.cs is:
using DevExpress.Blazor;
using DataModel.Models;
using Microsoft.EntityFrameworkCore;
using BlazorUI.Hubs;
using BlazorUI.Services;
using Xero.NetStandard.OAuth2.Config;
using BlazorUI.Services.Interfaces;
using DataModel.Xero.Interface;
using DataModel.DickerData.Interfaces;
using DataModel.DickerData;
using DataModel.Xero;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
var builder = WebApplication.CreateBuilder(args);
var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ') ?? builder.Configuration["MicrosoftGraph:Scopes"]?.Split(' ');
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph"))
.AddInMemoryTokenCaches();
builder.Services.AddControllersWithViews()
.AddMicrosoftIdentityUI();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor()
.AddMicrosoftIdentityConsentHandler();
builder.Services.AddScoped<ISettingService, SettingService>();
builder.Services.AddScoped<IXeroService, XeroService>();
builder.Services.AddScoped<IDickerDataService, DickerDataService>();
//XERO SETTINGS
builder.Services.Configure<XeroConfiguration>(builder.Configuration.GetSection("XeroConfiguration"));
//DICKER DATA SETTINGS
builder.Services.Configure<DickerConfig>(builder.Configuration.GetSection("DickerDataConfiguration"));
//DEVEXPRESS
builder.Services.AddDevExpressBlazor(configure => configure.BootstrapVersion = BootstrapVersion.v5);
//ENTITY FRAMEWORK
builder.Services.AddDbContextFactory<ApplicationDBContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DBConnection"));
options.EnableSensitiveDataLogging();
});
var app = builder.Build();
//DEVEXPRESS
builder.WebHost.UseWebRoot("wwwroot");
builder.WebHost.UseStaticWebAssets();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
//REGISTER SIGNAL R HUBS
app.MapHub<MessageHub>(MessageHub.PATHTOHUB);
app.Run();
Thank you so much to anyone that may be able to enlighten me.
You can add app roles to your application, assign them to selected users and obtain them as claims so they can be used in tandem with your AuthorizeAttribute.
Alternatively, you can further customize or augment the authorization criteria using Claim Based Authorization in tandem with your policy.

How to implement Single Sign On in ASP.NET MVC application

We have developed 2 applications in ASP.NET MVC. We have used ASP.NET Identity in both applications for user authentication. Both applications use the same database. Also both apps are hosted on Azure Portal.
We would like to implement SSO in both applications, so when I log in to one application, the second application doesn't ask for login again and authenticates the already logged in user.
We have implemented to share authentication cookies among ASP.NET apps as per the Microsoft document (open the link shared below), but it's not working. I have posted code below.
https://learn.microsoft.com/en-us/aspnet/core/security/cookie-sharing?view=aspnetcore-2.1#sharing-authentication-cookies-between-aspnet-4x-and-aspnet-core-applications
I have written this code in Startup.Auth.cs:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieName = ".AspNet.SharedCookie",
CookieDomain= ".azurewebsites.net",
SlidingExpiration = true,
ExpireTimeSpan = TimeSpan.FromMinutes(120),
LoginPath = PathString.FromUriComponent("/Account/Login"),
LogoutPath = PathString.FromUriComponent("/Account/Logout"),
TicketDataFormat = new AspNetTicketDataFormat(
new DataProtectorShim(
DataProtectionProvider.Create(new DirectoryInfo("C:\\ApplicationData"),
(builder) =>
{
builder.SetApplicationName("SharedCookieApp");
})
.CreateProtector(
"Microsoft.AspNetCore.Authentication.Cookies." +
"CookieAuthenticationMiddleware",
"Cookies.Application",
"v2"))),
CookieManager = new ChunkingCookieManager()
});
}
Also added claim when user logged in successfully in login method as below.
var user1 = await UserManager.FindByNameAsync(model.Email);
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, user1.Id));
claims.Add(new Claim(ClaimTypes.Name, model.Email));
var id = new ClaimsIdentity(claims,DefaultAuthenticationTypes.ApplicationCookie);
var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(new AuthenticationProperties()
{
AllowRefresh = true,
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddMinutes(30),
IssuedUtc = DateTime.UtcNow
}, id);
This works fine in localhost but when it is published in Azure portal, it doesn't work. It seems that the authentication cookie is not shared among the 2 apps on Azure Portal because Azure doesn't allow to access directory location hence it gives error like 'Access Denied' and I don't know how to use Azure Key vault or database to store cookie.
Can you please guide me if I have missed something or have did incorrectly. Your earlier response would be highly appreciated. Let me know if you need any other details.
Regards,
Kiran Shah

How to use Azure AppRoles in Blazor Server with Azure Active Directory

I have an up and running .NET 5 Web-API with a Blazor Server Client in Production. I'd like to switch from Individual User Accounts to Azure AD using App Roles to authenticate specific Users in my Controllers. I found lots of Information regarding Webassembly but none for Blazor Server.
Has somebody a working Solution for a .NET 5/6 Web-Api with a Blazor Server Client and integrating Azure App Roles?
Apps are already registered in the Azure Portal and so forth, I just need to know how to pass the App Roles specific stuff to my API, so my Controller can work with the [Authorize("Admin")] stuff. I suspect it will use Bearer Tokens aswell.
Edit:
Thanks a lot for reading. So I figured out that if I use something like this in my Controller only using the [Authorize] Attribute without any roles:
var identities = HttpContext.User.Identities.ToList();
foreach (var item in identities)
{
if (item.RoleClaimType == "admin")
{
// return or do something
}
}
It would just work fine but there has to be some smoother solution for this or am I doing this completly wrong? When I look at the WASM Samples, they pick up the AppRoles with their token and the Controller simply can use the [Authorize(Roles = "xyz")] Attribute. What am I missing here? :/
Btw, this is how my Program.cs looks right now:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
builder.Configuration.Bind("AzureAd", options);
options.TokenValidationParameters.RoleClaimType =
"admin";
options.TokenValidationParameters.RoleClaimType = "doku";
},
options => { builder.Configuration.Bind("AzureAd", options); });
Thank you guys/gals <3
Please check if the given references are of use in your case.
A SERVER API app can authorize users to access secure API endpoints with authorization policies for security groups, AAD Administrator Roles, and App Roles
In Program.cs of a SERVER app, specify the claim as roleclaim
example:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
Configuration.Bind("AzureAd", options);
options.TokenValidationParameters.RoleClaimType =
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
},
options => { Configuration.Bind("AzureAd", options); });
Then you can use admin role on authorization controller to access
[Authorize(Roles = "admin")]
Here in App roles section you can see the configuration for both
server and client.
Edit the app role in the manifest editor in portal and then give
proper api permissions , expose scopes and grant permission for admin
consent >see Add app roles and get them from a token .And the
procedural logic must contain those scopes required by api.
Note : The appRoles manifest property of both the client and the
server Azure portal app registrations must include the same configured
roles.
Please check this for more detailed information which guides for both server and client apps.
Other references:
using-app-roles-with-AAD-blazor-server-client scenario | codemaze.com
quickstart-configure-app-expose-web-apis
quickstart-configure-app-access-web-apis

How to do role based authorization in Azure with Asp.net webapi backend and front end as Angular

How I can do Azure role based authentication in webapi backend. I see tons of example for Asp.net MVC but none for webapi with front end as Angular. I have hosted my website developed in angular with backend as webapi and hosted it on Azure and enabled the Authentication/authorization as Azure Active directory in Azure website. Also I have done the setup for AD application for roles in its manifest files. After I hit website, I have to authenticate and then after authentication it redirects to my website . During my website load it calls my webapi and the Authentication token with claims is passed to my webapi. In webapi I am checking for InRole or [Authorize(Roles = "admin")] and based on that I am allowing access. However in token roles do not flow by default . So I query graph api to get roles by extracting the information from token and pass it to graph api to get roles. I am doing query in Owin Startup class to fetch role, But I am not able to get success. Is there anything wrong with the code, Please help . The code is copied below. Also I could have used ADAL JS library in Angular to authenticate with AD but I don't need to do so as I have enabled authentication in Azure website using the option "Authentication/Authorization". The layer of Authentication in website will do all token validation and forward it to webapi.
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IdentityModel.Tokens;
using System.Linq;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.ActiveDirectory;
using Owin;
using System.Security.Claims;
using System.Net;
using System.Web;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Owin.Security.OAuth;
using Microsoft.Azure.ActiveDirectory.GraphClient;
using System.Threading.Tasks;
namespace OneMap.Web
{
public partial class Startup
{
// Apply bearer token authentication middleware to Owin IAppBuilder interface.
private void ConfigureAuth(IAppBuilder app)
{
var tenantId = Common.Configuration.GetConfigurationSetting("ida:Tenant");
// ADAL authentication context for our Azure AD tenant.
var authenticationContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(
$"https://login.windows.net/{tenantId}", true, TokenCache.DefaultShared);
// Secret key that can be generated in the Azure portal to enable authentication of a
// specific application (in this case our Web API) against an Azure AD tenant.
var applicationKey = Common.Configuration.GetConfigurationSetting("ida:Password");
// Root URL for Azure AD Graph API.
var azureGraphApiUrl = "https://graph.windows.net";
var graphApiServiceRootUrl = new Uri(new Uri(azureGraphApiUrl), tenantId);
var clientId = Common.Configuration.GetConfigurationSetting("ida:ClientId");
// Add bearer token authentication middleware.
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
// The id of the client application that must be registered in Azure AD.
TokenValidationParameters = new TokenValidationParameters { ValidAudience = clientId },
// Our Azure AD tenant (e.g.: contoso.onmicrosoft.com).
Tenant = tenantId,
Provider = new OAuthBearerAuthenticationProvider
{
// This is where the magic happens. In this handler we can perform additional
// validations against the authenticated principal or modify the principal.
OnValidateIdentity = async context =>
{
try
{
// Retrieve user JWT token from request.
var authorizationHeader = context.Request.Headers["Authorization"];
var userJwtToken = authorizationHeader.Substring("Bearer ".Length).Trim();
// Get current user identity from authentication ticket.
var authenticationTicket = context.Ticket;
var identity = authenticationTicket.Identity;
// Credential representing the current user. We need this to request a token
// that allows our application access to the Azure Graph API.
var userUpnClaim = identity.FindFirst(ClaimTypes.Upn);
var userName = userUpnClaim == null
? identity.FindFirst(ClaimTypes.Email).Value
: userUpnClaim.Value;
var userAssertion = new UserAssertion(
userJwtToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
// Credential representing our client application in Azure AD.
var clientCredential = new ClientCredential(clientId, applicationKey);
// Get a token on behalf of the current user that lets Azure AD Graph API access
// our Azure AD tenant.
var authenticationResult = await authenticationContext.AcquireTokenAsync(
azureGraphApiUrl, clientCredential, userAssertion).ConfigureAwait(false);
// Create Graph API client and give it the acquired token.
var activeDirectoryClient = new ActiveDirectoryClient(
graphApiServiceRootUrl, () => Task.FromResult(authenticationResult.AccessToken));
// Get current user groups.
var pagedUserGroups =
await activeDirectoryClient.Me.MemberOf.ExecuteAsync().ConfigureAwait(false);
do
{
// Collect groups and add them as role claims to our current principal.
var directoryObjects = pagedUserGroups.CurrentPage.ToList();
foreach (var directoryObject in directoryObjects)
{
var group = directoryObject as Group;
if (group != null)
{
// Add ObjectId of group to current identity as role claim.
identity.AddClaim(new Claim(identity.RoleClaimType, group.ObjectId));
}
}
pagedUserGroups = await pagedUserGroups.GetNextPageAsync().ConfigureAwait(false);
} while (pagedUserGroups != null);
}
catch (Exception e)
{
throw;
}
}
}
});
}
}
}
AFAIK, the roles claim only issued in the id_token. After you change the manifest of app(refer here), you can using the SPA get the id_token and access the web API according the roles via the id_token.
And there is no need to using the Authentication/authorization since you have protect the web API using the Microsoft.Owin.Security.ActiveDirectory OWIN middleware. To authenticate the SPA you can refer this code sample.

Identity Server 3 AzureAd Claims not returning

I have a working Identity Server application, and I'm setting it up to work with Azure AD. I've got my Azure Ad App registration and I can authenticate with it properly.
Looking at this and trying to do something similar to store the 3rd party user IDs associated with a user, but I'm not getting the sub or nameIdentifier claims back from AAD.
Do I need to request these from AzureAD somehow? - Their docs seem to be to be saying that the "sub" claim is (or at least can be) returned: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-token-and-claims#_subject. This article seems to say that sub isn't returned, but it's for multitenant applications, so I'm not too sure if that's relevant.
I'm sure I'm missing something simple, but can't find anything relevant on Google.
Cheers,
Alex
The article Work with claims-based identities is too old and this Azure AD token reference article should be right about the token claims in the token issued by Azure AD.
Based on the test, I could get the sub claim from Azure AD and it also issued by the IdentityServer3 like figure below:
Here is the code I configed for the IdentityServer3 for your reference:
var webApp = WebApp.Start("https://localhost:44333", app =>
{
app.UseIdentityServer(new IdentityServerOptions
{
SiteName = "NDC Demo",
SigningCertificate = cert,
Factory = factory,
AuthenticationOptions = new AuthenticationOptions
{
IdentityProviders = ConfigureAdditionalIdentityProviders,
EnableAutoCallbackForFederatedSignout = true
}
});
});
public static void ConfigureAdditionalIdentityProviders(IAppBuilder app, string signInAsType)
{
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "aad",
Caption = "Azure AD",
SignInAsAuthenticationType = signInAsType,
Authority = "https://login.microsoftonline.com/{tenantId}",
ClientId = "{clientIdFromAzurePortal}",
RedirectUri = "{redirectUri}",
});
}
If you still have the problem, would you mind sharing the request to Azure AD which you can capture it using Fiddler.

Resources