Azure KeyVault - Use certificate and certificate private key - azure

I am working on an use case where I need to use the self-signed certificates, those I have created by using Azure Key Vault.
My application requires the certificate key and certificate private key to authenticate.
I want to understand how I can get these values by using Azure KeyVault Java API.
Also, please let me know how I can get the Azure user client-id and client-key?

Actually, no need to use the keyvault rest api, you could use java SDK for keyvault to get certificate.
package com.example.azure.keyvault;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* Based on example from Microsoft documentation:
* https://azure.github.io/azure-sdk-for-java/com/microsoft/azure/keyvault/authentication/KeyVaultCredentials.html
*/
public class ClientSecretKeyVaultCredential extends KeyVaultCredentials
{
private String clientId;
private String clientKey;
public ClientSecretKeyVaultCredential( String clientId, String clientKey ) {
this.clientId = clientId;
this.clientKey = clientKey;
}
#Override
public String doAuthenticate(String authorization, String resource, String scope) {
AuthenticationResult token = getAccessTokenFromClientCredentials(
authorization, resource, clientId, clientKey);
return token.getAccessToken();
}
private static AuthenticationResult getAccessTokenFromClientCredentials(
String authorization, String resource, String clientId, String clientKey) {
AuthenticationContext context = null;
AuthenticationResult result = null;
ExecutorService service = null;
try {
service = Executors.newFixedThreadPool(1);
context = new AuthenticationContext(authorization, false, service);
ClientCredential credentials = new ClientCredential(clientId, clientKey);
Future<AuthenticationResult> future = context.acquireToken(
resource, credentials, null);
result = future.get();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
service.shutdown();
}
if (result == null) {
throw new RuntimeException("authentication result was null");
}
return result;
}
For more details, you could follow the steps in this sample. The sample is to get secret, just use the method KeyVaultClient.getCertificate to get the certificate at last instead of getting secret.
Note: Don't forget to add your AD App in the Access Policies of the keyvault, otherwise your app will not have the permission.
Besides, you should note the client-id(i.e. application id) and client-key is for the Azure AD Application not the user, they are all mentioned in the sample doc. Or for more details, you could refer to : Create an Azure Active Directory application and create a secret for the app, save the secret by yourself and get values for signing in.

Related

Usage of the /common endpoint is not supported for such applications created after '10/15/2018' issue

Similar issue here. I have checked the answer and try to implement all the possible forms of link in my startup.cs class with the following code:
var idClient = ConfidentialClientApplicationBuilder.Create(appId)
.WithRedirectUri(redirectUri)
.WithTenantId(tenantId)
.WithClientSecret(appSecret)
.WithAuthority(Authority) // Authority contains the link as mentioned in the page(link attached above)
.Build();
I still get the similar error:
"OpenIdConnectMessage.Error was not null, indicating an error. Error: 'invalid_request'. Error_Description (may be empty): 'AADSTS50194: Application 'xxx-xxx-xxx-xxx-xxxx'(ASPNET-Quickstart) is not configured as a multi-tenant application. Usage of the /common endpoint is not supported for such applications created after '10/15/2018'. Use a tenant-specific endpoint or configure the application to be multi-tenant.
Trace ID: xxx-xxx-xxx-xxx-xxxx
Correlation ID: xxx-xxx-xxx-xxx-xxxx
Timestamp: 2022-06-11 05:33:24Z'. Error_Uri (may be empty): 'error_uri is null'."
The combination of links I have used in variable Authority are the following: "https://login.microsoftonline.com/MY_TENANT_NAME" and "https://login.microsoftonline.com/MY_TENANT_ID"
I am being redirect to login page but after entering credentials OnAuthenticationFailedAsync method is being executed. This is the code of my startup class:
[assembly: OwinStartup(typeof(Web.Startup))]
namespace Web
{
public partial class Startup
{
// Load configuration settings from PrivateSettings.config
private static string appId = ConfigurationManager.AppSettings["ida:AppId"];
private static string appSecret = ConfigurationManager.AppSettings["ida:AppSecret"];
private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
private static string graphScopes = ConfigurationManager.AppSettings["ida:AppScopes"];
private static string tenantId = ConfigurationManager.AppSettings["ida:tenantId"];
private static string aadInstance = EnsureTrailingSlash(ConfigurationManager.AppSettings["ida:AADInstance"]);
public static string Authority = "https://graph.microsoft.com/"+ tenantId;
string graphResourceId = "https://graph.microsoft.com/";
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = appId,
Authority = "https://login.microsoftonline.com/common/v2.0",
Scope = $"openid email profile offline_access {graphScopes}",
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectUri,
TokenValidationParameters = new TokenValidationParameters
{
// For demo purposes only, see below
ValidateIssuer = true
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailedAsync,
AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
}
}
);
}
private static Task OnAuthenticationFailedAsync(AuthenticationFailedNotification<OpenIdConnectMessage,
OpenIdConnectAuthenticationOptions> notification)
{
notification.HandleResponse();
string redirect = $"/Home/Error?message={notification.Exception.Message}";
if (notification.ProtocolMessage != null && !string.IsNullOrEmpty(notification.ProtocolMessage.ErrorDescription))
{
redirect += $"&debug={notification.ProtocolMessage.ErrorDescription}";
}
notification.Response.Redirect(redirect);
return Task.FromResult(0);
}
private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
{
var idClient = ConfidentialClientApplicationBuilder.Create(appId)
.WithRedirectUri(redirectUri)
.WithTenantId(tenantId)
.WithClientSecret(appSecret)
.WithAuthority(Authority)
.Build();
string email = string.Empty;
try
{
string[] scopes = graphScopes.Split(' ');
var result = await idClient.AcquireTokenByAuthorizationCode(
scopes, notification.Code).ExecuteAsync();
email = await GraphHelper.GetUserDetailsAsync(result.AccessToken);
}
catch (MsalException ex)
{
System.Diagnostics.Trace.TraceError(ex.Message);
}
notification.HandleResponse();
notification.Response.Redirect($"/Account/SignInAzure?email={email}");
}
private static string EnsureTrailingSlash(string value)
{
if (value == null)
{
value = string.Empty;
}
if (!value.EndsWith("/", StringComparison.Ordinal))
{
return value + "/";
}
return value;
}
}
}
My application is for single tenant so please don't suggest me to change the setting and make it for multi-tenant.
Please check below points:
After trying to change it to specific tenant i.e.;
After changing to Ex: - https://login.microsoftonline.com/contoso.onmicrosoft.com (or tenant id),
please save changes ,refresh portal / everything and try again.
If still it shows the error , check if the Application is registered to the Azure AD Tenant as Multi Tenant Application.
Then if it still remains check if the account is actually on Azure
AD ,as this error can occur when the user credentials you are trying
to use does not belong to the same tenant where the application is
actually registered in.
If it is different tenant and you are trying to access from different
account, then you may need to change its supported account types to
any organizational directory or you need to check for correct
credentials. If not check everything or create a new app registration
.
Also please check this "Use a tenant-specific endpoint or configure the application to be multi-tenant" when signing into my Azure website for possible
ways to solve the issue.
Else you can raise a support request
References:
msal - MsalException: Applicationis not configured as a multi-tenant
application. Android - Stack Overflow
Use single-tenant Azure AD apps with Microsoft Graph Toolkit -
Waldek Mastykarz

