I'm using Azure AD Free Edition. I'm trying to get all groups of the user that logged in and for that I'm using some examples:
One of them is
foreach (IdentityReference group in System.Web.HttpContext.Current.Request.LogonUserIdentity.Groups)
{
groups.Add(group.Translate(typeof(NTAccount)).ToString());
}
But with this I have this error:
namespace name 'HttpContext' does not existe in the namespace 'System.web'.
I tried adding the reference in my project but it does not appear in the list, so I assume it was added when I created the project.
Also this:
string username = User.FindFirst("name")?.Value;
List<string> result = new List<string>();
WindowsIdentity wi = new WindowsIdentity(username);
foreach (IdentityReference group in wi.Groups)
{
try
{
result.Add(group.Translate(typeof(NTAccount)).ToString());
}
catch (Exception ex) { }
}
result.Sort();
groups = result;
System.Collections.Generic.List`1[System.String]
This:
var g = User.Claims.Where(c => c.Type == "groups").ToList();
foreach(var nom in g){
grup += nom + " - ";
}
Exception: Windows Principal functionality is not supported on this platform.
I saw that in _LoginPartial (the view that is created by default when you assign Microsoft as Login Authentication) has #User.FindFirst("name")?.Value, that bring the username. I tried something like that but with failure #User.FindFirst("groups")?.Value.
I've been days trying this and I'm unable to do it. I read the Azure documentation and even the Microsoft gives us but is doesn´t help.
Update:
Also, I tried Adding a Policy:
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
options.AddPolicy("Policy-Name", p =>
{
p.RequireClaim("groups", "XXXX");
});
});
And in the controller I add the Authorize
[Authorize("Policy-Name")]
public IActionResult Index()
{
return View();
}
But intead of showing the view, I have the Access Denied message:
I don't know how to resolve this....
Edit:
I used some Loggers to finde where I have the error and I have this:
Authorization_RequestDenied Insufficient privileges to complete the operation. azure ad asp.net
The problem is that I configured all what I need in Azure to avoid this problem but I still have it
Related
I am writing a web app that I would like to have access to Sharepoint Document Libraries from a particular site using the currently logged on user credentials. I have looked at a number of articles that suggest using the PnP Framework and using a certificate instead of the client/secret ids.
I have tried both, the code of which is below:
string siteCollectionURL = "https://mycompanyname.sharepoint.com/sites/staffportal";
var authManager = new AuthenticationManager(ApplicationId, "C:\\pathtopfxfile\certifcatefx.pfx", "certificatepassword", "https://mycompany.sharepoint.com/sites/staffportal");
using (var clientContext = authManager.GetACSAppOnlyContext(siteCollectionURL,ApplicationId,ClientSecretId))
{
clientContext.Load(clientContext.Web, p => p.Title);
clientContext.ExecuteQuery();
return Ok(clientContext.Web.Title);
}
Unfortunately on the ExecuteQuery line I am consistently getting the 401 error, indicating that I am not authorized.
I registered the app in Azure -> Enterprise applications:
I have checked the following articles:
How to use the PnP Framework in a c# application
Secure Authentication of SharePoint with PnP Framework with C#(Code)
And tried the code snippets, but I cannot seem to find anything that suggests using the currently logged in user to the Web app.(see screen shot) - the user is a global administrator
Below is the error:
Any suggestions would be much appreciated.
Regards,
Darren
UPDATE TO ARTICLE
jimas13's link is what pointed me in the right direction. The tweaks I mentioned in the comment I have posted below for anyone wanting to write an MVC C# web app. This does require that the app needs to be registered and needs a self-signed certificate setup.
The two Async lines need to be written as follows:
public static async Task<AuthenticationResult> GetToken(IConfidentialClientApplication app, string[] scopes)
{
return await app.AcquireTokenForClient(scopes).ExecuteAsync();
}
public static async Task<Web> GetClientContext(string Uri,AuthenticationResult authResult)
{
using (var clientContext = ContextHelper.GetClientContext(Uri, authResult.AccessToken))
{
Web web = clientContext.Web;
clientContext.Load(web);
await clientContext.ExecuteQueryAsync();
return web;
}
}
The rest of the code is here:
public IActionResult Index()
{
AuthenticationConfiguration.AuthenticationConfiguration config = AuthenticationConfiguration.AuthenticationConfiguration.ReadFromJsonFile("appsettings.json");
string siteURL = config.SiteUrl;
string[] scopes = new string[] { config.Scope };
CertificateDescription certificate = config.Certificate;
ICertificateLoader certificateLoader = new DefaultCertificateLoader();
certificateLoader.LoadIfNeeded(certificate);
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithCertificate(certificate.Certificate)
.WithTenantId(config.Tenant)
.WithAuthority(config.Authority)
.Build();
AuthenticationResult result = GetToken(app, scopes).Result;
Web WebSite = GetClientContext(siteURL, result).Result;
return Ok(WebSite.Title);
}
The .SiteUrl and .Scope were added to the AuthenticationConfiguration.cs file as a property and then also added to the appsettings.json file.
I'm trying to connect to SharePoint online in a console App and print the title of the site.
Its giving me the error : "The sign-in name or password does not match one in the Microsoft account system."
I have checked and made sure the username and password are 100% right.
I dont know what else to check
Heres my code:
private static void SPCredentialsConnect()
{
const string SiteUrl = "https://tenant.sharepoint.com/sites/mysite";
const string pwd = "appPassword";
const string username = "username#tenant.onmicrosoft.com";
SecureString securestring = new SecureString();
pwd.ToCharArray().ToList().ForEach(s => securestring.AppendChar(s));
ClientContext context = new ClientContext(SiteUrl);
context.Credentials = new SharePointOnlineCredentials(username, securestring);
try
{
var web = context.Web;
context.Load(web);
context.ExecuteQuery();
Console.WriteLine($"web title: {web.Title}");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Have your issue fixed? “The sign-in name or password does not match one in the Microsoft account system” Error will occur sometimes and fixed after a while with nothing changed.
AppOnly Authentication for sharepointonline can't be registed in Azure Active Directory.
It should be register in
https://contoso.sharepoint.com/_layouts/15/appregnew.aspx
And grant permission in
https://contoso-admin.sharepoint.com/_layouts/15/appinv.aspx
You can refer to following document
https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azureacs
Consider using the PnP.Framework (a NuGet package), and use the AuthenticationManager object for SPO sites. This method bypasses MFA (which is mandatory in our organization, FWIW). You can find a lot more information and examples here, including steps on getting the client id and client secret for a site. Here is what we use to log into SPO sites:
using (ClientContext context =
new AuthenticationManager().GetACSAppOnlyContext(SiteUrl, clientID, clientSecret))
{
...
}
Also, once you connect, you should adjust the Context.Load to grab the title if you want to use that value right away. Here's what I used in my code:
context.Load(web, p => p.Id, p => p.Title);
context.ExecuteQuery();
Console.WriteLine($"Logged into source {web.Title} ({web.Id})");
Good luck!
Steve in Spain
I am using c# code in MVC web app to validate a user and find the list of user groups that particular user belongs to and using the below code
try
{
List<string> user_groups= new List<string>(); //save the groups the user belongs to
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "mydomain.com",model.Email,model.Password))
{
bool valid=ctx.ValidateCredentials(model.Email, model.Password); //validate the user
if(valid)
{
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, model.Email);
if (user != null)
{
// get the user's groups
var groups = user.GetAuthorizationGroups();
foreach (GroupPrincipal group in groups)
{
// save those groups to session for further processing after login
if ((bool)group.IsSecurityGroup)
{
user_groups.Add(group.Name);
}
}
}
_groups = string.Join(",", user_groups);
ViewBag.Message = _groups;
}
else
{
ViewBag.Message = "Error while validating";
}
ctx.Dispose();
}
}
catch (PrincipalServerDownException)
{
//If server is down or some exception happends ,
// ad_verification = false;
ViewBag.Message = "Error at groups fetching as server is down ";
}
catch (Exception ex)
{
ViewBag.Message = "Error at groups fetching as "+ex.Message;
}
I deployed this to server and try to login as user1 and all went well The code validate the user credentials and returned the list of user groups the user1 belongs to
Now i logged in as user2 on server , then it returned the below error
Error at groups fetching as Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again.
It looks like i can still login as user1, but for all other users the error is same as above . While testing on local IIS no such problems
Any known reasons why the above lines is breaking for second user onwards and any suggestions to resolve this
You didn't say which line is throwing the exception, but it might not like that you're using the user's credentials to pull all the data.
If you're running this from a computer that is joined to the same domain (or a trusted domain) then you don't need to put the credentials here:
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "mydomain.com"))
The ValidateCredentials() line will validate the credentials, and everything else will be done with the credentials that the application is running under.
On a side note, you don't need to call ctx.Dispose() when ctx is the subject of your using block. The whole purpose of using is that it will call Dispose() after it leaves the using block. Take a look at the documentation.
I'm trying use Kerberos tokens directly in C# using the KerberosSecurityTokenProvider. Unfortunately, the documentation on its use is very limited and I've not had much success. I've written the following sample test application:
var oProvider = new KerberosSecurityTokenProvider("MACHINENAME",TokenImpersonationLevel.Identification);
var oToken = (KerberosRequestorSecurityToken)oProvider.GetToken(TimeSpan.FromHours(1));
Console.WriteLine(oToken.ValidFrom);
Console.WriteLine(oToken.ValidTo);
Console.WriteLine(oToken.Id);
var abRequest = oToken.GetRequest();
var sId = oToken.Id;
try
{
var oReceivedToken = new KerberosReceiverSecurityToken(abRequest, sId);
var oAuthenticator = new KerberosSecurityTokenAuthenticator();
var oCol = oAuthenticator.ValidateToken(oReceivedToken);
foreach (var o in oCol)
{
Console.WriteLine(o.Id);
}
}
catch(Exception e)
{
Console.WriteLine(e);
}
Where MACHINENAME is the name of my machine. It successfully gets a Kerberos Token, but when I try to validate it, I get:
System.IdentityModel.Tokens.SecurityTokenException: The AcceptSecurityContext failed. ---> System.ComponentModel.Win32Exception: The logon attempt failed
Which leaves me with a number of questions:
Is this the correct way to get/validate Kerberos Tokens in C#?
Why is it trying to perform a login if I am just saying I want to use the token for identification?
Is the error due to my code, or are there domain configuration issues that also need to be addressed?
Any comments on how to use your own Kerberos tokens in .NET?
All,
I am a beginner in Facebook programming. My test project is a simple website which displays Facebook account information (only name and id) and the list of albums of that Facebook account. The problem is, after authentication, I can get the profile data, but I cannot get the album list.
Here is code to get the profile information:
[FacebookAuthorize(LoginUrl = "~/Account/Login")]
public ActionResult Profile()
{
var fbWebContext = FacebookWebContext.Current;
if (fbWebContext.IsAuthorized())
{
try
{
var fb = new FacebookWebClient(fbWebContext);
var token = fb.AccessToken;
dynamic me = fb.Get("/me");
ViewBag.Name = me.name;
ViewBag.Id = me.id;
ViewBag.AccessToken = token;
}
catch (Exception ex)
{
{
fbWebContext.DeleteAuthCookie();
Session.Clear();
}
return RedirectToAction("Login", "Account");
}
}
return View();
}
and here is code to get the album list
[FacebookAuthorize(LoginUrl = "~/Account/Login")]
public ActionResult Album()
{
var fb = new FacebookWebClient(FacebookWebContext.Current);
IDictionary<string, object> albums = fb.Get("me/albums") as IDictionary<string, object>;
dynamic albumList = albums["data"];
foreach (dynamic albumInfo in albumList)
{
if (ViewBag.Albums == null)
ViewBag.Albums = new List<string>();
ViewBag.Albums.Add(albumInfo.id);
}
return View();
}
in above code, the item count of albumList always = 0.
Could you please help me to resolve this issue?
A minor note: my test website is a ASP.Net MVC3 web application written in C#.
Edit in response to Andy's answer:
In fact, I set lots of permissions but it still cannot get the album list. Here is code in my OAuth method.
var parameters = new Dictionary<string, object>();
parameters.Add("permissions", "user_about_me,offline_access,user_photos,publish_stream");
dynamic tokenResult = oAuthClient.ExchangeCodeForAccessToken(code, parameters);
Note that I did try to replace ""permissions" by "scope" but still failed.
Have you requested the user_photos permission? You need to request additional permissions during Authentication if you want to access additional user data.
See this Facebook permissions page for more info.
If you are using the Facebook JavaScript SDK FB.login method then you can simply add the user_photos permission to the perms option:
FB.login(function(response) {
if (response.session) {
if (response.perms) {
// user is logged in and granted some permissions.
// perms is a comma separated list of granted permissions
} else {
// user is logged in, but did not grant any permissions
}
} else {
// user is not logged in
}
}, {perms:'user_photos'});
Hope this helps.