Error Login failed for user ''.' when i try to connect through azure active directory interceptor in my solution - visual-studio

I am implementing the Azure active directory interceptor to connect my solution through active directory. My username is already added in the azure database and I am using below class as interceptor with like below.
public class AadAuthenticationDbConnectionInterceptor : DbConnectionInterceptor
{
public override InterceptionResult ConnectionOpening();
public override async Task<InterceptionResult> ConnectionOpeningAsync();
}
Its connecting fine through SSMS with the account but when I connect through my solution in visual studio it gives me below error:
Microsoft.Data.SqlClient.SqlException: 'Login failed for user ''.'
Help will be appreciated.

You need to use Azure Identity:
var resourceScope = "https://database.windows.net/.default";
var tokenCredential = new DefaultAzureCredential();
var accessToken = tokenCredential.GetToken(
new TokenRequestContext(scopes: new string[] { resourceScope }) { }
);
using (var connection = new SqlConnection($"Server={dbserver};Initial Catalog={db};Encrypt=True;TrustServerCertificate=True"))
{
connection.AccessToken = accessToken.Token;
connection.Open();
}

Related

Unable to add service account to a site added in google search console via an API

TLDR version
Is there an API to do this - https://support.google.com/webmasters/answer/7687615?hl=en, I want to be able to map service account to user using some API, (I am able to do it manually, but the list is long)
Long version
From what I understand there are 2 types of users
Type 1 - Normal user (human) logging in and using google search console
Type 2 - Google service accounts, used by application to pull data
Now I want to add several hundreds of site in Google Search Console, I found C# clients/API to do that.
I am able to add/list sites using normal user account using API, and then verify by using UI to see them getting added.
I am able (no error returned) to add/list sites using service accounts using API, but then unable to
see service account user being added in the user list of the site. But I still see the site when I call the list api
when pulling data for this site, I get errors
Google.Apis.Requests.RequestError
User does not have sufficient permission for site 'https://www.example.com/th-th/city/'. See also: https://support.google.com/webmasters/answer/2451999. [403]
Errors [Message[User does not have sufficient permission for site 'https://www.example.com/th-th/city/'. See also: https://support.google.com/webmasters/answer/2451999.] Location[ - ] Reason[forbidden] Domain[global]
It points me to this link - https://support.google.com/webmasters/answer/7687615?visit_id=1621866886080-4412438468466383489&rd=2 where I can use the UI and manually add my service account and then everything works fine.
But I want to do the same thing via API, because I will be having hundreds of sites to add to.
Please advice on how to go about this one?
Seems like this user also had similar problem, but no solution - How to connect Google service account with Google Search Console
CODE
This is the code I use to create site using normal user and client id/secret, here if I create a site I am able to see it on UI but the API (https://developers.google.com/webmaster-tools/search-console-api-original/v3/sites/add) does not have option to use service account.
public class WebmastersServiceWrapper
{
private string user = "realemail#example.com";
private readonly ClientSecrets _clientSecrets = new ClientSecrets
{
ClientId = "example.apps.googleusercontent.com",
ClientSecret = "example"
};
private readonly string[] _scopes = {
WebmastersService.Scope.WebmastersReadonly,
WebmastersService.Scope.Webmasters
};
public async Task<WebmastersService> GetWebmastersService()
{
var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(_clientSecrets, _scopes, user, CancellationToken.None);
var service = new WebmastersService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "WebMasters API Sample",
});
return service;
}
}
public class WebMasterSiteService
{
private readonly WebmastersServiceWrapper _connection;
public WebMasterSiteService()
{
_connection = new WebmastersServiceWrapper();
}
public async Task<IEnumerable<string>> GetSites()
{
var service = await _connection.GetWebmastersService();
var sitesResponse = await service.Sites.List().ExecuteAsync();
return SiteMapper.MapSites(sitesResponse);
}
public async Task DeleteSite(string site)
{
var service = await _connection.GetWebmastersService();
var response = await service.Sites.Delete(site).ExecuteAsync();
return;
}
public async Task AddSite(string site)
{
var service = await _connection.GetWebmastersService();
var response = await service.Sites.Add(site).ExecuteAsync();
return;
}
}
Here is the piece of code where I create sites using service worker, it gets created somewhere (as when I call list I get it back) but when I query that site using other APIs it fails with this error
Google.Apis.Requests.RequestError
User does not have sufficient permission for site 'https://www.example.com/th-th/city/'. See also: https://support.google.com/webmasters/answer/2451999. [403]
Errors [
Message[User does not have sufficient permission for site 'https://www.example.com/th-th/city/'. See also: https://support.google.com/webmasters/answer/2451999.] Location[ - ] Reason[forbidden] Domain[global]
]
public class SearchConsoleServiceWrapper
{
private readonly string[] _scopes = {
SearchConsoleService.Scope.WebmastersReadonly,
SearchConsoleService.Scope.Webmasters
};
public SearchConsoleService GetWebmastersService()
{
using var stream = new FileStream("key-downloaded-from-console-cloud-google.json", FileMode.Open, FileAccess.Read);
var credential = GoogleCredential.FromStream(stream)
.CreateScoped(_scopes)
.UnderlyingCredential as ServiceAccountCredential;
return new SearchConsoleService(new BaseClientService.Initializer
{
HttpClientInitializer = credential
});
}
}
public class SiteService
{
private readonly SearchConsoleServiceWrapper _connection;
public SiteService()
{
_connection = new SearchConsoleServiceWrapper();
}
public async Task<IEnumerable<string>> GetSites()
{
var service = _connection.GetWebmastersService();
var sitesResponse = await service.Sites.List().ExecuteAsync();
return SiteMapper.MapSites(sitesResponse);
}
public async Task DeleteSite(string site)
{
var service = _connection.GetWebmastersService();
var response = await service.Sites.Delete(site).ExecuteAsync();
return;
}
public async Task AddSite(string site)
{
var service = _connection.GetWebmastersService();
var response = await service.Sites.Add(site).ExecuteAsync();
return;
}
}
Final thoughts
Maybe I am missing something simple, also I haven't found a way to establish a relationship between my google search console account and my service account. But when I use my service account and add it as a user manually on a site, everything works and I am able to query properly.

How to implement Exchange online OAuth2.0 for unmanaged EWS API?

For managed EWS code, I have used to OAuth 2.0 to get token and it worked.
For unmanaged EWS, it is failing to connect to Exchange as an unauthorized error.
Below is the code to access unmanaged EWS.
How to make below code work with OAuth token instead of passing credentials as below?.
Binding = new ExchangeServiceBinding
{
Url = ServerUrl,
Credentials = new OAuthCredentials(token),
RequestServerVersionValue = new RequestServerVersion { Version = ExchangeVersionType.Exchange2007_SP1 },
ExchangeImpersonation = null
};
Above is not working as credential is asking of type ICredentials and it is not accepting token. Please help me.
Below is the code how I direct access managed EWS.
var authResult = await pca.AcquireTokenByUsernamePassword(ewsScopes, credential.UserName, credential.SecurePassword).ExecuteAsync();
configure the ExchangeService with the access token
ExchangeService = new ExchangeService();
ExchangeService.Url = new Uri(ServerUrl);
ExchangeService.Credentials = new OAuthCredentials(authResult.AccessToken);
One method i use (as I've never worked out how to override the WSDL classes) is if you modify the Reference.cs file that gets generated in the web references directory you can modify the GetWebResponse command (In this case the token is being passed via the credentials object password property but there a number of different approaches you can take here) eg
private String AnchorMailbox;
private bool oAuth;
protected override System.Net.WebResponse GetWebResponse(System.Net.WebRequest req)
{
if (xAnchorMailbox != null)
{
if (xAnchorMailbox != "")
{
req.Headers.Add("X-AnchorMailbox", AnchorMailbox);
}
}
if(req.Credentials is System.Net.NetworkCredential)
{
if(oAuth){
req.Headers.Add("Authorization", ("Bearer " + ((System.Net.NetworkCredential)req.Credentials).Password));
}
}
System.Net.HttpWebResponse
rep = (System.Net.HttpWebResponse)base.GetWebResponse(req);
return rep;
}

Google OAuth Api not redirecting on Login

I try to authenticate my user using Google authentication services
When i run this code on local server its working fine (It redirects to google login and after successful login its hit call back on redirectPath).
But when publish this code on Production server then its not working.
When I debug this code, I found its redirect and open the google login page on hosted environment(Where application is published).
here is my code - Please help
string redirecrPath = "http://localhost:1212/Admin/YouTubeIntegration/Success";
UserCredential credential;
using (var stream = new FileStream(Server.MapPath("/XmlFile/client_secrets.json"), FileMode.Open, FileAccess.Read))
{
GoogleAuth.RedirectUri = redirecrPath;
credential = await GoogleAuth.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { YouTubeService.Scope.Youtube, YouTubeService.Scope.YoutubeReadonly, YouTubeService.Scope.YoutubeUpload },
"user",
CancellationToken.None,
new FileDataStore(this.GetType().ToString())
);
}
Please let me know if you need more information.
Thanks in Advance
The code to login from a web page is not the same as the code to login with an installed application. Installed applications can spawn the login screen directly on the current machine. If you tried to do that on a webserver it wouldnt work the following is the code for using web login
using System;
using System.Web.Mvc;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Mvc;
using Google.Apis.Drive.v2;
using Google.Apis.Util.Store;
namespace Google.Apis.Sample.MVC4
{
public class AppFlowMetadata : FlowMetadata
{
private static readonly IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "PUT_CLIENT_ID_HERE",
ClientSecret = "PUT_CLIENT_SECRET_HERE"
},
Scopes = new[] { DriveService.Scope.Drive },
DataStore = new FileDataStore("Drive.Api.Auth.Store")
});
public override string GetUserId(Controller controller)
{
// In this sample we use the session to store the user identifiers.
// That's not the best practice, because you should have a logic to identify
// a user. You might want to use "OpenID Connect".
// You can read more about the protocol in the following link:
// https://developers.google.com/accounts/docs/OAuth2Login.
var user = controller.Session["user"];
if (user == null)
{
user = Guid.NewGuid();
controller.Session["user"] = user;
}
return user.ToString();
}
public override IAuthorizationCodeFlow Flow
{
get { return flow; }
}
}
}
copied from here