MSAL error "parsing_wstrust_response_failed" when trying to use AcquireTokenByIntegratedWindowsAuth

I'm attempting to acquire a token from AD or Azure AD but my call to AcquireTokenByIntegratedWindowsAuth results in this:
MSAL.Desktop.4.14.0.0.MsalClientException:
ErrorCode: parsing_wstrust_response_failed
Microsoft.Identity.Client.MsalClientException: An error occurred while sending the request.
---> System.Net.Http.HttpRequestException: An error occurred while sending the request.
---> System.Net.WebException: The remote server returned an error: (401) Unauthorized.
---> System.ComponentModel.Win32Exception: The system cannot contact a domain controller to service the authentication request. Please try again later
According to the team that registered my app in Azure I'm a public client and I've got rights to use 'user.read'
Any idea what could be up so that I can communicate something back to our firm's Azure team. It could be my fault, their fault or MS's fault, I'd just like to know who to complain to. Most of the code is generated by the Azure portal, I just changed the call to AcquireTokenInteractive to AcquireTokenByIntegratedWindowsAuth since my final goal is to silently get the token all the time.
public partial class MainWindow : Window
{
string graphAPIEndpoint = "https://graph.microsoft.com/v1.0/me";
string[] scopes = new string[] { "user.read" };
public MainWindow()
{
InitializeComponent();
}
private async void CallGraphButton_Click(object sender, RoutedEventArgs e)
{
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
AuthenticationResult authResult = null;
var app = App.PublicClientApp;
ResultText.Text = string.Empty;
TokenInfoText.Text = string.Empty;
var accounts = await app.GetAccountsAsync();
var firstAccount = accounts.FirstOrDefault();
try
{
authResult = await app.AcquireTokenSilent(scopes, firstAccount)
.ExecuteAsync();
}
catch (MsalUiRequiredException ex)
{
System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");
try
{
authResult = await app.AcquireTokenByIntegratedWindowsAuth(scopes)
.ExecuteAsync(CancellationToken.None);
}
catch (MsalException msalex)
{
ResultText.Text = $"Error Acquiring Token:{System.Environment.NewLine}{msalex}";
}
}
public partial class App : Application
{
static App()
{
_clientApp = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority($"{Instance}{Tenant}")
.WithDefaultRedirectUri()
.Build();
TokenCacheHelper.EnableSerialization(_clientApp.UserTokenCache);
}
private static string ClientId = "<My Client ID>";
private static string Tenant = "<Our Tenant ID>";
private static string Instance = "https://login.microsoftonline.com/";
private static IPublicClientApplication _clientApp ;
public static IPublicClientApplication PublicClientApp { get { return _clientApp; } }
}
Based on https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Integrated-Windows-Authentication, there are a number of constraints surrounding the AcquireTokenByIntegratedWindowsAuth method.
If you are testing with your own user account, consent must be granted to the application for your account. Also, 2FA cannot be enabled when using this Auth flow.
For other users, they will need to consent to the application accessing their account details, or the tenant admin must grant consent across the tenant using the Grant admin consent for Tenant button in the portal.
This flow only applies to "federated users" (e.g. created in AD rather than AzureAD).
This flow is targeted primarily at desktop applications. It only works with .net desktop, .net core and Windows Universal Apps.

Azure Ad authentication by passing username and password to get the jwt token

Currently i am trying to implement the azure active directory authentication by passing user name and password. So for this i have trying to get the access toke but facing issue to get the same. If i use the client id and client secret then i am able to get the token but when i try to by passing username and password then its not giving the result and throwing the exception :
"error":"invalid_client","error_description":"AADSTS70002: The request body must contain the following parameter: 'client_secret or client_assertion'
Below the code which i am using for this:
/// <summary>
/// Working with client id and client secret
/// </summary>
/// <returns></returns>
public async Task<string> GetTokenUsingClientSecret()
{
//authentication parameters
string clientID = "XXXXXXXXXXXXXXXXXXXXXXXXXX";
string clientSecret = "XXXXXXXXXXXXXXXXXXXXXXXXX";
string directoryName = "xxx.onmicrosoft.com";
var credential = new ClientCredential(clientID, clientSecret);
var authenticationContext = new AuthenticationContext("https://login.microsoftonline.com/" + directoryName, false);
var result = await authenticationContext.AcquireTokenAsync("https://management.core.windows.net/", clientCredential: credential);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
return token;
}
/// <summary>
/// Not Working with username and password.
/// </summary>
public async Task<string> GetTokenUsingUserNamePassword()
{
try
{
string user = "username.onmicrosoft.com";
string pass = "yourpassword";
string directoryName = "XXXX.onmicrosoft.com";
string authority = "https://login.microsoftonline.com";
string resource = "https://management.core.windows.net/";
string clientId = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX";
var credentials = new UserPasswordCredential(user, pass);
var authenticationContext = new AuthenticationContext($"{authority}/{directoryName}");
var result = authenticationContext.AcquireTokenAsync(resource: resource, clientId: clientId, userCredential: credentials);
return result.Result.AccessToken;
}
catch (Exception ex)
{
throw ex;
}
}
AADSTS70002: The request body must contain the following parameter: 'client_secret or client_assertion'.
According to your mentioned exception, I assume that you registry an Azure AD Web app/API application. Please have a try to use an Azure AD native appilcation then it should work. More details you could refer to this document -Constraints & Limitations section.
No web sites/confidential clients
This is not an ADAL limitation, but an AAD setting. You can only use those flows from a native client. A confidential client, such as a web site, cannot use direct user credentials.
How to reigstry Azure AD native Application.

NullReferenceException in Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireToken

I'm trying to get some MSFT Power BI SDK samples working. Unfortunately, the Microsoft.IdentityModel.Clients.ActiveDirectory library is giving me a lot of trouble with the initial external authentication step.
I'm using Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.28.3.860, from NuGet; this is the last version of the library before AcquireToken was removed, and I haven't figured out how to use its replacement (AcquireTokenAsync) in a way that's equivalent to what I see in the samples.
When I take the following code and modify the TODO lines to specify my actual Azure Client ID and authentication redirect page, I get as far as the AcquireToken line.
using System;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
public class Application
{
public static void Main(string[] args)
{
try
{
string clientID = "abcdef01-1234-1234-abcd-abcdabcd1234"; // TODO: actual Azure client ID
string redirectUri = "https://acmecorporation.okta.com/login/do-login"; // TODO: actual redirect
string resourceUri = "https://analysis.windows.net/powerbi/api";
string authorityUri = "https://login.windows.net/common/oauth2/authorize";
AuthenticationContext authContext = new AuthenticationContext(authorityUri);
AuthenticationResult ar = authContext.AcquireToken(
resourceUri,
clientID,
new Uri(redirectUri),
PromptBehavior.RefreshSession);
string token = ar.AccessToken;
Console.WriteLine("Success: " + token);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
At this point:
A "Sign in to your account" window pops up with the name of the app I've associated in Azure with the clientID GUID
I'm redirected to my organization's ("acmecorporation") sign-on page
I sign in using my AD credentials
The AcquireToken method throws the following NullReferenceExpection:
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.RunAsyncTask[T](Task`1 task)
at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.AcquireToken(String resource, String clientId, Uri redirectUri, PromptBehavior promptBehavior)
at PowerBISample.Application.Main(String[] args) in \\noxfile\users\ehirst\documents\visual studio 2015\Projects\PowerBISample\PowerBISample\Program.cs:line 18
Can anyone provide guidance on how to get past this? My goal is to get a POC working to determine whether we can integrate Power BI into a larger application, but so far it feels like I'm beta testing a pretty unstable system.
The NullReferenceException is a bug in the 2.x version of the ADAL library; it's fixed in current versions. It was triggered by an incorrect value of redirectUri; unfortunately the documentation was sparse on this one. A working code sample, adapted (thanks Kanishk!) to use the current 3.13.7 version of ADAL, is posted below.
namespace PowerBISample
{
using System;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Threading.Tasks;
public class Application
{
public static void Main(string[] args)
{
Run();
Console.ReadLine();
}
static async void Run()
{
try
{
string clientID = "abcdef01-1234-1234-abcd-abcdabcd1234"; // TODO: actual Azure client ID
/** THE REAL PROBLEM WAS HERE **/
string redirectUri = "https://login.live.com/oauth20_desktop.srf";
string resourceUri = "https://analysis.windows.net/powerbi/api";
string authorityUri = "https://login.windows.net/common/oauth2/authorize";
AuthenticationContext authContext = new AuthenticationContext(authorityUri);
AuthenticationResult ar = await authContext.AcquireTokenAsync(resourceUri, clientID, new Uri(redirectUri), new PlatformParameters(PromptBehavior.RefreshSession));
string token = ar.AccessToken;
Console.WriteLine("Success: " + token);
}
catch (Exception ex)
{
string error = ex.ToString();
Console.WriteLine(error);
}
}
}
}

Azure active directory and owin authentication

Just faced an strange issue with azure ad applicationS and owin openid authentication.
To reproduce the issue.
1.create a web app with azure ad authentication in vs 2015 choosing cloud app template .
2.let the standard code be as is.
3.let startup.auth as is.
4.Run the app on local it works fine.
5.now change code in startup àuth as follows
public partial class Startup
{
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private static string appKey = ConfigurationManager.AppSettings["ida:ClientSecret"];
private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
private static string tenantId = ConfigurationManager.AppSettings["ida:TenantId"];
private static string postLogoutRedirectUri = ConfigurationManager.AppSettings["ida:PostLogoutRedirectUri"];
public static readonly string Authority = aadInstance + tenantId;
// This is the resource ID of the AAD Graph API. We'll need this to request a token to call the Graph API.
string graphResourceId = "https://graph.windows.net";
private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public void ConfigureAuth(IAppBuilder app)
{
ApplicationDbContext db = new ApplicationDbContext();
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
logger.Debug("SetDefaultSignInAsAuthenticationType called");
//app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseCookieAuthentication(
new CookieAuthenticationOptions
{
Provider = new CookieAuthenticationProvider
{
OnResponseSignIn = ctx =>
{
//logger.Debug("OnResponseSignIn called");
////ctx.Identity = TransformClaims(ctx.Identity);
//logger.Debug("TransformClaims called");
}
}
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = Authority,
PostLogoutRedirectUri = postLogoutRedirectUri,
Notifications = new OpenIdConnectAuthenticationNotifications()
{
// If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
AuthorizationCodeReceived = (context) =>
{
var code = context.Code;
ClientCredential credential = new ClientCredential(clientId, appKey);
string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
logger.Debug("OnResponseSignIn called");
logger.Debug("signedInUserID =" + signedInUserID);
TransformClaims(context.AuthenticationTicket.Identity);
logger.Debug("TransformClaims called");
AuthenticationContext authContext = new AuthenticationContext(Authority, new ADALTokenCache(signedInUserID));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceId);
return Task.FromResult(0);
},
// we use this notification for injecting our custom logic
SecurityTokenValidated = (context) =>
{
logger.Debug("SecurityTokenReceived called");
//TransformClaims(); //pass the identity
return Task.FromResult(0);
},
}
});
}
private static void TransformClaims(System.Security.Claims.ClaimsIdentity identity)
{
if (identity != null && identity.IsAuthenticated == true)
{
var usserobjectid = identity.FindFirst(ConfigHelpers.Azure_ObjectIdClaimType).Value;
((System.Security.Claims.ClaimsIdentity)identity).AddClaim(new System.Security.Claims.Claim("DBID", "999"));
((System.Security.Claims.ClaimsIdentity)identity).AddClaim(new System.Security.Claims.Claim("Super","True"));
}
// return identity;
}
}
6.Run the app on local it will work perfect.
7.Deploy the app on azure websites and the startup àuth owin notification methods will never be called.however app works but identity transformation not
Can somebody help out what's wrong with this is azure ad apps doesn't support cookies or notification not firing or anything wrong with code.
Just to re-assert else than startup.àuth no standard code is changed.
I know this is a bit old, but I had exactly the same issue recently and spent hours trying to understand why it wouldn't work in Azure but it worked absolutely fine in my localhost.
This is basically a configuration issue: in portal.azure.com select your app and then go to settings > authentication / authorisation and make sure that app service authentication is OFF.
It turns out that this setting will take over your startup.auth settings.
I have to give full credit to Vittorio Bertocci as pointed that out to me.

Resources