azure sdk for net login is takes too long - azure-sdk-.net

I am using Fluent Library to develop a web app which can create a sql server on azure. The console app works great but when I implement the code to a web api it stuck in authentication step. I'm sure about the credentials which are true and I have a Service Principal.
// Authenticate
var credentials = new AzureCredentials(new ServicePrincipalLoginInformation { ClientId = ClientId, ClientSecret = Password }, tenantId, AzureEnvironment.AzureGlobalCloud);
var azure = Azure.Configure().Authenticate(credentials).WithDefaultSubscription();

I also can repro it on my side. I try to debug it with following code and add quick watch for azureauth.WithDefaultSubscription(), then get value The function evaluation requires all threads to run. So I guess that it may run some threads that WebAPI can't handle.
var azureauth = Azure.Configure().Authenticate(credentials);
azureauth.WithDefaultSubscription()
Please have a try to use following code to use specified subscriptionId as workaround. It works correctly on my side.
var azure = Azure.Configure().Authenticate(credentials).WithSubscription("subscriptionId");

Related

Obtain Access Token for the connection to PostgreSQL in Azure Functions

I have created some Azure Functions, and I would like to connect to Postgres database using an Access Token (for the connection of the user is doing the request to the endpoint of Azure Function). I've been following this page: https://learn.microsoft.com/en-us/azure/postgresql/howto-configure-sign-in-aad-authentication
For Authentication/Authorization in my functions I have created an Azure Active Directory app (in App registrarions). In this app, (not sure if this is useful) I have given permissions to the API of OSSRDBMS:
Then, I get the Access Token of the next endpoint of my App Service (where are my Functions):
MYAPP_SERVICE.azurewebsites.net/.auth/me
And I am trying to get the connection with this Access Token, but appearly is not the good one. What am I missing or how can I get the correct Access Token? I understand how works with Azure CLI, but I am trying to use the Access Token of the endpoint of my App Service... or can I do an HTTP Request to get the correct token?
I need a bit of guidance in this matter.
Thanks beforehand
If you want to connect Postgres database with Azure AD auth in Azure function, we can Azure Managed Identity to do Azure AD auth then get Azure AD access token and connect database.
The detailed steps are as below
Enable Azure MSI fro your Azure function app
Get the client id of the MSI
az login
az ad sp show --id <the object id of the msi> --query appId --output tsv
Configure Azure AD admin in Postgres database
Use the Azure AD admin to connect the database. (I use PgAdmin to connect)
SET aad_validate_oids_in_tenant = off;
CREATE ROLE <userName> WITH LOGIN PASSWORD '<the appid of the MSI>' IN ROLE azure_ad_user;
Configure Postgres server firewall. Please add the Azure function app outbound IP addresses in the firewall. Regarding how to get the Azure function app outbound IP addresses and configure Postgres server firewall, please refer to here and here
If you enable SSL, please download SSL certificate via the link
Function. (I use .net core to write the sample)
a. sdk
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.5.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.8" />
<PackageReference Include="Npgsql" Version="4.1.3.1" />
b. add above SSL certificate in project. For example, I create a folder cert in my project and save cert in the folder
c. code
[FunctionName("Http")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log, ExecutionContext context)
{
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://ossrdbms-aad.database.windows.net");
string Host = "test05.postgres.database.azure.com";
string User = "testuer#test05";
string Database = "postgres";
string connString =
String.Format(
"Server={0}; User Id={1}; Database={2}; Port={3}; Password={4};SSLMode=Require",
Host,
User,
Database,
5432,
accessToken);
string result = string.Empty;
using (var conn = new NpgsqlConnection(connString))
{
ProvideClientCertificatesCallback provideClientCertificates = clientCerts =>
{
string clientCertPath = context.FunctionAppDirectory + "\\cert\\BaltimoreCyberTrustRoot.crt.pem";
var cert = new X509Certificate2(clientCertPath);
clientCerts.Add(cert);
};
conn.ProvideClientCertificatesCallback += provideClientCertificates;
Console.Out.WriteLine("Opening connection using access token...");
conn.Open();
using (var command = new NpgsqlCommand("SELECT version()", conn))
{
var reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("\nConnected!\n\nPostgres version: {0}", reader.GetString(0));
result = reader.GetString(0);
}
}
}
return new OkObjectResult(result);
}
For more details, please refer to here

DevOps : Non-Interactive login in new DevOps(VSTS) not working getting error 'TF30063: You are not authorized to access

