'Access Denied' accessing SharePoint Online Site Collection with App Permission - sharepoint

I have created an App Principal in SharePoint Online using the Site Collections /AppRegNew.aspx page and then used page /appInv.aspx to grant that App Principal FullControl of the site collection using the following permission XML:
<AppPermissionRequests>
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl"/>
</AppPermissionRequests>
However, when I try to access a list in that site collection using CSOM and c# (using TokenHelper.cs), I get error:
'Access denied. You do not have permission to perform this action or access this resource.'
I have another App Principal which I had granted Tenant Admin permission for testing - if I use the ClientID and ClientSecret associated with that App Principal, my code runs properly (I am just reading a few list items for testing)
Am I doing something wrong with the AppPermissionRequests XML? is there some other step I am missing? I could use the Tenant Admin App Principal, but I want to do this the 'right' way - and from my research, it looks like it should be working with the SiteCollection FullControl permission.
Example code I am using to attempt access:
Uri siteUri = new Uri("https://MyCompany.sharepoint.com/sites/johntest");
string realm = TokenHelper.GetRealmFromTargetUrl(siteUri);
string accessToken = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, siteUri.Authority, realm).AccessToken;
using (ClientContext context = TokenHelper.GetClientContextWithAccessToken(siteUri.ToString(), accessToken))
{
Web thisWeb = context.Web;
context.Load(thisWeb);
context.ExecuteQuery();
List roomsList = context.Web.Lists.GetByTitle("Rooms");
context.Load(roomsList);
context.ExecuteQuery();
Console.WriteLine("List retrieved");
CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml = "<View><Query><Where><Eq><FieldRef Name='Title'/><Value Type='Text'>SomeValue</Value></Eq></Where></Query></View>";
ListItemCollection listItems = roomsList.GetItems(camlQuery);
context.Load(listItems);
context.ExecuteQuery();
Console.WriteLine("Query succeeded");
}

Because you are accessing the resource with an application login, by using TokenHelper.GetAppOnlyAccessToken, you must add the AllowAppOnlyPolicy="true" attribute to the AppPermissionRequest.
Friendly reminder, the client id and client secret should be treated like a user name and password when the AllowAppOnlyPolicy attribute is true, especially if the application is highly privileged, such as tenant admin or full control over a site collection. In any case, the client secret should be guarded, but it has to be combined with an authenticated user, if AllowAppOnlyPolicy is false.

Related

Authorization problem with SharePoint ClientContext created with ADAL Access Token

I am trying to automatize the provision of a SharePoint Online Site Collection. I am doing it with SharePoint CSOM. If I create the ClientContext(Microsoft.SharePoint.Client) object
with SharePointOnlineCredentials, everthing works fine such as creating sub sites/list/libraries, upload custom master pages, setting web properties etc. (By the way we are using Publishing Site)
ClientContext ctx = new ClientContext(contextWebUrl);
SecureString sec_pass = new SecureString();
Array.ForEach(contextPassword.ToArray(), sec_pass.AppendChar);
sec_pass.MakeReadOnly();
ctx.Credentials = new SharePointOnlineCredentials(contextUserName, sec_pass);
return ctx;
But i don't have user's password on production environment because we have to use ADAL authentication and we have only Access Token. So i have to create ClientContext object by using this token. Like;
ClientContext ctx = new ClientContext(siteUrl);
ctx.ExecutingWebRequest += delegate (object sender, WebRequestEventArgs e)
{
e.WebRequestExecutor.WebRequest.Headers.Add("Authorization", "Bearer " + siteToken.AccessToken);
if (digestValue != null)
{
e.WebRequestExecutor.WebRequest.Headers.Add("X-RequestDigest", digestValue.FormDigestValue);
e.WebRequestExecutor.WebRequest.Accept = "application/json;odata=verbose";
}
};
return ctx;
by this way getting something from SharePoint works but if i try to _set_ something such as create a subsite or deploy a master page to catalogs library i am getting 401 as below.
Access denied. You do not have permission to perform this action or access this resource
I thought that it was an update issue but even though i have used X-RequestDigest nothing changed.
Some people have encountered same issue when uploading documents but all answers are about using rest api directly and this cant solve my issue.
The token which is being used in second method is related to application client Id.
So Azure application needs necessary permission as similar as user's. In Azure Portal/Azure Active Directory, i gave AllSites.FullControl permission to the application which i use to signin and get access token.
Hereby this problem has been resolved.

Azure AD Graph - AppRole Creation using Application Credential Flow