How do I authenticate to CRM Online using a non-interactive user?

I'm creating a console application that needs to access data in CRM Online 2016. This will run as a scheduled job and not interactively. It appears that I need to use OAuth for authentication.
I've already done the following:
I created a non-interactive user in CRM for the purpose of this integration. - I've already registered my app with Azure AD and have the Client Id.
What I can't figure out is how to authenticate to the web services. I was led to this MSDN article:
https://msdn.microsoft.com/en-us/library/gg327838.aspx
It shows how to authenticate but the example it shows causes a window to pop up asking the user to type a user/password. This won't work for me since this application will not be run interactively. I've looked everywhere but have not been able to find any documentation that shows me how to authenticate without having that window pop up.
It seems like I should be able to use AuthenticationContext.AcquireTokenByAuthorizationCode but I can't find any good examples for how that should be used.
Any direction is much appreciated!
Add a NuGet Reference to Microsoft.CrmSdk.XrmTooling.CoreAssembly.
Include the connection string in your app config (can include username and password as well)
<connectionStrings>
<add name="CrmService" connectionString="Url=https://UniqueOrgName.crm.dynamics.com;AuthType=Office365;"/>
</connectionStrings>
Call this code:
private static CrmServiceClient CreateCrmConnection(string userName, string password)
{
var url = ConfigurationManager.ConnectionStrings["CrmService"].ConnectionString;
var client = new CrmServiceClient(string.Format("{0}UserName={1};Password={2};", url, userName, password));
if (client.IsReady)
{
return client;
}
else
{
// Display the last error.
Console.WriteLine("Error occurred: {0}", client.LastCrmError);
// Display the last exception message if any.
Console.WriteLine(client.LastCrmException.Message);
Console.WriteLine(client.LastCrmException.Source);
Console.WriteLine(client.LastCrmException.StackTrace);
throw new Exception("Unable to Connect to CRM");
}
}
If you have a properly configured app registration with ClientId and ClientSecret, along with a few other organization specific variables, you can authenticate with Azure Active Directory (AAD) to acquire an oauth token and construct an OrganizationWebProxyClient. I've never found a complete code example of doing this, but I have developed the following for my own purposes. Note that the token you acquire has an expiry of 1 hr.
internal class ExampleClientProvider
{
// Relevant nuget packages:
// <package id="Microsoft.CrmSdk.CoreAssemblies" version="9.0.2.9" targetFramework="net472" />
// <package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="4.5.1" targetFramework="net461" />
// Relevant imports:
// using Microsoft.IdentityModel.Clients.ActiveDirectory;
// using Microsoft.Crm.Sdk.Messages;
// using Microsoft.Xrm.Sdk;
// using Microsoft.Xrm.Sdk.Client;
// using Microsoft.Xrm.Sdk.WebServiceClient;
private const string TenantId = "<your aad tenant id>"; // from your app registration overview "Directory (tenant) ID"
private const string ClientId = "<your client id>"; // from your app registration overview "Application (client) ID"
private const string ClientSecret = "<your client secret>"; // secret generated in step 1
private const string LoginUrl = "https://login.microsoftonline.com"; // aad login url
private const string OrganizationName = "<your organization name>"; // check your dynamics login url, e.g. https://<organization>.<region>.dynamics.com
private const string OrganizationRegion = "<your organization region>"; // might be crm for north america, check your dynamics login url
private string GetServiceUrl()
{
return $"{GetResourceUrl()}/XRMServices/2011/Organization.svc/web";
}
private string GetResourceUrl()
{
return $"https://{OrganizationName}.api.{OrganizationRegion}.dynamics.com";
}
private string GetAuthorityUrl()
{
return $"{LoginUrl}/{TenantId}";
}
public async Task<OrganizationWebProxyClient> CreateClient()
{
var context = new AuthenticationContext(GetAuthorityUrl(), false);
var token = await context.AcquireTokenAsync(GetResourceUrl(), new ClientCredential(ClientId, ClientSecret));
return new OrganizationWebProxyClient(new Uri(GetServiceUrl()), true)
{
HeaderToken = token.AccessToken,
SdkClientVersion = "9.1"
};
}
public async Task<OrganizationServiceContext> CreateContext()
{
var client = await CreateClient();
return new OrganizationServiceContext(client);
}
public async Task TestApiCall()
{
var context = await CreateContext();
// send a test request to verify authentication is working
var response = (WhoAmIResponse) context.Execute(new WhoAmIRequest());
}
}
See also https://stackoverflow.com/a/54775571/185200 if you're encountering access denied issues, and verify you've properly configured / authenticated the app.