I am trying to connect to Azure DevOps previously known as VSTS using c#. I want to connect to it without the login screen of azure DevOps. I am currently trying the following code but some how it is not working
NetworkCredential netCred = new NetworkCredential("test#hotmail.com", "test");
Uri tfsuri = new Uri("https://dev.azure.com/test10");
VssBasicCredential bsCred = new VssBasicCredential(netCred);
VssCredentials vssCred = new VssClientCredentials(bsCred);
TfsTeamProjectCollection collection = new TfsTeamProjectCollection(tfsuri, vssCred);
collection.Authenticate();
var witClient = collection.GetClient<ProjectHttpClient>();
var listOfProjects = witClient.GetProjects().Result;
libraries I am using
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.VisualStudio.Services.Client;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.Operations;
using Microsoft.VisualStudio.Services.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
The code prompts a login screen, on which if I enter the password the auth still does not work. I dont want the login screen to appear and only want to connect with the username and password.
With alternate credentials this method is working but it is not my requirement and I can not use alternate credentials.
I have tried following the samples from the official site but no solution is working for the new DevOps.
Any Solution how can I authenticate with usernanme/password in the new DevOps without the login screen
The class TfsTeamProjectCollection is from the old .Net libraries, try the new Azure DevOps .Net libraries, and you can authenticate in a few ways:
NTLM
The most basic one is constructing a VssCredentials instance with no parameter at all and what you’ll be using is simply put integrated authentication / NTLM:
var visualStudioServicesConnection = new VssConnection(new Uri(baseUri), new VssCredentials());
Basic Authentication
VSTS and TFS also provide means to utilize Basic authentication (HTTP AUTH) which you need to create and enable first (see VSTS guidelines) and once you’ve done so, you can use them via the API like this:
var visualStudioServicesConnection = new VssConnection(new Uri(baseUri), new VssBasicCredential(username, password));
Personal Access Tokens
Next up are Personal Access Tokens (PAT) which you can easily create following the VSTS guidelines and those PATs are a means of authenticating separately from your actual credentials with a fine-grained & per access token scopes of security. Simply put it allows you to create a PAT for every use-case or even application and thereby enabling a secure and clearly separated way of giving an application or 3rd party access to your VSTS or TFS system on your behalf.
To use these via the API, you use the exact same mechanism as via Basic Authentication but you simply don’t provide any username (well – an empty one to be precise), and the PAT itself is used as the password:
var visualStudioServicesConnection = new VssConnection(new Uri(baseUri), new VssBasicCredential(string.Empty, pat));
Visual Studio Sign-in Prompt
Moreover, another way of authenticating is using the standard VS Sign-In prompt which is similarly easy and exposed via the VssClientCredentials class:
var visualStudioServicesConnection = new VssConnection(new Uri(baseUri), new VssClientCredentials());
OAuth Authentication
OAuth is a widely used but a slightly more tedious authorization protocol to implement but luckily there’s a thorough sample application available at CodePlex specifically for VSTS / VSO (which also works for on-premises).
Once you have the corresponding access token, you can use it to VSTS / TFS utilizing the VssOAuthCredential class:
var visualStudioServicesConnection = new VssConnection(new Uri(baseUri), new VssOAuthCredential(accessToken));
Azure Active Directory Authentication
Last but not least you can utilize Azure Active Directory identities to authenticate against a VSTS or TFS system via the VssAadCredential class:
var visualStudioServicesConnection = new VssConnection(new Uri(baseUri), new VssAadCredential(username, password));

Azure Key Vault: Secret not found error