I am creating a new role in azure application using Azure AD Graph API. what i'm doing is getting access token from azure using this code:
ClientCredential clientCredential = new ClientCredential(clientId, clientSecret);
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID);
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(graphResourceID, clientCredential);
return authenticationResult.AccessToken;
And Creating Role using following code:
//Fetch application Data from azure AD
IApplication application = await activeDirectoryClient.Applications.GetByObjectId(RoleModel.ApplicationID).ExecuteAsync();
AppRole NewRole = new AppRole
{
Id = CurrentRoleID,
IsEnabled = true,
AllowedMemberTypes = new List<string> { "User" },
Description = RoleModel.RoleDescription,
DisplayName = RoleModel.RoleName,
Value = RoleModel.RoleName
};
application.AppRoles.Add(NewRole as AppRole);
await application.UpdateAsync();
I also granted All Application Permissions not the Delegated Permissions from Azure portal to Microsoft Graph API. But i'm getting this error:
{"odata.error":{"code":"Authorization_RequestDenied","message":{"lang":"en","value":"Insufficient privileges to complete the operation."},"requestId":"e4187318-4b72-49fb-903d-42d419b65778","date":"2019-02-21T13:45:23"}}
Note:
I'm able to create new user and updated a user using this access token though.
For Testing:
For testing purpose, I granted Delegated Permissions to application and use client credential flow to get access token of current logged-in user and if the signed in user had enough directory role he/she can created role in application this is working fine.
Question:
So, is it possible to create a new role in application using application credential flow? if so, am i missing something?
Updated:
Added all Application Permission for API Windows Azure Active Directory and Grant admin consent.
Access Token:
Access Token returned from ADzure AD
Question: So, is it possible to create a new role in application using
application credential flow? if so, am i missing something?
Answer to your general question is Yes, you can add a new role to application's roles using Azure AD Graph API and client credentials flow.
Working Code
Given below is the working code (it's a quick and dirty console application, just to make sure I test it before confirming)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.ActiveDirectory.GraphClient;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
namespace AddAzureADApplicationRoles
{
class Program
{
static void Main(string[] args)
{
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(new Uri("https://graph.windows.net/{myTenantId}"),
async () => await GetTokenForApplication());
//Fetch application Data from azure AD
IApplication application = activeDirectoryClient.Applications.GetByObjectId("{MyAppObjectId}").ExecuteAsync().GetAwaiter().GetResult();
AppRole NewRole = new AppRole
{
Id = Guid.NewGuid(),
IsEnabled = true,
AllowedMemberTypes = new List<string> {"User"},
Description = "My Role Description..",
DisplayName = "My Custom Role",
Value = "MyCustomRole"
};
application.AppRoles.Add(NewRole as AppRole);
application.UpdateAsync().GetAwaiter().GetResult();
}
public static async Task<string> GetTokenForApplication()
{
string TokenForApplication = "";
AuthenticationContext authenticationContext = new AuthenticationContext(
"https://login.microsoftonline.com/{MyTenantId}",
false);
// Configuration for OAuth client credentials
ClientCredential clientCred = new ClientCredential("{AppId}",
"{AppSecret}"
);
AuthenticationResult authenticationResult =
await authenticationContext.AcquireTokenAsync("https://graph.windows.net", clientCred);
TokenForApplication = authenticationResult.AccessToken;
return TokenForApplication;
}
}
}
Probable Issue behind your specific exception
I think you have given application permissions on Microsoft Graph API, instead of permissions required for Azure AD Graph API.
While setting required permissions for your application, in Select an API dialog, make sure you select "Windows Azure Active Directory" and not "Microsoft Graph". I am giving screenshot for more detail next.
Steps to give required permissions
Notice that my app doesn't require any permissions on "Microsoft Graph API". It only has application permissions given for "Windows Azure Active Directory".
So, choose the appropriate application permission for your requirement, and make sure you do "Grant Permissions" at the end to provide Admin consent, as all the application permissions here mention Requires Admin as Yes.
On a side note, when you first create an app registration, it already has one delegated permission on Windows Azure Active Directory, so you may not need to explicitly select Windows Azure Active Directory again (unless you've removed it for your app), but just select the correct application permissions and do Grant Permissions as an administrator.

Status: Unauthorized (401) error while getting the reports from the workspace

I have created my app and registered over https://dev.powerbi.com/Apps as Native. In Azure, I added myself ad global admin user, registered myself to the application as admin, granted all Power BI API permissions. I created a workspace, added myself an admin user. Uploaded a Power BI report in my workspace. Works well when I am on browser.
I am trying to connect my report by using ASP.NET 4.61 MVC. My credentials, username and password work, so no problem for this code below:
var credential = new UserPasswordCredential(Username, Password);
// Authenticate using created credentials
var authenticationContext = new AuthenticationContext(AuthorityUrl);
var authenticationResult = await authenticationContext.AcquireTokenAsync(ResourceUrl, ApplicationId, credential);
if (authenticationResult == null)
{
result.ErrorMessage = "Authentication Failed.";
return View(result);
}
var tokenCredentials = new TokenCredentials(authenticationResult.AccessToken, "Bearer");
However, I am receiving the error: Status: Unauthorized (401) on the line GetReportsInGroupAsync(Workspaceid); where workspaceId is matching with my workspace.
// Create a Power BI Client object. It will be used to call Power BI APIs.
using (var client = new PowerBIClient(new Uri(ApiUrl), tokenCredentials))
{
// Get a list of reports.
var reports = await client.Reports.GetReportsInGroupAsync(WorkspaceId);
...
}
So the reports from my workspace I cannot reach because of unauthorization error, and I could not pass it. How can I authorize myself, I am already in AAD as Global Admin, added myself as application owner and in workspace I am already registered as admin.
I've found this topic below, but the answer did not fix my issue:unauthorized error 401 for power reports embedding
Followed this guideline, also did not work: https://learn.microsoft.com/en-us/power-bi/developer/register-app
Any help would be appreciated.
I had exact the same issue, and I checked the API call's header X-PowerBI-Error-Info. What I found there was: ServicePrincipalIsNotAllowedByTenantAdminSwitch.
So, your's tenant's admin should switch on "Allow service principals to use with Power BI APIs" and apply it to security group where Service Principal resides:
Admin portal

SharePoint 2010 Access Denied - Logged in user doesn't have permission to view the mebership of this sharepoint group

I have a scenario in my custom visual web part where I need to check for logged in User is a member of sharepoint group(sharepoint groups or users are stored in a sharepoint list). Actually if logged in users exists in the list, he will be given Edit access in my custom web part.
Since I have created a group name "SharePoint_Owners" with group settings as 'Who can View Membership of this group' to 'Group Members', Site is throwing error as 'Access denied' as logged in user doesn't have permission to view. I get error when my code executes this,
SPGroup oGroup = oWebsite.SiteGroups[strgroup];///strgroup is a group name
foreach (SPUser oUser in oGroup.Users) { }
Site throws this error when I try to open page which consists my webpart.
Can any one suggest me how do i proceed? is there a way to resolve this programmatically without actually giving View permission to "Everyone" for each group??
I thought RunWithElevatedPrivileges does my work but have no luck!
please help
Try this:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
string siteURL = SPContext.Current.Site.Url;
using (SPSite safeSite = new SPSite(siteURL))
{
using (SPWeb safeWeb = safeSite.OpenWeb())
{
SPGroup group = safeWeb.Groups["SharePoint_Owners"];
bool isMember = safeWeb.IsCurrentUserMemberOfGroup(group.ID);
}
}
});