Cannot get any facebook permissions with C# facebook SDK

I have a fairly simple site which allow users to connect via facebook.
I am using C# facebook sdk MVC.
At first i didn't need any specific permission so there were no problems for users to connect. my code looked like this
public class FacebookController : BaseController
{
public FacebookSession FacebookSession
{
get { return (new CanvasAuthorizer().Session); }
}
public ActionResult Profile()
{
var client = new FacebookClient(this.FacebookSession.AccessToken);
dynamic me = client.Get("me");
ViewBag.Name = me.name;
ViewBag.Id = me.id;
return View();
}
}
and on my webconfig
<facebookSettings appId="XXXXXXXXXXXXXX" appSecret="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"/>
After a while I needed more specific permissions so I added CanvasAuthorize to my action - as so
[CanvasAuthorize(Permissions = "user_about_me,user_relationships,email,publish_stream")]
public ActionResult Profile()
That got me this exception:
Exception Details: System.Exception: CanvasUrl is null or empty
So I added to my Webconfig the canvasUrl which got me the same error with out the canvasPage So now my web config has all 4
<facebookSettings appId="XXXXXXXXXX" appSecret="XXXXXXXXXXXXXXXXXXXXx" canvasUrl = "http://localhost:60606/" canvasPage = "https://apps.facebook.com/XXXXXXXXXXXX/"/>
So now my user can log in via facebook, my problem is that when he does log in he is getting redirect to my Facebook app (http://apps.facebook.com/XXXXXXXXX/facebook/profile)
instead back to my site(http://localhost:60606/facebook/profile)
How can I get the Permissions that i need and redirect my user back to my site after he logs in?
Thanks
Well, My bad
CanvasAuthorize is just as it sounds, authorization for canvas.
So you cannot use it without an app canvas on facebook.
What I should have done is use the FacebookOAuthClient
var oAuthClient = new FacebookOAuthClient(FacebookApplication.Current);
oAuthClient.RedirectUri = new Uri("XXXXXXXXXXXXXX");
var loginUri = oAuthClient.GetLoginUrl(new Dictionary<string, object> { { "state", null }, { "scope", "user_about_me,user_relationships,email" } });
return Redirect(loginUri.AbsoluteUri);

Resources