I've created the Key Vault and entered a secret. When I run my services locally using .NET, I am able to retrieve the secret via the key vault. Here's what I did:
1) Created an SSL certificate
2) Used that SSL certificate to create an AD application
3) Created a Service Principle for the above application
4) Gave full key vault access to this application
5) I put the VaultURI, ServicePrincipal.Application ID, and the cert thumbprint in the Web.config file
6) I also uploaded the *.pfx of that cert to my cloud service
When I run my service locally, I am able to retrieve the secret. I have even tried retrieving the secret via powershell and I have been successful. When I deploy my code to Azure, I am unable to retrieve the secret.
It says:
Type : Microsoft.Azure.KeyVault.Models.KeyVaultErrorException, Microsoft.Azure.KeyVault, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 Message : Secret not found: QSAccounts7126 Source : Microsoft.Azure.KeyVault Help link :
I have spent 3 days looking at it and retesting every possible scenario and haven't figured out what is wrong. Can someone please help in identifying the issue or directing me in the right path for debugging?
I even tried publishing the cloud service in debug mode in Azure, and for some reason that did not work either.
Any help you can provide would be greatly appreciated.
private async Task<string> getSecretConnection(string connectionName)
{
var kvName = ConfigurationManager.AppSettings["vaultName"];
var kvClientId = ConfigurationManager.AppSettings["clientId"];
var kvClientThumbprint = ConfigurationManager.AppSettings["clientThumbprint"];
using (keyVaultHelper = new AzureKeyVaultHelper(kvClientId, kvClientThumbprint, kvName))
{
var bundle = await keyVaultHelper.GetAzureKeyVaultSecretAsync(connectionName);
return bundle;
}
public async Task<string> GetAzureKeyVaultSecretAsync(string secretName)
{
var bundle = await this.KvClient.GetSecretAsync(KeyVaultUrl, secretName);
return bundle.Value;
}
This is the code that runs for authentication:
private async Task<string> getAccessTokenFromSPNAsync(string authority, string resource, string scope)
{
//clientID and clientSecret are obtained by registering
//the application in Azure AD
var certificate = CertificateHelper.FindCertificateByThumbprint(this.ClientThumbprint);
var assertionCert = new ClientAssertionCertificate(this.ClientId, certificate); //needed for authentication
var clientCredential = new ClientCredential(this.ClientId, this.ClientThumbprint);
var authContext = new AuthenticationContext(authority, TokenCache.DefaultShared);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, assertionCert);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the token from Azure AD using certificate");
}
return result.AccessToken;
}
Can someone please help in identifying the issue or directing me in the right path for debugging?
It seems that you need to add the WEBSITE_LOAD_CERTIFICATES in your Azure WebApp setting to load certification to your web applications personal certificate store. More details you could refer this blog. We also could remote debug the WebApp to get more detail error information.
Adding an app setting named WEBSITE_LOAD_CERTIFICATES with its value set to the thumbprint of the certificate will make it accessible to your web application. You can have multiple comma-separated thumbprint values or can set this value to “ * “ (without quotes) in which case all your certificates will be loaded to your web applications personal certificate store.
I am not sure that your code is correct.
For example the constructor for ClientCredential takes a Client ID and Client Secret, your code is passing in a Client ID and Certificate Thumbprint.
See the Microsoft article Use Azure Key Vault from a Web Application for example code. I have used the code in this article and it works as expected when deployed to Azure.

Identity Server Windows and Username Password

I have identity server 3 setup and working with Windows Authentication, I have the Identity Server instance and the Windows Auth in 2 separate projects, I store custom claims in the database so I add these claims to the token in order to not have to make Web Api use windows and have to check user claims on every request since I have a separate Javascript client that uses the service. Great all works.
How do I add other authencation options to the identity server instance other type of clients? For Windows users in the domain I want to use Windows Auth and for users outside the domain I want to be able to show the login with username password but I don't want the windows users inside the domain to see the Identity Server page with the windows button.
I'm a little confused on how to setup this line:
factory.UserService = new Registration<IUserService>(typeof(ExternalRegistrationUserService));
var options = new IdentityServerOptions
{
SigningCertificate = Certificate.Load(),
Factory = factory,
AuthenticationOptions = new AuthenticationOptions
{
EnableLocalLogin = false,
IdentityProviders = ConfigureIdentityProviders,
}
};
Do I need to seutp multiple Identity Servers or can one Instance Support Muliple AuthenticationOptions?
You don't need multiple identity servers for that. Are you using identityserver 3 or 4? IdentityServer4 has a page in the documentation explaining how to do it with WebListener or Kestrel: http://docs.identityserver.io/en/release/topics/windows.html

Access VSTS Service Endpoint credentials from extension

I'm developing a VSTS extension.
I have configured a VSTS Service Endpoint through the portal.
I need to use the credentials of the configured endpoint in my extension code.
Does anybody know how to do this?
-Thanks in advance.
You need to add the service endpoint you want to use into the task.json of your build extension and then you can use it in the build task. Refer to this link for details: Service Endpoints in Team Services.
And you can also look at the VSTS Agent Task in GitHub for how to use the service endpoint in a build task like this one.
Thanks Eddie,
I found a solution for this with your help,
I was using 0.5.8 version of the vsts-task-lib library and update it to 0.9.7 and did the following,
//Import the task lib 0.9.7
import tl = require('vsts-task-lib/task');
//Get the endpoint ID (a guid)
serverEndpoint = tl.getInput('serverEndpoint', true);
//Get the enpoint URL for the retrieved end point id and parse it to URL type
serverEndpointUrl: url.Url = url.parse(tl.getEndpointUrl(this.serverEndpoint, false));
//Extract authentication details from url
serverEndpointAuth = tl.getEndpointAuthorization(this.serverEndpoint, false);
//Read parameters to variable
//NOTE: You cant write this data to console, if you do write, it will write //asterisk (****) instead of real values.
username = this.serverEndpointAuth['parameters']['username'];
password = this.serverEndpointAuth['parameters']['password'];
//Pass the variables as parameters.