impersonate as different user inside the webpart code

I use the sharepoint lists as a database.
I want to somehow impersonate as different user inside the webpart code
and than as this user I will have both write and edit permission to the list.
My goal is to be able to have full premission only through the webpart code.
I am using MOSS 2007.
SPSecurity.RunWithElevatedPrivilieges() will execute your code as the system account, i.e. the account under which the application pool runs, which might or might not be what you want to do. For example, if you have a workflow attached to the list which is supposed to trigger when new items are added to the list, it will not fire if you insert a new list item under the credentials of the system account (this was a security fix introduced in SharePoint 2007 SP 1). In that case you will have to perform the insert operation under a different account that has the correct permissions on the list.
You can get the UserToken for any user using the following code:
SPUserToken userToken = null;
SPSecurity.RunWithElevatedPrivileges(() =>
{
using (SPSite site = new SPSite(SPContext.Current.Site.ID))
{
using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
{
userToken = web.AllUsers["domain\\username"].UserToken;
}
}
});
Replace the "domain\username" with the correct windows account name. Then you can pass this user token to one of the overloads of the SPSite object constructor to execute the code under this user's credentials like so:
using (SPSite site = new SPSite(SPContext.Current.Site.ID, userToken))
{
using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
{
// This code will execute under the credentials of the userToken user
}
}
Hope this helps.
You are looking for SPSecurity.RunWithElevatedPrivileges Method.

Resources