I have a multi tenant app in azure. I am able to login and get basic info of singed in user like name and email.
Now I need to get user's profile picture from azure. I tried some solutions provided on internet but none of them is working for me.
Here is my Startup.Auth.cs
code
public partial class Startup
{
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private string appKey = ConfigurationManager.AppSettings["ida:ClientSecret"];
private string graphResourceID = "https://graph.windows.net";
private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
private string authority = aadInstance + "common";
private ApplicationDbContext db = new ApplicationDbContext();
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions { });
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
// instead of using the default validation (validating against a single issuer value, as we do in line of business apps),
// we inject our own multitenant validation logic
ValidateIssuer = false,
},
Notifications = new OpenIdConnectAuthenticationNotifications()
{
SecurityTokenValidated = (context) =>
{
return Task.FromResult(0);
},
AuthorizationCodeReceived = (context) =>
{
var code = context.Code;
ClientCredential credential = new ClientCredential(clientId, appKey);
string tenantID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
AuthenticationContext authContext = new AuthenticationContext(aadInstance + tenantID, new ADALTokenCache(signedInUserID));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceID);
return Task.FromResult(0);
},
AuthenticationFailed = (context) =>
{
context.OwinContext.Response.Redirect("/Home/Error");
context.HandleResponse(); // Suppress the exception
return Task.FromResult(0);
}
}
});
}
}
Here is code for getting user's basic info
private ApplicationDbContext db = new ApplicationDbContext();
private string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private string appKey = ConfigurationManager.AppSettings["ida:ClientSecret"];
private string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
private string graphResourceID = "https://graph.windows.net";
// GET: UserProfile
public async Task<ActionResult> Index()
{
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
try
{
Uri servicePointUri = new Uri(graphResourceID);
Uri serviceRoot = new Uri(servicePointUri, tenantID);
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot,
async () => await GetTokenForApplication());
// use the token for querying the graph to get the user details
var result = await activeDirectoryClient.Users
.Where(u => u.ObjectId.Equals(userObjectID))
.ExecuteAsync();
IUser user = result.CurrentPage.ToList().First();
return View(user);
}
catch (AdalException)
{
// Return to error page.
return View("Error");
}
// if the above failed, the user needs to explicitly re-authenticate for the app to obtain the required token
catch (Exception)
{
return View("Relogin");
}
}
public void RefreshSession()
{
HttpContext.GetOwinContext().Authentication.Challenge(
new AuthenticationProperties { RedirectUri = "/UserProfile" },
OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
public async Task<string> GetTokenForApplication()
{
string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
// get a token for the Graph without triggering any user interaction (from the cache, via multi-resource refresh token, etc)
ClientCredential clientcred = new ClientCredential(clientId, appKey);
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's database
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID, new ADALTokenCache(signedInUserID));
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenSilentAsync(graphResourceID, clientcred, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
return authenticationResult.AccessToken;
}
I also tried this and getting error
Insufficient privileges to complete the operation.
My app has following permissions
- Sign in and read user profile
- Read directory data
Code for getting user photo
var servicePoint = new Uri("https://graph.windows.net");
var serviceRoot = new Uri(servicePoint, "<your tenant>"); //e.g. xxx.onmicrosoft.com
const string clientId = "<clientId>";
const string secretKey = "<secretKey>";// ClientID and SecretKey are defined when you register application with Azure AD
var authContext = new AuthenticationContext("https://login.windows.net/<tenant>/oauth2/token");
var credential = new ClientCredential(clientId, secretKey);
ActiveDirectoryClient directoryClient = new ActiveDirectoryClient(serviceRoot, async () =>
{
var result = await authContext.AcquireTokenAsync("https://graph.windows.net/", credential);
return result.AccessToken;
});
var user = await directoryClient.Users.Where(x => x.UserPrincipalName == "<username>").ExecuteSingleAsync();
DataServiceStreamResponse photo = await user.ThumbnailPhoto.DownloadAsync();
using (MemoryStream s = new MemoryStream())
{
photo.Stream.CopyTo(s);
var encodedImage = Convert.ToBase64String(s.ToArray());
}