I'm using Office 365 API Tools for Visual Studio. When I run the following code everything works fine and my documents are returned.
string SPResourceID = "https://tenant.sharepoint.com";
string SPServiceRoot = "https://tenant.sharepoint.com/_api";
var authenticator = new Authenticator();
var result = await authenticator.AuthenticateAsync(SPResourceID, ServiceIdentifierKind.Resource);
// Create a client proxy:
this.client = new SharePointClient(new Uri(SPServiceRoot), result.GetAccessToken);
this.client.Context.IgnoreMissingProperties = true;
However, when I try to access a sub web such as:-
string SPResourceID = "https://tenant.sharepoint.com/test";
string SPServiceRoot = "https://tenant.sharepoint.com/test/_api";
I am asked to reauthenticate and then get the error "AADSTS50001: Resource 'https://tenant.sharepoint.com/test/' is not registered for the account". Has anyone got any ideas as to how I can access libraries in a sub web and is it possible to pass in the name of the library rather than relying on it being the default library.
Thanks,
Geoff
Your SPResourceID is still https://tenant.sharepoint.com/.
The resourceId is the ID your Office 365 subscription is registered with in azure ad.
Related
I am attempting to create a c# Windows service that periodically captures information from Microsoft Graph. This always fails with a "AADSTS700016: Application not found in the directory of our Microsoft 365 account."
Prior to trying to write this service, I created a test program to do same access. I set up an application in Azure Active Directory with a secret. When I run the exact same code in the this test program with the correct tenant ID, client ID and the secret, the program works fine from whatever computer I run it from.
However, the c# service always fails with the error noted above and detailed below. Can't be an issue with permissions as access IDs and secret are the same. I have even tried creating a separate application in AAD but get the same error.
Common c# statements:
var scopes = new[] { "https://graph.microsoft.com/.default" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientID, clientSecret, options); ;
graphClient = new GraphServiceClient(clientSecretCredential, scopes);
if (graphClient == null) throw new Exception("Unable able to obtain a GraphClient for this pass");
var groups = await graphClient.Groups.Request().Select(x => new { x.Id, x.DisplayName }).GetAsync();
Any help appreciated. I am sure it is something simple, but clueless at the moment.
Inner Exception 1:
AuthenticationFailedException: ClientSecretCredential authentication failed: AADSTS700016: Application with identifier 'c62d4eb9-587d-4b7f-a4d8-0640747f0958' was not found in the directory xxxx. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.
Trace ID: c8bfac15-c9d6-407e-89e7-36f21fb18300
Correlation ID: 9c8d25ad-c275-43c0-93c1-d295608e9f92
Timestamp: 2022-08-13 15:52:36Z
And just like that, I found the error. Good old global vs local variable name. I hope no one spent too much time on this.
I'm building a .net core 3 website where I'm trying to add a user to an Active Directory security group. The below code works fine in my development environment but once it's deployed to IIS I receive:
System.DirectoryServices.DirectoryServicesCOMException (0x8007202B):
A referral was returned from the server.
The error occurs at "group.Save();"
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "ad.xxx.com:389",
"DC=ad,DC=xxx,DC=com", svcAccountUsername, svcAccountPw))
{
GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, groupName);
group.Members.Add(pc, IdentityType.SamAccountName, username);
group.Save();
}
Again, this works locally in my development environment but not once deployed to IIS. Any suggestions on how to fix?
I would suggest looking up the account that you are trying to add to the AD. Other things i can suggest is using the debugger to confirm the account / group exists in the domain that you are running this under.
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "domain" ...))
{
GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, groupName);
// Do some validation / logging to make sure there is a group returned.
var principal = Principal.FindByIdentity(pc, IdentityType.SamAccountName, username);
// Do some validation here to make sure principal is not null
group.Members.Add(principal);
group.Save();
}
Make sure the server running this script has access to the domain you are updating.
A referral means that you aren't talking to the right server, but the server knows who you should be talking to. If you look into the exception object more, you might even find which server it wants to send you to.
This can happen if the group is not on the same domain that you passed to the PrincipalContext.
My goal is to allow users to connect to our Azure Sql Server using their Azure Active Directory credentials. I'm trying to follow the steps in this article, but I'm getting an error I can't sort out:
Connect to Azure SQL Database with Azure Multi-Factor Authentication
Below are the appropriate pieces of my code, which I largely copied from the example in the article (except my app is written in VB.NET so I had to translate). It requires the Microsoft.IdentityModel.Clients.ActiveDirectory assembly, which I got from NuGet.
Public Module DB
Private ConnectionProvider As ActiveDirectoryAuthProvider
'Gets run at application start
Public Sub SetProvider()
ConnectionProvider = New ActiveDirectoryAuthProvider
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, ConnectionProvider)
End Sub
End Module
'I can't believe Microsoft doesn't just have this as a class that's already been written
Public Class ActiveDirectoryAuthProvider
Inherits SqlAuthenticationProvider
Private ReadOnly _clientId As String = "Our Client ID From The Azure Portal"
Private ReadOnly _redirectUri As New Uri("A Valid URL")
Public Overrides Async Function AcquireTokenAsync(parameters As SqlAuthenticationParameters) As Task(Of SqlAuthenticationToken)
Dim authContext As New AuthenticationContext(parameters.Authority)
authContext.CorrelationId = parameters.ConnectionId
Dim result As AuthenticationResult
Select Case parameters.AuthenticationMethod
Case SqlAuthenticationMethod.ActiveDirectoryInteractive
result = Await authContext.AcquireTokenAsync(parameters.Resource, _clientId, _redirectUri, New PlatformParameters(PromptBehavior.Auto), New UserIdentifier(parameters.UserId, UserIdentifierType.RequiredDisplayableId))
Case SqlAuthenticationMethod.ActiveDirectoryIntegrated
result = Await authContext.AcquireTokenAsync(parameters.Resource, _clientId, New UserCredential())
Case SqlAuthenticationMethod.ActiveDirectoryPassword
result = Await authContext.AcquireTokenAsync(parameters.Resource, _clientId, New UserPasswordCredential(parameters.UserId, parameters.Password))
Case Else
Throw New InvalidOperationException()
End Select
Return New SqlAuthenticationToken(result.AccessToken, result.ExpiresOn)
End Function
Public Overrides Function IsSupported(ByVal authenticationMethod As SqlAuthenticationMethod) As Boolean
Return authenticationMethod = SqlAuthenticationMethod.ActiveDirectoryIntegrated OrElse authenticationMethod = SqlAuthenticationMethod.ActiveDirectoryInteractive OrElse authenticationMethod = SqlAuthenticationMethod.ActiveDirectoryPassword
End Function
End Class
'And finally, I create new connections like this:
New SqlConnection($"Server=tcp:ourserver.database.windows.net,1433;Initial Catalog=OurDatabase;TrustServerCertificate=True;Pooling=False;Encrypt=True;Authentication=""Active Directory Interactive"";User ID={Environment.UserName}#OurDomain.com;")
Using this code, I do get the popup from Azure asking me to sign in when I run SqlConnection.Open. As soon as I've signed in however, I get the following exception:
Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException
AADSTS7000218: The request body must contain the following parameter:
'client_assertion' or 'client_secret'.
Any idea how I can fix that?
So, in digging through every resource I could find, I came across this question:
“error_description”:"AADSTS70002: The request body must contain the following parameter: 'client_secret or client_assertion'
The answer linked above points to the "Redirect URI" registered with the application in Azure as the cause of the issue.
The Microsoft article in my question states: "For this article, any valid value is fine for RedirectUri, because it isn't used here." The example they use is: "https://mywebserver.com/".
Contrary to the quote from Microsoft, the answer I linked above points out that Azure uses the Redirect URI to determine the type of application that is being registered. Changing the URI from my company's website to "https://login.microsoftonline.com/common/oauth2/nativeclient" fixes my problem. That URL is one of the default values Azure lets you pick from. It evidently indicates to Azure that you are registering a native app, not a web app. Once Azure knows this, it seems to stop demanding a "'client_assertion' or 'client_secret'", which I can only assume are things required for web app authentication.
I faced with this problem a bit earlier, spent a lot of time to figure out the problem and the only solution which helped was adding of "https://login.microsoftonline.com/common/oauth2/nativeclient" on "Authentication" tab to "Redirect URIs" like it was mentioned by Keith Stein
I am using ReportExecutionServiceSoapClient in .Net Core i got the latest version of .net Core and tried to get a report from reporting services to work. after I've used the WCF connection service I was able to add the code with looks like bellow
// Instantiate the Soap client
ReportExecutionServiceSoap rsExec = new ReportExecutionServiceSoapClient(ReportExecutionServiceSoapClient.EndpointConfiguration.ReportExecutionServiceSoap);
// Create a network credential object with the appropriate username and password used
// to access the SSRS web service
string historyID = null;
TrustedUserHeader trustedUserHeader = new TrustedUserHeader();
ExecutionHeader execHeader = new ExecutionHeader();
// Here we call the async LoadReport() method using the "await" keyword, which means any code below this method
// will not execute until the result from the LoadReportAsync task is returned
var taskLoadReport = rsExec.LoadReportAsync(reportPath, historyID);
// By the time the LoadReportAsync task is returned successfully, its "executionInfo" property
// would have already been populated. Now the remaining code in this main thread will resume executing
string deviceInfo = null;
string format = "EXCEL";
// Now, similar to the above task, we will call the RenderAsync() method and await its result
var taskRender = await rsExec.RenderAsync(renderReq);
When it hist renderAsync all falls apart because the credentials for the service are not set anywhere. I've tried to Login async with no success. Also I've tried to set the credentials with SetExecutionCredentialsAsync but I've got and error saying "The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'NTLM'." I don't know how to change that for ReportExecutionServiceSoapClient.
I have read some posts in which Microsoft guys says that the authentication with a soap is not resolved but for me it seems so close to be true. I feel like I am missing something.
Technology stack: VS 2017, .net Core web api, ssrs 2016, sql server 2016 standard
How can I authenticate the user for this call?
I know this is an old question but I had the same issue and stumbled onto the answer.
After creating the ReportExecutionServiceSoap object you can specify the username and password in the ClientCredentials. I've had success with this using the Basic client credential type. Be sure you are using HTTPS, otherwise your password is sent in plaintext to the reporting server. I also recommend storing the user/password in a secure place and not code.
BasicHttpBinding rsBinding = new BasicHttpBinding();
rsBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
rsBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
EndpointAddress rsEndpointAddress = new EndpointAddress("https://servername/ReportServer/ReportExecution2005.asmx");
var rsExec = new ReportExecutionServiceSoapClient(rsBinding, rsEndpointAddress);
rsExec.ClientCredentials.UserName.UserName = "username";
rsExec.ClientCredentials.UserName.Password = "pass";
i need help for my application "Google App Script".
I am the owner of a Spreadsheet that I use as a DB in my application; this spreadsheet must remain private.
My application is executed as Gadget in Google Site, in this application a user runs the script as himself (not under the owner's identity).
I need that all users who access the application can get some data from the DB Spreadsheet.
How can users get this data, if the Spreadsheet is only accessible to me?
Can I use oAuth?
Sorry for the bad English
Following Zig answer and to illustrate, here is an example of such a contentService webapp, one can call it with this url either in a browser or in urlFetch
The app is deployed as follows : execute as me and anyone can access even anonymous
https://script.google.com/macros/s/AKfycbxfk5YR-JIlhv7HG9R7F-cPxmL0NZRzrdGF4VFGxGivBkYeZY4/exec?&user=chris&row=4&sheet=Sheet1
and here is the demo script
function doGet(e) {
if(e.parameter.user!='serge' && e.parameter.user!='chris' ){return ContentService.createTextOutput("logging error, you are not allowed to see this").setMimeType(ContentService.MimeType.TEXT)};
var sheet = e.parameter.sheet;
var row = Number(e.parameter.row);
Logger.log(sheet+' '+row);
var ss = SpreadsheetApp.openById("0AnqSFd3iikE3dENnemR2LVFMTFM5bDczNGhfSG11LVE");// this sheet is private but anyone can call this app
var sh = ss.getSheetByName(sheet);
var range = sh.getRange(row,1,1,sh.getLastColumn());
var val = Utilities.jsonStringify(range.getValues());
var result = ContentService.createTextOutput(val).setMimeType(ContentService.MimeType.JSON);
return result;
}
No you cant use oauth from the gadget as the user doesnt have read permission.
However you can publish a second script to extract needed data that runs as you with anonymous public access and call that one with urlfetch from the 1st. Slower thou.