I had below code to fetch key vault secrets in Azure:
var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetToken));
var sec = await kv.GetSecretAsync(ConfigurationManager.AppSettings["SomeURI"]);
secretValue = sec.Value ;
In App Config I had:
<add key="SomeURI" value="https://baseURL/KeyName/b75cabsdf45667nhjhe516c674457" />
Since I have been using this many times in my application, I have created a class and called that class. The class looks like this:
public static class KeyVaultFetch
{
public async static Task<string> GetCachedSecret(string secretname)
{
try
{
string BaseUri = ConfigurationManager.AppSettings["keyvaultBaseURI"].ToString();
var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetToken));
var secretbundle = await kv.GetSecretAsync($"{BaseUri}{secretname}").ConfigureAwait(false);
return secretbundle.Value;
}
catch (Exception ex)
{
log.Error("Exception raised in GetCachedSecret.");
log.Error("Exception Details: " + ex.Message);
log.Error("Inner Exception Details: " + ex.InnerException);
throw;
}
}
public static async Task<string> GetToken(string authority, string resource, string scope)
{
try
{
var authContext = new AuthenticationContext(authority);
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
if (result == null)
throw new InvalidOperationException("Failed to obtain the JWT token");
return result.AccessToken;
}
catch (Exception ex)
{
log.Error("Exception raised while Getting token : " + ex.Message);
log.Error("Inner Exception Details: " + ex.InnerException);
throw;
}
}
}
And I have written below line to get the secret every time:
secretValue = await KeyVaultFetch.GetCachedSecret(keyName);
But I'm geeting the below exception , when I run my code :
Exception raised in GetCachedSecret.
Exception Details: Invalid ObjectIdentifier: https://baseURL/. Bad number of segments: 2
What am I doing wrong?
You should use GetSecretAsync with 2 parameters:
await kv.GetSecretAsync(BaseUri, secretname);
At least that's how it is in our apps :)
Related
I need to log exceptions and bad requests in my API. Currently I am using try catch to catch the exception and add to my logs in the catch block. Is this the right way? I read about Global Error Handling in ASP.NET. How can I implement that approach for this case?
Below is my API Controller example:
[HttpPost]
[Authorize]
[ValidateModel]
[Route("CheckProgramOwner")]
public async Task<IHttpActionResult> CheckProgramOwner([FromBody] CheckProgramOwner _data)
{
try
{
using (var db = new VisualVoiceFlowEntities())
{
var Result= await db.VVF_ScriptFlow.Where(s => s.ProgramId == _data.ProgramId).OrderByDescending(s => s.ID).FirstOrDefaultAsync();
if(Result== null)
{
Log.Error("Error in CheckProgramOwner POST Request - " + "ProgramId not found");
return Content(HttpStatusCode.BadRequest, "ProgramId not found");
}
string CurrentOwner = Result.ReadBy.ToString();
return Ok(CurrentOwner);
}
}
catch (Exception ex)
{
Log.Error("Error in CheckProgramOwner POST Request - " + ex.Message, ex);
NewRelic.Api.Agent.NewRelic.NoticeError("Error in CheckProgramOwner POST Request - " + ex.Message, null);
return Content(HttpStatusCode.InternalServerError, "Internal Server Error. Please Contact Admin.");
}
}
If you read the document previously posted by Casey, you will find a link to the following document, which explains how to implement and register an exception filter globally:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/error-handling/exception-handling#registering_exception_filters
You could then implement your logging logic in the filter's body thus avoiding having to repetitively log errors on each try/catch. I would suggest logging the more obvious errors using your original approach and use the filter to log any other errors (that you might not expect.)
I did it using ExceptionFilter.
I created Exception Filter Class as below -
public class MyExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
log4net.ThreadContext.Properties["addr"] = HttpContext.Current.Request.UserHostAddress;
log4net.ThreadContext.Properties["Hostname"] = Dns.GetHostName().ToString();
log4net.ThreadContext.Properties["PCName"] = Dns.GetHostAddresses(Environment.MachineName)[0].ToString();
string RequestMethod = context.Request.Method.Method;
dynamic ControllerInfo = context.ActionContext.ControllerContext.Controller;
string RequestName = ControllerInfo.Url.Request.RequestUri.LocalPath.ToString().Replace("/api/", "").Replace("/VVFAPI", "");
Log.Error("Error in " + RequestName +" "+ RequestMethod+ " Request - " + context.Exception.Message, context.Exception);
NewRelic.Api.Agent.NewRelic.NoticeError("Error in " + RequestName + " " + RequestMethod + " Request - " + context.Exception.Message, null);
HttpResponseMessage msg = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("Internal Server Error. Please Contact Admin."),
ReasonPhrase = "Critical Exception."
};
context.Response = msg;
}
}
Also, I changed my controller accordingly
[HttpPost]
[Authorize]
[ValidateModel]
[MyExceptionFilter]
[Route("CheckProgramOwner")]
public async Task<IHttpActionResult> CheckProgramOwner([FromBody] CheckProgramOwner _data)
{
Log.Info("CheckProgramOwner POST Request");
using (var db = new VisualVoiceFlowEntities())
{
var Result = await db.VVF_ScriptFlow.Where(s => s.ProgramId == _data.ProgramId).OrderByDescending(s => s.ID).FirstOrDefaultAsync();
if (Result == null)
{
Log.Error("Error in CheckProgramOwner POST Request - " + "ProgramId not found");
return Content(HttpStatusCode.BadRequest, "ProgramId not found");
}
string CurrentOwner = Result.ReadBy.ToString();
return Ok(CurrentOwner);
}
}
I'm having an issue with sending a POST request for Pinterest in a UWP app I'm working on. I already have the access code from a previous WebAuthenticationBroker function. I've tried using the WebAuthenticationBroker with the UseHttpPost option under options with authenticating async, but, as I've provided my if functions, it returns ERROR. I just get a "message": "405: Method Not Allowed" and "type" : "http". I've looked all over, I've even tried using an HttpClient and PostAsync(), but I couldn't get it to get the access token. Any advise to what I'm doing wrong?
private void OutputToken(string TokenUri)
{
int tokenString = TokenUri.IndexOf('=');
string TheTokenUri = TokenUri.Substring(tokenString + 54);
PinterestReturnedTokenText.Text = TheTokenUri;
outputToken = TheTokenUri;
}
private async void auth()
{
try
{
string CallbackUrl = "https://localhost/";
string PinterestUrl = "https://api.pinterest.com/v1/oauth/token?grant_type=authorization_code&client_id=" + PinterestClientID + "&client_secret=" + PinterestClientSecret + "&code=" + outputCode;
Uri StartUri = new Uri(PinterestUrl);
Uri EndUri = new Uri(CallbackUrl);
WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.UseHttpPost, StartUri, EndUri);
if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
{
OutputToken(WebAuthenticationResult.ResponseData.ToString());
await GetPinterestNameAsync(WebAuthenticationResult.ResponseData.ToString());
}
else if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
{
OutputToken("HTTP Error returned by AuthenticateAsync() : " + WebAuthenticationResult.ResponseErrorDetail.ToString());
}
else
{
OutputToken("Error returned by AuthenticateAsync() : " + WebAuthenticationResult.ResponseStatus.ToString());
}
}
catch (Exception Error)
{
PinterestReturnedTokenText.Text = "ERROR";
}
}
So I've been working for a couple days attempting to create a working example of an application grabbing data, such as a list of the user's contacts, and display it. My attempts so far have be unsuccessful. I have followed a few guides and have read many forums but I can't seem to get them to work.
I got the feeling I have one of the following issues.
Either my application or I do not have the proper permissions on my employer's domain
I am missing a concept
I have a grammatical error in my code.
I have incorrect settings in portal.azure.com or manage.windowsazure.com for my application
As for the where my asp.net project kept breaking here is the code, look at var authResult = await authContext.AcquireTokenSilentAsync(discServResouceId, cc, userid);. I got the original from here AuthenticationHelper
internal class AuthenticationHelper
{
internal static async Task<OutlookServicesClient> EnsureOutlookServicesClientCreatedAsync(string capabilityName)
{
var signInUserId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
var userObjectId =
ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
var authContext = new AuthenticationContext(SettingsHelper.Authority, new ADALTokenCache(signInUserId));
try
{
var discClient = new DiscoveryClient(SettingsHelper.DiscoveryServiceEndpointUri,
async () =>
{
var cid = SettingsHelper.ClientId;
var appkey = SettingsHelper.AppKey;
var discServResouceId = SettingsHelper.DiscoveryServiceResourceId;
var cc = new ClientCredential(cid, appkey);
var userid = new UserIdentifier(userObjectId, UserIdentifierType.UniqueId);
var authResult = await authContext.AcquireTokenSilentAsync(discServResouceId, cc, userid);
//AcquireTokenSilentAsync is where my application throws an
//AdalException with the error code "AdalError.FailedToAcquireTokenSilently"
return authResult.AccessToken;
});
var dcr = await discClient.DiscoverCapabilityAsync(capabilityName);
return new OutlookServicesClient(dcr.ServiceEndpointUri,
async () =>
{
var authResult = await authContext.AcquireTokenSilentAsync(dcr.ServiceResourceId,
new ClientCredential(SettingsHelper.ClientId,
SettingsHelper.AppKey),
new UserIdentifier(userObjectId,
UserIdentifierType.UniqueId));
return authResult.AccessToken;
});
}
catch (AdalException exception)
{
//Handle token acquisition failure
if (exception.ErrorCode == AdalError.FailedToAcquireTokenSilently)
{
Debug.Print(exception.ErrorCode);
authContext.TokenCache.Clear();
//throw exception;
}
return null;
}
catch (Microsoft.Office365.Discovery.DiscoveryFailedException ex)
{
Debug.Print(ex.Message);
return null;
}
}
}
As far as I know everything is being given to AcquireTokenSilentAsync correctly. For that reason I think it's a permission issue with active directory. Any help is appreciated.
i'm new to Live SDK and i'm trying to use it to connect to a user's profile and get data from it
i have read about it and used the following code to login to user's account
private async void btnSignin_SessionChanged(object sender, LiveConnectSessionChangedEventArgs e)
{
if (e.Status == LiveConnectSessionStatus.Connected)
{
session = e.Session;
client = new LiveConnectClient(session);
try
{
LiveAuthClient auth = new LiveAuthClient(btnSignin.ClientId);
//LiveLoginResult initializeResult = await auth.InitializeAsync();
try
{
LiveLoginResult loginResult = await auth.LoginAsync(new string[] { "wl.basic" });
if (loginResult.Status == LiveConnectSessionStatus.Connected)
{
LiveConnectClient connect = new LiveConnectClient(auth.Session);
LiveOperationResult operationResult = await connect.GetAsync("me");
dynamic result = operationResult.Result;
if (result != null)
{
this.infoTextBlock.Text = string.Join(" ", "Hello", result.name, "!");
}
else
{
this.infoTextBlock.Text = "Error getting name.";
}
}
}
catch (LiveAuthException exception)
{
this.infoTextBlock.Text = "Error signing in: " + exception.Message;
}
catch (LiveConnectException exception)
{
MessageBox.Show("Error calling API: " + exception.Message);
}
}
catch (LiveAuthException exception)
{
this.infoTextBlock.Text = "Error initializing: " + exception.Message;
}
}
else
{
client = null;
}
}
it logs in on my emulator and one of my 2 lumia 620 devices but with the other device it gives me the following Exception
**
*> {client_error: Microsoft.Live.LiveConnectException: Exception of type
'Microsoft.Live.LiveConnectException' was thrown. at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at PhoneApp2.MainPage.d__6.MoveNext()}*
**
I followed a 43 minute video tutorial on the Channel 9 site and read the LiveConnect page where it shows code and I don't see what I'm doing wrong. It keeps giving me a NullReferenceException error and it doesn't even bring up the "Do you want to allow app X to access skydrive" thing, it just breaks immediately. I've set breakpoints everywhere but there is nothing. Just null, null everywhere.
OnNavigatedTo event:
LoadProfile();
private async void LoadProfile()
{
try
{
LiveAuthClient auth = new LiveAuthClient();
LiveLoginResult loginResult = await auth.LoginAsync(new string[] { "wl.basic" });
if (loginResult.Status == LiveConnectSessionStatus.Connected)
{
this.pageTitle.Text = "Signed in.";
}
}
catch (LiveAuthException exception)
{
this.pageTitle.Text = "Error signing in: " + exception.Message;
}
}
And the exception says:
I finally found a solution.
Subscribe to a button-click event or whatever, then use this code:
LoadProfile();
which calls this method:
public async void LoadProfile()
{
try
{
LiveAuthClient auth = new LiveAuthClient();
LiveLoginResult initializeResult = await auth.InitializeAsync();
try
{
LiveLoginResult loginResult = await auth.LoginAsync(new string[] { "wl.basic" });
if (loginResult.Status == LiveConnectSessionStatus.Connected)
{
LiveConnectClient connect = new LiveConnectClient(auth.Session);
LiveOperationResult operationResult = await connect.GetAsync("me");
dynamic result = operationResult.Result;
if (result != null)
{
this.pageTitle.Text = string.Join(" ", "Hello", result.name, "!");
}
else
{
this.pageTitle.Text = "Error getting name.";
}
}
}
catch (LiveAuthException exception)
{
this.pageTitle.Text = "Error signing in: " + exception.Message;
}
catch (LiveConnectException exception)
{
this.pageTitle.Text = "Error calling API: " + exception.Message;
}
}
catch (LiveAuthException exception)
{
this.pageTitle.Text = "Error initializing: " + exception.Message;
}
}
Before you debug, add your app to the Windows Store Dashboard. Then go back to Visual Studio, find Package.appxmanifest in Solution Explorer and add the Internet Capability. Then go to the Project menu > Store > Associate App with the Store.
Find your app's name in the list of apps that appears, select it and click Next/Finish and then debug. It should now be working.
Please try this code instead of yours:
LiveAuthClient auth = new LiveAuthClient();
LiveLoginResult loginResult = await auth.InitializeAsync(new string[] { "wl.basic" });
if ( loginResult.Status == LiveConnectSessionStatus.Connected )
{
LiveConnectClient connect = new LiveConnectClient( auth.Session );
...